Cree aplicaciones livianas e instalables escritas en HTML, CSS, JavaScript y PHP para los sistemas operativos de escritorio Windows, Mac y Linux.

Lo que se puede crear con PHP App Server son aplicaciones de software reales e instalables que toman una fracción del tiempo para crear en comparación con el desarrollo tradicional de aplicaciones de escritorio. Vaya de la idea/concepto a la implementación completa en 1/10 el tiempo y admite cada sistema operativo de escritorio importante con una sola base de código.

PHP App Server es un servidor web totalmente ofrecido y extensible escrito en PHP con características personalizadas especialmente diseñadas para ser utilizadas en un entorno tradicional de escritorio. Cuando el usuario ejecuta el software a través de su menú de inicio, lanzador de aplicaciones, etc., el software inicia el servidor y luego inicia el navegador web preferido del usuario para acceder a la aplicación. PHP alimenta el backend, mientras que el navegador web maneja todos los detalles de la esgalencia de la interfaz de usuario. Los scripts de instalador listos simplifican el proceso de creación de paquetes de lanzamiento finales para la entrega a los sistemas informáticos de su usuario.
Descargue o clone la última versión de software. Al clonar, asegúrese de usar un tenedor y crear una rama para su aplicación antes de comenzar a desarrollar. Hacerlo evita sobrescribir accidentalmente su software cada vez que obtiene actualizaciones aguas arriba para el servidor de aplicaciones PHP.
Para el resto de esta guía, se supone que se instala una versión reciente de PHP. Hay muchas maneras de hacer que eso suceda.
Desde una línea de comandos, ejecute lo siguiente para obtener una lista de opciones de línea de comandos:
php server.php -?
Inicie un servidor web en el puerto 9002 ejecutando:
php server.php -port=9002
La estructura del directorio del servidor de aplicaciones PHP es la siguiente:
server.php para operar. Cree un archivo index.php en el directorio 'www':
<?php
phpinfo ();Conéctese al servidor en ejecución con su navegador web en:
http://127.0.0.1:9002/
La salida de phpinfo() se muestra en el navegador y el resultado de la solicitud se escribe en la línea de comandos.
Cambie la URL a:
http://127.0.0.1:9002/api/v1/account/info
Se ejecuta el mismo archivo index.php .
Cambie el nombre o copie el archivo index.php a api.php y vuelva a cargar la página. Ahora se llama a api.php . La función de directorio virtual del servidor PHP App es algo que puede encontrar útil a medida que desarrolla su aplicación.
Las aplicaciones de software instaladas no pueden escribir en 'www'. Las aplicaciones generalmente son instaladas por un usuario privilegiado en el sistema, pero la persona que ejecuta el software generalmente no tendrá permisos suficientes para escribir en el directorio 'www'. Esta es una consideración importante a tener en cuenta al desarrollar una aplicación de software utilizando el servidor PHP App. Afortunadamente, hay una solución a este problema ya integrado en el servidor: raíces de documentos duales.
Cuando el código PHP se está ejecutando desde el directorio 'www' de la aplicación, tiene acceso a cinco variables $_SERVER que se transmiten y son exclusivas del entorno del servidor de aplicaciones PHP:
DOCUMENT_ROOT_USER . También se puede escribir, pero no puede ser referenciado por URL. Útil para almacenar datos privados para la aplicación (por ejemplo, una base de datos SQLite).server.php ). Útil para acceder a archivos en el subdirectorio support . Cuando se realiza una solicitud en el servidor web, el servidor de aplicaciones PHP busca primero archivos en el directorio 'www' de la aplicación. Si no encuentra un archivo allí, luego verifica el archivo en la ruta especificada por DOCUMENT_ROOT_USER .
Escribir una aplicación de servidor localhost que se basa en un navegador web puede dar como resultado graves violaciones de seguridad del sistema que van desde la pérdida de control de datos hasta dañar el sistema de archivos del usuario. Mientras la aplicación se escriba correctamente, las políticas del navegador web generalmente protegerán al usuario de sitios web y usuarios maliciosos que intentan acceder al contenido controlado por el servidor de aplicaciones PHP.
Sin embargo, aquí hay algunos elementos importantes relacionados con la seguridad que todas las aplicaciones de software basadas en el servidor de aplicaciones PHP deben defenderse activamente (en orden de importancia):
$_SERVER["PAS_USER_FILES"] o una ubicación definida por el usuario para almacenar datos de usuario confidenciales en lugar de $_SERVER["DOCUMENT_ROOT_USER"] . Siempre pregunte al usuario qué hacer si podría considerar que algo es sensible (por ejemplo, preguntar podría ser tan simple como mostrar una casilla de verificación al usuario). Las personas centradas en la privacidad generalmente decir lo que piensan.$_SERVER["PAS_SECRET"] combinado con el paquete de administrador de Cubiclesoft u otros marcos de aplicaciones ayudan a manejar este problema. Las extensiones del servidor también generalmente requieren un token de autenticación basado en $_SERVER["PAS_SECRET"] .Hay muchas otras consideraciones de seguridad que están en la lista de los 10 mejores de OWASP y la lista de ataques de OWASP para tener en cuenta, pero esas son las grandes.
PHP App Server incluye una potente extensión del servidor y dos SDK para facilitar el inicio, la administración y el monitoreo de procesos de larga duración y seguros de PHP y JavaScript. Los procesos iniciados se ejecutan como el usuario que el servidor de aplicaciones PHP se ejecuta, pero no está limitado por los tiempos de espera o los límites de memoria como las solicitudes regulares de CGI/FASTCGI. Los procesos de ejecución se pueden monitorear activamente e incluso interactuar desde el navegador web a través del SDK JavaScript incluido.

