PHP fournit un serveur Web intégré depuis la version 5.4.
Ceci est principalement utilisé pour le développement local. Ne peut pas être utilisé dans des environnements en ligne. Je vais maintenant vous présenter comment utiliser cet outil.
Nous supposons d'abord que le répertoire du projet est /home/baoguoxiao/www/php/demo
et que le répertoire accessible au monde extérieur est /home/baoguoxiao/www/php/demo/public
. Ensuite, le port accédé est 8000
et les fichiers d'entrée sont index.php
et index.html
. Ensuite nous pouvons exécuter la commande suivante :
cd /home/baoguoxiao/www/php/demo/public php -S localhost:8000
Vous pourrez ensuite y accéder normalement.
Alors maintenant il y a une question, est-il nécessaire de saisir le dossier public
à chaque fois pour démarrer le serveur web ? En fait, on peut préciser le répertoire racine, puis on peut utiliser la commande suivante :
cd /home/baoguoxiao/www/php/demo php -S localhost:8000 -t public/
Alors maintenant, il y a une question, c'est-à-dire si nous utilisons une seule entrée et utilisons toujours le mode PATHINFO. Il se peut alors qu'il y ait un problème avec ce qui précède.
Pour cela, nous pouvons utiliser la solution suivante :
cd /home/baoguoxiao/www/php/demo php -S localhost:8000 router.php
Code du fichier 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";
Grâce à ce fichier de routage, nous pouvons prendre en charge les situations de développement actuellement couramment utilisées.
La méthode ci-dessus est notre propre implémentation, nous pouvons donc également examiner les méthodes d'implémentation de frameworks bien connus associés.
Tels que Laravel et Symfony.
Dans la section Installation de Laravel, une commande est introduite pour obtenir un accès externe à l'aide du serveur Web intégré PHP. La commande implémentée est :
php artisan serve
Nous pouvons jeter un œil au code correspondant :
Le chemin de fichier spécifique est : supplier/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')) ); }
Traduisez la commande ci-dessus, elle est en fait exécutée
cd ./public php -S 0.0.0.0:8000 ../server.php
note :
Ici, nous pouvons voir une différence, qui est le code que j'ai écrit auparavant. , les hôtes sont tous localhost, mais ce qui est écrit ici est 0.0.0.0. Quelle est la différence entre ces deux ?
En fait, la différence est très simple. Par exemple, l'adresse IP liée à localhost que j'ai écrite auparavant est 127.0.0.1. Cela équivaut à une adresse de bouclage, nous autorisons donc uniquement l'accès à l'adresse IP locale. Et 0.0.0.0 signifie que nous n'avons aucune restriction sur l'IP et que toutes les IP sont accessibles.
Jetons ensuite un coup d'œil au server.php
sous le répertoire racine du projet :
/** * 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';
et constatons que c'est le même que le fichier de routage que j'ai écrit auparavant. Oui, je l'ai copié d'ici.
En gros, voici comment Larvel l'implémente.
Si vous utilisez le framework Symfony, vous constaterez que Symfony possède un composant appelé web-server-bundle. Ce composant a la même fonction que Laravel. et ne nécessite aucune aide. Le serveur Web permet d'accéder aux applications via un navigateur.
Pour les opérations de base, veuillez vous référer à cette page
Je parlerai principalement de la façon dont Symfony est implémenté ici.
Il y a un morceau de code dans Symfony c'est comme ça :
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('Unable to start the server process.'); } // 进入这个判断,表示执行的是父进程,表示不用继续向下执行 if ($pid > 0) { return self::STARTED; } // 从此往后是子进程运行,首先通过 posix_setsid 变为守护进程,意思是使其脱离终端的管理,自立门户,谁也没办法管理这个进程,除了PID。 if (posix_setsid() < 0) { throw new \RuntimeException('Unable to set the child process as session leader.'); } // 创建命令,命令类似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; }
J'ai commenté dans le code ci-dessus pour décrire comment Symfony est démarré. Il y a un problème dans
qui consiste à utiliser pcntl_fork
, Cette extension n'est pas prise en charge sous Windows. Par conséquent, le framework Symfony vous demandera d'utiliser la commande pour exécuter le programme php bin/console server:run
. Je n'ai pas entièrement compris cette partie du code et je pense que cela peut être discuté dans quelques chapitres distincts. J'espère avoir cette opportunité à l'avenir. php -S
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!