Windows、Mac、およびLinuxデスクトップオペレーティングシステム向けに、HTML、CSS、JavaScript、およびPHPで記述された軽量のインストール可能なアプリケーションを作成します。

PHP App Serverで作成できるものは、従来のデスクトップアプリケーション開発と比較した場合に作成に時間がかかるリアルでインストール可能なソフトウェアアプリケーションです。アイデア/コンセプトから完全な展開に移動して、1/10の時間で、1つのコードベースですべての主要なデスクトップOSをサポートします。

PHP App Serverは、従来のデスクトップOS環境で使用されるように特別に設計されたカスタム機能を備えたPHPで記述された完全に機能した拡張可能なWebサーバーです。ユーザーがスタートメニュー、アプリケーションランチャーなどを介してソフトウェアを実行すると、ソフトウェアはサーバーを起動し、ユーザーの優先Webブラウザーを起動してアプリケーションにアクセスします。 PHPはバックエンドに動きますが、Webブラウザはユーザーインターフェイスを表示するすべての核心の詳細を処理します。既製のインストーラースクリプトは、ユーザーのコンピューターシステムに配信するための最終リリースパッケージを作成するプロセスを簡素化します。
最新のソフトウェアリリースをダウンロードまたはクローンします。クローニングするときは、開発を開始する前に、フォークを使用してアプリ用のブランチを作成してください。そうすることで、PHP App Server自体のアップストリームアップデートを取得するたびに、誤ってソフトウェアを上書きすることができません。
このガイドの残りの部分では、PHPの最近のバージョンがインストールされると想定されています。それを実現するには多くの方法があります。
コマンドラインから、次のように実行して、コマンドラインオプションのリストを取得します。
php server.php -?
実行して、ポート9002でWebサーバーを開始します。
php server.php -port=9002
PHPアプリサーバーのディレクトリ構造は次のとおりです。
server.phpが操作するために必要なファイルが含まれています。 'www'ディレクトリでindex.phpファイルを作成します。
<?php
phpinfo ();Webブラウザで実行中のサーバーに接続してください。
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の仮想ディレクトリ機能は、アプリケーションを開発するときに役立つと思われるものです。
インストールされているソフトウェアアプリケーションは、「www」に書き込むことができません。アプリケーションは通常、システム上の特権ユーザーによってインストールされますが、ソフトウェアを実行している人は通常、「www」ディレクトリに書き込むのに十分なアクセス許可を持っていません。これは、PHP App Serverを使用してソフトウェアアプリケーションを開発する際に留意するための重要な考慮事項です。幸いなことに、サーバーにすでに組み込まれているこの問題に対する解決策があります:デュアルドキュメントルーツ。
PHPコードがアプリケーションの「www」ディレクトリから実行されている場合、PHP App Server環境に渡され、固有の5つの$_SERVER変数にアクセスできます。
DOCUMENT_ROOT_USERの親ディレクトリ。また書くこともできますが、URLで参照することはできません。アプリケーションのプライベートデータの保存に役立ちます(例:SQLiteデータベース)。server.phpが存在する場合)。 supportディレクトリ内のファイルにアクセスするのに役立ちます。 Webサーバーにリクエストが行われると、PHP App Serverは、アプリケーションの「www」ディレクトリのファイルを最初に検索します。そこにファイルが見つからない場合は、 DOCUMENT_ROOT_USERで指定されたパス内のファイルをチェックします。
Webブラウザに依存するLocalHost Serverアプリケーションを作成すると、データ制御の損失からユーザーのファイルシステムの損傷に至るまで、深刻なシステムセキュリティ違反が発生する可能性があります。アプリケーションが正しく記述されている限り、Webブラウザのポリシーは一般に、PHP App Server制御のコンテンツにアクセスしようとする悪意のあるWebサイトやユーザーからユーザーを保護します。
ただし、ここにいくつかの重要な、すべてのPHPアプリサーバーベースのソフトウェアアプリケーションが積極的に防御しなければならない(重要な順に)選択されたセキュリティ関連項目をいくつか紹介します。
$_SERVER["PAS_USER_FILES"]またはユーザー定義の場所を使用して、 $_SERVER["DOCUMENT_ROOT_USER"]の代わりに敏感なユーザーデータを保存します。何かが敏感であると考えるかもしれない場合は、常にユーザーに何をすべきか尋ねます(例えば、ユーザーにチェックボックスを表示するのと同じくらい簡単です)。プライバシー中心の個人は一般に心を話すでしょう。$_SERVER["PAS_SECRET"]とCubicalsoft管理パックまたはその他のアプリケーションフレームワークを組み合わせて、この問題の処理に役立ちます。サーバー拡張機能には、通常、 $_SERVER["PAS_SECRET"]に基づく認証トークンも必要です。OWASPトップ10リストとOWASP攻撃リストにある他の多くのセキュリティ上の考慮事項も覚えていますが、それらは大きなものです。
PHP App Serverには、強力なサーバー拡張機能と2つのSDKが含まれており、PHPとJavaScriptの両方から簡単かつ安全に開始、管理、および監視します。 PHPアプリサーバーが実行されているが、通常のCGI/FastCGIリクエストのようなタイムアウトまたはメモリ制限によって制限されていないユーザーとして開始プロセスが実行されます。実行中のプロセスは、積極的に監視され、含まれているJavaScript SDKを介してWebブラウザーからやり取りすることもできます。

