PHP built in server and .htaccess mod rewrites
Solution 1
Here's the router that I use for the builtin php webserver that serves assets from the filesystem if they exist and otherwise performs a rewrite to an index.php file.
Run using:
php -S localhost:8080 router.php
router.php:
<?php
chdir(__DIR__);
$filePath = realpath(ltrim($_SERVER["REQUEST_URI"], '/'));
if ($filePath && is_dir($filePath)){
// attempt to find an index file
foreach (['index.php', 'index.html'] as $indexFile){
if ($filePath = realpath($filePath . DIRECTORY_SEPARATOR . $indexFile)){
break;
}
}
}
if ($filePath && is_file($filePath)) {
// 1. check that file is not outside of this directory for security
// 2. check for circular reference to router.php
// 3. don't serve dotfiles
if (strpos($filePath, __DIR__ . DIRECTORY_SEPARATOR) === 0 &&
$filePath != __DIR__ . DIRECTORY_SEPARATOR . 'router.php' &&
substr(basename($filePath), 0, 1) != '.'
) {
if (strtolower(substr($filePath, -4)) == '.php') {
// php file; serve through interpreter
include $filePath;
} else {
// asset file; serve from filesystem
return false;
}
} else {
// disallowed file
header("HTTP/1.1 404 Not Found");
echo "404 Not Found";
}
} else {
// rewrite to our index file
include __DIR__ . DIRECTORY_SEPARATOR . 'index.php';
}
Solution 2
It is not possible to handle .htaccess using PHP's built-in webserver (it is not relying on apache, it is implemented entirely in PHP's core). However, you can use router script (described here: http://php.net/manual/en/features.commandline.webserver.php).
E.g. php -S localhost -S localhost:8080 router.php
Solution 3
We're currently working with legacy projects and I came accross with the same problem. Based on @Caleb's answer, we managed to add a few more controls:
- Route the request to an old htaccess router (
url.php
on the example below); - Work with query string;
- Change the current directory to work with PHP includes;
- Plus: naming to
server.php
to match Laravel's PHP Builtin router.
Just type in the cmd: php -S localhost:8888 server.php
chdir(__DIR__);
$queryString = $_SERVER['QUERY_STRING'];
$filePath = realpath(ltrim(($queryString ? $_SERVER["SCRIPT_NAME"] : $_SERVER["REQUEST_URI"]), '/'));
if ($filePath && is_dir($filePath)){
// attempt to find an index file
foreach (['index.php', 'index.html'] as $indexFile){
if ($filePath = realpath($filePath . DIRECTORY_SEPARATOR . $indexFile)){
break;
}
}
}
if ($filePath && is_file($filePath)) {
// 1. check that file is not outside (behind) of this directory for security
// 2. check for circular reference to server.php
// 3. don't serve dotfiles
if (strpos($filePath, __DIR__ . DIRECTORY_SEPARATOR) === 0
&& $filePath != __DIR__ . DIRECTORY_SEPARATOR . 'server.php'
&& substr(basename($filePath), 0, 1) != '.'
) {
if (strtolower(substr($filePath, -4)) == '.php') {
// change directory for php includes
chdir(dirname($filePath));
// php file; serve through interpreter
include $filePath;
} else {
// asset file; serve from filesystem
return false;
}
} else {
// disallowed file
header("HTTP/1.1 404 Not Found");
echo "404 Not Found";
}
} else {
// rewrite to our router file
// this portion should be customized to your needs
$_REQUEST['valor'] = ltrim($_SERVER['REQUEST_URI'], '/');
include __DIR__ . DIRECTORY_SEPARATOR . 'url.php';
}
Martyn
Updated on July 09, 2022Comments
-
Martyn almost 2 years
Does PHP's built in server not make use of .htaccess? Makes sense, I suppose, as it isn't relying upon Apache(?). Anyway, is it possible to tell the server to make use of these files - can it handle URL rewrites? I have some projects in frameworks that rely upon these files.
APPLICATION_ENV=development php -S localhost:8000 -t public/
-
unixmiah over 9 yearsthen you need to use .htaccess
-
Agares over 9 yearsYou can't use .htaccess with PHP's built-in server. It is not supported. If you want to use .htaccess and not other way of configuring your webserver, then you either have to use Apache or parse .htaccess yourself in PHP (that probably would be a difficult thing)
-
unixmiah over 9 yearsahh that makes sense. yes I agree.
-
Vahid Amiri over 5 yearsI use this instead of making a whole new Apache virtual host when testing things out. Very useful snippet.
-
He Yifei 何一非 over 3 years(Note that you could use
$_SERVER['REQUEST_URI']
inindex.php
to get the actual request URL.)