Skip to content

Instantly share code, notes, and snippets.

@tawfekov
Forked from brendo/class.rewrite.php
Created April 25, 2013 05:29

Revisions

  1. @brendo brendo created this gist Mar 10, 2012.
    177 changes: 177 additions & 0 deletions class.rewrite.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,177 @@
    <?php

    /**
    * @package toolkit
    */

    /**
    * URL rewriter for use in conjunction with the PHP 5.4 internal HTTP server and `rounter.php`.
    */
    namespace Rewrite;

    class Storage {
    static $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) {
    return isset(Storage::$matches[$bit[1]])
    ? Storage::$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'];

    // From and To given:
    if (isset($to)) {
    $url = preg_replace($from, $to, $url);
    }

    // Use results from last test:
    else {
    $url = parse_matches($from);
    }

    set_environment(
    parse_parameters($url)
    );

    return true;
    }

    /**
    * Redirect the client 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.
    */
    function redirect($from, $to = null) {
    if (defined('REWRITER_FINALIZED')) return false;

    $url = $_SERVER['SCRIPT_NAME'];

    // From and To given:
    if (isset($to)) {
    $url = preg_replace($from, $to, $url);
    }

    // Use results from last test:
    else {
    $url = parse_matches($from);
    }

    $url = parse_parameters($url);

    header('Location: ' . $url); exit;
    }

    /**
    * Compare a regular expression against the current request, store the matches for later use.
    * @return boolean
    */
    function test($expression) {
    if (defined('REWRITER_FINALIZED')) return false;

    return 0 < (integer)preg_match($expression, $_SERVER['SCRIPT_NAME'], Storage::$matches);
    }

    /**
    * Does the current request point to a directory?
    * @return boolean
    */
    function is_dir() {
    if (defined('REWRITER_FINALIZED')) return false;

    return \is_dir($_SERVER['DOCUMENT_ROOT'] . $_SERVER['REQUEST_URI']);
    }

    /**
    * Does the current request point to a file?
    * @return boolean
    */
    function is_file() {
    if (defined('REWRITER_FINALIZED')) return false;

    return \is_file($_SERVER['DOCUMENT_ROOT'] . $_SERVER['REQUEST_URI']);
    }
    57 changes: 57 additions & 0 deletions router.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,57 @@
    <?php

    /**
    * Router for the testing HTTP server built into PHP 5.4.
    * Use with the following command from the root directory
    * of your Symphony installation:
    *
    * php -S localhost:8080 router.php
    *
    * If you need to add your own rules, copy this file and
    * use it as your own custom router.
    */

    namespace Rewrite;

    require_once 'symphony/lib/toolkit/class.rewrite.php';

    // Prepare environment:
    initialize();

    // SECURITY - Protect crucial files
    test('%^/manifest/(.*)%')
    | test('%.+\.(sql|xsl)$%')
    | test('%^/\.%')
    && die('<h1>Access Denied</h1>');

    // Do not apply rules when requesting actual files:
    if (is_file()) return false;

    // Make sure the URL ends in a trailing slash:
    test('%(?=/$)%')
    || redirect('%^.+%', '$0/');

    // Remove references to index.php:
    test('%/(symphony/)?index.php(/.*/?)%')
    && redirect('$1$2');

    // Admin area rewrite:
    test('%^/symphony/?$%')
    && rewrite('/index.php?mode=administration&%{QUERY_STRING}')
    && finalize();

    test('%/symphony(\/(.*\/?))?$%')
    && rewrite('/index.php?symphony-page=$1&mode=administration&%{QUERY_STRING}')
    && finalize();

    // Frontend page rewrite:
    rewrite('%^/(.*\/?)$%', '/index.php?symphony-page=$1&%{QUERY_STRING}')
    && finalize();

    if (isset($_SERVER['SCRIPT_FILENAME'])) {
    include_once $_SERVER['SCRIPT_FILENAME'];
    }

    else {
    include_once 'index.php';
    }