長期にわたるスクリプトは、理想的には、メインPHPアプリサーバー「サポート」ディレクトリから「スクリプト」サブディレクトリに保存する必要があります。そうすれば、それらはメインのWebルートから離れていますが、アプリケーションは$_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接続のセットアップを示し、それをTerminalManagerインスタンスに接続して、「デモ」タグでプロセスを監視しています。 TerminalManagerは、入力基準に基づいて1つ以上のエクセクタミナル(また含まれている)を自動的に作成および管理するJavaScriptクラスを含む含まれています。この場合、TerminalManagerは、「デモ」タグで作成されたプロセスに自動的に添付されます。エクセクターミナルは次のようになります:

各エクセクターミナルは、追加機能を備えたXterm.js端末インスタンスをまとめます。
もっと。
ターミナルマネージャーとエクセクターミナルは、長期にわたるプロセスを管理するために必要ではありませんが、かなりのいくつかの一般的なシナリオを処理していることに注意してください。上記の例のコードは、できることの表面を引っ掻くだけです。
ターミナルマネージャーオプションの完全なリストは次のとおりです。
含まれているXterm PHPクラスは、ブラウザの長期にわたるスクリプトからXterm互換のXecterminalへの出力に対するシームレスで簡素化された制御を提供します。 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" ;
?>最後に、Cubicalsoft 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 App Serverの仕組みについて少し知識が必要です。スタートアップ中に拡張機能が早い段階でロードされるため、必要に応じてスタートアップシーケンスに参加できる(主にセキュリティ関連の拡張機能のためだけに)。 Webサーバーが開始されたら、すべてのWebリクエストが拡張機能のリストを通過し、「このリクエストを処理できますか?」と尋ねます。拡張機能が肯定で応答した場合(つまり、真実を返す)、リクエストの残りの部分は拡張機能に渡されて処理されます。
拡張機能はコアサーバーと直接インラインで実行されるため、大幅なパフォーマンスブーストを得て、通常のPHPパスによって30秒後に殺される通常の長いランニングプロセスを開始するなどのことを行うことができます。
ただし、これらの利点には2つの大きな欠点があります。 1つ目は、拡張機能が無作法な例外を引き起こすか、そうでなければクラッシュする場合、Webサーバー全体にそれを使用することです。 2つ目は、拡張機能にコードを変更するには、変更をテストするためにWebサーバーを再起動する必要があることです。これは少し手間がかかる可能性があります。一般に、通常の「www」パスはほとんどのニーズには十分であり、拡張機能は特殊なロジックの時折のセグメントに適しています。
含まれるセキュリティトークン拡張機能は、リクエストを適切に処理できる拡張機能を構築するための優れた出発点です。セキュリティトークンの拡張機能は、かなり短く、適切に対応されており、機能しています。
サーバーは、ファイル名がクラス名の一部であると想定しています。 PHPファイルの名前が何であれ、クラス名は訴訟に従う必要があります。そうしないと、PHP App Serverは拡張機能のロードに失敗します。拡張名は数字で始まる必要があります。これは、拡張機能を呼び出す予定の順序を示します。
通常のPHPスクリプトで利用可能な変数は、グローバル$baseenv変数( $baseenv["DOCUMENT_ROOT_USER"]および$baseenv["PAS_USER_FILES"] )を介して拡張機能にも使用できます。 $baseenv値を変更しないでください。これは、アプリケーションの残りの部分に悪影響を与えるためです。
拡張機能内で外部の長期にわたるプロセスを開始するときに、 ProcessHelper::StartProcess()静的関数を常に使用します。 ProcessHelperクラスは、すべてのプラットフォームでバックグラウンドで非ブロッキングプロセスを開始するように設計されています。長期にわたるプロセスを開始するための好ましい方法は、長期にわたるプロセス拡張機能を使用することであることに注意してください。
特定のタスクについては、PHPアプリサーバーに終了するように指示することが重要です。たとえば、WindowsでPHP App Serverアプリケーションをアップグレードする場合、PHP自体を更新する必要があるため、アップグレード中に実行できません。また、最後のブラウザタブが閉じてからそれほど長く後にアプリケーションを終了することは、一般的に良い動作です。
サーバーの早期終了をトリガーするための2つの利用可能な方法があります。
/exit-app/へのWebSocket接続を確立し、有効なauthtokenとJSONオブジェクトのdelay送信して、サーバーを終了するのを待つ秒数を指定します。使用すると、アプリのすべてのページが/exit-app/に接続して、サーバーを生かし続ける必要があります。最低3秒遅延をお勧めします。 Webブラウザーは、ページを離れるか、タブが閉じられるとすぐにWebSocket接続をドロップする傾向があります。X-Exit-Appヘッダーを送信します。ヘッダーの値は、サーバーを終了するのを待つ整数秒数です。最低3秒遅延をお勧めします。この特別なヘッダーは、Webブラウザに渡されるのではなく、内部で処理されます。Exitアプリ拡張法の例の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」ファイルは、Web Server(server.php)を起動してからユーザーのWebブラウザーを起動する実際のアプリケーションスタートアップシーケンスを実行するPHPファイルです。ファイルには、アプリケーションのニーズに合わせて変更する必要がある$optionsアレイがあります。
最後の3つのオプションは、高度に専門化されたシナリオを対象としています。 「ホスト」を「127.0.1.1」のようなものに変更するのは大丈夫かもしれませんが、「0.0.0.0」または「:: 0」を使用しないでください。特定の「ポート」番号にバインドすると、ユーザーがアプリケーションを再起動しようとすると、ユーザーがエラーメッセージについて不平を言うまで良い考えのように思えるかもしれません。
「quitdelay」オプションは興味深いです。 PHP App Serverのサーバー部分は、最後のクライアントが切断されてから数分後に「Quitdelay」まで固執します。アプリケーションは、5分ごとに「ハートビート」リクエストを送信して、ユーザーがアプリケーションを使用して完了する前にWebサーバーが終了しないことを保証する必要があります。
各プラットフォームパッケージツールには、独自の指示があります。
xdg-utils (GNOME、KDE、XFCEなどをサポートするFreedSktop.orgに準拠したウィンドウマネージャーが必要です。既知のパッケージングの問題がいくつかあります:
インストーラーとサーバーソフトウェアには、それらの背後にいくつかの興味深い物語があります。いつかそれらの話を共有するかもしれません。とりあえず、PHP App Serverで次のアプリケーションを構築してください!