php.htaccessurl-rewritingvanity-url

Combine .htaccess rules: remove extension and rewrite URL variables


I have an .htaccess file with the following rules

# replace 'RewriteBase' with current working folder
# put '<base href="/">' in <head> if you are in the root folder
# put '<base href="/foldername/">' in <head> if you are in a subfolder of the root
Options +FollowSymLinks
RewriteEngine On
RewriteBase /pretty-urls

# Remove slash if file
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)/$ $1 [R=301,L]

# Redirect to extensionless url
RewriteCond %{THE_REQUEST} ^(.+)\.php([#?][^\ ]*)?\ HTTP/
RewriteRule ^(.+)\.php$ $1 [R=301,L]

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php [L]

RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule .* - [L]
RewriteRule ^(.*)$ user.php?u=$1 [NC]

This basically transforms and redirects any of the following URLS, www.mysite.com/about.php, www.mysite.com/about and www.mysite.com/about/ to www.mysite.com/about and also should allow me to write www.mysite.com/user/john but instead throws a Internal Server Error plus a 500.

I can't figure out what is wrong, the code is based on this ( How-to? Vanity URL & ignore .PHP extension with .htaccess )

My php looks like this

foreach ( $users as $user ) {
    echo '<p><a href="user/'.$user->username.'">'.$user->username.'</a></p>';
}

Any help is appreciated, thank you.

EDIT: the Apache error log says

[Fri Sep 27 14:26:26.539589 2013] [core:error] [pid 2276:tid 1680] [client ::1:60023] AH00124: Request exceeded the limit of 10 internal redirects due to probable configuration error. Use 'LimitInternalRecursion' to increase the limit if necessary. Use 'LogLevel debug' to get a backtrace., referer: http://localhost/pretty-urls/users

As suggested, I removed the [NC] flag and added the [L] flag, but the same error persists.


Solution

  • The error Request exceeded the limit of 10 internal redirects is usually caused by a rewrite rule that both matches the original url as well as the rewritten url. The L flag will only stop rewriting for the current cycle, but as apache pushes the request through .htaccess again anyway, this will not stop these faulty internal redirects.

    When recreating this on my own localhost, I noticed that the problem is the rule that adds .php to your url.

    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME}\.php -f
    RewriteRule ^(.*)$ $1.php [L]
    

    %{REQUEST_FILENAME} contains the filepath to document_root/user in my case. You test if document_root/user.php is a file (which it is), but then add .php to the url, which will result in /user/john/.php. I think the problem can be fixed to move your files to a subdirectory, so that the virtual url will never match a file or directory in your folders.

    You could change the rule to something like the following, but I am not sure if this will eliminate the problem completely:

    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME}\.php -f
    RewriteRule ^([^/]+)/?(.*)$ $1.php?q=$2 [L]
    

    This will rewrite link.url/test/qwer to test.php?q=qwer and link.url/test to test.php?q=.

    Your rule to make an internal rewrite for user.php should be moved above the 'general' rule and should be changed to:

    RewriteRule ^user/(.*)/?$ user.php?u=$1 [NC,L]
    

    This will rewrite link.url/user/john/ to user.php?u=john.

    As always, see the documentation. To properly debug .htaccess, put LogLevel alert rewrite:trace3 in your httpd.conf and restart the service. This would have showed lines like the following, which give you a clue what is happening:

    [rewrite:trace1] [pid 4800:tid 1532] mod_rewrite.c(468): [client ::1:49451] ::1 - - [localhost/sid#3ecb48][rid#12b1a88/initial/redir#2] [perdir C:/wamp/www/] internal redirect with /user/john/.php.php.php [INTERNAL REDIRECT]