当前位置: 首页 > 后端技术 > PHP

PHP内置web服务器

时间:2023-03-29 17:16:59 PHP

首发于:我的博客前言PHP从5.4开始就提供了内置web服务器。这个主要用于本地开发。它不能在在线环境中使用。现在我将介绍如何使用这个工具。基础应用首先,我们假设项目目录为/home/baoguoxiao/www/php/demo,对外可访问的目录为/home/baoguoxiao/www/php/demo/public。那么访问的端口是8000,入口文件是index.php和index.html。然后我们可以执行如下命令:cd/home/baoguoxiao/www/php/demo/publicphp-Slocalhost:8000此时就可以正常访问了。那么现在有个问题,是不是每次启动webserver都要进入public文件夹呢?其实我们可以指定根目录,所以我们可以使用如下命令:cd/home/baoguoxiao/www/php/demophp-Slocalhost:8000-tpublic/现在有个问题,如果我们使用单入口,并且仍然使用PATHINFO模式。那么上面的可能有问题。为此,我们可以使用如下方案:cd/home/baoguoxiao/www/php/demophp-Slocalhost:8000router.phprouter.php文件的代码/***解析URL,得到请求的文件名*/$uri=urldecode(parse_url($_SERVER["REQUEST_URI"],PHP_URL_PATH));/***判断文件是否存在,不存在则继续加载入口文件*/if($uri!=="/"&&file_exists(__DIR__."$uri")){returnfalse;}/***加载入口文件*/require_once"./index.php";通过这个路由文件,我们可以支持目前常见的开发情况。上面的框架参考方法是我们自己实现的,所以大家也可以看看相关知名框架的实现方法。比如Laravel和Symfony。Laravel的安装在Laravel部分介绍了一个可以使用PHP内置的web服务器进行外部访问的命令。实现的命令为:phpartisanserve我们可以看下相关代码:具体文件路径为:vendor/laravel/framework/src/Illuminate/Foundation/Console/ServeCommand.php/***执行命令。**@returnint**@throws\Exception*/publicfunctionhandle(){//将路径切换到公共目录chdir(public_path());//在命令控制台输出相关内容$this->line("Laravel开发服务器已启动host()}:{$this->port()}>");//执行外部程序,$status为系统passthru的返回状态($this->serverCommand(),$status);//如果$status为0,表示执行正常,如果是其他大于0的数字,表示有错误,端口可能被抢占。此时会继续判断是否再进行Tryif($status&&$this->canTryAnotherPort()){//绑定的端口号加1,默认为8000,如果失败则重试该端口端口号为8001,如果再次失败,则端口号为8002重试,以此类推。$this->portOffset+=1;//再次调用这个程序return$this->handle();}//返回状态值return$status;}/***获取完整的服务器命令。**@returnstring*/protectedfunctionserverCommand(){returnsprintf('%s-S%s:%s%s',//获取PHP可执行命令的路径ProcessUtils::escapeArgument((newPhpExecutableFinder)->find(false)),//获取需要绑定的主机$this->host(),//获取需要绑定的端口$this->port(),//转义需要的参数要执行的,这里的server就是我们之前说的路由文件,它在项目的根路径下执行cd./publicphp-S0.0.0.0:8000../server.php注意:这里可以看到一个不同的是我之前写的代码,host是localhost,而这里是0.0.0.0。这两者有什么区别?其实区别很简单。比如我之前写的localhost绑定的ip是127.0.0.1,相当于一个环回地址,所以我们只允许本机IP访问。而0.0.0.0表示我们不限制IP,所有IP都可以访问。然后我们看一下项目根目录下的server.php:/***Laravel-APHPFrameworkForWebArtisans**@packageLaravel*@authorTaylorOtwell*/$uri=urldecode(parse_url($_SERVER['REQUEST_URI'],PHP_URL_PATH));//这个文件允许我们从内置的PHPWeb服务器模拟Apache的“mod_rewrite”功能。//这提供了一种测试Laravel应用程序的便捷方法,//无需在此处安装“真正的”Web服务器软件。如果($uri!=='/'&&file_exists(__DIR__.'/public'.$uri)){returnfalse;}require_once__DIR__.'/public/index.php';发现和我之前写的一样的路由文件。是的,我是从这里复制的。这基本上就是Larvel实现它的方式。Symfony如果您使用的是Symfony框架,您会发现Symfony有一个名为web-server-bundle的组件。该组件的功能与Laravel相同。它还可以在不借助Web服务器的情况下通过浏览器访问应用程序。基本操作请参考本页。这里我主要说说Symfony是如何实现的。Symfony中有一段代码是这样的://判断是否正在运行,如果正在运行,会提示已经在监听if($this->isRunning($pidFile)){thrownew\RuntimeException(sprintf('Aprocessisalreadylisteningonhttp://%s.',$config->getAddress()));}//fork一个子进程,如果成功,两个进程会同时执行以下文件,父进程,即当前正在执行的进程,会返回子进程的PID,子进程返回的PIDprocessis0,//如果失败,则不会创建子进程,父进程返回的pid为-1。更多信息请参考https://www.php.net/manual/zh/function.pcntl-fork.php$pid=pcntl_fork();//表示fork进程失败if($pid<0){thrownew\RuntimeException('Unabletostarttheserverprocess.');}//进入这个判断,表示执行的是父进程,也就是说不需要继续执行if($pid>0){returnself::STARTED;}//从此,子进程开始运行。首先,它通过posix_setsid成为守护进程,也就是说脱离了终端的管理,独立存在。除了PID之外,没有人可以管理这个过程。if(posix_setsid()<0){thrownew\RuntimeException('无法将子进程设置为会话领导者。');}//创建命令,命令类似于Laravel,但是这里的路由文件类似于Laravel。它还处理加载规则并加载入口文件。具体router.php路径为://vendor\symfony\web-server-bundle/Resources/router.php//下面是禁用输出,开始运行$process=$this->createServerProcess($config);$process->disableOutput();$进程->开始();//判断操作是否成功if(!$process->isRunning()){thrownew\RuntimeException('Unabletostarttheserverprocess.');}//写入PID文件file_put_contents($pidFile,$config->getAddress());//检测PID文件,如果PID文件被删除,进程会立即退出。while($process->isRunning()){if(!file_exists($pidFile)){$process->stop();}睡眠(1);}//返回停止状态returnself::STOPPED;}/***启动PHP内置的web服务器*@returnProcess进程*/privatefunctioncreateServerProcess(WebServerConfig$config){//查找PHP的可执行程序$finder=新的PhpExecutableFinder();if(false===$binary=$finder->find(false)){thrownew\RuntimeException('无法找到PHP二进制文件。');$xdebugArgs=ini_get('xdebug.profiler_enable_trigger')?['-dxdebug.profiler_enable_trigger=1']:[];//实例化PHP要执行的命令php_path-dvariables_order=EGPCS-S127.0.0.1:8000vendor\symfony\web-server-bundle/Resources/router.php$process=newProcess(array_merge([$binary],$finder->findArguments(),$xdebugArgs,['-dvariables_order=EGPCS','-S',$config->getAddress(),$config->getRouter()]));//设置工作目录$process->setWorkingDirectory($config->getDocumentRoot());//设置超时$process->setTimeout(null);//设置环境变量$process->inheritEnvironmentVariables();}//返回相关变量return$process;}我在上面的代码中注释,描述了Symfony是如何启动的使用pcntl_fork有问题,windows不支持。所以Symfony框架会提示你使用phpbin/consoleserver:run命令来运行程序。其实还有另一种展望未来的方式,那就是Workman是通过自己实现的web服务器,不使用php-S命令。这块的代码我还没有完全看懂,我觉得这个也可以分几章再说。希望以后能有这样的机会。总结通过我们对PHP命令实现web服务器访问的学习,以及对Laravel和Symfony框架的分析,了解到在Windows的开发过程中,可以使用这种方式摆脱对web服务器的依赖。方便我们使用Windows环境开发,学习一门PHP技能。感觉很好。如果您对此有任何疑问,可以评论交流。参考PHP:Built-inWebServer-ManualLaravelHowtoUsePHP'sbuilt-inWebServerPHP:pcntl_fork-ManualPHP:posix_setsid-Manual

最新推荐
猜你喜欢