亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

PHP之內(nèi)置web服務(wù)器

MorePainMoreGain / 655人閱讀

摘要:首發(fā)于我的博客前言從開始,就提供了一個(gè)內(nèi)置的服務(wù)器。在中的安裝一節(jié)中介紹了一個(gè)命令可以使用內(nèi)置服務(wù)器實(shí)現(xiàn)外部訪問(wèn)的命令。

首發(fā)于:我的博客
前言

PHP從5.4開始,就提供了一個(gè)內(nèi)置的web服務(wù)器。

這個(gè)主要是用來(lái)做本地的開發(fā)用的。不能用于線上環(huán)境?,F(xiàn)在我就介紹一下這個(gè)工具如何使用。

基礎(chǔ)應(yīng)用

首先我們假定項(xiàng)目目錄是/home/baoguoxiao/www/php/demo,外界可訪問(wèn)的目錄是/home/baoguoxiao/www/php/demo/public。然后訪問(wèn)的端口是8000,入口文件是index.phpindex.html。那么我們可以執(zhí)行如下命令:

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

然后這個(gè)時(shí)候就可以正常訪問(wèn)了。

那么現(xiàn)在有個(gè)問(wèn)題,就是難道每次必須要進(jìn)入public文件夾才能啟動(dòng)web服務(wù)器嗎,其實(shí)我們可以指定根目錄的,那么可以使用如下命令:

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

那么現(xiàn)在有一個(gè)問(wèn)題就是說(shuō),如果我們使用了單入口,而且還是用了PATHINFO模式。那么上面的可能就有問(wèn)題了。

對(duì)此,我們可以使用如下方案:

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

router.php 文件的代碼

/**
 * 對(duì)URL進(jìn)行解析,并獲取請(qǐng)求的文件名
 */
$uri = urldecode(parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH));

/**
 * 判斷是否存在該文件,如果不存在,則直接繼續(xù)加載入口文件
 */
if ($uri !== "/" && file_exists(__DIR__ . "$uri")) {
    return false;
}

/**
 * 加載入口文件
 */
require_once "./index.php";

通過(guò)這個(gè)路由文件,我們就可以支持目前常用的開發(fā)情況了。

框架參考

上面的方式是我們自己的實(shí)現(xiàn),那么我們也可以看看相關(guān)知名框架的實(shí)現(xiàn)方法。

比如 Laravel 和 Symfony。

Laravel

在Laravel中的安裝一節(jié)中介紹了一個(gè)命令可以使用PHP內(nèi)置web服務(wù)器實(shí)現(xiàn)外部訪問(wèn)的命令。實(shí)現(xiàn)的命令是:

php artisan serve

我們可以看一下相關(guān)代碼:

具體的文件路徑為:vendor/laravel/framework/src/Illuminate/Foundation/Console/ServeCommand.php

/**
 * 執(zhí)行命令.
 *
 * @return int
 *
 * @throws Exception
 */
public function handle()
{
    // 切換路徑到 public 目錄
    chdir(public_path());

    // 在命令臺(tái)進(jìn)行輸出相關(guān)內(nèi)容
    $this->line("Laravel development server started: host()}:{$this->port()}>");

    // 執(zhí)行外部程序,并且 $status 為系統(tǒng)的返回狀態(tài)
    passthru($this->serverCommand(), $status);

    // $status 為0 表示執(zhí)行正常, 為其他大于0的數(shù)字表示出現(xiàn)了錯(cuò)誤,有可能是端口被搶占了,這個(gè)時(shí)候就會(huì)接著判斷是否進(jìn)行再次嘗試
    if ($status && $this->canTryAnotherPort()) {
        // 對(duì)綁定的端口號(hào)加1 默認(rèn)是8000, 如果失敗則重試端口號(hào)為8001,再次失敗重試端口號(hào)為8002,以此類推。
        $this->portOffset += 1;
        // 再次調(diào)用此程序
        return $this->handle();
    }
    // 返回狀態(tài)值
    return $status;
}

/**
 * 獲取完整的 server 命令.
 *
 * @return string
 */
