views:

308

answers:

4

Hey folks,

I am trying to get URL rewriting to work on my website. Here is the contents of my .htaccess:

RewriteEngine On
RewriteRule ^blog/?$ index.php?page=blog [L]
RewriteRule ^about/?$ index.php?page=about [L]
RewriteRule ^portfolio/?$ index.php?page=portfolio [L]
#RewriteRule ^.*$ index.php?page=blog [L]

Now the 3 uncommented rewrite rules work perfectly, if I try http://www.mysite.com/blog/, I get redirected to http://www.mysite.com/index.php?page=blog, the same for "about" and "portfolio". However, if I mistype blog, say I try http://www.mysite.com/bloh/, then obviously I get a 404 error. The last rule, the commented one, was to help prevent that. Any URL should get redirected to the blog, but of course this rule is still parsed even if we have successfully used a previous one, so I used the "last" flag ([L]). If I uncomment my last rule, anything, including blog, about, and portfolio, redirect to blog. Shouldn't the "last" flag stop the execution as soon as it finds a matching rule?

Thanks.

+3  A: 

Yes, the Last flag means it won't apply any of the rules following this rule in this request.

After rewriting the URL, it makes an internal request using the new rewritten URL which would match your last RewriteRule and thus your redirects go into an infinite loop.

Use the RewriteCond directive to limit rewriting to URLs that don't start with index.php, and you should be fine.

andri
+1  A: 

From apache's mod_rewrite docs

'last|L' (last rule) Stop the rewriting process here and don't apply any more rewrite rules. This corresponds to the Perl last command or the break command in C. Use this flag to prevent the currently rewritten URL from being rewritten further by following rules. Remember, however, that if the RewriteRule generates an internal redirect (which frequently occurs when rewriting in a per-directory context), this will reinject the request and will cause processing to be repeated starting from the first RewriteRule.

You could use

 ErrorDocument 404 /index.php?page=blog

but you should be aware of the fact that it doesn't return 404 error code, but a redirect one and I don't know if that is such a good practice.

andi
Thanks for the answer. My current regex already takes the optional trailing slash in consideration if you look carefully.
Xeon06
Oh, yeah. I didn't see that. Sorry :)
andi
+1  A: 

You could add a condition like:

RewriteCond %{REQUEST_URI} !^index\.php

I'll also mention that using RewriteRule ^.*$ is a good way to break all of your media requests (css, js, images) as well. You might want to add some conditions like:

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

To make sure you're not trying to rewrite actual files or directories that exist on your server. Otherwise they'll be unreachable unless index.php serves those too!

Gabriel Hurley
Thanks, that fixed it!
Xeon06
+1  A: 

After you [L]eave processing for the request, the whole processing runs again for the new (rewritten) URL. You could get out of that loop by using this before your other rules:

RewriteRule ^index.php - [L]

which means "for index.php, don't rewrite and leave processing."

Piskvor