内置 Web Server

警告

该 Web 服务器目的是帮助应用程序开发。还可用于测试目的或在受控环境中运行的应用程序演示。但并不是一个功能齐全的 Web 服务器。不应该在公共网络上使用。

CLI SAPI 提供了内置的 Web 服务器。

Web 服务器仅运行一个单线程进程,因此如果堵塞了请求,PHP 应用程序将停止运行。

URI 请求将从启动 PHP 的当前工作目录提供服务,除非使用 -t 选项指定文档根目录。如果 URI 请求未指定文件,则返回指定目录中的 index.php 或 index.html。如果两个文件都不存在,则将在父目录中继续查找 index.php 和 index.html,依此类推,直到找到一个文件或到达文档根目录。如果找到 index.php 或 index.html,则将其返回,并将 $_SERVER['PATH_INFO'] 设置为 URI 的尾部部分。否则将返回 404 响应代码。

如果在命令行上启动 Web 服务器时指定了 PHP 文件,则会将其视为“router”脚本。该脚本在每个 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 开始,内置 Web 服务器可以配置为派生多个工作线程,以便测试需要向内置 Web 服务器发出多个并发请求的代码。在启动服务器之前,将 PHP_CLI_SERVER_WORKERS 环境变量设置为所需的 worker 数量。

注意:

此功能不支持 Windows。

警告

此实验功能不适用于生产用途。通常,内置 Web 服务器不适合生产用途。

示例 #1 启动 Web 服务器

$ 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

在 URI 请求 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

请注意,在 PHP 7.4.0 之前,在 Windows 上无法访问符号链接的静态资源,除非 router 脚本可以处理这些资源。

示例 #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 使用 router 脚本

在此示例中,请求图像将显示图片,但对 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 Web 服务器的使用

要在使用 CLI Web 服务器开发期间以及稍后使用生产 Web 服务器重复使用的框架 router 脚本:

<?php
// router.php
if (php_sapi_name() == 'cli-server') {
    /* 发送静态资源并返回 false */
}
/* 继续正常的 index.php 操作 */
?>
$ php -S localhost:8000 router.php

示例 #5 处理不支持的文件类型

如果需要提供不由 CLI Web 服务器处理的静态资源的 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 Web 服务器

可以通过以下方式使 Web 服务器可通过端口 8000 接受任何链接:

$ php -S 0.0.0.0:8000
警告

内置 Web 服务器不应该在公共网络上使用。

+添加备注

用户贡献的备注 9 notes

up
125
jonathan at reinink dot ca
12 years ago
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()).
up
80
Mark Simon
10 years ago
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.
up
53
oan at vizrt dot com
9 years ago
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.
up
31
tamas at bartatamas dot hu
12 years ago
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
up
32
Ivan Ferrer
13 years ago
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.
up
27
matthes at leuffen dot de
10 years ago
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>";
?>
up
17
deep at deepshah dot me
6 years ago
Listen on all addresses of IPv4:
php -S 0.0.0.0:80

Listen on all addresses of IPv6:
php -S [::0]:80
up
-2
aroian at naiora dot fr
1 month ago
If you use a router script and a custom docroot the order of the parameters matters !

cd /path/to/project
php -S localhost:8000 router.php -t dist

In this case $_SERVER['DOCUMENT_ROOT'] is '/path/to/project'

While with

php -S localhost:8000 -t dist router.php

$_SERVER['DOCUMENT_ROOT'] is '/path/to/project/dist'

The argument parser seems to stop when it encounters router script positional argument.

This is especially important when you want to let the webserver handle files that exist by returning `false`.
up
0
sony at sony-ak dot com
6 years ago
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