目錄
前言
基礎應用程式
框架參考
Laravel
Symfony
未來展望
總結
首頁 後端開發 php教程 PHP之內建web伺服器

PHP之內建web伺服器

Jun 19, 2019 am 10:11 AM
php 網頁伺服器

PHP之內建web伺服器

前言

#PHP從5.4開始,就提供了一個內建的web伺服器。

這個主要是用來做本地的開發用的。不能用於線上環境。現在我就介紹一下這個工具如何使用。

基礎應用程式

首先我們假定專案目錄是/home/baoguoxiao/www/php/demo,外界可存取的目錄是/home/baoguoxiao /www/php/demo/public。然後存取的連接埠是8000,入口檔案是index.phpindex.html。那我們可以執行以下指令:

cd /home/baoguoxiao/www/php/demo/public
php -S localhost:8000
登入後複製

然後這個時候就可以正常存取了。

那麼現在有個問題,就是難道每次必須進入public資料夾才能啟動web伺服器嗎,其實我們可以指定根目錄的,那麼可以使用如下指令:

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:

這裡我們可以看到一個差異就是之前我自己寫的程式碼,host 都是localhost, 但這裡寫的是0.0.0.0。這兩個有什麼差別呢?

其實差別很簡單,像是我之前寫的 localhost 綁定的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指令執行程式.

未來展望

#其實還有一個方式, 就是Workman 是透過自身的實現的web伺服器,它並沒有借助php -S指令。這一塊的代碼我還沒吃透,我覺得這個也可以單獨拎幾章出來講。希望以後有這個機會。

總結

透過我們學習PHP 指令實現web伺服器存取以及對Laravel 和Symfony 框架的分析, 讓我了解到在Windows的開發過程中,我們完全可以藉助該方式來擺脫對web伺服器的依賴.既能方便我們在Windows環境進行開發並且學習了PHP一個技巧.感覺挺好的.

大家如果對此有什麼疑問可以評論進行交流.

#更多PHP相關技術文章,請造訪PHP教學欄位進行學習!

以上是PHP之內建web伺服器的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

在PHP API中說明JSON Web令牌(JWT)及其用例。 在PHP API中說明JSON Web令牌(JWT)及其用例。 Apr 05, 2025 am 12:04 AM

JWT是一種基於JSON的開放標準,用於在各方之間安全地傳輸信息,主要用於身份驗證和信息交換。 1.JWT由Header、Payload和Signature三部分組成。 2.JWT的工作原理包括生成JWT、驗證JWT和解析Payload三個步驟。 3.在PHP中使用JWT進行身份驗證時,可以生成和驗證JWT,並在高級用法中包含用戶角色和權限信息。 4.常見錯誤包括簽名驗證失敗、令牌過期和Payload過大,調試技巧包括使用調試工具和日誌記錄。 5.性能優化和最佳實踐包括使用合適的簽名算法、合理設置有效期、

php程序在字符串中計數元音 php程序在字符串中計數元音 Feb 07, 2025 pm 12:12 PM

字符串是由字符組成的序列,包括字母、數字和符號。本教程將學習如何使用不同的方法在PHP中計算給定字符串中元音的數量。英語中的元音是a、e、i、o、u,它們可以是大寫或小寫。 什麼是元音? 元音是代表特定語音的字母字符。英語中共有五個元音,包括大寫和小寫: a, e, i, o, u 示例 1 輸入:字符串 = "Tutorialspoint" 輸出:6 解釋 字符串 "Tutorialspoint" 中的元音是 u、o、i、a、o、i。總共有 6 個元

您如何在PHP中解析和處理HTML/XML? 您如何在PHP中解析和處理HTML/XML? Feb 07, 2025 am 11:57 AM

本教程演示瞭如何使用PHP有效地處理XML文檔。 XML(可擴展的標記語言)是一種用於人類可讀性和機器解析的多功能文本標記語言。它通常用於數據存儲

解釋PHP中的晚期靜態綁定(靜態::)。 解釋PHP中的晚期靜態綁定(靜態::)。 Apr 03, 2025 am 12:04 AM

靜態綁定(static::)在PHP中實現晚期靜態綁定(LSB),允許在靜態上下文中引用調用類而非定義類。 1)解析過程在運行時進行,2)在繼承關係中向上查找調用類,3)可能帶來性能開銷。

什麼是PHP魔術方法(__ -construct,__destruct,__call,__get,__ set等)並提供用例? 什麼是PHP魔術方法(__ -construct,__destruct,__call,__get,__ set等)並提供用例? Apr 03, 2025 am 12:03 AM

PHP的魔法方法有哪些? PHP的魔法方法包括:1.\_\_construct,用於初始化對象;2.\_\_destruct,用於清理資源;3.\_\_call,處理不存在的方法調用;4.\_\_get,實現動態屬性訪問;5.\_\_set,實現動態屬性設置。這些方法在特定情況下自動調用,提升代碼的靈活性和效率。

PHP和Python:比較兩種流行的編程語言 PHP和Python:比較兩種流行的編程語言 Apr 14, 2025 am 12:13 AM

PHP和Python各有優勢,選擇依據項目需求。 1.PHP適合web開發,尤其快速開發和維護網站。 2.Python適用於數據科學、機器學習和人工智能,語法簡潔,適合初學者。

說明匹配表達式(PHP 8)及其與開關的不同。 說明匹配表達式(PHP 8)及其與開關的不同。 Apr 06, 2025 am 12:03 AM

在PHP8 中,match表達式是一種新的控制結構,用於根據表達式的值返回不同的結果。 1)它類似於switch語句,但返回值而非執行語句塊。 2)match表達式使用嚴格比較(===),提升了安全性。 3)它避免了switch語句中可能的break遺漏問題,增強了代碼的簡潔性和可讀性。

什麼是跨站點偽造(CSRF),您如何在PHP中實施CSRF保護? 什麼是跨站點偽造(CSRF),您如何在PHP中實施CSRF保護? Apr 07, 2025 am 12:02 AM

在PHP中可以通過使用不可預測的令牌來有效防範CSRF攻擊。具體方法包括:1.生成並在表單中嵌入CSRF令牌;2.在處理請求時驗證令牌的有效性。

See all articles