Heim  >  Artikel  >  Backend-Entwicklung  >  In PHP integrierter Webserver

In PHP integrierter Webserver

步履不停
步履不停Original
2019-06-19 10:11:227814Durchsuche

In PHP integrierter Webserver

Vorwort

PHP stellt seit 5.4 einen integrierten Webserver bereit.

Dies wird hauptsächlich für die lokale Entwicklung verwendet. Kann nicht in Online-Umgebungen verwendet werden. Jetzt werde ich Ihnen die Verwendung dieses Tools vorstellen.

Basisanwendung

Zuerst gehen wir davon aus, dass das Projektverzeichnis /home/baoguoxiao/www/php/demo und das für die Außenwelt zugängliche Verzeichnis /home/baoguoxiao/www/php/demo/public ist. Dann ist der Port, auf den zugegriffen wird, 8000 und die Eintragsdateien sind index.php und index.html. Dann können wir den folgenden Befehl ausführen:

cd /home/baoguoxiao/www/php/demo/public
php -S localhost:8000

Dann können Sie normal darauf zugreifen.

Jetzt stellt sich die Frage: Ist es notwendig, jedes Mal den Ordner public einzugeben, um den Webserver zu starten? Tatsächlich können wir das Stammverzeichnis angeben und dann den folgenden Befehl verwenden:

cd /home/baoguoxiao/www/php/demo
php -S localhost:8000 -t public/

Jetzt stellt sich also die Frage, ob wir einen einzelnen Eintrag verwenden und trotzdem den PATHINFO-Modus verwenden. Dann liegt möglicherweise ein Problem mit dem oben Gesagten vor.

Hierfür können wir die folgende Lösung verwenden:

cd /home/baoguoxiao/www/php/demo
php -S localhost:8000 router.php

Code der router.php-Datei

/**
 * 对URL进行解析,并获取请求的文件名
 */$uri = urldecode(parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH));/**
 * 判断是否存在该文件,如果不存在,则直接继续加载入口文件
 */if ($uri !== "/" && file_exists(__DIR__ . "$uri")) {    return false;
}/**
 * 加载入口文件
 */require_once "./index.php";

Durch diese Routing-Datei können wir derzeit häufig verwendete Entwicklungssituationen unterstützen.

Framework-Referenz

Die obige Methode ist unsere eigene Implementierung, daher können wir uns auch die Implementierungsmethoden verwandter bekannter Frameworks ansehen.

Wie Laravel und Symfony.

Laravel

Im Abschnitt Installation in Laravel wird ein Befehl eingeführt, um externen Zugriff über den in PHP integrierten Webserver zu erreichen. Der implementierte Befehl lautet:

php artisan serve

Wir können einen Blick auf den relevanten Code werfen:

Der spezifische Dateipfad lautet: 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'))
    );
}

Übersetzen Sie den obigen Befehl, er wird tatsächlich ausgeführt

cd ./public
php -S 0.0.0.0:8000 ../server.php

Hinweis:

Hier können wir einen Unterschied sehen, nämlich den Code, den ich zuvor geschrieben habe. , Hosts sind alle localhost, aber was hier geschrieben steht, ist 0.0.0.0. Was ist der Unterschied zwischen diesen beiden?

Tatsächlich ist der Unterschied sehr einfach. Die an localhost gebundene IP ist beispielsweise 127.0.0.1. Dies entspricht einer Loopback-Adresse, daher erlauben wir nur den Zugriff auf die lokale IP. Und 0.0.0.0 bedeutet, dass wir keine IP-Einschränkungen haben und auf alle IPs zugegriffen werden kann.

Dann werfen wir einen Blick auf das server.php im Projektstammverzeichnis:

/**
 * 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';

und stellen fest, dass es mit der Routing-Datei identisch ist, die ich zuvor geschrieben habe. Ja, ich habe es von hier kopiert.

Im Grunde ist dies die Art und Weise, wie Larvel es umsetzt.

Symfony

Wenn Sie das Symfony-Framework verwenden, werden Sie feststellen, dass Symfony eine Komponente namens Web-Server-Bundle hat. Diese Komponente hat die gleiche Funktion wie Laravel und erfordert keine Hilfe. Der Webserver ermöglicht den Zugriff auf Anwendungen über einen Browser.

Grundlegende Vorgänge finden Sie auf dieser Seite

Ich werde hier hauptsächlich darüber sprechen, wie Symfony implementiert wird.

Es gibt einen Code in Symfony ist das so:

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;
}

Ich habe im obigen Code einen Kommentar abgegeben, um zu beschreiben, wie Symfony gestartet wird. Es gibt ein Problem in

, das darin besteht, pcntl_fork, Diese Erweiterung wird in Windows nicht unterstützt. Daher fordert das Symfony-Framework dazu auf, den Befehl php bin/console server:runFuture Outlook

zu verwenden Das heißt, Workman verwendet seinen eigenen Der implementierte Webserver verwendet nicht den Befehl

. Ich habe diesen Teil des Codes nicht vollständig verstanden und denke, dass dies in einigen separaten Kapiteln besprochen werden kann. Ich hoffe, diese Gelegenheit in Zukunft zu haben.

php -SZusammenfassung

Durch unser Erlernen von PHP-Befehlen zum Erreichen des Webserverzugriffs und die Analyse von Laravel- und Symfony-Frameworks habe ich gelernt, dass wir diese Methode im Entwicklungsprozess von Windows vollständig nutzen können Loswerden Die Abhängigkeit vom Webserver erleichtert nicht nur unsere Entwicklung in der Windows-Umgebung, sondern ermöglicht uns auch das Erlernen einer PHP-Fähigkeit. Es fühlt sich gut an.

Wenn Sie Fragen dazu haben, können Sie einen Kommentar abgeben und kommunizieren.

Weitere technische Artikel zum Thema PHP finden Sie in der Spalte

PHP-Tutorial zum Lernen!

Das obige ist der detaillierte Inhalt vonIn PHP integrierter Webserver. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn