PHP built in server and .htaccess mod rewrites

36,843

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:

  1. Route the request to an old htaccess router (url.php on the example below);
  2. Work with query string;
  3. Change the current directory to work with PHP includes;
  4. 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';
}
Share:
36,843
Martyn
Author by

Martyn

Updated on July 09, 2022

Comments

  • Martyn
    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
    unixmiah over 9 years
    then you need to use .htaccess
  • Agares
    Agares over 9 years
    You 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
    unixmiah over 9 years
    ahh that makes sense. yes I agree.
  • Vahid Amiri
    Vahid Amiri over 5 years
    I use this instead of making a whole new Apache virtual host when testing things out. Very useful snippet.
  • He Yifei 何一非
    He Yifei 何一非 over 3 years
    (Note that you could use $_SERVER['REQUEST_URI'] in index.php to get the actual request URL.)