PHP組み込みWebサーバー

步履不停
步履不停オリジナル
2019-06-19 10:11:227962ブラウズ

PHP組み込みWebサーバー

まえがき

PHP は 5.4 以降、組み込み Web サーバーを提供しています。

これは主にローカル開発に使用されます。オンライン環境ではご利用いただけません。今回はこのツールの使い方を紹介します。

基本的なアプリケーション

最初に、プロジェクト ディレクトリが /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
これで、現時点では通常どおりアクセスできるようになります。

そこで質問がありますが、Web サーバーを起動するたびに

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

Laravel の

インストール セクションでは、PHP 組み込み Web サーバーを使用して外部アクセスを実現できるコマンドが紹介されています。実装されたコマンドは次のとおりです:

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:

ここで違いがわかります。これは、以前に書いたコードです。 , hostsは全てlocalhostですが、ここに書かれているのは0.0.0.0です。これら 2 つの違いは何ですか?

実際、違いは非常に単純です。たとえば、前に書いたローカルホストにバインドされている 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';
を見てみましょう。これが、私が作成したルーティング ファイルと同じであることを確認してください。前に。はい、ここからコピーしました。

基本的には、これが Larvel の実装方法です。

Symfony

Symfony フレームワークを使用している場合、Symfony には

web-server-bundle というコンポーネントがあり、このコンポーネントは Laravel と同じ機能を持っています。 Web サーバーを使用すると、ブラウザーを介してアプリケーションにアクセスできます。

基本的な操作については、

このページを参照してください。

ここでは主に 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(&#39;Unable to start the server process.&#39;);
    }

    // 进入这个判断,表示执行的是父进程,表示不用继续向下执行
    if ($pid > 0) {
        return self::STARTED;
    }

    // 从此往后是子进程运行,首先通过 posix_setsid 变为守护进程,意思是使其脱离终端的管理,自立门户,谁也没办法管理这个进程,除了PID。
    if (posix_setsid() < 0) {
        throw new \RuntimeException(&#39;Unable to set the child process as session leader.&#39;);
    }

    // 创建命令,命令类似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 コマンドを使用するように求めるメッセージを表示します。

将来の Outlook

実は、別の方法があります。つまり、Workman は独自に実装された Web サーバーであり、

php -S コマンドに依存しません。私はコードのこの部分を完全には理解していませんが、これについてはいくつかの別の章で説明できると思います。将来的にはこのような機会があれば幸いです。

まとめ

Web サーバーへのアクセスを実現するための PHP コマンドの学習と、Laravel および Symfony フレームワークの分析を通じて、Windows の開発プロセスでこの方法を完全に使用できることを学びました。 Web サーバーへの依存を取り除くことで、Windows 環境での開発が容易になるだけでなく、PHP のスキルを学ぶこともできます。これはとても良いことです。

これについて質問がある場合は、コメントしてください。

その他の PHP 関連の技術記事については、

PHP チュートリアル # 列にアクセスして学習してください。

以上がPHP組み込みWebサーバーの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。