Way to stop rewrites processing if true?

Hi,

I have a ton of rewrite rules in my .htaccess file, and I’m hoping to trim them down a bit. For example:

RewriteCond %{QUERY_STRING} nh=(\d+)
RewriteRule ^blog/cat_.+_c([0-9]+)\.html /cgi-bin/blog.cgi?cat=$1;nh=%1 [L]
RewriteRule ^blog/cat_.+_c([0-9]+)\.html /cgi-bin/blog.cgi?cat=$1 [L]
RewriteRule ^blog/article_.+_a([0-9]+)\.html /cgi-bin/blog.cgi?article=$1 [L]
RewriteRule ^blog/$ /cgi-bin/blog.cgi [L]

What I want to do, is stop anything processing IF the requested URI is either a directory, or a file that exists. So I could do:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{QUERY_STRING} nh=(\d+)
RewriteRule ^blog/cat_.+_c([0-9]+)\.html /cgi-bin/blog.cgi?cat=$1;nh=%1 [L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^blog/cat_.+_c([0-9]+)\.html /cgi-bin/blog.cgi?cat=$1 [L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^blog/article_.+_a([0-9]+)\.html /cgi-bin/blog.cgi?article=$1 [L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^blog/$ /cgi-bin/blog.cgi [L]

But, as you can see, there is a LOT of repetition! (which will make managing it a PITA)

My question - is there a way I can put this up near the top of the .htaccess file, so that it will just ignore any rules above if it matches?

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

TIA

Andy

Andy,

Before all your mod_rewrite statements (except RewriteEngine on), test for a prior (internal) redirection then use the Skip flag to skip the number of RewriteRules to skip if the value of %{IS_SUBREQ} is true.

As usual, you might benefit from the mod_rewrite tutorial at http://dk.co.nz/seo as it contains explanations and sample code. It’s helped many SitePoint members in the past and should help you, too.

Regards,

DK

Hi,

Thanks - I’m quite savvy when it comes to rewrites - just not this instance. So there is no way to also “wrap” it in a condition? Kinda like I would do when coding:

if (-e $request|| -d $request) {
  # run these rules
}

I was hoping to be able to just do it with a single query, instead of having to place it before every single rule (which makes reading/tweaking it harder in the future)

Cheers

Andy

Ah actually, could this work:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .? - [S=500]

(set to 500, just so it ignores anything after)

?

Andy,

You’ve got the idea BUT, if you’re trying to allow a single redirect and then no other (internal) redirects, you missed the value of the {IS_SUBREQ} variable.

Of course, the Skip rule is designed to skip a specific number of RewriteRULEs but a little overkill should do the trick, too. If you’re intention is to use it with the file and directory test, you need to use the logical INVERSE of the tests you have made for each RewriteRule set in order to skip over these rule sets.

Regards,

DK

Ah yeah, good point! :slight_smile:

For the IS_SUBREQ - maybe I’m missing something, but I’m not sure that would help in my case?

Cheers

Andy

Andy,

You’ve got it (logical inverse).

On a re-read of your first post, I missed the point that you simply wanted to avoid the -f -d tests (I “read” that you wanted to only redirect ONCE and not a second time - my bad).

Combining rewrite statements can look complicated but offers greater speed in processing the rules. I haven’t looked closely at your set of rules (argh!) but believe that you should be able to do better. For instance:

RewriteCond %{QUERY_STRING} nh=(\d+) RewriteRule ^blog/cat_.+_c([0-9]+)\.html /cgi-bin/blog.cgi?cat=$1;nh=%1 [L] RewriteRule ^blog/cat_.+_c([0-9]+)\.html /cgi-bin/blog.cgi?cat=$1 [L]

should be replaced with:

RewriteRule ^blog/cat_.+_c([0-9]+)\.html /cgi-bin/blog.cgi?cat=$1 [QSA,L]

“Why?” did I hear you ask? Well, if nh exists in a query string, you NEED the QSA to retain the string because you’ve created a new query string (and need to specify that nh={value} not be discarded). Two down to one.

If blog.cgi can cope with bogus values being mixed in with read values, the article RewriteRule can be merged, too in the cat RewriteRule like:

RewriteRule ^^blog/(cat|article)_.+_(c|a)([0-9]+)\.html /cgi-bin/blog.cgi?cat=$3&article=$3 [QSA,L]

Okay, that REQUIRES that blog.cgi be smarter than mod_rewrite (which should be easy - mod_rewrite is a server tool, not a coding language).

RewriteRule ^blog/$ /cgi-bin/blog.cgi [L]

is a little more problematic as I see two potential problems:

First, are you REQUIRING the trailing /? What happens if it’s not present? Yes, it should be (blog is supposed to be a directory which SHOULD have a trailing /) but … why not redirect to blog/ first ([R-301] to display the link as blog/) then send it to the cgi-bin? Moving the blog => blog/ redirection first, you COULD make the cat|article’s regex (after blog/) optional and bump the $ value in the redirection and be done with it in a single RewriteRule (excluding the blog => blog/ redirection). Please note that I said COULD as that seems a bit overly complex just for the sake of shortening the mod_rewrite to a single line (plus forcing the proper request for blog as a directory) so I would not go to quite that extreme.

Well, you asked. :wink:

Regards,

DK

1 Like

haha thanks. Yeah, the rules could do with a bit of a cleanup They have come in from different versions of the site, over a few years - so some are ever redundant. I was trying to host my own CDN for the site, but for some reason I just can’t get it fast enough. I’m now having a play around with some pay-for services, with physical servers around the world (rather than just my one, which is based in Canada)

Maybe something to look at on my Christmas holidays

Only if your Apache version is 2.4+.

http://httpd.apache.org/docs/2.4/mod/core.html#if

Thanks Jeff - looks like we are only on 2.2.29 though :frowning:

Thanks for the reply though!

Note the CORE in JM’s response. That means it’s applicable to the Apache CORE directives. Unfortunately, these do not flow through to mod_rewrite (yet).

Personally, I am glad that mod_rewrite is NOT supposed to be a programming language but a simple (and fast) instruction set for Apache to allow redirections upon conditions established within each RewriteRule set (RewriteCond statements belonging to a RewriteRule).

Regards,

DK

Ah ok :smile:

Yeah, I think I’m gonna re-do all my rewrites at some point - to try and condense them as much as possible. ATM, I have 150 lines - but some of it is stuff like:

RewriteCond %{HTTP_HOST} ^site.net
RewriteCond %{REQUEST_FILENAME} !\.(jpe?g|gif|js|css|xml|png|php|cgi|pl|JPE?G|GIF|BMP|flv|swf|xml|txt|ico|cur)$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/? https://site.net [R=301,L]

That could easily be cleaned up into 1 line now (I’ve moved my CDN onto a 3rd party system, and the -f and -d stuff are now dealt with by the S=x rule… and the long regex is pointless now, as the -f deals with it )

Something to look at over Christmas me thinks (joys of a bit of “time off” :wink: haha)

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.