6

In many rewrite rule answers, when testing the url for a certain condition, I often see a mix of using RewriteCond with REQUEST_URI, and the RewriteRule itself.

Is this just personal preferences, or is there a performance reason, or just clarity of the rules? All of these are valid reasons, in my opinion; I'm just wondering if there's a particular reason.

I know there are conditions where RewriteCond is the only choice. I'm interested here in the cases where the RewriteRule would also work. Generally these are simpler rules.

Here are some examples:

EXAMPLE 1

This answer has a common pattern, allow certain folders as-is. Htaccess maintenance mode allow certain directories

# always allow these folders
RewriteCond %{REQUEST_URI} ^/display_me_always [OR]
RewriteCond %{REQUEST_URI} ^/another_folder [OR]
RewriteCond %{REQUEST_URI} ^/even_more_folders
RewriteRule .+ - [L]

This could be done with just a RewriteRule as:

RewriteRule ^/(?:display_me_always|another_folder|even_more_folders) - [L]

(Added the ?: for non-capturing. I'm never quite sure if it's faster to have a simpler rule, or not to capture.)

EXAMPLE 2

Modifying this for a more common scenario, redirect certain folders to other folders.

RewriteCond %{REQUEST_URI} ^/display_me_always [OR]
RewriteCond %{REQUEST_URI} ^/another_folder [OR]
RewriteCond %{REQUEST_URI} ^/even_more_folders
RewriteRule ^/[^/]+/(.*)$ /other_location/$1 [L]

This seems simpler with the rule only.

RewriteRule ^/(?:display_me_always|another_folder|even_more_folders)/(.*)$ /other_location/$1 [R=301,NC]

EXAMPLE 3

This answer has a common pattern, redirect if not already in the target location. Mod Rewrite rule to redirect all pdf request to another location. Test the folder with the RewriteCond, then test the file with the rule.

I can see a negative condition being much clearer to do with RewriteCond, but it's still possible with RewriteRule.

RewriteCond %{REQUEST_URI} !^/web_content/pdf/
RewriteRule ^(.+\.pdf)$ /web_content/pdf/$1 [L]

This could be written as

RewriteRule ^(?!/web_content/pdf/)(.+\.pdf)$ /web_content/pdf/$1 [L]
Community
  • 1
  • 1
goodeye
  • 2,389
  • 6
  • 35
  • 68

2 Answers2

2

One simple reason: it's much easier to understand for a non regex guru.

The rewrite rule that you will give to a OP today, he may need to modify one day later .. and the easier the rule to understand the more chances that he will look into it himself and not running again to this place for yet another small fix / new similar rule.

Yes, combined rule is faster -- no doubts here. But the time spent at URL rewriting is still so small compared to a single script execution ... that it only can make some difference on very-very CPU busy servers and when there are a lot of such rewrites.

Therefore, the most optimal will be something in between -- which is still easy to read and is compact and efficient at the same time. Instead of

# always allow these folders
RewriteCond %{REQUEST_URI} ^/display_me_always [OR]
RewriteCond %{REQUEST_URI} ^/another_folder [OR]
RewriteCond %{REQUEST_URI} ^/even_more_folders
RewriteRule .+ - [L]

offer

# always allow these folders
RewriteCond %{REQUEST_URI} ^/(display_me_always|another_folder|even_more_folders)
RewriteRule .+ - [L]

You cannot become a master in a day or two (unless, maybe, you are some kind of genius) -- everything takes time. And the more practical experience you have (by modifying these rules yourself) the better it is for you to move further, to produce more efficient/stable rule.

BTW: This rule will not work if placed in .htaccess (URL in matching pattern starts with no leading slash):

RewriteRule ^/(?:display_me_always|another_folder|even_more_folders) - [L]

But will work fine if placed in server config / virtual host context -- that's one of the "nuances" you need to know.

LazyOne
  • 158,824
  • 45
  • 388
  • 391
  • Thanks for the insight. I'm a big fan of design-time winning out over run-time. I came up from isapi_rewrite v2, before learning v3 (and mod_rewrite). So I'm generally an expert at very very complicated RewriteRule rules, but never picked up RewriteCond like this. Now I can start simplifying. – goodeye Sep 02 '11 at 02:05
  • And yes, I meant to make a comment about the slashes being a variable here; we evolved with .htaccess as the "only" rule files in separate websites (isapi_rewrite), and I tend to use an empty RewriteBase to start all the rules with a slash, to be explicit. I'll start leaning to mod_rewrite conventions when answering generic .htaccess questions. – goodeye Sep 02 '11 at 02:07
  • 1
    One small addition: Lot of people who work with URL rewriting will know what `.*` in `RewriteRule .* - [F,L]` will do (I'm skipping the RewriteCond here). But a lot of them will still be surprise that `^` in `RewriteRule ^ - [F,L]` will do the same and will be much faster (depends on how long the URL is -- the longer the more steps is required for regex engine to match `.*`). Most of them will not know what `^` does on it's own. Yeah .. specific thing maybe .. but just one more example of complexity/efficiency vs readability. – LazyOne Sep 02 '11 at 02:26
0

In general, I'd say you're right: RewriteCond is really largely for use with matching items OTHER than the REQUEST_URI. I'd expect that most of the cases you're looking at cases in an .htaccess. From the spec:

If you wish to match against the full URL-path in a per-directory (htaccess) RewriteRule, use the %{REQUEST_URI} variable in a RewriteCond.

Femi
  • 64,273
  • 8
  • 118
  • 148