从PHP5.4开始,PHP内置了一个Web服务器。它虽然不是一个功能齐全的Web服务器,但是可以很好的在开发环境中使用,避免了开发环境对于Nginx、Apache等Web服务器的依赖。
路由脚本
<?php
use \Throwable;
use \Exception;
// 根目录
$root = $_SERVER['DOCUMENT_ROOT'];
// 使用抛异常方式来处理错误,中断程序的同时,避免整个进程终止
class HTTPException extends Exception
{
public function __construct($code = 400, $message = '')
{
parent::__construct($message, $code);
}
}
function abort($status) {
throw new HTTPException($status);
}
try {
// url path
$path = '/' . ltrim(parse_url($_SERVER['REQUEST_URI'])['path'], '/');
// 绝对路径
$abs = $root . $path;
// 访问文件直接引入
if (is_file($abs)) {
if (strpos($abs, '.php') !== false) {
require_once $abs;
return true;
} else if (strpos($abs, '.sqlite') !== false) {
abort(403);
} else {
return false;
}
}
// 文件夹的情况需要处理路径的标准化,否则html使用的相对链接会有问题
if (is_dir($abs)) {
// 标准化url
if ( substr($path, -1) !== '/' ) {
header('location:' . $path . '/');
exit;
}
// 没有index.php禁止访问
if (!is_file($abs . '/index.php')) {
return false;
}
require_once $abs . '/index.php';
return true;
}
// 其他所有情况都交给根目录的index.php处理
require_once $root . '/index.php';
return true;
} catch (HTTPException $e) {
http_response_code($e->getCode());
return true;
} catch (Throwable $e) {
error_log('catch: ' . $e->getMessage());
return false;
}
运行命令
php -S 0.0.0.0:9000 -t /var/www/html -c php.ini route.php
-S 监听地址
-t 根目录
-c 配置文件
如果希望多进程运行,在PHP 7.4及以上的版本中可以通过设置PHP_CLI_SERVER_WORKERS环境变量来指定运行的进程数量。
关于PHP内置服务器的更多信息,可以参考官方文档: PHP: Built-in web server