Jeroen
Jeroen

Reputation: 385

mod_rewrite exclude multiple words

I'm going to implement a "pretty rewrite" redirect solution through htaccess and mod_rewrite. What I want to achieve is the following:

example.com/test123 --> example.com/page.php?c=test123

This is easily done with a single RewriteRule:

RewriteRule ^(.*) page.php?c=$1 [L,NC]

But I want to exclude some urls:

I've tried some regex, but so far with no avail. I would like some help to make sure that the listed directories do not get rewritten, but any other keyword is rewritten.


Some things I've tried:

The following excerpts cancel any rewriting:

The first one:

RewriteCond %{QUERY_STRING} "^!prijslijst/{0,1}(.*)"
RewriteCond %{QUERY_STRING} "^!werk/{0,1}(.*)"
RewriteCond %{QUERY_STRING} "^!js/{0,1}(.*)"
RewriteCond %{QUERY_STRING} "^!css/{0,1}(.*)"
RewriteCond %{QUERY_STRING} "^!CMS/{0,1}(.*)"
RewriteCond %{QUERY_STRING} "^!images/{0,1}(.*)"
RewriteCond %{QUERY_STRING} "^!contact/{0,1}(.*)"
RewriteRule ^(.*) page.php?c=$1 [L,NC]

The second one:

RewriteCond %{QUERY_STRING} "^!(prijslijst|werk|js|css|CMS|images|contact)/{0,1}(.*)"
RewriteRule ^(.*) page.php?c=$1 [L,NC]

The third one:

RewriteRule ^!(prijslijst|werk|js|css|CMS|images|contact)/{0,1}(.*) page.php?c=$1 [L,NC]

A slight adjustment of the top one resulted in everything being rewritten, even the stuff I wanted to exclude:

RewriteCond %{QUERY_STRING} "!prijslijst/{0,1}(.*)"
RewriteCond %{QUERY_STRING} "!werk/{0,1}(.*)"
RewriteCond %{QUERY_STRING} "!js/{0,1}(.*)"
RewriteCond %{QUERY_STRING} "!css/{0,1}(.*)"
RewriteCond %{QUERY_STRING} "!CMS/{0,1}(.*)"
RewriteCond %{QUERY_STRING} "!images/{0,1}(.*)"
RewriteCond %{QUERY_STRING} "!contact/{0,1}(.*)"
RewriteRule ^(.*) page.php?c=$1 [L,NC]

(^ was removed from the start of every second parameter of RewriteCond)


EDIT

I've submitted an answer of my own to document the final solution. @ndn's answer was of great influence, it gave me a push in the right direction. Many thanks!

Upvotes: 0

Views: 1647

Answers (2)

Jeroen
Jeroen

Reputation: 385

My solution (with thanks to @ndn)

@ndn gave me a starting point to find the right solution. I'd like to thank him for giving me a pointer in the right direction!

In the end, I reduced the amount of RewriteConds. Unlike @ndn sugggested, I did not go for a negative regex in the RewriteRule. I think it gives a better overview to use RewriteConds for constraining the rewriting, but it can be done within both RewriteRule and RewriteCond, it's a matter of preference.

So what did I end up with? Here it is:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /ut-taertje/
RewriteCond %{REQUEST_URI} !^/ut-taertje/(?:.{0}$|css|CMS|js|images|prijslijst|contact|werk)(?:$|/.*)?$
RewriteCond %{REQUEST_URI} !^/ut-taertje/(?:page\.php|index\.php)$
RewriteRule ^(.*)$ page.php?c=$1 [L,NC]
</IfModule>

I'll explain it shortly. I did not include the RewriteBase in the question, but given the fact it plays a part in the RewriteCond, it would clarify it better. Replace the subdirectory /ut-taertje/ with / to make it apply to the root.

So I put my rewriting constraints into two RewriteConds. The upper one is a regex group to exclude the various directories I wanted to exclude. Note that the group includes .{0}$, as it should also exclude the root of the directory itself, which does not have anything after the leading / of the request URI. Next to that, I have a second regex group ((?:$|/.*)?) which enables me to exclude not only the directories themselves, but also anything that comes after the slash (not only js/, but also js/codebase.js or js/jquery/).

The second RewriteCond is to exclude an edge case. When testing, I used 301 redirects, rather than "invisible" redirects. It appeared that rewriting to page.php?c=<the original request URI> triggered an infinite loop of redirect requests from the server. Why? Because it was not part of the exclusion from the first RewriteCond!

So that's it. The RewriteRule is rather simple, it rewrites anything that passes the conditional filters from both RewriteConds.

Upvotes: 0

ndnenkov
ndnenkov

Reputation: 36110

RewriteRule ^(?!/$|css/|images/|CMS/|js/|contact/|prijslijst/|werk/)(.*) page.php?c=$1 [L,NC]

Basically, I just took your original rewrite and added negative lookahead for the list of things you wanted skipped (?!/$|css/|images/|CMS/|js/|contact/|prijslijst/|werk/).

Upvotes: 3

Related Questions