protected function serverCommand()
{
    return sprintf("%s -S %s:%s %s",
        
        // 獲取PHP可執(zhí)行命令的路徑
        ProcessUtils::escapeArgument((new PhpExecutableFinder)->find(false)),
        
        // 獲取需要綁定的host
        $this->host(),

        // 獲取需要綁定的端口
        $this->port(),

        // 對(duì)需要執(zhí)行的參數(shù)進(jìn)行轉(zhuǎn)義處理。這里的 server 就是我們之前說(shuō)的路由文件,它在項(xiàng)目的根路徑下
        ProcessUtils::escapeArgument(base_path("server.php"))
    );
}

對(duì)上面的命令進(jìn)行翻譯一下,實(shí)際上就是執(zhí)行的

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

這里我們可以看到一個(gè)區(qū)別就是之前我自己寫的代碼,host 都是 localhost, 但是這里寫的是 0.0.0.0。這兩個(gè)有什么區(qū)別呢?

其實(shí)區(qū)別很簡(jiǎn)單,比如我之前寫的 localhost 綁定的ip 是 127.0.0.1, 這個(gè)相當(dāng)于一個(gè)回環(huán)地址,那么我們就只允許本機(jī)的IP進(jìn)行訪問(wèn)。而 0.0.0.0,則表示我們對(duì)ip不進(jìn)行限制,所有的IP都可以進(jìn)行訪問(wèn)。

那我們接著再來(lái)看看項(xiàng)目根目錄下面的server.php:

/**
 * Laravel - A PHP Framework For Web Artisans
 *
 * @package  Laravel
 * @author   Taylor Otwell 
 */

$uri = urldecode(
    parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH)
);

// 這個(gè)文件允許我們從內(nèi)置 PHP web 服務(wù)器中模擬 Apache 的 "mod_rewrite" 功能.
// 這提供了一種測(cè)試 Laravel 應(yīng)用程序的便捷方法,
// 而無(wú)需在此安裝"真正的" web 服務(wù)器軟件。
if ($uri !== "/" && file_exists(__DIR__."/public".$uri)) {
    return false;
}

require_once __DIR__."/public/index.php";

發(fā)現(xiàn)跟我之前寫的路由文件相同。沒(méi)錯(cuò),我就是從這里抄過(guò)來(lái)的。

基本上 Larvel 的實(shí)現(xiàn)方法就是這樣了。

Symfony

如果你在使用 Symfony 框架話,發(fā)現(xiàn)Symfony有一個(gè)組件叫做web-server-bundle,這個(gè)組件的作用跟Laravel相同,也是不借助web服務(wù)器,實(shí)現(xiàn)通過(guò)瀏覽器訪問(wèn)應(yīng)用程序。

基本的操作可以參考該頁(yè)面

我在這里主要說(shuō)一下Symfony是如何實(shí)現(xiàn)的.

在Symfony中有一段代碼是這樣的:

public function start(WebServerConfig $config, $pidFile = null)
{
    // 獲取默認(rèn)的PID文件位置
    $pidFile = $pidFile ?: $this->getDefaultPidFile();

    // 判斷是否在運(yùn)行,如果運(yùn)行則提示已經(jīng)在監(jiān)聽了
    if ($this->isRunning($pidFile)) {
        throw new RuntimeException(sprintf("A process is already listening on http://%s.", $config->getAddress()));
    }

    // fork了一個(gè)子進(jìn)程,如果成功,會(huì)有兩個(gè)進(jìn)程進(jìn)行同時(shí)執(zhí)行下面的文件,父進(jìn)程,也就是當(dāng)前執(zhí)行的進(jìn)程會(huì)返回子進(jìn)程的PID,而子進(jìn)程則返回的PID為0,
    // 如果失敗,則子進(jìn)程不會(huì)創(chuàng)建,并且父進(jìn)程會(huì)返回的pid為-1。更多內(nèi)容可查看 https://www.php.net/manual/zh/function.pcntl-fork.php
    $pid = pcntl_fork();

    // 表示fork進(jìn)程失敗
    if ($pid < 0) {
        throw new RuntimeException("Unable to start the server process.");
    }

    // 進(jìn)入這個(gè)判斷,表示執(zhí)行的是父進(jìn)程,表示不用繼續(xù)向下執(zhí)行
    if ($pid > 0) {
        return self::STARTED;
    }

    // 從此往后是子進(jìn)程運(yùn)行,首先通過(guò) posix_setsid 變?yōu)槭刈o(hù)進(jìn)程,意思是使其脫離終端的管理,自立門戶,誰(shuí)也沒(méi)辦法管理這個(gè)進(jìn)程,除了PID。
    if (posix_setsid() < 0) {
        throw new RuntimeException("Unable to set the child process as session leader.");
    }

    // 創(chuàng)建命令,命令類似Laravel,不過(guò)這里的路由文件跟Laravel類似。也是處理加載規(guī)則,并加載入口文件。具體的router.php 路徑為:
    // vendorsymfonyweb-server-bundle/Resources/router.php
    // 下面是禁用輸出并且開始運(yùn)行
    $process = $this->createServerProcess($config);
    $process->disableOutput();
    $process->start();

    // 判斷是否運(yùn)行成功
    if (!$process->isRunning()) {
        throw new RuntimeException("Unable to start the server process.");
    }

    // 寫入PID文件
    file_put_contents($pidFile, $config->getAddress());

    // 檢測(cè)PID文件,如果PID文件刪除了,那么進(jìn)程就立即退出。
    while ($process->isRunning()) {
        if (!file_exists($pidFile)) {
            $process->stop();
        }

        sleep(1);
    }

    // 返回停止的狀態(tài)
    return self::STOPPED;
}

