Search code examples
phpapache.htaccessphp-builtin-server

Routing PHP 5.4+ Built-in Web Server like .htaccess


I have started using the PHP 5.6's built in web server using the following command:

php -S localhost:80

I was using WAMP Server before. And the manual also says that, if you give a router script to the above command, say like:

php -S localhost:80 router.php

We can achieve something like .htaccess. But I couldn't find a reliable tutorial to how to do the redirection or include. Right now, my .htaccess file has this contents:

RewriteEngine On
RewriteRule (.*)-(.*)\.htm$ ./?page=$1&sub=$2&%{QUERY_STRING} 
RewriteRule ^([^/]*)\.htm$ ./?page=$1&%{QUERY_STRING} [L]

What am I supposed to put in the router.php in order to achieve the same output that I had in the Apache Web Server? Thanks in Advance.


Solution

  • <?php
        $_matches = array();
    
        /**
         * Initialize the rewrite environment.
         */
        function initialize() {
            set_environment($_SERVER['REQUEST_URI']);
        }
    
        /**
         * Set important environment variables and re-parse the query string.
         * @return boolean
         */
        function finalize() {
            if (defined('REWRITER_FINALIZED')) return false;
    
            define('REWRITER_FINALIZED', true);
    
            if (\is_file($_SERVER['DOCUMENT_ROOT'] . $_SERVER['SCRIPT_NAME'])) {
                $_SERVER['SCRIPT_FILENAME'] = $_SERVER['DOCUMENT_ROOT'] . $_SERVER['SCRIPT_NAME'];
            }
    
            if (isset($_SERVER['QUERY_STRING'])) {
                $_GET = [];
                parse_str($_SERVER['QUERY_STRING'], $_GET);
            }
    
            $_SERVER['PHP_SELF'] = $_SERVER['SCRIPT_NAME'];
    
            return true;
        }
    
        /**
         * Adjust the server environment variables to match a given URL.
         * @param string $url
         */
        function set_environment($url) {
            $url = rtrim($url, '&?');
            $request_uri = $script_name = $url;
            $query_string = null;
    
            if (strpos($url, '?') > 0) {
                $script_name = substr($url, 0, strpos($url, '?'));
                $query_string = substr($url, 1 + strpos($url, '?'));
            }
    
            $_SERVER['REQUEST_URI'] = $request_uri;
            $_SERVER['SCRIPT_NAME'] = $script_name;
            $_SERVER['QUERY_STRING'] = $query_string;
        }
    
        /**
         * Parse regular expression matches. eg. $0 or $1
         * @param string $url
         * @return string
         */
        function parse_matches($url) {        
            $replace = function($bit) {
                global $matches;
                return isset($matches[$bit[1]])
                    ? $matches[$bit[1]]
                    : null;
            };
    
            return preg_replace_callback('/\$([0-9]+)/', $replace, $url);
        }
    
        /**
         * Parse Apache style rewrite parameters. eg. %{QUERY_STRING}
         * @param string $url
         * @return string
         */
        function parse_parameters($url) {
            $replace = function($bit) {
                return isset($_SERVER[$bit[1]])
                    ? $_SERVER[$bit[1]]
                    : null;
            };
            return preg_replace_callback('/%\{([A-Z_+]+)\}/', $replace, $url);
        }
    
        /**
         * Change the internal url to a different url.
         * @param string $from Regular expression to match current url, or optional when used in conjunction with `test`.
         * @param string $to URL to redirect to.
         * @return boolean
         */
        function rewrite($from, $to = null) {
            if (defined('REWRITER_FINALIZED')) return false;
    
            $url = $_SERVER['SCRIPT_NAME'];
    
            if (isset($to)) {
                $url = preg_replace($from, $to, $url);
            } else {
                $url = parse_matches($from);
            }
    
            set_environment(
                parse_parameters($url)
            );
    
            return true;
        }
    
        /**
         * Compare a regular expression against the current request, store the matches for later use.
         * @return boolean
         */
        function test($expression) {
            global $matches;
            if (defined('REWRITER_FINALIZED')) return false;
            return 0 < (integer)preg_match($expression, $_SERVER['SCRIPT_NAME'], $matches);
        }
    
        initialize();
    
        // Your rewrite rules here.
        test('%/(.*)-(.*)\.htm$%') && rewrite('/?page=$1&sub=$2&%{QUERY_STRING}') && finalize();
        test('%^([^/]*)\.htm$%') && rewrite('/?page=$0&%{QUERY_STRING}') && finalize();
    
        echo "<pre>";
        var_dump($_SERVER);
        // include index.php or something
    

    I've included a bunch of 'helper' functions which will make it easier to write your rewrite rules (borrowed here).