2024年PHP日本大会

内置Web服务器

警告

此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文件,则将其视为“路由器”脚本。该脚本在每个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环境变量设置为所需的工作进程数。

注意此功能在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

在对https://127.0.0.1:8000/和https://127.0.0.1:8000/myscript.html的URI请求之后,终端将显示类似以下内容

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上不可访问。

示例 #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文件的请求将显示“欢迎使用PHP”

<?php
// router.php
if (preg_match('/\.(?:png|jpg|jpeg|gif)$/', $_SERVER["REQUEST_URI"])) {
return
false; // 按原样提供请求的资源。
} else {
echo
"<p>欢迎使用PHP</p>";
}
?>
$ php -S localhost:8000 router.php

示例 #4 检查CLI Web服务器的使用

在使用CLI Web服务器进行开发以及稍后与生产Web服务器一起使用时,重用框架路由器脚本

<?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服务器。

添加注释

用户贡献的注释 10条注释

jonathan at reinink dot ca
10年前
为了设置项目特定的配置选项,只需将php.ini文件添加到您的项目中,然后使用此标志运行内置服务器

php -S localhost:8000 -c php.ini

这对于无法在运行时设置的设置(ini_set())尤其有用。
Mark Simon
8年前
虽然没有直接提及,也可能不太明显,但您也可以用它来创建一个虚拟主机。当然,这需要用到您的hosts文件。

步骤如下:

1. 编辑 /etc/hosts 文件
127.0.0.1 www.example.com

2. 进入项目根目录:
php -S www.example.com:8000

4. 浏览器访问:
http://www.example.com:8000/index.php

结合简单的SQLite数据库,您就拥有了一个非常方便的测试环境。
oan at vizrt dot com
7年前
我痛苦地经历了一些这里似乎没有记录的行为,所以我希望通过以下提示来避免大家重蹈覆辙。

在Mac(在我的情况下是macOS Sierra)上使用`php -S`启动本地服务器时,我遇到了与旧版Java连接的问题。

事实证明,如果您使用以下命令启动PHP服务器:
"php -S localhost:80"
服务器将仅以IPv6支持模式启动!

要通过IPv4访问它,您需要更改启动命令,如下所示:
"php -S 127.0.0.1:80"
这将仅以IPv4模式启动服务器。
tamas at bartatamas dot hu
10年前
如果您的URI包含点号,在使用内置Web服务器时,您将丢失`$_SERVER['PATH_INFO']`变量。
我想编写一个API,并在URI中使用“.json”结尾,但是框架的路由机制却坏了,而发现其原因花费了我大量时间,因为它依赖于`$_SERVER['PATH_INFO']`。

参考资料
https://bugs.php.net/bug.php?id=61286
matthes at leuffen dot de
8年前
要在命令行上输出调试信息,您可以将输出写入`php://stdout`。

<?php
$path
= $_SERVER["SCRIPT_FILENAME"];

file_put_contents("php://stdout", "\nRequested: $path");
echo
"<p>Hello World</p>";
?>
Ivan Ferrer
11年前
在Windows上,您可能会发现将包含以下内容的`phpserver.bat`文件添加到shell:sendto中很有用:
explorer https://127.0.0.1:8888
rem 检查参数是文件还是目录
if exist "%~1\" (
php -S localhost:8888 -t "%~1"
) else (
php -S localhost:8888 -t "%~dp1"
)

) 这样,对于快速的Web测试,您只需将文件或文件夹“发送到”此bat文件,它就会打开您的浏览器并运行服务器。
deep at deepshah dot me
4年前
监听所有IPv4地址:
php -S 0.0.0.0:80

监听所有IPv6地址:
php -S [::0]:80
sony at sony-ak dot com
4年前
要发送环境变量到PHP内置web服务器,请键入如下命令:

~$ MYENV=dev php -d variables_order=EGPCS -S 0.0.0.0:8000

在PHP脚本中,您可以使用以下代码进行检查:

<?php
echo getenv('MYENV'); // 输出 dev
dachund at gmail dot com
6年前
我尝试使用内置web服务器,但在处理不包含点号和文件扩展名的静态文件时遇到了问题。

对于URI类似于“/testfile”的文件,web服务器返回200状态码,但没有任何内容。

我不确定这是否是bug,但我创建了一个router.php,它现在不再使用“return false;”操作来传递内置web服务器的静态文件。

我改用fpassthru()来处理。

此外,我的router.php可以配置为:
- ... 请求目录时使用特定的index文件
- ... 配置正则表达式路由,以便如果REQUEST_URI匹配正则表达式,则请求特定的文件或目录。(类似于nginx配置或.htaccess ModRewrite)

也许有人会觉得这很有用。

================================

<?php

$indexFiles
= ['index.html', 'index.php'];
$routes = [
'^/api(/.*)?$' => '/index.php'
];

$requestedAbsoluteFile = dirname(__FILE__) . $_SERVER['REQUEST_URI'];

// 检查请求是否匹配已定义的路由之一
foreach ($routes as $regex => $fn)
{
if (
preg_match('%'.$regex.'%', $_SERVER['REQUEST_URI']))
{
$requestedAbsoluteFile = dirname(__FILE__) . $fn;
break;
}
}

// 如果请求的是目录,则检查index文件是否存在
if (is_dir($requestedAbsoluteFile))
{
foreach (
$indexFiles as $filename)
{
$fn = $requestedAbsoluteFile.'/'.$filename;
if (
is_file($fn))
{
$requestedAbsoluteFile = $fn;
break;
}
}
}

// 如果请求的文件不存在或为目录 => 404
if (!is_file($requestedAbsoluteFile))
{
header($_SERVER['SERVER_PROTOCOL'].' 404 Not Found');
printf('"%s" does not exist', $_SERVER['REQUEST_URI']);
return
true;
}

// 如果请求的文件不是php文件
if (!preg_match('/\.php$/', $requestedAbsoluteFile)) {
header('Content-Type: '.mime_content_type($requestedAbsoluteFile));
$fh = fopen($requestedAbsoluteFile, 'r');
fpassthru($fh);
fclose($fh);
return
true;
}

// 如果请求的文件是php文件,则包含它
include_once $requestedAbsoluteFile;
devoldemar
11个月前
内置Web服务器使用SAPI日志子系统。因此,所有消息都写入标准错误流,而不是标准输出流。
如果要将服务器日志保存到文件中,可以使用以下命令:
php -S 0.0.0.0:80 2>&1 | tee out.log
To Top