Andy  Gee
Andy Gee

Reputation: 3335

Mod_Rewrite Rule Conflict Drving me Crazy

I have a .htaccess as follows and some rules are conflicting - I need to somehow make a condition so they don't

RewriteEngine On
RewriteRule ^search$ results_template.php [L]
RewriteRule ^load-([a-z0-9-]+)$ index.php?key=$1 [L]
RewriteRule ^([a-z0-9-]+)$ http://domain.com/share/index.php?key=$1 [L]

The .htaccess file is located at http://domain.com/directory/.htaccess


The first rule is supposed to just rewrite the name search to results_template.php and stop processing more rules

http://domain.com/directory/search

loads

http://domain.com/directory/results_template.php


The second rule is supposed to take the abcdef-1 from

http://domain.com/directory/load-abcdef-1

and send it as a parameter to

http://domain.com/directory/index.php?key=abcdef-1 and then stop processing rules.


The third rule is supposed to take the abcdef-1 from

http://domain.com/directory/abcdef-1

and send it as a parameter to

http://domain.com/share/index.php?key=abcdef-1 and then stop processing rules.


The problem I'm having is no matter how I try to make these play nicely together whenever I request http://domain.com/directory/search the third rule is invoked and I'm redirected.

I'm sure it's just complete tiredness or complete stupidity but I've been at this small step for too many hours now so any help would really be good. Thanks

Upvotes: 2

Views: 329

Answers (3)

regilero
regilero

Reputation: 30496

Your problem is what @Jan explained that when the first rewrite id done search becomes results_template.php. To understand it fully I will add that the [L] tag on the rewrite is really stoping the rewrite and pushing the resulting path to Apache but in fact an internal redirection is performed in apache and mod-rewrite is re-applied after that internal redirection.

It's the hardest thing to understand with mod-rewrite. Using RewriteLog and RewriteLogLevel may help you greatly to detect such problems when dealing with theses not so simple rules.

No the solution provided by Jan will work but a more generic solution exists. If you want your rules to be applied only once, only on the url provided by browsers, and if you are not chaining several layers of redirections then the simpliest way of ensuring your rules is to prevent them from being applied after the internal redirection. And this can be done by checking before each rule that the environ,ent variable REDIRECT_STATUS is empty

# prevent this rule from being applied after first pass
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ...

EDIT

But I've just been reading @baynezy (+1) answer and the [NS] or [nosubreq] tag seems to be doing the same thing. You should try it also.

Upvotes: 1

baynezy
baynezy

Reputation: 7066

You need to add the [NS] flag to third rule. This makes it not fire on internal sub requests.

Upvotes: 1

Jan
Jan

Reputation: 43169

You will need RewriteConds:

RewriteEngine On
RewriteBase /directory
RewriteRule ^search$ results_template.php [L]
RewriteRule ^load-([a-z0-9-]+)$ index.php?key=$1 [L] 
RewriteCond %{QUERY_STRING} !^results_template.php
RewriteRule ^([a-z0-9-]+)$ http://domain.com/share/index.php?key=$1 [L]

E.g. a user requests /search, then the query is transformed to results_template.php. With this new query /results_template.php all rules are checked again and of course the last rule fits as it is the most general one.

Upvotes: 1

Related Questions