views:

339

answers:

2

I have a simple URL rewriting setup with a .htaccess file. Excerpt:

RewriteEngine On

RewriteRule ^home(/)?$    index.php?mod=frontpage&com=showFrontpage
RewriteRule ^signup(/)?$      index.php?mod=usermanager&com=showRegistrationForm

This works perfectly fine. However, so does a request on the old style URL. When such a request comes in, I want to perform a 301 Permanent Redirect to the SEO friendly URL, however I cannot seem to figure out how I would map /index.php?mod=frontpage&com=showFrontpage to /home. Would I have to parse the .htaccess file and do some Regex hacking for this?

The URL rewriting was introduced pretty late into the project so the PHP script isn't 'aware' of the URL rewriting that's taking place; the .htaccess file is the only place this data is saved...

A: 

You can accomplish this in two ways:

  1. via .htaccess
  2. via phpcode

In either ways, be sure to not fall into a rediretion loop.

Via .htaccess

Use RewriteCond to check the QUERY_STRING and redirect depending on the querystring. Don't forget to add the [L] flag to prevent Apache to continue executing other rewrite rules and the R=301 flag to redirect the client.

Via php

Here you must distinguish between request from the client and requests from the server. You might want to change your rewrite rule and pass an additional parameter, example

RewriteRule ^home(/)?$ index.php?mod=frontpage&com=showFrontpage&server=1

Then, in your code, check whether the parameter exists and redirect if not.

Simone Carletti
A: 

In case anyone's interested, I solved this myself using this (probably absolutely horrible) piece of PHP code.

class clsURL {
    static function checkURL() {
     // don't allow requests on old style URL's
     if (($_SERVER['SCRIPT_NAME'] . '?' . $_SERVER['QUERY_STRING']) == $_SERVER['REQUEST_URI'] &&
       $_SERVER['REQUEST_METHOD'] != 'POST') {

      // redirect to new style URL
      $redirectTable = self::createReverseTable();
      $currentURL = $_SERVER['REQUEST_URI'];
      if (substr($currentURL, 0, 1) == "/")
       $currentURL = substr($currentURL, 1);
      $newURL = self::getReverseURL($currentURL, $redirectTable);

      if ($newURL) {
       header ('HTTP/1.1 301 Moved Permanently');
       header ('Location: /' . $newURL);

       exit;
      }
     }
    }

    static function getReverseURL($current, $reverseTable) {
     // filter out some common stuff
     $current = preg_replace("/&mid=[0-9]+/", "", $current);

     foreach ($reverseTable as $pair) {
      if (preg_match("|" . $pair['from'] . "|", $current)) {
       return preg_replace("|" . $pair['from'] . "|", $pair['to'], $current);
      }
     }

     // nothing found
     return false;
    }

    static function createReverseTable() {
     $file = fopen('.htaccess', 'r');
     $reverse = array();

     while ($line = fgets($file)) {
      if (stripos($line, 'RewriteRule') === 0) {
       $parts = preg_split("/[\\s\\t]/", $line, 3, PREG_SPLIT_NO_EMPTY);

       $regex = trim($parts[1]);
       $url = trim($parts[2]);
       $parts[2] = $url;

       $matches = array();
       if (preg_match_all("/\\$[0-9]/", $url, $matches)) {
        $matches = $matches[0]; // why? don't know.
        $from = str_replace('?', '\\?', $url);
        $to = $regex;

        foreach ($matches as $match) {
         $index = substr($match, 1);
         $bracket = 0;

         for ($i = 0; $i < strlen($regex); ++$i) {
          if (substr($regex, $i, 1) == "(") {
           $bracket++;

           if ($bracket == $index) {
            $pattern = "";

            $j = $i + 1;
            while (substr($regex, $j, 1) != ")") {
             $pattern .= substr($regex, $j, 1);
             $j++;
            }

            $from = str_replace('$' . $index, '(' . $pattern . ')', $from);
            $to = preg_replace('/\\(' . preg_quote($pattern, '/') . '\\)/', '\\$' . $index, $to, 1);
           }
          }
         }
        }

        // remove optional stuff that we don't use
        $to = str_replace('(-(.*))?', '', $to);

        // remove ^ and (/)?$
        $to = substr($to, 1);
        if (substr($to, -5) == '(/)?$')
         $to = substr($to, 0, strlen($to) - 5);
        $from = '^' . $from . '$';

        // index.php is optional
        $from = str_replace('index.php', '(?:index\\.php)?', $from);

        $reverse[] = array(
         'from' => $from,
         'to'   => $to
        );
       } else {
        $from = str_replace('?', '\\?', $url);
        $to = $regex;

        // remove ^ and (/)?$
        $to = substr($to, 1);
        if (substr($to, -5) == '(/)?$')
         $to = substr($to, 0, strlen($to) - 5);
        $from = '^' . $from . '$';

        // index.php is optional
        $from = str_replace('index.php', '(?:index\\.php)?', $from);

        $reverse[] = array(
         'from' => $from,
         'to'   => $to
        );
       }
      }
     }
     fclose($file);

     return $reverse;
    }
}
Aistina