.htaccess url rewriting generates an Internal Server Error

Marco Gasi
Marco Gasi used Ask the Experts™
I have a problem with the url rewriting in my .htaccess.
I use following lines to remove php extension:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^ %{REQUEST_URI}.php [L]

Open in new window

Originally my pages where in the document root and the following lines worked great to rewrite urls
RewriteCond %{THE_REQUEST} \s/categoria\?c=(\w+)\s [NC]
RewriteRule ^ /categoria/%1? [R=302,L]

Open in new window

But now I have put my pages in different subfolders accordingly to the chosen language. The main language is spanish and I have a folder 'es' where the spanish pages are. So I changed, or better I tried to change my htaccess to use subfolders:
RewriteCond %{THE_REQUEST} \s/es/categoria\?c=(\w+)\s [NC]
RewriteRule ^ es/categoria/%1? [R=302,L]

Open in new window

This works, because the url is actually rewritten, but it also generates an Internal Server Error. After some investigation I realized that it looks like there are too many redirections and once the limit is reached, Apache raises the error 500. But the suggeted solution to put an exclamation mark to the RewriteCond for files:
RewriteCond %{REQUEST_FILENAME}.php !-f

Open in new window

prevents the removing of the php extension.
Any idea?
Thank you.
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
David FavorFractional CTO
Distinguished Expert 2018

Tip: Simple way to debug is to comment out all your .htacess rules you've added, then start uncommenting them one by one. Whichever rule generates 500 errors is the offending rule.

Tip: Using a bare last flag ([L]) is a very bad idea, because this implies R=301 which will cause far more problems than you realize. Best to always use [R=302,L] for your last flag syntax.

Attach a copy of your full .htaccess file (as text, not an image), rather than just a snippet.

Attach a copy of your entire domain/host Apache config file with full <VirtualHost> stanzas.

Also attach a copy of your Apache error.log file.

Tip: Likely only you can debug this, as only you have access to your Apache config + log files. Increase your log verbosity for rewrite debugging + likely you'll instantly see the exact line where the problem exists.
Marco GasiFreelancer
Top Expert 2010


Hi David.

The lines which produce the error are the following ones:
RewriteCond %{THE_REQUEST} \s/es/categoria\?c=(\w+)\s [NC]
RewriteRule ^ es/categoria/%1? [R=302,L]

Open in new window

The same lines worked fine in the root directory changed as follows:
RewriteCond %{THE_REQUEST} \s/categoria\?c=(\w+)\s [NC]
RewriteRule ^ /categoria/%1? [R=302,L]

Open in new window

This is my full .htaccess:
<IfModule mod_rewrite.c>

RewriteEngine on

#Options -MultiViews

#RewriteCond %{HTTPS} !on

RewriteBase /
# First rewrite to HTTPS:
# Don't put www. here. If it is already there it will be included, if not
# the subsequent rule will catch it.
#RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [L,R=302]

#RewriteCond %{REQUEST_FILENAME} !-d
#RewriteCond %{REQUEST_FILENAME}.php -f
#RewriteCond %{REQUEST_URI} ^(.+)\.php$
#RewriteRule (.*)\.php$ /$1 [R=302,L]

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^ %{REQUEST_URI}.php [L]

# redirect "/section.php?id=xxx" to "/section/xxx"
RewriteCond %{THE_REQUEST} \s/es/categoria\?c=(\w+)\s [NC]
RewriteRule ^ es/categoria/%1? [R=302,L]


<IfModule mod_expires.c>
## Enable expirations
ExpiresActive On

## Default directive
ExpiresDefault "access plus 1 year"

## My favicon
ExpiresByType image/x-icon "access plus 1 year"
AddType image/x-icon .ico
## Images
ExpiresByType image/gif "access plus 1 year"
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/jpg "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType image/ico "access plus 1 year"
ExpiresByType image/x-icon "access plus 1 year"

## Files
ExpiresByType text/html "access plus 1 year"
ExpiresByType text/css "access plus 1 year"
ExpiresByType text/javascript "access plus 1 year"
ExpiresByType application/x-javascript "access plus 1 year"
ExpiresByType application/x-download "access plus 1 year"
ExpiresByType application/pdf "access plus 1 year"


	<FilesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)(\.gz)?$">
		Header unset ETag
		FileETag None
		Header set Last-Modified "Mon, 31 Aug 2009 00:00:00 GMT"

<ifModule mod_gzip.c>
mod_gzip_on Yes
mod_gzip_dechunk Yes
#mod_gzip_item_include file .(html?|txt|css|js|php|pl)$
mod_gzip_item_include file .(html?|txt|js|php|pl)$
mod_gzip_item_include handler ^cgi-script$
mod_gzip_item_include mime ^text/.*
mod_gzip_item_include mime ^application/x-javascript.*
mod_gzip_item_exclude mime ^image/.*
mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*

<IfModule mod_deflate.c>
  # Compress HTML, CSS, JavaScript, Text, XML and fonts
  AddOutputFilterByType DEFLATE application/javascript
  AddOutputFilterByType DEFLATE application/rss+xml
  AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
  AddOutputFilterByType DEFLATE application/x-font
  AddOutputFilterByType DEFLATE application/x-font-opentype
  AddOutputFilterByType DEFLATE application/x-font-otf
  AddOutputFilterByType DEFLATE application/x-font-truetype
  AddOutputFilterByType DEFLATE application/x-font-ttf
  AddOutputFilterByType DEFLATE application/x-javascript
  AddOutputFilterByType DEFLATE application/xhtml+xml
  AddOutputFilterByType DEFLATE application/xml
  AddOutputFilterByType DEFLATE font/opentype
  AddOutputFilterByType DEFLATE font/otf
  AddOutputFilterByType DEFLATE font/ttf
  AddOutputFilterByType DEFLATE image/svg+xml
  AddOutputFilterByType DEFLATE image/x-icon
  AddOutputFilterByType DEFLATE text/css
  AddOutputFilterByType DEFLATE text/html
  AddOutputFilterByType DEFLATE text/javascript
  AddOutputFilterByType DEFLATE text/plain
  AddOutputFilterByType DEFLATE text/xml

  # Remove browser bugs (only needed for really old browsers)
  BrowserMatch ^Mozilla/4 gzip-only-text/html
  BrowserMatch ^Mozilla/4\.0[678] no-gzip
  BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
  Header append Vary User-Agent

Open in new window

I have required a copy of the Apache config file to my provider because I'm on a shared hosting.

About the Apache error.log, here's the problem:
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://dev.ilpinguinoweb.com/es/index

Open in new window

Trying to solve changing this line
RewriteCond %{REQUEST_FILENAME}.php -f

Open in new window

to this
RewriteCond %{REQUEST_FILENAME} !-f

Open in new window

doesn't solve the issue.

Hope this helps
Top Expert 2010
Since I've not been able to find a solution to make .htaccess rules work even with subfolder, I have totally refactored my code to use php in order to rewrite urls.
Thank you.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial