Windows, Mac 및 Linux 데스크톱 운영 체제 용 HTML, CSS, JavaScript 및 PHP로 작성된 가벼운 설치 가능한 응용 프로그램을 만듭니다.

PHP 앱 서버로 생성 할 수있는 것은 기존 데스크톱 애플리케이션 개발과 비교할 때 생성하는 데 시간이 많이 걸리는 실제 설치 가능한 소프트웨어 응용 프로그램입니다. 아이디어/개념에서 1/10 시간에 아이디어/개념에서 전체 배포로 이동하여 하나의 코드베이스만으로 모든 주요 데스크톱 OS를 지원하십시오.

PHP App Server는 전통적인 데스크탑 OS 환경에서 사용되도록 특별히 설계된 사용자 정의 기능을 갖춘 PHP로 작성된 완벽하고 확장 가능한 웹 서버입니다. 사용자가 시작 메뉴, 애플리케이션 런처 등을 통해 소프트웨어를 실행하면 소프트웨어가 서버를 시작한 다음 사용자의 선호하는 웹 브라우저를 시작하여 응용 프로그램에 액세스합니다. Web Browser는 백엔드에 전원을 공급하는 반면 웹 브라우저는 사용자 인터페이스를 표시하는 모든 Nitty Gritty 세부 사항을 처리합니다. 기성품 설치 프로그램 스크립트는 사용자의 컴퓨터 시스템으로 전달하기 위해 최종 릴리스 패키지를 작성하는 프로세스를 단순화합니다.
최신 소프트웨어 릴리스를 다운로드하거나 복제하십시오. 복제 할 때는 개발을 시작하기 전에 포크를 사용하고 앱의 지점을 만들어야합니다. 그렇게하면 PHP 앱 서버 자체에 대한 업스트림 업데이트를 가져올 때마다 실수로 소프트웨어를 덮어 쓰는 것을 피할 수 있습니다.
이 가이드의 나머지 부분에서는 최근 버전의 PHP가 설치된 것으로 가정합니다. 그렇게하는 방법에는 여러 가지가 있습니다.
명령 줄에서 다음을 실행하여 명령 줄 옵션 목록을 얻으십시오.
php server.php -?
실행하여 포트 9002에서 웹 서버를 시작하십시오.
php server.php -port=9002
PHP 앱 서버의 디렉토리 구조는 다음과 같습니다.
server.php 가 작동 해야하는 파일이 포함되어 있습니다. 'www'디렉토리에서 index.php 파일 생성 :
<?php
phpinfo ();웹 브라우저를 사용하여 실행중인 서버에 연결하십시오.
http://127.0.0.1:9002/
phpinfo() 의 출력은 브라우저에 표시되며 요청 결과는 명령 줄에 기록됩니다.
URL을 다음으로 변경합니다.
http://127.0.0.1:9002/api/v1/account/info
동일한 index.php 파일이 실행됩니다.
index.php 파일을 api.php 로 이름을 바꾸거나 복사하고 페이지를 다시로드하십시오. 이제 api.php 호출되고 있습니다. PHP App Server의 Virtual Directory 기능은 애플리케이션을 개발할 때 유용 할 수있는 것입니다.
설치된 소프트웨어 응용 프로그램은 'www'에 쓸 수 없습니다. 응용 프로그램은 일반적으로 시스템의 권한있는 사용자가 설치하지만 소프트웨어를 실행하는 사람은 일반적으로 'www'디렉토리에 쓸 수있는 충분한 권한이 없습니다. PHP 앱 서버를 사용하여 소프트웨어 응용 프로그램을 개발하면서 명심해야 할 중요한 고려 사항입니다. 다행히도 서버에 이미 내장 된이 문제에 대한 해결책이 있습니다 : 듀얼 문서 루츠.
Application의 'www'디렉토리에서 PHP 코드가 실행될 때 PHP 앱 서버 환경에 의해 전달되고 고유 한 5 $_SERVER 변수에 액세스 할 수 있습니다.
DOCUMENT_ROOT_USER 의 상위 디렉토리. 또한 작성할 수 있지만 URL에서는 참조 할 수 없습니다. 응용 프로그램에 대한 개인 데이터를 저장하는 데 유용합니다 (예 : SQLITE 데이터베이스).server.php 가있는 위치). support 서브 디렉토리에서 파일에 액세스하는 데 유용합니다. 웹 서버에 요청이 이루어지면 PHP 앱 서버는 Application의 'www'디렉토리에서 파일을 먼저 찾습니다. 파일을 찾지 못하면 DOCUMENT_ROOT_USER 로 지정된 경로의 파일을 확인합니다.
웹 브라우저에 의존하는 LocalHost 서버 응용 프로그램을 작성하면 데이터 제어 손실에서 사용자 파일 시스템 손상에 이르기까지 심각한 시스템 보안 위반이 발생할 수 있습니다. 응용 프로그램이 올바르게 작성되는 한 웹 브라우저의 정책은 일반적으로 PHP 앱 서버 제어 콘텐츠에 액세스하려는 악의적 인 웹 사이트 및 사용자로부터 사용자를 보호합니다.
그러나 모든 PHP 앱 서버 기반 소프트웨어 애플리케이션이 적극적으로 방어 해야하는 몇 가지 중요한 보안 관련 항목이 있습니다.
$_SERVER["PAS_USER_FILES"] 또는 사용자 정의 위치를 사용하여 $_SERVER["DOCUMENT_ROOT_USER"] 대신에 민감한 사용자 데이터를 저장하기 위해 사용하십시오. 민감한 것으로 간주 할 수 있는지 항상 사용자에게 어떻게 해야하는지 물어보십시오 (예 : 사용자에게 확인란을 표시하는 것만 큼 간단 할 수 있습니다). 프라이버시 중심의 개인은 일반적으로 마음을 말할 것입니다.$_SERVER["PAS_SECRET"] Cubiclesoft Admin Pack 또는 기타 응용 프로그램 프레임 워크와 결합 하여이 문제를 처리하는 데 도움이됩니다. 서버 확장자는 일반적으로 $_SERVER["PAS_SECRET"] 를 기반으로 한 인증 토큰이 필요합니다.OWASP Top 10 목록과 OWASP 공격 목록에도 다른 보안 고려 사항이 많이 있지만 큰 사람이지만 큰 것입니다.
PHP App Server에는 PHP 및 JavaScript에서 장기 실행 프로세스를 쉽고 안전하게 시작, 관리 및 모니터링하기위한 강력한 서버 확장과 2 개의 SDK가 포함되어 있습니다. 시작 프로세스는 PHP 앱 서버가 실행 중이지만 일반 CGI/FASTCGI 요청과 같은 시간 초과 또는 메모리 제한으로 제한되지 않는 사용자로 실행됩니다. 실행중인 프로세스는 포함 된 JavaScript SDK를 통해 웹 브라우저에서 적극적으로 모니터링하고 상호 작용할 수 있습니다.

장기 실행 스크립트는 메인 PHP 앱 서버 '지원'디렉토리의 '스크립트'하위 디렉토리에 이상적으로 저장되어야합니다. 이렇게하면 기본 웹 루트에서 멀리 떨어져 있지만 응용 프로그램은 여전히 $_SERVER["PAS_ROOT"] 를 통해 찾을 수 있습니다.
다음은 PHP SDK를 사용하여 'test.php'라는 PHP 스크립트를 시작하는 예입니다.
<?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. " ;
?>각 프로세스에는 태그가 주어 지므로 여러 실행 프로세스를 태그로 그룹화 할 수 있습니다. 위의 예에서 태그를 "데모"라고합니다. JavacsRipt SDK는 나중에 특정 태그를 사용하는 프로세스 만 표시하는 데 사용될 수 있습니다.
<?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>PHP SDK는 필요한 CSS 및 JAVScript 종속성을 HTML로 방출하는 것을 단순화합니다. 위의 코드는 PHP App Server 확장에 대한 WebSocket 연결을 설정하고 "Demo"태그로 프로세스를 모니터링하기 위해 TerminalManager 인스턴스에 연결하는 것을 보여줍니다. TerminalManager는 입력 기준에 따라 하나 이상의 execterminals (또한 포함)를 자동으로 생성하고 관리하는 포함 된 JavaScript 클래스입니다. 이 경우 TerminalManager는 "데모"태그로 생성 된 모든 프로세스에 자동으로 첨부됩니다. execterminal은 다음과 같습니다.

