Началось в:мой блог
предисловие
Начиная с версии 5.4, PHP предоставляет встроенный веб-сервер.
Это в основном используется для местного развития. Нельзя использовать в онлайн-среде. Теперь я расскажу, как использовать этот инструмент.
Базовое приложение
Сначала мы предполагаем, что каталог проекта/home/baoguoxiao/www/php/demo
, доступный извне каталог/home/baoguoxiao/www/php/demo/public
. Затем доступ к порту8000
, входной файлindex.php
а такжеindex.html
. Затем мы можем выполнить следующую команду:
cd /home/baoguoxiao/www/php/demo/public
php -S localhost:8000
Затем вы можете получить к нему доступ в обычном режиме.
Так вот теперь вопрос, обязательно каждый раз входить?public
Папка для запуска веб-сервера, на самом деле мы можем указать корневой каталог, тогда мы можем использовать следующую команду:
cd /home/baoguoxiao/www/php/demo
php -S localhost:8000 -t public/
Итак, теперь есть проблема, если мы используем одну запись и все еще используем режим PATHINFO. Тогда может быть проблема с вышеперечисленным.
Для этого можно использовать следующую схему:
cd /home/baoguoxiao/www/php/demo
php -S localhost:8000 router.php
Код файла router.php
/**
* 对URL进行解析,并获取请求的文件名
*/
$uri = urldecode(parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH));
/**
* 判断是否存在该文件,如果不存在,则直接继续加载入口文件
*/
if ($uri !== "/" && file_exists(__DIR__ . "$uri")) {
return false;
}
/**
* 加载入口文件
*/
require_once "./index.php";
С помощью этого файла маршрутизации мы можем поддерживать текущую общую ситуацию разработки.
ссылка на кадр
Приведенный выше метод является нашей собственной реализацией, тогда мы также можем посмотреть на методы реализации связанных известных фреймворков.
Например, Laravel и Symfony.
Laravel
в ЛаравелеУстановитьВ этом разделе описывается команда, которая разрешает внешний доступ с помощью встроенного в PHP веб-сервера. Реализованная команда:
php artisan serve
Мы можем взглянуть на соответствующий код:
Конкретный путь к файлу: vendor/laravel/framework/src/Illuminate/Foundation/Console/ServeCommand.php.
/**
* 执行命令.
*
* @return int
*
* @throws \Exception
*/
public function handle()
{
// 切换路径到 public 目录
chdir(public_path());
// 在命令台进行输出相关内容
$this->line("<info>Laravel development server started:</info> <http://{$this->host()}:{$this->port()}>");
// 执行外部程序,并且 $status 为系统的返回状态
passthru($this->serverCommand(), $status);
// $status 为0 表示执行正常, 为其他大于0的数字表示出现了错误,有可能是端口被抢占了,这个时候就会接着判断是否进行再次尝试
if ($status && $this->canTryAnotherPort()) {
// 对绑定的端口号加1 默认是8000, 如果失败则重试端口号为8001,再次失败重试端口号为8002,以此类推。
$this->portOffset += 1;
// 再次调用此程序
return $this->handle();
}
// 返回状态值
return $status;
}
/**
* 获取完整的 server 命令.
*
* @return string
*/
protected function serverCommand()
{
return sprintf('%s -S %s:%s %s',
// 获取PHP可执行命令的路径
ProcessUtils::escapeArgument((new PhpExecutableFinder)->find(false)),
// 获取需要绑定的host
$this->host(),
// 获取需要绑定的端口
$this->port(),
// 对需要执行的参数进行转义处理。这里的 server 就是我们之前说的路由文件,它在项目的根路径下
ProcessUtils::escapeArgument(base_path('server.php'))
);
}
Переведите приведенную выше команду, она фактически выполняется
cd ./public
php -S 0.0.0.0:8000 ../server.php
note:
Здесь мы видим разницу в том, что в коде, который я написал ранее, хост — это локальный хост, а здесь — 0.0.0.0. В чем разница между этими двумя?
На самом деле разница очень проста: например, IP-адрес, привязанный к локальному хосту, равен 127.0.0.1, что эквивалентно петлевому адресу, поэтому мы разрешаем доступ только по IP-адресу локальной машины. А 0.0.0.0 означает, что мы не ограничиваем IP, и все IP доступны.
Затем давайте посмотрим на корневую директорию проекта.server.php
:
/**
* Laravel - A PHP Framework For Web Artisans
*
* @package Laravel
* @author Taylor Otwell <taylor@laravel.com>
*/
$uri = urldecode(
parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)
);
// 这个文件允许我们从内置 PHP web 服务器中模拟 Apache 的 "mod_rewrite" 功能.
// 这提供了一种测试 Laravel 应用程序的便捷方法,
// 而无需在此安装"真正的" web 服务器软件。
if ($uri !== '/' && file_exists(__DIR__.'/public'.$uri)) {
return false;
}
require_once __DIR__.'/public/index.php';
Выяснилось, что файл маршрутизации, который я написал ранее, тот же самый. Да, скопировал отсюда.
В основном это то, как Ларвел это реализует.
Symfony
Если вы используете фреймворк Symfony, вы обнаружите, что в Symfony есть компонент с именемweb-server-bundle, функция этого компонента такая же, как и у Laravel, а также возможен доступ к приложению через браузер без помощи веб-сервера.
Основные операции могут относиться кэта страница
Здесь я в основном рассказываю о том, как реализован Symfony.
В Symfony есть такой фрагмент кода:
public function start(WebServerConfig $config, $pidFile = null)
{
// 获取默认的PID文件位置
$pidFile = $pidFile ?: $this->getDefaultPidFile();
// 判断是否在运行,如果运行则提示已经在监听了
if ($this->isRunning($pidFile)) {
throw new \RuntimeException(sprintf('A process is already listening on http://%s.', $config->getAddress()));
}
// fork了一个子进程,如果成功,会有两个进程进行同时执行下面的文件,父进程,也就是当前执行的进程会返回子进程的PID,而子进程则返回的PID为0,
// 如果失败,则子进程不会创建,并且父进程会返回的pid为-1。更多内容可查看 https://www.php.net/manual/zh/function.pcntl-fork.php
$pid = pcntl_fork();
// 表示fork进程失败
if ($pid < 0) {
throw new \RuntimeException('Unable to start the server process.');
}
// 进入这个判断,表示执行的是父进程,表示不用继续向下执行
if ($pid > 0) {
return self::STARTED;
}
// 从此往后是子进程运行,首先通过 posix_setsid 变为守护进程,意思是使其脱离终端的管理,自立门户,谁也没办法管理这个进程,除了PID。
if (posix_setsid() < 0) {
throw new \RuntimeException('Unable to set the child process as session leader.');
}
// 创建命令,命令类似Laravel,不过这里的路由文件跟Laravel类似。也是处理加载规则,并加载入口文件。具体的router.php 路径为:
// vendor\symfony\web-server-bundle/Resources/router.php
// 下面是禁用输出并且开始运行
$process = $this->createServerProcess($config);
$process->disableOutput();
$process->start();
// 判断是否运行成功
if (!$process->isRunning()) {
throw new \RuntimeException('Unable to start the server process.');
}
// 写入PID文件
file_put_contents($pidFile, $config->getAddress());
// 检测PID文件,如果PID文件删除了,那么进程就立即退出。
while ($process->isRunning()) {
if (!file_exists($pidFile)) {
$process->stop();
}
sleep(1);
}
// 返回停止的状态
return self::STOPPED;
}
/**
* 启动PHP内置web服务器
* @return Process The process
*/
private function createServerProcess(WebServerConfig $config)
{
// 查找PHP的可执行程序
$finder = new PhpExecutableFinder();
if (false === $binary = $finder->find(false)) {
throw new \RuntimeException('Unable to find the PHP binary.');
}
$xdebugArgs = ini_get('xdebug.profiler_enable_trigger') ? ['-dxdebug.profiler_enable_trigger=1'] : [];
// 实例化PHP要执行的命令 php_path -dvariables_order=EGPCS -S 127.0.0.1:8000 vendor\symfony\web-server-bundle/Resources/router.php
$process = new Process(array_merge([$binary], $finder->findArguments(), $xdebugArgs, ['-dvariables_order=EGPCS', '-S', $config->getAddress(), $config->getRouter()]));
// 设置工作目录
$process->setWorkingDirectory($config->getDocumentRoot());
// 设置超时时间
$process->setTimeout(null);
// 设置环境变量
if (\in_array('APP_ENV', explode(',', getenv('SYMFONY_DOTENV_VARS')))) {
$process->setEnv(['APP_ENV' => false]);
$process->inheritEnvironmentVariables();
}
// 返回相关变量
return $process;
}
В приведенном выше коде я прокомментировал, как запускается Symfony.
Есть проблема с использованиемpcntl_fork
, это расширение не поддерживается в Windows, поэтому фреймворк Symfony предложит использоватьphp bin/console server:run
команда для запуска программы.
перспективы на будущее
На самом деле есть другой способ, то есть Workman — это реализованный сам веб-сервер, он не использует помощьphp -S
Заказ. Я не полностью понял код этой части, и я думаю, что это также можно обсудить в нескольких главах. Надеюсь на такую возможность в будущем.
Суммировать
Благодаря нашему изучению команд PHP для достижения доступа к веб-серверу и анализу фреймворков Laravel и Symfony я узнал, что в процессе разработки Windows мы можем полностью избавиться от зависимости от веб-сервера с помощью этого метода.Это удобно для нас в среде Windows. Развивайте и изучайте навыки в PHP. Это приятно.
Если у вас есть какие-либо вопросы по этому поводу, пожалуйста, не стесняйтесь комментировать.