PHP built in server and .htaccess mod rewrites
Asked Answered
F

3

45

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/

Firecracker answered 9/12, 2014 at 14:37 Comment(6)
php -S is not apache, why should it to read any apache config files?Bohannon
you can to say to server your front controller by php -S ... public/index.phpBohannon
Yeh but .htaccess files are commonly used in applications so I wondered if at all PHP server did handle them. I guess not. Pointing to a front controller is fine, but when I want to rewrite something like /news/view/205 url currently I can't.Firecracker
I don't understand your question that clearly. If you want you don't have to use .htaccess but you can in apache httpd.conf; there you can set url rewrite rules in between your virtualhost config directive. as a result; if you want to use rules on certain directory you can define it there. if you were to do that you'd need to reload the httpd.conf file when you do that.Bumpkin
I have no idea.Bumpkin
My solution is here https://mcmap.net/q/374446/-fatfree-routing-with-php-built-in-web-server/73006303#73006303Clactonian
I
54

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';
}
Isolation answered 12/8, 2016 at 20:33 Comment(2)
I use this instead of making a whole new Apache virtual host when testing things out. Very useful snippet.Phocomelia
(Note that you could use $_SERVER['REQUEST_URI'] in index.php to get the actual request URL.)Berky
F
22

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

Frag answered 9/12, 2014 at 14:40 Comment(3)
then you need to use .htaccessBumpkin
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)Frag
ahh that makes sense. yes I agree.Bumpkin
O
2

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';
}
Otho answered 17/4, 2021 at 10:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.