/**
 * 啟動(dòng)PHP內(nèi)置web服務(wù)器
 * @return Process The process
 */
private function createServerProcess(WebServerConfig $config)
{
    // 查找PHP的可執(zhí)行程序
    $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"] : [];

    // 實(shí)例化PHP要執(zhí)行的命令 php_path -dvariables_order=EGPCS -S 127.0.0.1:8000 vendorsymfonyweb-server-bundle/Resources/router.php
    $process = new Process(array_merge([$binary], $finder->findArguments(), $xdebugArgs, ["-dvariables_order=EGPCS", "-S", $config->getAddress(), $config->getRouter()]));
    // 設(shè)置工作目錄
    $process->setWorkingDirectory($config->getDocumentRoot());
    // 設(shè)置超時(shí)時(shí)間
    $process->setTimeout(null);

    // 設(shè)置環(huán)境變量
    if (in_array("APP_ENV", explode(",", getenv("SYMFONY_DOTENV_VARS")))) {
        $process->setEnv(["APP_ENV" => false]);
        $process->inheritEnvironmentVariables();
    }

    // 返回相關(guān)變量
    return $process;
}

我在上面的代碼中進(jìn)行了注釋, 描述了Symfony是如何啟動(dòng)的.

里面有一個(gè)問(wèn)題就是使用pcntl_fork, 該擴(kuò)展在Windows中是不受支持的. 所以 Symfony框架會(huì)提示使用php bin/console server:run命令運(yùn)行程序.

未來(lái)展望

其實(shí)還有一個(gè)方式, 就是 Workman 是通過(guò)自身的實(shí)現(xiàn)的web服務(wù)器,它并沒(méi)有借助php -S命令。這一塊的代碼我還沒(méi)有吃透,并且我覺得這個(gè)也可以多帶帶拎幾章出來(lái)講。希望以后有這個(gè)機(jī)會(huì)。

總結(jié)

通過(guò)我們學(xué)習(xí) PHP 命令實(shí)現(xiàn)web服務(wù)器訪問(wèn)以及對(duì) Laravel 和 Symfony 框架的分析, 讓我了解到在Windows的開發(fā)過(guò)程中,我們完全可以借助該方式來(lái)擺脫對(duì)web服務(wù)器的依賴.既能方便我們?cè)赪indows環(huán)境進(jìn)行開發(fā)并且學(xué)習(xí)了PHP一個(gè)技巧.感覺挺好的.

大家如果對(duì)此有什么疑問(wèn)可以評(píng)論進(jìn)行交流.

參考

PHP: 內(nèi)置Web Server - Manual

Laravel

How to Use PHP"s built-in Web Server

PHP: pcntl_fork - Manual

PHP: posix_setsid - Manual

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/31529.html