Idealmente, los scripts de larga duración deberían almacenarse en un subdirectorio de 'scripts' en el directorio de 'soporte' del servidor de aplicaciones PHP principal. De esa manera, están lejos de la raíz web principal, pero la aplicación aún puede encontrarlas a través de $_SERVER["PAS_ROOT"] .
Aquí hay un ejemplo de iniciar un script PHP llamado 'test.php' usando el PHP SDK:
<?php
$ rootpath = str_replace ( "\" , " / " , dirname ( __FILE__ ));
// Load the PHP App Server common functions.
require_once $ _SERVER [ " PAS_ROOT " ] . " /support/process_helper.php " ;
require_once $ _SERVER [ " PAS_ROOT " ] . " /support/pas_functions.php " ;
$ cmd = escapeshellarg ( PAS_GetPHPBinary ());
$ cmd .= " " . escapeshellarg ( realpath ( $ _SERVER [ " PAS_ROOT " ] . " /support/scripts/test.php " ));
$ options = array (
// "rules" => array(
// "start" => time() + 5,
// "maxqueued" => 3
// ),
// "stdin" => false,
// "dir" => $_SERVER["PAS_ROOT"] . "/support/scripts/",
// "env" => ProcessHelper::GetCleanEnvironment(),
// "extraenv" => array("PASSWORD" => "supersecret"),
// "extra" => array(
// "title" => "Custom window title",
// "inputmode" => "readline"
// )
);
// Start the process.
require_once $ rootpath . " /support/pas_run_process_sdk.php " ;
$ rp = new PAS_RunProcessSDK ();
$ result = $ rp -> StartProcess ( " demo " , $ cmd , $ options );
if (! $ result [ " success " ]) echo " An error occurred while starting a long-running process. " ;
echo " Done. " ;
?>Cada proceso recibe una etiqueta, que permite que múltiples procesos de ejecución se agrupen mediante la etiqueta. En el ejemplo anterior, la etiqueta se llama "demostración". El JavacSript SDK se puede usar más tarde para mostrar solo procesos que usan una etiqueta específica:
<?php
header ( " Content-Type: text/html; charset=UTF8 " );
?>
<!DOCTYPE html>
<html>
<body>
<?php
$ rootpath = str_replace ( "\" , " / " , dirname ( __FILE__ ));
require_once $ rootpath . " /support/pas_run_process_sdk.php " ;
PAS_RunProcessSDK:: OutputCSS ();
PAS_RunProcessSDK:: OutputJS ();
?>
<div id="terminal-manager"></div>
<script type="text/javascript">
// NOTE: Always put Javascript RunProcesSDK and TerminalManager class instances in a Javascript closure like this one to limit the XSRF attack surface.
(function() {
// Establish a new connection with a compatible WebSocket server.
var runproc = new RunProcessSDK(' <?= PAS_RunProcessSDK:: GetURL () ?> ', false, ' <?= PAS_RunProcessSDK:: GetAuthToken () ?> ');
// Debugging mode dumps incoming and outgoing packets to the web browser's debug console.
runproc.debug = true;
// Establish a new terminal manager instance.
var elem = document.getElementById('terminal-manager');
// Automatically attach to all channels with the 'demo' tag.
var options = {
tag: 'demo'
};
var tm = new TerminalManager(runproc, elem, options);
})();
</script>
</body>
</html>El PHP SDK simplifica la emisión de las dependencias CSS y Javscript necesarias en el HTML. El código anterior demuestra configurar una conexión WebSocket a la extensión del servidor de aplicaciones PHP y conectarlo a una instancia de TerminalManager para monitorear los procesos con la etiqueta "Demo". TerminalManager es una clase de JavaScript incluida que crea y administra automáticamente uno o más Execerminales (también incluidos) en función de los criterios de entrada. En este caso, TerminalManager se adjuntará automáticamente a cualquier proceso creado con una etiqueta de "demostración". Un EXECMERAL se ve así:

Cada Execerminal envuelve una instancia de terminal Xterm.JS con características adicionales:
Y más.
Tenga en cuenta que TerminalManager y ExecMinal no son necesarios para administrar procesos de larga duración, pero manejan bastantes escenarios comunes. El código de ejemplo anterior solo rasca la superficie de lo que se puede hacer.
Aquí está la lista completa de opciones de TerminalManager:
La clase PHP XMTER incluida ofrece un control perfecto y simplificado sobre la salida de un script de larga duración al EXECMERTAL compatible con Xterm en el navegador. No es necesario recordar los códigos de escape ANSI. Aquí hay un script de ejemplo:
<?php
if (! isset ( $ _SERVER [ " argc " ]) || ! $ _SERVER [ " argc " ])
{
echo " This file is intended to be run from the command-line. " ;
exit ();
}
$ rootpath = str_replace ( "\" , " / " , dirname ( __FILE__ ));
require_once $ rootpath . " /../xterm.php " ;
for ( $ x = 0 ; $ x < 5 ; $ x ++)
{
echo " Test: " . ( $ x + 1 ) . "n" ;
sleep ( 1 );
}
echo " That's boring. Let's... " ;
sleep ( 1 );
XTerm:: SetItalic ();
echo " spice it up! n" ;
XTerm:: SetItalic ( false );
sleep ( 1 );
$ palette = XTerm:: GetBlackOptimizedColorPalette ();
for ( $ x = 5 ; $ x < 10 ; $ x ++)
{
$ num = mt_rand ( 17 , 231 );
XTerm:: SetForegroundColor ( $ palette [ $ num ]);
echo " Test: " . ( $ x + 1 ) . " (Color " . $ palette [ $ num ] . " ) n" ;
sleep ( 1 );
}
XTerm:: SetForegroundColor ( false );
XTerm:: SetTitle ( " Changing the title... " );
usleep ( 250000 );
XTerm:: SetTitle ( " Changing the title...like " );
usleep ( 250000 );
XTerm:: SetTitle ( " Changing the title...like a " );
usleep ( 250000 );
XTerm:: SetTitle ( " Changing the title...like a BOSS! " );
usleep ( 500000 );
echo "n" ;
echo " Enter some text: " ;
$ line = rtrim ( fgets ( STDIN ));
XTerm:: SetBold ();
echo " Here's what you wrote: " . $ line . "nn" ;
XTerm:: SetBold ( false );
echo " [Switching to 'readline_secure' mode] nn" ;
XTerm:: SetCustomInputMode ( ' readline_secure ' );
echo " Enter some more text: " ;
XTerm:: SetColors ( 0 , 0 );
$ line = rtrim ( fgets ( STDIN ));
XTerm:: SetColors ( false , false );
XTerm:: SetCustomInputMode ( ' readline ' );
XTerm:: SetBold ();
echo " Here's what you wrote: " . $ line . "nn" ;
XTerm:: SetBold ( false );
echo " Done. n" ;
?>Finalmente, si usa el paquete de administrador de Cubiclesoft o FlexForms para crear su aplicación, el SDK PHP incluye la integración Native FlexForms (es decir, no es necesario escribir JavaScript/HTML):
<?php
// Admin Pack and FlexForms integration.
require_once " support/pas_run_process_sdk.php " ;
$ contentopts = array (
" desc " => " Showing all long-running processes with the 'demo' tag. " ,
" fields " => array (
array (
" type " => " pas_run_process " ,
// "debug" => true,
" options " => array (
" tag " => " demo "
)
)
)
);
BB_GeneratePage ( " Process Demo " , $ menuopts , $ contentopts );
?> Escribir una extensión requiere un poco de conocimiento sobre cómo funciona el servidor de aplicaciones PHP: las extensiones se cargan desde el principio durante el inicio para que puedan involucrarse en la secuencia de inicio si lo necesitan (principalmente solo para extensiones relacionadas con la seguridad). Una vez que el servidor web ha comenzado, cada solicitud web pasa a través de la lista de extensiones y pregunta: "¿Puede manejar esta solicitud?" Si una extensión responde en la afirmativa (es decir, devuelve verdadero), entonces el resto de la solicitud se pasa a la extensión para manejar.
Dado que las extensiones se ejecutan directamente en línea con el servidor central, obtienen un aumento significativo de rendimiento y pueden hacer cosas como responder a través de WebSocket o comenzar procesos de larga duración que normalmente se matarían después de 30 segundos por la ruta PHP normal.
Sin embargo, esos beneficios vienen con dos inconvenientes principales. El primero es que si una extensión plantea una excepción no captura o se bloquea, se lleva todo el servidor web. El segundo es que hacer cambios en el código en una extensión requiere reiniciar el servidor web para probar los cambios, lo que puede ser un poco complicado. En general, la ruta normal 'www' es suficiente para la mayoría de las necesidades y extensiones son para segmentos ocasionales de lógica especializada.
La extensión de token de seguridad incluida es un excelente punto de partida para construir una extensión que pueda manejar correctamente las solicitudes. La extensión del token de seguridad es bastante corta, bien comentada y funciona.
El servidor asume que el nombre de archivo es parte del nombre de la clase. Como se denomina el archivo PHP, el nombre de clase dentro tiene que seguir su ejemplo, de lo contrario, PHP App Server no cargará la extensión. Los nombres de extensión deben comenzar con un número, lo que indica el orden esperado para llamar a la extensión.
Las variables disponibles para los scripts PHP normales también están disponibles para las extensiones a través de la variable global $baseenv (por ejemplo, $baseenv["DOCUMENT_ROOT_USER"] y $baseenv["PAS_USER_FILES"] ). No altere los valores de $baseenv , ya que afectará negativamente al resto de la aplicación.
Siempre use la función estática ProcessHelper::StartProcess() al comenzar procesos externos de larga duración dentro de una extensión. La clase ProcessHelper está diseñada para comenzar los procesos que no son de bloqueo en el fondo en todas las plataformas. Tenga en cuenta que la forma preferida de iniciar procesos de larga duración es utilizar la extensión de procesos de larga duración.
Para ciertas tareas, es importante decirle al servidor de aplicaciones PHP que salga. Por ejemplo, al actualizar una aplicación de servidor de aplicaciones PHP en Windows, PHP en sí mismo debe actualizarse y, por lo tanto, no se puede ejecutar durante la actualización. En general, también es un buen comportamiento salir de una aplicación no mucho después de que se cierre la última pestaña del navegador.
Hay dos métodos disponibles para activar la terminación temprana del servidor:
/exit-app/ y envíe un authtoken válido y un delay en un objeto JSON que especifica el número de segundos para esperar para terminar el servidor. Una vez utilizada, cada página de la aplicación debe conectarse a /exit-app/ para mantener vivo el servidor. Se recomienda un retraso mínimo de 3 segundos. Los navegadores web tienden a eliminar las conexiones WebSocket tan pronto como salen de la página o la pestaña está cerrada.X-Exit-App en la respuesta de un script PHP. El valor del encabezado es el número entero de segundos para esperar para terminar el servidor. Se recomienda un retraso mínimo de 3 segundos. Este encabezado especial no se pasa al navegador web, sino que se maneja internamente.Ejemplo de código PHP para el método de extensión de la aplicación de salida:
<script type="text/javascript">
// NOTE: Always put WebSocket class instances in a Javascript closure like this one to limit the XSRF attack surface.
( function () {
function InitExitApp ()
{
var ws = new WebSocket ((window.location.protocol === ' https: ' ? ' wss:// ' : ' ws:// ' ) + window.location.host + ' /exit-app/ ' );
ws. addEventListener ( ' open ' , function ( e ) {
var msg = {
authtoken: ' <?=hash_hmac("sha256", "/exit-app/", $_SERVER["PAS_SECRET"])?> ' ,
delay: 3
};
ws. send ( JSON . stringify (msg));
});
ws. addEventListener ( ' close ' , function ( e ) {
setTimeout (InitExitApp, 500 );
});
}
InitExitApp ();
})();
</script>Ejemplo de código PHP para el método de encabezado:
<?php
// User clicked an "Exit application" link or something.
header ( " X-Exit-App: 3 " );
?>La extensión es un método más confiable para detectar que todas las pestañas del navegador a la aplicación se han cerrado. Sin embargo, si la aplicación no puede admitir la extensión por alguna razón, use el método de encabezado en su lugar. El método de encabezado se usa mejor en páginas donde tiene sentido (por ejemplo, una página con información de actualización).
Antes de ejecutar los diversos scripts que generan paquetes de instalación, se deben crear, renombrar y modificar varios archivos varios archivos. Cada archivo que comience con "YourApp" debe cambiar el nombre al nombre de su aplicación, preferiblemente restringido a todos los AZ y guiones en minúsculas. Esto debe hacerse para que las actualizaciones del software no sobrescriban accidentalmente su trabajo y que cualquier usuario entrometido que se burle de la estructura del directorio vea el nombre real de la aplicación en lugar de "YourApp".
El archivo 'YourApp.PhpApp' es un archivo PHP que realiza la secuencia de inicio de la aplicación real de iniciar el servidor web (server.php) y luego iniciar el navegador web del usuario. Hay una matriz $options en el archivo que debe modificarse para las necesidades de su aplicación:
Las últimas tres opciones están destinadas a escenarios altamente especializados. Cambiar 'host' a algo como "127.0.1.1" podría estar bien, pero no use "0.0.0.0" o ":: 0", lo que une el servidor públicamente a la interfaz de red. Vinificar a un número específico de 'puerto' puede parecer una buena idea hasta que los usuarios comiencen a quejarse de los mensajes de error cuando intentan reiniciar la aplicación.
La opción 'Quitdelay' es interesante. La parte del servidor del servidor de aplicaciones PHP se quedará hasta 'QuitDelay' minutos después de que el último cliente se desconecte. La aplicación debe enviar una solicitud "Heartbeat" cada cinco minutos para garantizar que el servidor web no se terminará antes de que el usuario termine utilizando la aplicación.
Cada herramienta de embalaje de plataforma tiene sus propias instrucciones:
xdg-utils (GNOME, KDE, XFCE, etc. están bien).Hay algunos problemas de empaque conocidos:
Los instaladores y el software del servidor tienen algunos cuentos interesantes detrás de ellos. Quizás comparta esas historias algún día. ¡Por ahora, disfruta de la creación de su próxima aplicación en el servidor de aplicaciones PHP!