ビルトインウェブサーバー
このウェブサーバーは、アプリケーション開発の支援用として設計されたものです。 テスト用に使ったり、制約のある環境でアプリケーションをデモするために使ったりすることもできるでしょう。 あらゆる機能を兼ね備えたウェブサーバーを目指したものではないので、 公開ネットワーク上で使ってはいけません。
CLI SAPI にはウェブサーバーの機能が組み込まれています。
このウェブサーバーは単一のシングルスレッドプロセスしか実行しないので、 リクエストがブロックされると、PHP アプリケーションはストールします。
URI リクエストの処理は、PHP を開始した時点の作業ディレクトリから行われます。 -t オプションを使えば、ドキュメントルートを明示的に指定することができます。 URI リクエストにファイルが含まれない場合は、指定したディレクトリにある index.php あるいは index.html を返します。どちらも存在しない場合は、 親ディレクトリにさかのぼって index.php と index.html を探します。 どちらか一方が見つかるか、あるいはドキュメントルートに達するまでこれが続きます。 index.php あるいは index.html が見つかるとそれを返し、 $_SERVER['PATH_INFO'] が URI の末尾にセットされます。 見つからなかった場合はレスポンスコード 404 を返します。
ウェブサーバーの開始時にコマンドラインで PHP ファイルを指定すると、
そのファイルをウェブサーバーの "ルーター" スクリプトとして使います。
このスクリプトは、各 HTTP リクエストの開始時に動きます。このスクリプトが
false
を返すと、リクエストされたリソースをそのままの形式で返します。
それ以外の場合はスクリプトの出力をブラウザに返します。
以下にあげる拡張子のファイルについては、標準の MIME タイプを返します:
.3gp
, .apk
, .avi
, .bmp
, .css
, .csv
, .doc
, .docx
, .flac
, .gif
, .gz
, .gzip
, .htm
, .html
, .ics
, .jpe
, .jpeg
, .jpg
, .js
, .kml
, .kmz
, .m4a
, .mov
, .mp3
, .mp4
, .mpeg
, .mpg
, .odp
, .ods
, .odt
, .oga
, .ogg
, .ogv
, .pdf
, .png
, .pps
, .pptx
, .qt
, .svg
, .swf
, .tar
, .text
, .tif
, .txt
, .wav
, .webm
, .wmv
, .xls
, .xlsx
, .xml
, .xsl
, .xsd
, .zip
PHP 7.4.0 以降では、ビルトインウェブサーバーに対して複数のリクエストを並列で投げる必要があるテストコードのために、 複数のワーカーをフォークさせるよう設定できるようになりました。 サーバーを起動する前に欲しいワーカーの数を PHP_CLI_SERVER_WORKERS 環境変数に設定してください。
注意: この機能は Windows ではサポートされていません。
この機能は 実験的なもの であり、 本番環境で使うことを意図した機能では ありません。 ビルトインウェブサーバーは本番環境で使うものではありません。
例1 ウェブサーバーの起動
$ cd ~/public_html $ php -S localhost:8000
ターミナルには次のように表示されます。
PHP 5.4.0 Development Server started at Thu Jul 21 10:43:28 2011 Listening on localhost:8000 Document root is /home/me/public_html Press Ctrl-C to quit
http://localhost:8000/ と http://localhost:8000/myscript.html をリクエストした後のターミナルの表示は、 このようになります。
PHP 5.4.0 Development Server started at Thu Jul 21 10:43:28 2011 Listening on localhost:8000 Document root is /home/me/public_html Press Ctrl-C to quit. [Thu Jul 21 10:48:48 2011] ::1:39144 GET /favicon.ico - Request read [Thu Jul 21 10:48:50 2011] ::1:39146 GET / - Request read [Thu Jul 21 10:48:50 2011] ::1:39147 GET /favicon.ico - Request read [Thu Jul 21 10:48:52 2011] ::1:39148 GET /myscript.html - Request read [Thu Jul 21 10:48:52 2011] ::1:39149 GET /favicon.ico - Request read
Windows 環境、かつ PHP 7.4.0 より前のバージョンでは、 ルーティングを行うスクリプトがシンボリックリンク先の静的なリソースを処理しない限り、 それらのリソースにアクセスできませんでした。
例2 ドキュメントルートディレクトリを指定した起動
$ cd ~/public_html $ php -S localhost:8000 -t foo/
ターミナルには次のように表示されます。
PHP 5.4.0 Development Server started at Thu Jul 21 10:50:26 2011 Listening on localhost:8000 Document root is /home/me/public_html/foo Press Ctrl-C to quit
例3 ルータースクリプトの使用
この例では、画像ファイルをリクエストすればそのまま表示し、HTML ファイルをリクエストすると "Welcome to PHP" と表示します。
<?php
// router.php
if (preg_match('/\.(?:png|jpg|jpeg|gif)$/', $_SERVER["REQUEST_URI"])) {
return false; // リクエストされたリソースをそのままの形式で扱います。
} else {
echo "<p>Welcome to PHP</p>";
}
?>
$ php -S localhost:8000 router.php
例4 CLI ウェブサーバーを使っているかどうかのチェック
フレームワークのルータースクリプトを、開発中は CLI ウェブサーバーで使って その後は本番環境のウェブサーバーでも使うという例です。
<?php
// router.php
if (php_sapi_name() == 'cli-server') {
/* 静的コンテンツのルーティングをして false を返します */
}
/* 通常の index.php の処理を続きます */
?>
$ php -S localhost:8000 router.php
例5 未サポートのファイル形式の処理
CLI ウェブサーバーで対応していない MIME タイプの静的リソースを扱うには、このようにします。
<?php
// router.php
$path = pathinfo($_SERVER["SCRIPT_FILENAME"]);
if ($path["extension"] == "el") {
header("Content-Type: text/x-script.elisp");
readfile($_SERVER["SCRIPT_FILENAME"]);
}
else {
return FALSE;
}
?>
$ php -S localhost:8000 router.php
例6 CLI ウェブサーバーへのリモートマシンからのアクセス
ウェブサーバーを、任意のインターフェイスからポート 8000 でアクセスできるようにするには、このようにします。
$ php -S 0.0.0.0:8000
ビルトインウェブサーバーは、公開ネットワークで使うべきではありません。
User Contributed Notes 10 notes
In order to set project specific configuration options, simply add a php.ini file to your project, and then run the built-in server with this flag:
php -S localhost:8000 -c php.ini
This is especially helpful for settings that cannot be set at runtime (ini_set()).
It’s not mentioned directly, and may not be obvious, but you can also use this to create a virtual host. This, of course, requires the help of your hosts file.
Here are the steps:
1 /etc/hosts
127.0.0.1 www.example.com
2 cd [root folder]
php -S www.example.com:8000
3 Browser:
http://www.example.com:8000/index.php
Combined with a simple SQLite database, you have a very handy testing environment.
I painfully experienced behaviour that I can't seem to find documented here so I wanted to save everyone from repeating my mistake by giving the following heads up:
When starting php -S on a mac (in my case macOS Sierra) to host a local server, I had trouble with connecting from legacy Java.
As it turned out, if you started the php server with
"php -S localhost:80"
the server will be started with ipv6 support only!
To access it via ipv4, you need to change the start up command like so:
"php -S 127.0.0.1:80"
which starts server in ipv4 mode only.
If your URI contains a dot, you'll lose the $_SERVER['PATH_INFO'] variable, when using the built-in webserver.
I wanted to write an API, and use .json ending in the URI-s, but then the framework's routing mechanism broke, and it took a lot of time to discover that the reason behind it was its router relying on $_SERVER['PATH_INFO'].
References:
https://bugs.php.net/bug.php?id=61286
To output debugging information on the command line you can write output to php://stdout:
<?php
$path = $_SERVER["SCRIPT_FILENAME"];
file_put_contents("php://stdout", "\nRequested: $path");
echo "<p>Hello World</p>";
?>
On Windows you may find useful to have a phpserver.bat file in shell:sendto with the folowing:
explorer http://localhost:8888
rem check if arg is file or dir
if exist "%~1\" (
php -S localhost:8888 -t "%~1"
) else (
php -S localhost:8888 -t "%~dp1"
)
then for fast web testing you only have to SendTo a file or folder to this bat and it will open your explorer and run the server.
Listen on all addresses of IPv4:
php -S 0.0.0.0:80
Listen on all addresses of IPv6:
php -S [::0]:80
To send environment variable as long as with PHP built-in web server, type like this.
~$ MYENV=dev php -d variables_order=EGPCS -S 0.0.0.0:8000
On PHP script we can check with this code.
<?php
echo getenv('MYENV'); // print dev
I fiddled around with the internal webserver and had issues regarding handling static files, that do not contain a dot and a file extension.
The webserver responded with 200 without any content for files with URIs like "/testfile".
I am not certain if this is a bug, but I created a router.php that now does not use the "return false;" operation in order to pass thru the static file by the internal webserver.
Instead I use fpassthru() to do that.
In addition to that, my router.php can be configured to...
- ... have certain index files, when requesting a directory
- ... configure regex routes, so that, if the REQUEST_URI matches the regex, a certain file or directory is requested instead. (something you would do with nginx config or .htaccess ModRewrite)
Maybe someone finds this helpful.
================================
<?php
$indexFiles = ['index.html', 'index.php'];
$routes = [
'^/api(/.*)?$' => '/index.php'
];
$requestedAbsoluteFile = dirname(__FILE__) . $_SERVER['REQUEST_URI'];
// check if the the request matches one of the defined routes
foreach ($routes as $regex => $fn)
{
if (preg_match('%'.$regex.'%', $_SERVER['REQUEST_URI']))
{
$requestedAbsoluteFile = dirname(__FILE__) . $fn;
break;
}
}
// if request is a directory call check if index files exist
if (is_dir($requestedAbsoluteFile))
{
foreach ($indexFiles as $filename)
{
$fn = $requestedAbsoluteFile.'/'.$filename;
if (is_file($fn))
{
$requestedAbsoluteFile = $fn;
break;
}
}
}
// if requested file does not exist or is directory => 404
if (!is_file($requestedAbsoluteFile))
{
header($_SERVER['SERVER_PROTOCOL'].' 404 Not Found');
printf('"%s" does not exist', $_SERVER['REQUEST_URI']);
return true;
}
// if requested file is'nt a php file
if (!preg_match('/\.php$/', $requestedAbsoluteFile)) {
header('Content-Type: '.mime_content_type($requestedAbsoluteFile));
$fh = fopen($requestedAbsoluteFile, 'r');
fpassthru($fh);
fclose($fh);
return true;
}
// if requested file is php, include it
include_once $requestedAbsoluteFile;
Built-in web server uses SAPI logging subsystem. Therefore all messages are written to standard error, and not to standard output stream.
If you want to save server logs into a file, the following command will work:
php -S 0.0.0.0:80 2>&1 | tee out.log