Maison  >  Article  >  développement back-end  >  Serveur Web intégré PHP

Serveur Web intégré PHP

步履不停
步履不停original
2019-06-19 10:11:227920parcourir

Serveur Web intégré PHP

Préface

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.

Application de base

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.

Référence du framework

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.

Laravel

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.

Symfony

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(&#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;
}

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

Future Outlook

En fait, il existe un autre moyen. , c'est-à-dire que Workman utilise son propre serveur Web implémenté n'utilise pas la commande

. 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

Résumé

Grâce à notre apprentissage des commandes PHP pour accéder au serveur web et à l'analyse des frameworks Laravel et Symfony, j'ai appris que dans le processus de développement de Windows, on peut tout à fait utiliser cette méthode pour s'en débarrasser La dépendance au serveur web facilite non seulement notre développement dans l'environnement Windows mais nous permet également d'acquérir une compétence en PHP Ça fait du bien.

Si vous avez des questions à ce sujet, vous pouvez commenter. et communiquer.

Pour plus d'articles techniques liés à PHP, veuillez visiter la colonne

Tutoriel PHP pour apprendre !

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!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn