今天小編給大家分享的是PHP內(nèi)置web服務(wù)器應(yīng)該怎么做,很多人都不太了解,今天小編為了讓大家更加了解PHP內(nèi)置web服務(wù)器的方法,所以給大家總結(jié)了以下內(nèi)容,一起往下看吧。一定會有所收獲的哦。
創(chuàng)新互聯(lián)是專業(yè)的溧水網(wǎng)站建設(shè)公司,溧水接單;提供成都做網(wǎng)站、網(wǎng)站設(shè)計(jì)、外貿(mào)營銷網(wǎng)站建設(shè),網(wǎng)頁設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行溧水網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來合作!
PHP從5.4開始,就提供了一個(gè)內(nèi)置的web服務(wù)器。
這個(gè)主要是用來做本地的開發(fā)用的。不能用于線上環(huán)境?,F(xiàn)在我就介紹一下這個(gè)工具如何使用。
首先我們假定項(xiàng)目目錄是/home/baoguoxiao/www/php/demo
,外界可訪問的目錄是/home/baoguoxiao/www/php/demo/public
。然后訪問的端口是8000
,入口文件是index.php
和index.html
。那么我們可以執(zhí)行如下命令:
cd /home/baoguoxiao/www/php/demo/public php -S localhost:8000
然后這個(gè)時(shí)候就可以正常訪問了。
那么現(xiàn)在有個(gè)問題,就是難道每次必須要進(jìn)入public
文件夾才能啟動web服務(wù)器嗎,其實(shí)我們可以指定根目錄的,那么可以使用如下命令:
cd /home/baoguoxiao/www/php/demo php -S localhost:8000 -t public/
那么現(xiàn)在有一個(gè)問題就是說,如果我們使用了單入口,而且還是用了PATHINFO模式。那么上面的可能就有問題了。
對此,我們可以使用如下方案:
cd /home/baoguoxiao/www/php/demo php -S localhost:8000 router.php
router.php 文件的代碼
/** * 對URL進(jìn)行解析,并獲取請求的文件名 */$uri = urldecode(parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH));/** * 判斷是否存在該文件,如果不存在,則直接繼續(xù)加載入口文件 */if ($uri !== "/" && file_exists(__DIR__ . "$uri")) { return false; }/** * 加載入口文件 */require_once "./index.php";
通過這個(gè)路由文件,我們就可以支持目前常用的開發(fā)情況了。
上面的方式是我們自己的實(shí)現(xiàn),那么我們也可以看看相關(guān)知名框架的實(shí)現(xiàn)方法。
比如 Laravel 和 Symfony。
在Laravel中的安裝一節(jié)中介紹了一個(gè)命令可以使用PHP內(nèi)置web服務(wù)器實(shí)現(xià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()); // 在命令臺進(jìn)行輸出相關(guān)內(nèi)容 $this->line("<info>Laravel development server started:</info> <http://{$this->host()}:{$this->port()}>"); // 執(zhí)行外部程序,并且 $status 為系統(tǒng)的返回狀態(tài) passthru($this->serverCommand(), $status); // $status 為0 表示執(zhí)行正常, 為其他大于0的數(shù)字表示出現(xiàn)了錯(cuò)誤,有可能是端口被搶占了,這個(gè)時(shí)候就會接著判斷是否進(jìn)行再次嘗試 if ($status && $this->canTryAnotherPort()) { // 對綁定的端口號加1 默認(rèn)是8000, 如果失敗則重試端口號為8001,再次失敗重試端口號為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(), // 對需要執(zhí)行的參數(shù)進(jìn)行轉(zhuǎn)義處理。這里的 server 就是我們之前說的路由文件,它在項(xiàng)目的根路徑下 ProcessUtils::escapeArgument(base_path('server.php')) ); }
對上面的命令進(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ū)別很簡單,比如我之前寫的 localhost 綁定的ip 是 127.0.0.1, 這個(gè)相當(dāng)于一個(gè)回環(huán)地址,那么我們就只允許本機(jī)的IP進(jìn)行訪問。而 0.0.0.0,則表示我們對ip不進(jìn)行限制,所有的IP都可以進(jìn)行訪問。
那我們接著再來看看項(xiàng)目根目錄下面的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) ); // 這個(gè)文件允許我們從內(nèi)置 PHP web 服務(wù)器中模擬 Apache 的 "mod_rewrite" 功能. // 這提供了一種測試 Laravel 應(yīng)用程序的便捷方法, // 而無需在此安裝"真正的" web 服務(wù)器軟件。 if ($uri !== '/' && file_exists(__DIR__.'/public'.$uri)) { return false; } require_once __DIR__.'/public/index.php';
發(fā)現(xiàn)跟我之前寫的路由文件相同。沒錯(cuò),我就是從這里抄過來的。
基本上 Larvel 的實(shí)現(xiàn)方法就是這樣了。
如果你在使用 Symfony 框架話,發(fā)現(xiàn)Symfony有一個(gè)組件叫做web-server-bundle,這個(gè)組件的作用跟Laravel相同,也是不借助web服務(wù)器,實(shí)現(xiàn)通過瀏覽器訪問應(yīng)用程序。
基本的操作可以參考該頁面
我在這里主要說一下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)程,如果成功,會有兩個(gè)進(jìn)程進(jìn)行同時(shí)執(zhí)行下面的文件,父進(jìn)程,也就是當(dāng)前執(zhí)行的進(jìn)程會返回子進(jìn)程的PID,而子進(jìn)程則返回的PID為0, // 如果失敗,則子進(jìn)程不會創(chuàng)建,并且父進(jìn)程會返回的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)行,首先通過 posix_setsid 變?yōu)槭刈o(hù)進(jìn)程,意思是使其脫離終端的管理,自立門戶,誰也沒辦法管理這個(gè)進(jìn)程,除了PID。 if (posix_setsid() < 0) { throw new \RuntimeException('Unable to set the child process as session leader.'); } // 創(chuàng)建命令,命令類似Laravel,不過這里的路由文件跟Laravel類似。也是處理加載規(guī)則,并加載入口文件。具體的router.php 路徑為: // vendor\symfony\web-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()); // 檢測PID文件,如果PID文件刪除了,那么進(jìn)程就立即退出。 while ($process->isRunning()) { if (!file_exists($pidFile)) { $process->stop(); } sleep(1); } // 返回停止的狀態(tài) return self::STOPPED; } /** * 啟動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 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()])); // 設(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是如何啟動的.
里面有一個(gè)問題就是使用pcntl_fork
, 該擴(kuò)展在Windows中是不受支持的. 所以 Symfony框架會提示使用php bin/console server:run
命令運(yùn)行程序.
其實(shí)還有一個(gè)方式, 就是 Workman 是通過自身的實(shí)現(xiàn)的web服務(wù)器,它并沒有借助php -S
命令。這一塊的代碼我還沒有吃透,并且我覺得這個(gè)也可以單獨(dú)拎幾章出來講。希望以后有這個(gè)機(jī)會。
通過我們學(xué)習(xí) PHP 命令實(shí)現(xiàn)web服務(wù)器訪問以及對 Laravel 和 Symfony 框架的分析, 讓我了解到在Windows的開發(fā)過程中,我們完全可以借助該方式來擺脫對web服務(wù)器的依賴.既能方便我們在Windows環(huán)境進(jìn)行開發(fā)并且學(xué)習(xí)了PHP一個(gè)技巧.感覺挺好的.
看完上訴內(nèi)容,你們對PHP內(nèi)置web服務(wù)器應(yīng)該怎么做大概了解了嗎?如果想了解更多,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道哦!
本文名稱:PHP內(nèi)置web服務(wù)器應(yīng)該怎么做
URL鏈接:http://muchs.cn/article22/gddccc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供云服務(wù)器、定制開發(fā)、、App開發(fā)、微信小程序、動態(tài)網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)