mod_rewrite to remove .php but still serve the .php file?

I just wanted to do a simple thing with mod_rewrite. I have a site which uses .php files, and I wanted to rewrite those to cleaner URLs, and remove the .php. So, files would be www.mysite.com/contact and so on.

This does work how I wanted, but I had expected that it would still serve my contact.php file, but just show the user that they were at /contact rather than contact.php. But, it is looking for a file just called contact, which, is not there.

So, what so I need to do, do still use my contact.php file, but rewrite the URL for the user to /contact ?

Here is what I am using:

SetEnv APPLICATION_ENV development
RewriteEngine on
RewriteBase /

# Always use www.
RewriteCond %{HTTP_HOST} ^mysite\.com$ [NC]
RewriteRule ^(.*)$ http://www.mysite.com/$1 [L,R=301]

# Change urlpath.php to urlpath
RewriteCond %{HTTP_HOST} ^www\.mysite\.com$ [NC]
RewriteRule ^(.*)\.php$ http://www.mysite.com/$1 [L,R=301]

Here is Solutions:

We have many solutions to this problem, But we recommend you to use the first solution because it is tested & true solution that will 100% work for you.

Solution 1

For this solution, I have followed the following rules:

  1. If the user tries to load /something.php they should be externally redirected to /something.
  2. If the user tries to load /something then they should be internally redirected to /something.php.
  3. If the user passed any query string parameters to the URL then these should be preserved through the redirects.
  4. If the user tries to load a different file which really exists on the filesystem (a stylesheet, image etc) then this should be loaded as is.

And here’s the final set of mod_rewrite magic:

RewriteEngine on
RewriteBase /

## Always use www.
RewriteCond %{HTTP_HOST} ^mysite\.com$ [NC]
RewriteRule ^(.*)$ http://www.mysite.com/$1 [L,R=301]

# Change urlpath.php to urlpath
## Only perform this rule if we're on the expected domain
RewriteCond %{HTTP_HOST} ^www\.mysite\.com$ [NC]
## Don't perform this rule if we've already been redirected internally
RewriteCond %{QUERY_STRING} !internal=1 [NC]
## Redirect the user externally to the non PHP URL
RewriteRule ^(.*)\.php$ $1 [L,R=301]

# if the user requests /something we need to serve the php version if it exists

## Only perform this rule if we're on the expected domain
RewriteCond %{HTTP_HOST} ^www\.mysite\.com$ [NC]
## Perform this rule only if a file with this name does not exist
RewriteCond %{REQUEST_FILENAME} !-f
## Perform this rule if the requested file doesn't end with '.php'
RewriteCond %{REQUEST_FILENAME} !\.php$ [NC]
## Only perform this rule if we're not requesting the index page
RewriteCond %{REQUEST_URI} !^/$
## Finally, rewrite the URL internally, passing through the user's query string
## using the [qsa] flag along with an 'internal=1' identifier so that our first
## RewriteRule knows we've already redirected once.
RewriteRule ^(.*)$ $1.php?internal=1 [L, QSA]

Solution 2

Your third rule should be the other way around:

# Change urlpath.php to urlpath
RewriteCond %{HTTP_HOST} ^www\.mysite\.com$ [NC]
RewriteCond %{REQUEST_FILENAME} !\.php$ [NC]
RewriteRule ^/?(.*)$ $1.php [L,R=301]

Once the user goes to /contact, it’ll load contact.php. The extra RewriteCond is so that if people DO go to contact.php, it won’t try to load contact.php.php

Solution 3

As I understand you want the URL to be /contact even if the URL was /contact.php.

You can check for the .php extension and do a redirect to remove it. Use R=301 (as you do).

Then you have to make your server accept the URL without the .php extension. It might actually already do that.

That’s what mod_negotiation does. It should be installed by default, but you might have to enable it.

You can also do that with mod_rewrite, but remove the R from the options. It will redirect internally instead of answering with an HTTP redirect.

Note: Use and implement solution 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply