Question

I'm building a fairly large website and my .htaccess is starting to feel a bit bloated, is there a way of replacing my current system of - one rule for each of the possibile number of vars that could be passed, to one catch all expression that can account for varying numbers of inputs ?

for example I currently have:

RewriteRule ^([a-z]+)/([^/]*)/([^/]*)/([^/]*)/([^/]*)/([^/]*)$ /index.php?mode=$1&id=$2&$3=$4&$5=$6
RewriteRule ^([a-z]+)/([^/]*)/([^/]*)/([^/]*)$ /index.php?mode=$1&id=$2&$3=$4
RewriteRule ^([a-z]+)/([^/]*)$ /index.php?mode=$1&id=$2
RewriteRule ^([a-z]+)$ /index.php?mode=$1

the first backreference is always the mode and (if any more exist) the second is always id, thereafter any further backreferences alternate between the name of the input and its value

http://www.example.com/search
http://www.example.com/search/3039/sort_by/name_asc/page/23

I would love to be able to have one expression to gracefully handle all the inputs.

Was it helpful?

Solution

Do like Drupal:

  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]

And then handle all the stuff in your script using php code something like this

$pathmap = ();
if ($_GET["q"]){
    $path = split("/", $_GET["q"]);
    for ($i=0; $i+1<count($path); $i++){
        $pathmap[$path[$i]] = $path[$i+1];
        $i++;
    }
}

OTHER TIPS

I don't know if it can be done with a single expression, but it can be done with a fixed number of expressions, no matter how long the query string.

Your mod_rewrite rules will be called repeatedly, giving you what is sometimes called mod_rewrite recursion. There are techniques for avoiding it, but I think you want to use it.

Set up a rule that replaces the last pair with name=value&

Keep tacking on the input query string to the output. Every time through, your query string will get longer and your URL will get shorter.

Eventually you have only a single value that matches your last rule.

You have to capture the query string with

RewriteCond %{QUERY_STRING} ^(.*)$

And then you add it back to the output with %1

You'd end up with four lines.

I know four lines is what you started with, but you'd match as many parameters as you want without having to add a fifth line.

RewriteCond %{QUERY_STRING} ^(.*)$
RewriteRule ^(.*/)([^/]+)/([^/]+) $1?$2=$3&%1 [L]
RewriteCond %{QUERY_STRING} ^(.*)$
RewriteRule ^([^/]+)/ $1.php?%1 [L]

This will rewrite the following

/mypage/param1/val1/param2/val2/param3/val3/...     --->
/mypage.php?param1=val1&param2=val2&param3=val3&...

It stops when there is only one parameter remaining. It will take the first "parameter" and call the .php file with that name. There is no limit to the number of param/val pairs.

I don't believe that their is a way - but I'd say that your best bet would be to have the script "index.php" process a path instead of having to do so many back references.

So for example, your rewriterule would be

RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

Or similar... This would then make the $_SERVER['REQUEST_URI'] variable contain the path information, which you can split and parse.

$path = split('/', $_SERVER['REQUEST_URI']);
array_shift($path); // We always have a first null value
$mode = array_shift($path);

This ends up with $mode containing the mode, and $path containing an array of elements that are the rest of your path, so

http://example.com/foo/bar/baz

Would leave you with $mode being 'foo' and $path being an array containing 'bar' and 'baz'

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top