To send environment variable as long as with PHP built-in web server, type like this.
~$ MYENV=dev php -d variables_order=EGPCS -S 0.0.0.0:8000
On PHP script we can check with this code.
<?php
echo getenv('MYENV'); // print dev
PHP 5.4.0起, CLI SAPI 提供了一个内置的Web服务器。
这个内置的Web服务器主要用于本地开发使用,不可用于线上产品环境。
URI请求会被发送到PHP所在的的工作目录(Working Directory)进行处理,除非你使用了-t参数来自定义不同的目录。
如果请求未指定执行哪个PHP文件,则默认执行目录内的index.php 或者 index.html。如果这两个文件都不存在,服务器会返回404错误。
当你在命令行启动这个Web Server时,如果指定了一个PHP文件,则这个文件会作为一个"路由"脚本,意味着每次请求都会先执行这个脚本。如果这个脚本返回 FALSE
,那么直接返回请求的文件(例如请求静态文件不作任何处理)。否则会把输出返回到浏览器。
Example #1 启动Web服务器
$ cd ~/public_html $ php -S localhost:8000
终端窗口会显示:
PHP 5.4.0 Development Server started at Thu Jul 21 10:43:28 2011 Listening on localhost:8000 Document root is /home/me/public_html Press Ctrl-C to quit
接着访问http://localhost:8000/和http://localhost:8000/myscript.html,窗口会显示:
PHP 5.4.0 Development Server started at Thu Jul 21 10:43:28 2011 Listening on localhost:8000 Document root is /home/me/public_html Press Ctrl-C to quit. [Thu Jul 21 10:48:48 2011] ::1:39144 GET /favicon.ico - Request read [Thu Jul 21 10:48:50 2011] ::1:39146 GET / - Request read [Thu Jul 21 10:48:50 2011] ::1:39147 GET /favicon.ico - Request read [Thu Jul 21 10:48:52 2011] ::1:39148 GET /myscript.html - Request read [Thu Jul 21 10:48:52 2011] ::1:39149 GET /favicon.ico - Request read
Example #2 启动时指定根目录
$ cd ~/public_html $ php -S localhost:8000 -t foo/
终端窗口显示:
PHP 5.4.0 Development Server started at Thu Jul 21 10:50:26 2011 Listening on localhost:8000 Document root is /home/me/public_html/foo Press Ctrl-C to quit
Example #3 使用路由(Router)脚本
请求图片直接显示图片,请求HTML则显示"Welcome to PHP"
<?php
// router.php
if (preg_match('/\.(?:png|jpg|jpeg|gif)$/', $_SERVER["REQUEST_URI"]))
return false; // 直接返回请求的文件
else {
echo "<p>Welcome to PHP</p>";
}
?>
$ php -S localhost:8000 router.php
执行之后终端显示:
PHP 5.4.0 Development Server started at Thu Jul 21 10:53:19 2011 Listening on localhost:8000 Document root is /home/me/public_html Press Ctrl-C to quit. [Thu Jul 21 10:53:45 2011] ::1:55801 GET /mylogo.jpg - Request read [Thu Jul 21 10:53:52 2011] ::1:55803 GET /abc.html - Request read [Thu Jul 21 10:53:52 2011] ::1:55804 GET /favicon.ico - Request read
To send environment variable as long as with PHP built-in web server, type like this.
~$ MYENV=dev php -d variables_order=EGPCS -S 0.0.0.0:8000
On PHP script we can check with this code.
<?php
echo getenv('MYENV'); // print dev
For serving static content like .css or .js and otherwise using a router (for me it was index.php) this worked out of the box for me:
php -S localhost:8000
Due to my router file was index.php. But
php -S localhost:8000 index.php
did not work, because my static files are not served via my router.
In order to set project specific configuration options, simply add a php.ini file to your project, and then run the built-in server with this flag:
php -S localhost:8000 -c php.ini
This is especially helpful for settings that cannot be set at runtime (ini_set()).
I have found a strange issue while executing shell scripts on my Mac (High Sierra), PHP 7.2 with both the server and Laravel Valet.
It seems like the PATH=/usr/bin:/bin:/usr/sbin:/sbin which are the default Mac paths, but does not take into account the shell path from my .bash_profile which means that mysql and other utilities cannot be found.
Is there any workaround for injecting a PATH variable on execution
if you encountered this error:
Unknown: php_network_getaddresses: getaddrinfo failed
try this:
1. make sure you have a `localhost` entry in your hosts file
2. or use `php -S 127.0.0.1:8888`
I fiddled around with the internal webserver and had issues regarding handling static files, that do not contain a dot and a file extension.
The webserver responded with 200 without any content for files with URIs like "/testfile".
I am not certain if this is a bug, but I created a router.php that now does not use the "return false;" operation in order to pass thru the static file by the internal webserver.
Instead I use fpassthru() to do that.
In addition to that, my router.php can be configured to...
- ... have certain index files, when requesting a directory
- ... configure regex routes, so that, if the REQUEST_URI matches the regex, a certain file or directory is requested instead. (something you would do with nginx config or .htaccess ModRewrite)
Maybe someone finds this helpful.
================================
<?php
$indexFiles = ['index.html', 'index.php'];
$routes = [
'^/api(/.*)?$' => '/index.php'
];
$requestedAbsoluteFile = dirname(__FILE__) . $_SERVER['REQUEST_URI'];
// check if the the request matches one of the defined routes
foreach ($routes as $regex => $fn)
{
if (preg_match('%'.$regex.'%', $_SERVER['REQUEST_URI']))
{
$requestedAbsoluteFile = dirname(__FILE__) . $fn;
break;
}
}
// if request is a directory call check if index files exist
if (is_dir($requestedAbsoluteFile))
{
foreach ($indexFiles as $filename)
{
$fn = $requestedAbsoluteFile.'/'.$filename;
if (is_file($fn))
{
$requestedAbsoluteFile = $fn;
break;
}
}
}
// if requested file does not exist or is directory => 404
if (!is_file($requestedAbsoluteFile))
{
header($_SERVER['SERVER_PROTOCOL'].' 404 Not Found');
printf('"%s" does not exist', $_SERVER['REQUEST_URI']);
return true;
}
// if requested file is'nt a php file
if (!preg_match('/\.php$/', $requestedAbsoluteFile)) {
header('Content-Type: '.mime_content_type($requestedAbsoluteFile));
$fh = fopen($requestedAbsoluteFile, 'r');
fpassthru($fh);
fclose($fh);
return true;
}
// if requested file is php, include it
include_once $requestedAbsoluteFile;
submit_btn.addEventListener(MouseEvent.CLICK, sendMessage);
function sendMessage(e:MouseEvent):void{
var my_vars:URLVariables = new URLVariables();
my_vars.senderName = name_txt.text;
my_vars.senderEmail = email_txt.text;
my_vars.senderMsg = message_txt.text;
var my_url:URLRequest = new URLRequest("mail.php");
my_url.method = URLRequestMethod.POST;
my_url.data = my_vars;
var my_loader:URLLoader = new URLLoader();
my_loader.dataFormat = URLLoaderDataFormat.VARIABLES;
my_loader.load(my_url);
name_txt.text = "";
email_txt.text = "";
message_txt.text = "Message Sent";
}
Just a note to people who also use windows 8.1, or anyone who has had this problem when running the using the PHP server CLI.
`PHP -S localhost:8000 -t /public` <-- Not going to work.
`PHP -S localhost:8000 -t public` <-- Works!
And there is something else up in the notes saying something about you can't serve a project folder and a router file. Well, actually you can! At least for me.
`PHP -S localhost:8000 router.php -t public` <-- Perhaps someone tries this and it doesn't work.
`PHP -S localhost:8000 -t public router.php` <-- Works!
You can also print messages to the server's STDOUT via error_log().
Also the documentation doesn't make it clear that when you use router script if a PHP file is requested and you return false, the PHP file will be served (i.e. you do not need to load and eval it manually).
Note: The built-in web server has a file size limit. For files larger than 5 GB, it will always serve a "File not found" error page.
I painfully experienced behaviour that I can't seem to find documented here so I wanted to save everyone from repeating my mistake by giving the following heads up:
When starting php -S on a mac (in my case macOS Sierra) to host a local server, I had trouble with connecting from legacy Java.
As it turned out, if you started the php server with
"php -S localhost:80"
the server will be started with ipv6 support only!
To access it via ipv4, you need to change the start up command like so:
"php -S 127.0.0.1:80"
which starts server in ipv4 mode only.
$_SERVER['SERVER_ADDR'] is not defined when using php as the built-in commandline web server, so you can not use $_SERVER['SERVER_ADDR'] to detect the Server's IP address.
P.S.: This is tested on Windows with PHP 7.1 on 2016-12-22.
Below is the printed $_SERVER variable.
Array
(
[DOCUMENT_ROOT] => E:\Programs\PHPServer\www\srv
[REMOTE_ADDR] => 118.117.61.32
[REMOTE_PORT] => 10865
[SERVER_SOFTWARE] => PHP 7.1.0 Development Server
[SERVER_PROTOCOL] => HTTP/1.1
[SERVER_NAME] => 0.0.0.0
[SERVER_PORT] => 8080
[REQUEST_URI] => /
[REQUEST_METHOD] => GET
[SCRIPT_NAME] => /index.php
[SCRIPT_FILENAME] => E:\Programs\PHPServer\www\srv\index.php
[PHP_SELF] => /index.php
[HTTP_HOST] => www.wuxiancheng.cn:8080
[HTTP_CONNECTION] => keep-alive
[HTTP_CACHE_CONTROL] => max-age=0
[HTTP_UPGRADE_INSECURE_REQUESTS] => 1
[HTTP_USER_AGENT] => Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
[HTTP_ACCEPT] => text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
[HTTP_DNT] => 1
[HTTP_ACCEPT_ENCODING] => gzip, deflate, sdch
[HTTP_ACCEPT_LANGUAGE] => zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4
[HTTP_COOKIE] => qbbs_2132_saltkey=fZ7509n5; qbbs_2132_lastvisit=1482156014; Hm_lvt_f812a4362ef73c80c4d13485d1ab3a49=1482159614; _ga=GA1.2.1594404236.1482159615; su=727vL6EEPLqjcyfJcad-za9eVYOh1i7e; Hm_lvt_6a65b0f2004e441e86ecea9c3562d997=1482232509,1482241896,1482242293,1482296586
[REQUEST_TIME_FLOAT] => 1482390410.65625
[REQUEST_TIME] => 1482390410
)
To output debugging information on the command line you can write output to php://stdout:
<?php
$path = $_SERVER["SCRIPT_FILENAME"];
file_put_contents("php://stdout", "\nRequested: $path");
echo "<p>Hello World</p>";
?>
Do NOT use the -t option if you want to use a router script, you can change current working directory to the web document root before launching the php built-in web server.
[works fine]
cd /d C:\Web\Server
php -S www.51-n.com:80 router.php -n -d expose_php=0 -d display_errors=0 -d extension_dir="ext"
[always gets a 500 error]
php -S www.51-n.com:80 router.php -t C:\Web\Server -n -d expose_php=0 -d display_errors=0 -d extension_dir="ext"
It's not mentioned directly, and may not be obvious, but you can also use this to create a virtual host. This, of course, requires the help of your hosts file.
Here are the steps:
1 /etc/hosts
127.0.0.1 www.example.com
2 cd [root folder]
php -S www.example.com:8000
3 Browser:
http://www.example.com:8000/index.php
Combined with a simple SQLite database, you have a very handy testing environment.
I improved Ivan Ferrer's phpserver.bat to open the Send To'd files in the browser directly:-
rem check if arg is file or dir
if exist "%~1\" (
explorer http://localhost:8888
php -S localhost:8888 -t "%~1"
) else (
explorer http://localhost:8888/%~nx1
php -S localhost:8888 -t "%~dp1"
)
when I need to up a server for develop with rewrite, I use it:
// php -S 0.0.0.0:8080 -file webServer.php
// webServer.php
<?php
if (preg_match('/\.css|\.js|\.jpg|\.png|\.map$/', $_SERVER['REQUEST_URI'], $match)) {
$mimeTypes = [
'.css' => 'text/css',
'.js' => 'application/javascript',
'.jpg' => 'image/jpg',
'.png' => 'image/png',
'.map' => 'application/json'
];
$path = __DIR__ . $_SERVER['REQUEST_URI'];
if (is_file($path)) {
header("Content-Type: {$mimeTypes[$match[0]]}");
require $path;
exit;
}
}
require_once __DIR__.'/../app/bootstrap.php';
Note that to listen on a naked IPv6 address, you have to strangely enclose the address in so-called square brackets. Example:
$ php -S [9990:116:a001:1900::1001]:8080 -t web/
My routing file looks like this:
if (file_exists($_SERVER["DOCUMENT_ROOT"] . $_SERVER["REQUEST_URI"])) {
return false;
} else {
require "index.php";
}
The reason is to support all static files.
If your URI contains a dot, you'll lose the $_SERVER['PATH_INFO'] variable, when using the built-in webserver.
I wanted to write an API, and use .json ending in the URI-s, but then the framework's routing mechanism broke, and it took a lot of time to discover that the reason behind it was its router relying on $_SERVER['PATH_INFO'].
References:
https://bugs.php.net/bug.php?id=61286
In order to set project specific configuration options, simply add a php.ini file to your project, and then run the built-in server with this flag:
php -S localhost:8000 -c php.ini
This is especially helpful for settings that cannot be set at runtime (ini_set()).
On Windows you may find useful to have a phpserver.bat file in shell:sendto with the folowing:
explorer http://localhost:8888
rem check if arg is file or dir
if exist "%~1\" (
php -S localhost:8888 -t "%~1"
) else (
php -S localhost:8888 -t "%~dp1"
)
then for fast web testing you only have to SendTo a file or folder to this bat and it will open your explorer and run the server.