views:

391

answers:

3

Hi guys and gals,

I'm trying to create a rule used in a .htaccess file to match anything but a particular string, in this case: index.

I thought that it should be possible to match this special string first and use [L] but that's not working,
and it should be possible using the following regex, but it causes a 500 error.

I want to match:

  • pagename1
  • pagename2/whatever
  • pagename3/234/whatever
  • about
  • contact-us
  • (etc)

but not

  • index/123
  • index/124/whatever

(BTW "index" is the name of a file with no extension, not my choice, this is a work thing)

^(?!index)[\w/\-]+

I assume that apache's implementation of regex doesn't cope with the (?!xxx) rule.

Any help/suggestions will be much appreciated.

+1  A: 

(Please read the comments. I doubt it and I've never encountered problems, while it gives one much cleaner .htaccess files, but: using RewriteCond might be preferred over using RewriteRule with a dash, due to how rulesets are processed?)

Just use RewriteRule as follows, to not rewrite (the dash), and stop subsequent rewriting (the [L]) for anything that starts with index/:

# Do not rewrite anything that starts with index/
RewriteRule ^index/ - [L]

After this, do any rewriting you like.

Or maybe even limit some more first:

# Do not rewrite files, directories or symbolic links 
RewriteCond %{REQUEST_FILENAME} -f [OR] 
RewriteCond %{REQUEST_FILENAME} -d [OR] 
RewriteCond %{REQUEST_FILENAME} -l 
RewriteRule . - [L]
Arjan
Ah, that may well be the answer I was looking for, I didn't know about `-` in .htaccess
jezmck
Conds are safer. If you have another rule matching index later on things could get weird. [L] is not the last pass ever, just terminates the current pass, there are various cases where the request passes more than one time through the rules.
Vinko Vrsalovic
@Vinko, multiple passes are good to keep in mind indeed. But how would a RewriteCond (especially a negative RewriteCond) not be subject to weird matches during another pass then?
Arjan
+4  A: 

You can use RewriteConds to do this, for example:

RewriteCond %{REQUEST_URI} !^index
RewriteRule (.*) index.php?what=$1

That will rewrite every URL which doesn't start by index. If you want it to avoid it anywhere in the URL, remove the ^

Vinko Vrsalovic
A: 

Apache used three different regular expression implementations. The first was System V8, since Apache 1.3 they used POSIX ERE and since Apache 2 they use PCRE. And only PCRE supports look-ahead assertions. So you need Apache 2 to use that rule.

But now to your question. If you use this rule:

RewriteRule ^index/ - [L]

anything that starts with /index/ should be catched by this rule and no further rule should be applied.

But if that doesn’t work, try this:

RewriteRule !^index/ …

Again, this rule will be applied on any request that’s URL path doesn’t start with /index/.

And if you want to capture anything from the URL, use a RewriteCond condition to test either the full URL path itself (%{REQUEST_URI}) or just the match of one of your pattern groups:

RewriteCond %{REQUEST_URI} !^/index/
RewriteRule (.*) …
# or
RewriteCond $1 !^index$
RewriteRule ^([^/]+)/(.*) …
Gumbo