php内置的http server, 类似于nodejs里面和golang里面的
原文:https://www.sitepoint.com/taking-advantage-of-phps-built-in-server/
------------------------------------------------------------------------------------
One of the cooler features of the new PHP 5.4 release is a built-in web server designed specifically for development and testing. Now you can write and test your code without having to have a full-fledged LAMP configuration – just launch a the built-in server from the command line, test your code, and then shut it down when you’re finished.
The server lends itself to other creative uses, too. For example, you could distribute portable web applications on CD ROMs or USB sticks, or even as desktop applications, all created with PHP without needing GTK or other graphic libraries.
Some may point out that PHP is a language originally designed to be used on the web in the first place, while other languages like Python and Ruby are not, so it makes more sense for the others to provide a basic server environment to help kick-start web development. They’ll argue PHP doesn’t need a built-in server. Besides, most systems today come with a personal web server already installed or installable with a few commands or clicks.
Indeed the PHP manual stresses that the new built-in server is intended for development use only and recommends against using it in production. There are no special INI directives for it except for one (which colorizes logging output sent to the console), and the general tone of the documentation seems to be “we too have a web server now, stop bothering us.”
Despite this, the server made it in version 5.4, and it’s my opinion it can be a valuable tool for both developing and testing. On my machine for example I use OSX’s pre-installed Apache with a custom configuration that suits my development style, but sometimes I want to try a some new webapp. With PHP’s built-in server, I could test the application right from my download or temp directories and then move it to my regular environment only if I really need to.
Well, it’s not so simple at first because a lot of apps are written with Apache in mind and make use of .htaccess
files and mod_rewrite
. But I’m quite sure that someone out there (maybe one of you, why not?) will write and adapter for this features and I’d like to be the first to test it.
In this article I’ll explain some basic uses of the new built-in server and show you how to build a portable personal development server useful for quickly testing your applications. I’m sure you’re just as anxious as I am to get started, so let’s do it!
Using the Built-in Server
You’ll need to have PHP 5.4 or greater installed to use the built-in server. To verify your version of PHP, invoke php -v
in a terminal. You can then determine if the server is available in your build by running php -h
and looking for the -S
and -t
options which are specific to the server.
You can test the server by creating a basic index.php
file in the your current directory which contains a call to phpinfo()
, and then launching the server like so:
[ec2-user@ip-10-229-67-156 ~]$ php -S <localhost or your public IP>:8080
PHP 5.4.0RC7 Development Server started at Fri Feb 26 18:49:29 2012
Listening on <YourIP>:8080
Document root is /home/ec2-user
Press Ctrl-C to quit.
In your browser you should now be able to see the content served by the built-in server.
A new log line will be written to the console window for each client access:
[Sun Feb 26 18:55:30 2012] 80.180.55.37:36318 [200]: /
[Sun Feb 26 18:56:23 2012] 80.180.55.37:36584 [200]: /
Looking back at the PHP’s command line options, -S
is used to specify the address which the server will bind to. Its value can be:
localhost
– the server is accessible only at the local machine0.0.0.0
– the server is accessible from any interface of your machine, wired or wireless- any of your public or private IP addresses – the server is accessible only at the specific address
-t
allows you to tell the server to target another directory for its document root. For example:
[ec2-user@ip-10-229-67-156 ~]$ php -S <localhost or your public IP>:8090 -t /home/ec2-user/public
Alternatively, you can also provide the name of a specific PHP file, such as an index.php
or a custom router.php
file.
[ec2-user@ip-10-229-67-156 ~]$ php -S >localhost or your public IP>:8080 -t /home/ec2-user/public public/index.php
The output of such a router script will be parsed and executed by the server. Here is a basic example:
<?php
$extensions = array("php", "jpg", "jpeg", "gif", "css");
$path = parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);
$ext = pathinfo($path, PATHINFO_EXTENSION);
if (in_array($ext, $extensions)) {
// let the server handle the request as-is
return false;
}
echo "<p>Welcome to PHP</p>";
If the script returns false then the requested URI will be processed by the server, which outputs the requested resource either as-is or as a 404 error. If the script returns something else, then the output is passed to the client.
While such an approach gives us more control, there are a couple of things you should be aware of. First, the PHP server returns only a minimal set of HTTP headers:
Connection: closed
Content-Type: text/html
Host: aws-dev-01.vtardia.com
X-Powered-By: PHP/5.4.0RC7
Compare this to the set of typical HTTP headers returned by Apache:
Accept-Ranges: bytes
Connection: Keep-Alive
Content-Length: 631
Content-Type: text/html
Date: Sat, 04 Feb 2012 18:24:42 GMT
Etag: "bbb99-277-4ace8c5470a40"
Keep-Alive: timeout=15, max=100
Last-Modified: Wed, 14 Sep 2011 15:54:09 GMT
Server: Apache/2.2.21 (Unix) DAV/2
If your application makes use of server headers, these must be consistent in both the development/test environment (the built-in server) and the production environment (Apache/IIS/Nginx).
Second, the PHP server has a different SAPI (Server API), so you perform the routing conditionally whether index.php
is served from the built-in server or a production server. php_sapi_name()
will return “cli-server” when you’re using the built-in server.
<?php
if (php_sapi_name() == "cli-server") {
// running under built-in server so
// route static assets and return false
$extensions = array("php", "jpg", "jpeg", "gif", "css");
$path = parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);
$ext = pathinfo($path, PATHINFO_EXTENSION);
if (in_array($ext, $extensions)) {
return false;
}
}
There is one special INI directive for the built-in server; the cli_server.color
directive turns on colorized log output in the console output. Create an empty text file called cli-server.ini
and insert this line:
cli_server.color = on
You can create a unique configuration environment for your server inside your new custom INI file, and any non specified directives will assume the default value. Here we’ve just specified the cli_server.color directive
.
Kill the previously running process, and start it again but this time use -c
to specify the new file.
[ec2-user@ip-10-229-67-156 ~]$ php -S <localhost or your public IP>:8080 -c cli-server.ini
If your terminal supports color you should see colored output lines now. 200 statuses are shown in green, orange is used for 404 statuses, and you’ll see red for errors inside the requested script.
Building a Custom Server
Now that you know all there is to know about the built-in web server in PHP, let’s use that knowledge to do something cool. Let’s program a custom portable server!
I’ll start with the following sample directory structure for the application:
The library
directory contains the application’s code, the public
directory will be our document root and will contain the index.php
and some sample static files. The focus of this tutorial will be the server
directory, so the application will consist on a simple HelloWorld script and some static content (an image and a CSS file).
The goal is to be able to start the server from within the application directory with one command and our server will take care of routing, headers, and HTTP errors.
[ec2-user@ip-10-229-67-156 myapp]$ ./start.sh
Let’s start to examine the start script, which is a simple shell script:
[shell]#! /bin/bash
INIFILE="$(pwd)/server/server.ini"
DOCROOT="$(pwd)/public"
ROUTER="$(pwd)/server/router.php"
HOST=0.0.0.0
PORT=8080
PHP=$(which php)
if [ $? != 0 ] ; then
echo "Unable to find PHP"
exit 1
fi
$PHP -S $HOST:$PORT -c $INIFILE -t $DOCROOT $ROUTER[/shell]
The lines just after the #!
shebang are definable settings. I’m assuming the script is started from the application directory, so the INIFILE
, DOCROOT
and ROUTER
paths are all calculated from there using pwd
. Then the path to PHP is identified using the output of the which
command. If PHP is not found in the user’s $PATH
by which, the command returns a non-zero value and the script will exit with an error.
The approach here works well enough, but you may have to be more robust depending on your needs. An alternate approach would be to provide the user an option to override any of the defined settings from the command line, for example:
[shell]if [ ! -z $INIFILE ]; then
INIFILE="$(pwd)/server/server.ini"
fi[/shell]
Continuing on, the errors
directory contains files for HTTP error messages. Here’s an example of the 403 message; though I’ve used only HTML, the script will be included using include
in the router so you can add any PHP you’d like.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>403</title>
</head>
<body>
<h1>403: Forbidden</h1>
<p>Sorry, the requested resource is not accessible.</p>
</body>
</html>
And then there’s the router.php
file that does all the work. The goal of this file is to grab and manage all the requests and pass them to the server only if they are existing files. All the error pages are managed internally by including the templates.
<?php
// Set timezone
date_default_timezone_set("UTC");
// Directory that contains error pages
define("ERRORS", dirname(__FILE__) . "/errors");
// Default index file
define("DIRECTORY_INDEX", "index.php");
// Optional array of authorized client IPs for a bit of security
$config["hostsAllowed"] = array();
function logAccess($status = 200) {
file_put_contents("php://stdout", sprintf("[%s] %s:%s [%s]: %sn",
date("D M j H:i:s Y"), $_SERVER["REMOTE_ADDR"],
$_SERVER["REMOTE_PORT"], $status, $_SERVER["REQUEST_URI"]));
}
// Parse allowed host list
if (!empty($config['hostsAllowed'])) {
if (!in_array($_SERVER['REMOTE_ADDR'], $config['hostsAllowed'])) {
logAccess(403);
http_response_code(403);
include ERRORS . '/403.php';
exit;
}
}
// if requesting a directory then serve the default index
$path = parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);
$ext = pathinfo($path, PATHINFO_EXTENSION);
if (empty($ext)) {
$path = rtrim($path, "/") . "/" . DIRECTORY_INDEX;
}
// If the file exists then return false and let the server handle it
if (file_exists($_SERVER["DOCUMENT_ROOT"] . $path)) {
return false;
}
// default behavior
logAccess(404);
http_response_code(404);
include ERRORS . "/404.php";
In the first lines I define some global settings such as the directory index file and the error templates directory. The parameter of date_default_timezone_set()
must match with that of your system or you will have an inconsistency between the log entries of the script and that of the server. I’ve also added an optional list of allowed client IPs to improve the security.
The logAccess()
function is needed because when the router script takes care of the request the server default log is bypassed. This function takes only the status code parameter and formats the output to match exactly that of the server.
Our first parsing task is the security check: if a list of hosts is defined above and the client is not in this list we serve an error message and close the script. We need to output a status code different than 200 in case of error and the header()
function will not work in this context, so the right function to use is the new http_response_code()
.
If the client is allowed to go further, the next thing we do is to extract the requested path and its extension. In case the extension is empty the user is requesting a directory so we build the complete path using the default directory index file.
Finally if the requested path corresponds to an existing file the script returns false and let the server handle it. If not, the default behavior is performed, displaying a 404 error page.
Summary
And that’s it. As you can see, the PHP server is simple and rather straightforward to use. Our custom quick server is very basic, the code could be optimized and encapsulated into a more complex and full-featured class. As usual you can download the source code from GitHub to play with. Happy coding!
php内置的http server, 类似于nodejs里面和golang里面的的更多相关文章
- PHP内置的Web Server的使用
自PHP5.4之后 PHP内置了一个Web 服务器. 让我们来看看php Web Server的简单使用: 启动php Web Server php -S localhost:8080 通过 php ...
- C#构造方法(函数) C#方法重载 C#字段和属性 MUI实现上拉加载和下拉刷新 SVN常用功能介绍(二) SVN常用功能介绍(一) ASP.NET常用内置对象之——Server sql server——子查询 C#接口 字符串的本质 AJAX原生JavaScript写法
C#构造方法(函数) 一.概括 1.通常创建一个对象的方法如图: 通过 Student tom = new Student(); 创建tom对象,这种创建实例的形式被称为构造方法. 简述:用来初 ...
- 初识 Asp.Net内置对象之Server对象
Server对象 Server对象定义了一个于Web服务器相关联的类提供对服务器上的方法和属性的访问,用于访问服务器上的资源. Server对象的常用属性 属性 MarhineName 获取服务器 ...
- 使用Java内置的Http Server构建Web应用
一.概述 使用Java技术构建Web应用时, 我们通常离不开tomcat和jetty之类的servlet容器,这些Web服务器功能强大,性能强劲,深受欢迎,是运行大型Web应用的必备神器. 虽然Jav ...
- nodejs分离html文件里面的js和css
摘要: 本文要实现的内容,使用nodejs 对文件的增删改查,演示的例子->分离出一个html 文件里面的script 和style 里面的内容,然后单独生成js文件和css 文件.中间处理异步 ...
- ASP.NET常用内置对象之——Server
简介 Server对象是HttpServerUtility的一个实例,也是上下文对象context的一个属性,提供用于处理Web请求的Helper方法. 常用成员 一.Server.MapPath() ...
- sql server内置存储过程、查看系统信息
1.检索关键字:sql server内置存储过程,sql server查看系统信息 2.查看磁盘空间:EXEC master.dbo.xp_fixeddrives , --查看各个数据库所在磁盘情况S ...
- Python3中的内置函数
内置函数 我们一起来看看python里的内置函数.什么是内置函数?就是Python给你提供的,拿来直接用的函数,比如print,input等等.截止到python版本3.6.2,现在python一共为 ...
- 总结day13 ----内置函数
内置函数 我们一起来看看python里的内置函数.什么是内置函数?就是Python给你提供的,拿来直接用的函数,比如print,input等等.截止到python版本3.6.2,现在python一共为 ...
随机推荐
- UVA10298 Power Strings [KMP]
题目传送门 Power Strings 格式难调,题面就不放了. 一句话题意,求给定的若干字符串的最短循环节循环次数. 输入样例#1: abcd aaaa ababab . 输出样例#1: 1 4 3 ...
- Django+Nginx+uwsgi搭建自己的博客(五)
在上一篇博文中,向大家介绍了Users App和Index的前端部分的实现,以及前端与Django的通信部分.至此,我们的博客已经具备一个简单的雏形,可以将其部署在本地的服务器上了.目前较为流行的we ...
- BZOJ3262陌上花开(三维偏序问题(CDQ分治+树状数组))+CDQ分治基本思想
emmmm我能怎么说呢 CDQ分治显然我没法写一篇完整的优秀的博客,因为我自己还不是很明白... 因为这玩意的思想实在是太短了: fateice如是说道: 如果说对于一道题目的离线操作,假设有n个操作 ...
- jquery实用的一些方法
做个购物车功能,需要修改下前端页面 有些实用的方法总结一下 当你想实现最基本的加减法的时候,对于转换number实用Number(str)即可 首先明确下页面的每一行是动态的,这个时候绑定事件的时候不 ...
- JAVA基础关键字小结一
基础部分总是看起来简单,若要明白原理和使用场景,需要慢慢的体会. 本文对常用的关键字如final,transient,volatile,static以及foreach循环的原理重新梳理了一遍. 一.f ...
- linux——(6)vim与vi
概念:vi与vim的区别 vi是一款老式的文字处理软件,不过现在依然广泛使用,所有的UnixLike系统都会内置vi文本编辑器. vim可以看出vi的升级版,不过vi更像是一个程序开发工具,功能也比v ...
- 变量的解构赋值--ES6
1. 数组的解构赋值 基本用法 let [a, b, c] = [1, 2, 3]; let [a,,c] = [1,2,3]; let [a,...b] = [1,2,3]; // a=1; b=[ ...
- HDU 1880 简单Hash
题目链接:[http://acm.hdu.edu.cn/showproblem.php?pid=1880] 中文题面,题意很简单: 题解: 把每个 魔咒 和 对应的功能分别Hash,然后分别映射到ma ...
- hdu 3642 体积并
题意:求三个矩形体积的并 链接:点我 枚举z #include<stdio.h> #include<iostream> #include<stdlib.h> #in ...
- Apache commons——Apache旗下的通用工具包项目
Apache Commons是Apache旗下的一个开源项目,包含了很多开源的工具,用于解决平时编程经常会遇到的问题,减少重复劳动 这里是Apache commons的官方网站 下面是工具的简单介绍: ...