相關(guān)文章

  • 【modernPHP專題(14)】內(nèi)置的http務(wù)器

    摘要:起就在中內(nèi)置了服務(wù)器但只是提供開發(fā)測(cè)試使用,不推薦使用中生產(chǎn)環(huán)境中。因?yàn)檫@個(gè)服務(wù)器接受處理請(qǐng)求時(shí)順序執(zhí)行的,不能并發(fā)處理。這個(gè)內(nèi)置的服務(wù)器使用起來(lái)非常的方便,你只需要執(zhí)行下面的命令啟動(dòng)服務(wù)器然后就可以訪問(wèn)了。 PHP 5.4起就在CLI SAPI中內(nèi)置了web服務(wù)器,但只是提供開發(fā)測(cè)試使用,不推薦使用中生產(chǎn)環(huán)境中。因?yàn)檫@個(gè)服務(wù)器接受處理請(qǐng)求時(shí)順序執(zhí)行的,不能并發(fā)處理。 這個(gè)內(nèi)置的web...

    RancherLabs 評(píng)論0 收藏0
  • PHP新特性字節(jié)碼緩存和內(nèi)置務(wù)器

    摘要:從開始,內(nèi)置了字節(jié)碼緩存功能,名為。因?yàn)槭墙忉屝哉Z(yǔ)言,解釋器執(zhí)行腳本時(shí)會(huì)解析腳本代碼,生成一系列的操作碼,然后執(zhí)行字節(jié)碼,每次的請(qǐng)求都是這樣,會(huì)消耗很多資源,使用字節(jié)碼緩存可以緩存預(yù)先編譯的字節(jié)碼,減少響應(yīng)時(shí)間,降低系統(tǒng)資源的壓力。 Zend OPcache 1).從PHP5.0開始,內(nèi)置了字節(jié)碼緩存功能,名為Zend OPcache。因?yàn)镻HP是解釋性語(yǔ)言,PHP解釋器執(zhí)行PHP腳本...

    lolomaco 評(píng)論0 收藏0
  • Swoft 系列教程:(1)使用 Docker 安裝部署 Swoft

    摘要:即異步非阻塞,,事件驅(qū)動(dòng)。優(yōu)雅的注解聲明,容器,嚴(yán)格遵循規(guī)范。鏡像的主要用途官方提供了基于的鏡像。鏡像中已安裝配置好運(yùn)行的所需組件及依賴。修改鏡像的使得容器啟動(dòng)時(shí)不同時(shí)啟動(dòng)服務(wù),這就不需要要求我們掛載的本地項(xiàng)目必須完全安裝好依賴了。 之前有寫過(guò)一篇 Docker 安裝部署 Swoft 的文章,但有些冗余混亂,故重寫作為教程的開篇。要不讀讀看? Swoft項(xiàng)目:https://gith...

    psychola 評(píng)論0 收藏0
  • Swoft 系列教程:(1)使用 Docker 安裝部署 Swoft

    摘要:即異步非阻塞,,事件驅(qū)動(dòng)。優(yōu)雅的注解聲明,容器,嚴(yán)格遵循規(guī)范。鏡像的主要用途官方提供了基于的鏡像。鏡像中已安裝配置好運(yùn)行的所需組件及依賴。修改鏡像的使得容器啟動(dòng)時(shí)不同時(shí)啟動(dòng)服務(wù),這就不需要要求我們掛載的本地項(xiàng)目必須完全安裝好依賴了。 之前有寫過(guò)一篇 Docker 安裝部署 Swoft 的文章,但有些冗余混亂,故重寫作為教程的開篇。要不讀讀看? Swoft項(xiàng)目:https://gith...

    宋華 評(píng)論0 收藏0
  • PHP 自 5.2 到 5.6 中新增的功能詳解

    摘要:本文將會(huì)介紹自起,直至中增加的新特征。棄用的功能以下幾個(gè)功能被棄用,若在配置文件中啟用,則會(huì)在運(yùn)行時(shí)發(fā)出警告。該類的完整限定名是其中第一個(gè)反斜杠表示全局命名空間。目的在于模仿的不對(duì),目的是為了讓發(fā)布應(yīng)用程序更加方便。 截至目前(2014.2), PHP 的最新穩(wěn)定版本是 PHP5.5, 但有差不多一半的用戶仍在使用已經(jīng)不在維護(hù) [注] 的 PHP5.2, 其余的一半用戶在使用 PHP5...

    番茄西紅柿 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<