각 Execterminal은 추가 기능으로 XTERM.JS 터미널 인스턴스를 마무리합니다.
그리고 더.
TerminalManager 및 Execterterminal은 장기 실행 프로세스를 관리하는 데 필요하지 않지만 몇 가지 일반적인 시나리오를 처리합니다. 위의 예제 코드는 수행 할 수있는 것의 표면 만 긁습니다.
다음은 TerminalManager 옵션의 전체 목록입니다.
포함 된 XTREM PHP 클래스는 장기 실행 스크립트에서 브라우저의 Xterm 호환 execterminal 로의 출력에 대한 원활하고 단순화 된 제어를 제공합니다. ANSI 탈출 코드를 기억할 필요가 없습니다. 다음은 예제 스크립트입니다.
<?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" ;
?>마지막으로 Cubiclesoft Admin Pack 또는 FlexForms를 사용하여 응용 프로그램을 구축하는 경우 PHP SDK에는 기본 Flexforms 통합이 포함되어 있습니다 (즉, 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 );
?> 연장을 작성하려면 PHP 앱 서버의 작동 방식에 대한 약간의 지식이 필요합니다. 시작 중에 확장이 조기에로드되어 필요한 경우 시작 시퀀스에 참여할 수 있습니다 (주로 보안 관련 확장). 웹 서버가 시작되면 모든 웹 요청은 확장 목록을 따라 걸어 "이 요청을 처리 할 수 있습니까?"라고 묻습니다. 확장자가 긍정적으로 응답하면 (즉, 진실이 반환), 나머지 요청은 처리 할 확장으로 전달됩니다.
확장은 Core Server와 직접 인라인으로 실행되므로 상당한 성능 향상을 받고 WebSocket을 통해 응답하거나 정상적인 PHP 경로에 의해 30 초 후에 일반적으로 죽을 장기적으로 실행되는 프로세스를 시작할 수 있습니다.
그러나 이러한 이점에는 두 가지 주요 단점이 있습니다. 첫 번째는 확장자가 데치가 예외를 제기하거나 다른 방식으로 추락하면 전체 웹 서버를 사용한다는 것입니다. 두 번째는 코드를 확장으로 변경하려면 변경 사항을 테스트하기 위해 웹 서버를 다시 시작해야한다는 것입니다. 이는 약간 번거 로움이 될 수 있습니다. 일반적으로, 정상적인 'www'경로는 대부분의 요구에 충분하며 확장은 때때로 전문 논리의 세그먼트를위한 것입니다.
포함 된 보안 토큰 확장은 요청을 올바르게 처리 할 수있는 확장을 구축하기위한 훌륭한 출발점입니다. 보안 토큰 확장은 상당히 짧고 잘 작성되었으며 작동합니다.
서버는 파일 이름이 클래스 이름의 일부라고 가정합니다. PHP 파일의 이름이 무엇이든간에 클래스 이름은 따라야합니다. 그렇지 않으면 PHP App Server가 확장을로드하지 못합니다. 확장자 이름은 숫자로 시작해야하며, 이는 확장자를 호출 할 것으로 예상되는 순서를 나타냅니다.
일반 PHP 스크립트에서 사용할 수있는 변수는 글로벌 $baseenv 변수 (예 : $baseenv["DOCUMENT_ROOT_USER"] 및 $baseenv["PAS_USER_FILES"] ]를 통해 확장 프로그램도 사용할 수 있습니다. 나머지 응용 프로그램에 부정적인 영향을 미치기 때문에 $baseenv 값을 변경하지 마십시오.
확장 내에서 외부, 장기 실행 프로세스를 시작할 때 항상 ProcessHelper::StartProcess() 정적 함수를 사용하십시오. ProcessHelper 클래스는 모든 플랫폼에서 백그라운드에서 비 블로킹 프로세스를 시작하도록 설계되었습니다. 장기적으로 실행되는 프로세스를 시작하는 선호하는 방법은 장기 실행 프로세스 확장을 사용하는 것입니다.
특정 작업의 경우 PHP 앱 서버에게 종료하도록 지시하는 것이 중요합니다. 예를 들어, Windows에서 PHP 앱 서버 응용 프로그램을 업그레이드 할 때는 PHP 자체를 업데이트해야하므로 업그레이드 중에 실행할 수 없습니다. 또한 마지막 브라우저 탭이 닫힌 후 너무 오래 걸리지 않고 응용 프로그램을 종료하는 것도 일반적으로 좋은 행동입니다.
서버의 조기 종료를 트리거하는 두 가지 방법이 있습니다.
/exit-app/ 에 대한 authtoken 연결과 JSON 객체에서 서버를 종료하기 위해 2 초를 지정하는 JSON 객체에서 delay 보냅니다. 일단 사용되면, 앱의 모든 페이지는 서버를 살아있게하려면 /exit-app/ 에 연결해야합니다. 최소 3 초의 지연이 권장됩니다. 웹 브라우저는 페이지를 떠나거나 탭이 닫히 자마자 WebSocket 연결을 떨어 뜨리는 경향이 있습니다.X-Exit-App 헤더를 보내십시오. 헤더의 값은 서버를 종료하기 위해 대기하는 정수 수입니다. 최소 3 초의 지연이 권장됩니다. 이 특수 헤더는 웹 브라우저로 전달되지 않고 내부적으로 처리됩니다.출구 앱 확장 방법의 PHP 코드 예 :
<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>헤더 메소드의 PHP 코드 예 :
<?php
// User clicked an "Exit application" link or something.
header ( " X-Exit-App: 3 " );
?>확장자는 애플리케이션에 대한 모든 브라우저 탭이 닫혔다는 것을 감지하는보다 신뢰할 수있는 방법입니다. 그러나 응용 프로그램이 어떤 이유로 확장을 지원할 수없는 경우 대신 헤더 메소드를 사용하십시오. 헤더 방법은 의미가있는 페이지에서 가장 잘 사용됩니다 (예 : 업그레이드 정보가 포함 된 페이지).
설치 프로그램 패키지를 생성하는 다양한 스크립트를 실행하기 전에 다양한 파일을 생성, 이름을 바꾸거나 수정해야합니다. "YourApp"으로 시작하는 모든 파일의 이름을 응용 프로그램 이름으로 바꿔야하며, 바람직하게는 모든 소문자 AZ 및 하이픈으로 제한됩니다. 이를 통해 소프트웨어에 대한 업데이트가 실수로 작업을 덮어 쓰지 않도록해야하며 디렉토리 구조를 중심으로 한 코가 "yourApp"대신 응용 프로그램의 실제 이름을 볼 수 있도록해야합니다.
'YourApp.phpapp'파일은 웹 서버 (Server.php)를 시작한 다음 사용자의 웹 브라우저를 시작하는 실제 애플리케이션 시작 시퀀스를 수행하는 PHP 파일입니다. 파일에는 응용 프로그램의 요구에 맞게 수정 해야하는 $options 배열이 있습니다.
마지막 세 가지 옵션은 고도로 전문화 된 시나리오를위한 것입니다. "127.0.1.1"과 같은 것으로 '호스트'를 변경하는 것은 괜찮을 수 있지만 "0.0.0.0"또는 ":: 0"을 사용하지 않으며, 이는 서버를 네트워크 인터페이스에 공개적으로 바인딩합니다. 특정 '포트'번호에 바인딩하면 응용 프로그램을 다시 시작하려고 할 때 사용자가 오류 메시지에 대해 불평하기 시작할 때까지 좋은 아이디어처럼 보일 수 있습니다.
'Quitdelay'옵션은 흥미 롭습니다. PHP 앱 서버의 서버 부분은 마지막 클라이언트가 연결이 끊어진 후 'Quitdelay'몇 분까지 계속됩니다. 응용 프로그램은 5 분마다 "하트 비트"요청을 보내서 사용자가 애플리케이션을 사용하여 웹 서버가 종료되지 않도록해야합니다.
각 플랫폼 포장 도구에는 자체 지침이 있습니다.
xdg-utils (gnome, kde, xfce 등)를 지원하는 Freedesktop.org-Compliant Window Manager가 필요합니다.알려진 포장 문제가 있습니다.
설치자와 서버 소프트웨어에는 그 뒤에 흥미로운 이야기가 있습니다. 어쩌면 나는 언젠가 그 이야기를 나누겠습니다. 지금은 PHP 앱 서버에서 다음 애플리케이션을 구축하십시오!