I have a website that is in the root folder. It has a .htaccess with teh code below:

RewriteEngine on
RewriteRule ^(.*)/$ $1.php

When I open http://example.com/login/ I get a "404 Not Found" error but when I open http://example.com/login without the trailing / the URL opens without any problem.

I need .htaccess code to set in the root directory to open PHP file like login.php as /login/ or /login (without trailing /).


Try ^([^/]+)/?$ and see if it works as expected.

  • After try this code RewriteEngine on RewriteRule ^([^/]+)/?$ $1.php i got 500 error – Mahmood Aug 19 '12 at 16:21
  • By simply making the trailing slash optional (and still having an all-encompassing capturing subpattern) you would expect this to create a rewrite loop (hence the 500 error). A request for /login/ would rewrite to /login.php to /login.php.php to /login.php.php.php, etc. – DocRoot May 24 at 21:33

This behavior is typical of a conflict with MuiltiViews. You should disable MultiViews at the top of your .htaccess file:

Options -MultiViews

This explains why /login without the trailing / successfully serves the file - your RewriteRule is entirely bypassed in this scenario.

With MultiViews enabled, when requesting /login/, mod_negotiation mocks up a rewrite map and issues an internal subrequest for /login.php before mod_rewrite gets to process the URL. The path-info (trailing /) is added back, to become /login.php/. This is passed back for further processing and matches your overly-generic (^(.*)/$) RewriteRule pattern, resulting in an internal rewrite to /login.php.php/ etc. Depending on your config, this could result in a 403 (as it can result in a malformed request), or a 404 (as you appear to be seeing).

Disabling MultiViews alone (as mentioned above) would solve this problem. However, you should also consider making your RewriteRule pattern more restictive. For example, to avoid matching URLs that already contain a dot (ie. have a file extension):

RewriteRule ^([^.]+)/$ $1.php [L]

Simply making the regex more restrictive may even "fix" the error. However, it would be MultiViews making the internal subrequest, not mod_rewrite (your rule would simply be bypassed).

as /login/ or /login (with or without the trailing /)

To allow the rule to work with either /login/ or /login (ie. with or without the trailing slash) you would need to make the trailing slash optional, ie. /?. But you would also need to either make the preceding pattern non-greedy or include the slash in the negated character class in order to avoid capturing the trailing slash in the backreference.

For example, either:

RewriteRule ^([^.]+?)/?$ $1.php [L]


RewriteRule ^([^./]+)/?$ $1.php [L]

But the second rule would only work with URLs that contain a single path segment, whereas the first would work with a URL of the form /foo/bar/login.

In Summary

Options -MultiViews

RewriteEngine On
RewriteRule ^([^.]+?)/?$ $1.php [L]

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.