133

Yes, I've read the Apache manual and searched here. For some reason I simply cannot get this to work. The closest I've come is having it remove the extension, but it points back to the root directory. I want this to just work in the directory that contains the .htaccess file.

I need to do three things with the .htaccess file.

  1. I need it to remove the .php

a. I have several pages that use tabs and the URL looks like page.php#tab - is this possible?

b. I have one page that uses a session ID appended to the URL to make sure you came from the right place, www.domain.example/download-software.php?abcdefg.

Is this possible? Also in doing this, do I need to remove .php from the links in my header nav include file? Should IE "<a href="support.php">support</a>" be <a href="support">support</a>?

  1. I would like it to force www before every URL, so it's not domain.example, but www.domain.example/page.
  2. I would like to remove all trailing slashes from pages.

I'll keep looking, trying, etc. Would being in a sub directory cause any issues?

Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
Dirty Bird Design
  • 5,333
  • 13
  • 64
  • 121
  • possible duplicate of [How to remove file extension from website address? (sample photos attached)](http://stackoverflow.com/questions/6534904/how-to-remove-file-extension-from-website-address-sample-photos-attached) – Dave Jarvis Apr 08 '12 at 00:02
  • I'm just curious, what benefit is this? Is this so that your users don't know what file on your server they're accessing? – Kellen Stuart Sep 20 '16 at 22:10
  • two fold. so they dont know what file types we are serving, and it just looks cleaner IMO – Dirty Bird Design Sep 28 '16 at 20:20
  • Another related question: https://stackoverflow.com/questions/6534904/how-to-remove-file-extension-from-website-address . – Edward Dec 15 '18 at 21:28
  • If none of the solutions provided below work. You can check out this post https://helponnet.com/2020/02/04/remove-html-and-php-extension-with-htaccess-rewriterule-url-rewriting-tips/ And learn from their how to do it yourself. – Amit Verma Jul 20 '21 at 15:34

18 Answers18

148

Gumbo's answer in the Stack Overflow question How to hide the .html extension with Apache mod_rewrite should work fine.

Re 1) Change the .html to .php

Re a.) Yup, that's possible, just add #tab to the URL.

Re b.) That's possible using QSA (Query String Append), see below.

This should also work in a sub-directory path:

RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule !.*\.php$ %{REQUEST_FILENAME}.php [QSA,L]
Andy
  • 49,085
  • 60
  • 166
  • 233
Pekka
  • 442,112
  • 142
  • 972
  • 1,088
  • thx for your help man, for whatever reason, Id bet due to the session appended url being hardcoded in the PHP file (long story) I am able to access it without the above. I really appreciate your help, this .htaccess stuff is tricky for me. – Dirty Bird Design Oct 26 '10 at 19:00
  • 9
    @Pekka웃 remove space between `[L,` space `QSA]` flags, otherwise _500 Internal Server Error_ will cause. – Rahil Wazir Mar 02 '14 at 17:12
  • 1
    this will make `/index/bla/bla` to be the same as `index.php` – elkebirmed Jan 10 '16 at 18:47
  • ! means not. That rule says to only rewrite to add .php if it doesn't already end in .php – mmiddleton Oct 28 '19 at 18:41
75

Apache mod_rewrite

What you're looking for is mod_rewrite,

Description: Provides a rule-based rewriting engine to rewrite requested URLs on the fly.

Generally speaking, mod_rewrite works by matching the requested document against specified regular expressions, then performs URL rewrites internally (within the Apache process) or externally (in the clients browser). These rewrites can be as simple as internally translating example.com/foo into a request for example.com/foo/bar.

The Apache docs include a mod_rewrite guide and I think some of the things you want to do are covered in it. Detailed mod_rewrite guide.

Force the www subdomain

I would like it to force "www" before every URL, so its not domain.example but www.domain.example/page

The rewrite guide includes instructions for this under the Canonical Hostname example.

Remove trailing slashes (Part 1)

I would like to remove all trailing slashes from pages

I'm not sure why you would want to do this as the rewrite guide includes an example for the exact opposite, i.e., always including a trailing slash. The docs suggest that removing the trailing slash has great potential for causing issues:

Trailing Slash Problem

Description:

Every webmaster can sing a song about the problem of the trailing slash on URLs referencing directories. If they are missing, the server dumps an error, because if you say /~quux/foo instead of /~quux/foo/ then the server searches for a file named foo. And because this file is a directory it complains. Actually it tries to fix it itself in most of the cases, but sometimes this mechanism need to be emulated by you. For instance after you have done a lot of complicated URL rewritings to CGI scripts etc.

Perhaps you could expand on why you want to remove the trailing slash all the time?

Remove .php extension

I need it to remove the .php

The closest thing to doing this that I can think of is to internally rewrite every request document with a .php extension, i.e., example.com/somepage is instead processed as a request for example.com/somepage.php. Note that proceeding in this manner would would require that each somepage actually exists as somepage.php on the filesystem.

With the right combination of regular expressions this should be possible to some extent. However, I can foresee some possible issues with index pages not being requested correctly and not matching directories correctly.

For example, this will correctly rewrite example.com/test as a request for example.com/test.php:

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

But will make example.com fail to load because there is no example.com/.php

I'm going to guess that if you're removing all trailing slashes, then picking a request for a directory index from a request for a filename in the parent directory will become almost impossible. How do you determine a request for the directory 'foobar':

example.com/foobar

from a request for a file called foobar (which is actually foobar.php)

example.com/foobar

It might be possible if you used the RewriteBase directive. But if you do that then this problem gets way more complicated as you're going to require RewriteCond directives to do filesystem level checking if the request maps to a directory or a file.

That said, if you remove your requirement of removing all trailing slashes and instead force-add trailing slashes the "no .php extension" problem becomes a bit more reasonable.

# Turn on the rewrite engine
RewriteEngine  on
# If the request doesn't end in .php (Case insensitive) continue processing rules
RewriteCond %{REQUEST_URI} !\.php$ [NC]
# If the request doesn't end in a slash continue processing the rules
RewriteCond %{REQUEST_URI} [^/]$
# Rewrite the request with a .php extension. L means this is the 'Last' rule
RewriteRule ^(.*)$ $1.php [L]

This still isn't perfect -- every request for a file still has .php appended to the request internally. A request for 'hi.txt' will put this in your error logs:

[Tue Oct 26 18:12:52 2010] [error] [client 71.61.190.56] script '/var/www/test.peopleareducks.com/rewrite/hi.txt.php' not found or unable to stat

But there is another option, set the DefaultType and DirectoryIndex directives like this:

DefaultType application/x-httpd-php
DirectoryIndex index.php index.html

Update 2013-11-14 - Fixed the above snippet to incorporate nicorellius's observation

Now requests for hi.txt (and anything else) are successful, requests to example.com/test will return the processed version of test.php, and index.php files will work again.

I must give credit where credit is due for this solution as I found it Michael J. Radwins Blog by searching Google for php no extension apache.

Remove trailing slashes

Some searching for apache remove trailing slashes brought me to some Search Engine Optimization pages. Apparently some Content Management Systems (Drupal in this case) will make content available with and without a trailing slash in URLs, which in the SEO world will cause your site to incur a duplicate content penalty. Source

The solution seems fairly trivial, using mod_rewrite we rewrite on the condition that the requested resource ends in a / and rewrite the URL by sending back the 301 Permanent Redirect HTTP header.

Here's his example which assumes your domain is blamcast.net and allows the the request to optionally be prefixed with www..

#get rid of trailing slashes
RewriteCond %{HTTP_HOST} ^(www.)?blamcast\.net$ [NC]
RewriteRule ^(.+)/$ http://%{HTTP_HOST}/$1 [R=301,L]

Now we're getting somewhere. Lets put it all together and see what it looks like.

Mandatory www., no .php, and no trailing slashes

This assumes the domain is foobar.example and it is running on the standard port 80.

# Process all files as PHP by default
DefaultType application/x-httpd-php
# Fix sub-directory requests by allowing 'index' as a DirectoryIndex value
DirectoryIndex index index.html

# Force the domain to load with the www subdomain prefix
# If the request doesn't start with www...
RewriteCond %{HTTP_HOST}   !^www\.foobar\.com [NC]
# And the site name isn't empty
RewriteCond %{HTTP_HOST}   !^$
# Finally rewrite the request: end of rules, don't escape the output, and force a 301 redirect
RewriteRule ^/?(.*)         http://www.foobar.example/$1 [L,R,NE]

#get rid of trailing slashes
RewriteCond %{HTTP_HOST} ^(www.)?foobar\.com$ [NC]
RewriteRule ^(.+)/$ http://%{HTTP_HOST}/$1 [R=301,L]

The 'R' flag is described in the RewriteRule directive section. Snippet:

redirect|R [=code] (force redirect) Prefix Substitution with http://thishost[:thisport]/ (which makes the new URL a URI) to force a external redirection. If no code is given, a HTTP response of 302 (MOVED TEMPORARILY) will be returned.

Final Note

I wasn't able to get the slash removal to work successfully. The redirect ended up giving me infinite redirect loops. After reading the original solution closer I get the impression that the example above works for them because of how their Drupal installation is configured. He mentions specifically:

On a normal Drupal site, with clean URLs enabled, these two addresses are basically interchangeable

In reference to URLs ending with and without a slash. Furthermore,

Drupal uses a file called .htaccess to tell your web server how to handle URLs. This is the same file that enables Drupal's clean URL magic. By adding a simple redirect command to the beginning of your .htaccess file, you can force the server to automatically remove any trailing slashes.

Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
Tim Bielawa
  • 6,935
  • 2
  • 17
  • 11
  • wow thanks for all that. Actually I was able to get it to work, turns out there was some weird stuff on my server I had to change. Anyway, now onto the next problem, removing the .php from all pages except one. thx man – Dirty Bird Design Oct 27 '10 at 03:45
  • I love seeing well thought out, organized answers. Nice work... One thing I noticed: did you mean `DirectoryIndex index index.html`? or `DirectoryIndex index.php index.html`? – nicorellius Nov 08 '13 at 21:33
  • @nicorellius believe you are correct. I have updated my original answer with your observation. – Tim Bielawa Nov 15 '13 at 00:25
  • 1
    I must say this does not always work. Try the answer below (of user 1079877) – DonJoe Jun 09 '18 at 21:41
  • You are the real MVP. – ZainZaheer06 Aug 19 '19 at 16:26
  • Nothing worked for me till I added `Options Indexes FollowSymLinks` – Íhor Mé Apr 22 '20 at 22:00
  • @ÍhorMé Specifically, only `FollowSymLinks` is required (`Indexes` enables directory listings, which you probably don't want to enable). Although `FollowSymLinks` is the default value, so if you are having to enable this then it's been overridden (or removed) earlier in the config. – MrWhite Oct 18 '21 at 22:49
  • First time got this to work! Years looking for such configuration. index.php, index.html works / in the end of path works Files file.php can be accessed using both file.php and file - replay of above: # Turn on the rewrite engineRewriteEngine on # If the request doesn't end in .php (Case insensitive) continue processing rules RewriteCond %{REQUEST_URI} !\.php$ [NC] # If the request doesn't end in a slash continue processing the rules RewriteCond %{REQUEST_URI} [^/]$ # Rewrite the request with a .php extension. L means this is the 'Last' rule RewriteRule ^(.*)$ $1.php [L]` – Rodrigo Aug 20 '22 at 04:49
65

In addition to other answers above,

You may also try this to remove .php extensions completely from your file and to avoid infinite loop:

RewriteEngine On
RewriteBase /
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s([^.]+)\.php [NC]
RewriteRule ^ %1 [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*?)/?$ $1.php [NC,L]

This code will work in Root/.htaccess, Be sure to change the RewriteBase if you want to place this to a htaccess file in sub directory.

On Apache 2.4 and later, you can also use the END flag to prevent infinite loop error. The following example works same as the above on Apache 2.4,

RewriteEngine on

RewriteRule ^(.+)\.php$ /$1 [R,L]
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*?)/?$ /$1.php [NC,END]
Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
Amit Verma
  • 40,709
  • 21
  • 93
  • 115
26

The following code works fine for me:

RewriteEngine on 
RewriteCond %{REQUEST_FILENAME} !-d 
RewriteCond %{REQUEST_FILENAME}\.php -f 
RewriteRule ^(.*)$ $1.php
Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
user1079877
  • 9,008
  • 4
  • 43
  • 54
15

After changing the parameter AllowOverride from None to All in /etc/apache2/apache2.conf (Debian 8), following this, the .htaccess file just must contain:

Options +MultiViews
AddHandler php5-script php
AddType text/html php

And it was enough to hide .php extension from files

Rodney Salcedo
  • 1,228
  • 19
  • 23
  • 1
    Wish this one was higher up. Why bother with the overhead of URL rewriting when `MultiViews` does this out-of-the-box – Phil Jan 18 '18 at 23:14
  • This is great. Any drawbacks? – reformed Mar 06 '18 at 15:27
  • @reformed Thanks. I had to change links from ``link`` to ``link`` in the source code – Rodney Salcedo Mar 14 '18 at 01:45
  • 1
    `MultiViews` effectively enables extensionless URLs on _everything_. All your static resources (images, CSS, JS, etc) will also be accessible both with and without the file extension. However, one of the biggest "drawbacks" are unexpected conflicts with mod_rewrite, because MultiViews (mod_negotiation) is processed first and effectively rewrites the URL before handing the "rewritten" URL to mod_rewrite. This can cause the mod_rewrite directives to not match the request you are expecting. @reformed – MrWhite Oct 18 '21 at 22:36
  • Still works 2022 – Matias Jimenez Oct 27 '22 at 14:57
15

I've ended up with the following working code:

RewriteEngine on 
RewriteCond %{THE_REQUEST} /([^.]+)\.php [NC]
RewriteRule ^ /%1 [NC,L,R]

RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^ %{REQUEST_URI}.php [NC,L]
Chris Albert
  • 2,462
  • 8
  • 27
  • 31
Nadeem
  • 259
  • 3
  • 3
14

Here's a method if you want to do it for just one specific file:

RewriteRule ^about$ about.php [L]

Ref: http://css-tricks.com/snippets/htaccess/remove-file-extention-from-urls/

sbuck
  • 1,846
  • 4
  • 24
  • 40
9

Try this
The following code will definitely work

RewriteEngine on
RewriteCond %{THE_REQUEST} /([^.]+)\.php [NC]
RewriteRule ^ /%1 [NC,L,R]

RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^ %{REQUEST_URI}.php [NC,L]
Samarth Saxena
  • 1,121
  • 11
  • 18
8

Not sure why the other answers didn't work for me but this code I found did:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.php [NC,L]

That is all that is in my htaccess and example.com/page shows example.com/page.php

Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
Jon
  • 6,437
  • 8
  • 43
  • 63
4

To remove the .php extension from a PHP file for example yoursite.example/about.php to yoursite.example/about: Open .htaccess (create new one if not exists) file from root of your website, and add the following code.

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.php [NC,L]

To remove the .html extension from a HTML file for example yoursite.example/about.html to yoursite.example/about: Open .htaccess (create new one if not exists) file from root of your website, and add the following code.

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.html [NC,L]

Reference: How to Remove PHP Extension from URL

Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
3

Try this:-

RewriteEngine On
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule !.*\.php$ %{REQUEST_FILENAME}.php [QSA,L]
2

If you're coding in PHP and want to remove .php so you can have a URL like:

http://yourdomain.example/blah -> which points to /blah.php

This is all you need:

<IfModule mod_rewrite.c>
    RewriteRule ^(.+)/$ http://%{HTTP_HOST}/$1 [R=301,L]
</IfModule>
Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
Jeff Hays
  • 21
  • 1
2

I found 100% working Concept for me:

# Options is required by Many Hosting
Options +MultiViews

RewriteEngine on

# For .php & .html URL's:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
RewriteRule ^([^\.]+)$ $1.html [NC,L]

Use this code in Root of your website .htaccess file like :

offline - wamp\www\YourWebDir

online - public_html/

If it doesn't work correct, then change the settings of your Wamp Server: 1) Left click WAMP icon 2) Apache 3) Apache Modules 4) Left click rewrite_module

Irshad Khan
  • 5,670
  • 2
  • 44
  • 39
  • 1
    You can't have two `RewriteRule`s with the tag `L` next to each other. `[L]` tells `mod_rewrite` that it's the last rule for the specified `RewriteCond`. – MD XF Feb 07 '17 at 16:47
  • It's the `Options +MultiViews` that makes this work (the rest of the directives can be removed)! But this now means that _any_ URL can be called without the extension (including all your images, CSS, JS, etc.). – MrWhite Oct 18 '21 at 21:42
2

Here is the code that I used to hide the .php extension from the filename:

## hide .php extension
# To redirect /dir/foo.php to /dir/foo
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s([^.]+)\.php [NC]
RewriteRule ^ %1 [R=301,L,NC]

Note: R=301 is for permanent redirect and is recommended to use for SEO purpose. However if one wants just a temporary redirect replace it with just R

Rahul Gupta
  • 9,775
  • 7
  • 56
  • 69
2

Try

RewriteEngine On 
RewriteCond %{REQUEST_FILENAME} !-d 
RewriteCond %{REQUEST_FILENAME} !-f 
RewriteCond %{REQUEST_FILENAME}.php -f 
RewriteRule ^(.*)$ $1.php [L] 
Inderjeet
  • 1,488
  • 2
  • 17
  • 30
1

If your URL in PHP like http://yourdomain.example/demo.php than comes like http://yourdomain.example/demo

This is all you need:

create file .htaccess

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
#RewriteRule ^([^\.]+)$ $1.html [NC,L]
RewriteRule ^([^\.]+)$ $1.php [NC,L]
Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
Kamlesh Kumar
  • 1,632
  • 2
  • 21
  • 31
0

For AWS Hosted (Ubuntu related servers) sites

STEP 1 : You need to edit the apache2 config file located in /etc/apache2/apache2.conf.

sudo nano /etc/apache2/apache2.conf

STEP 2 : You have to edit the line that look like that:

<Directory /var/www/html/>
  Option Indexes FollowSymbLinks
  AllowOverride None    <-------- FOCUS ON THIS
  Require all granted
</Directory>

You need to replace the AllowOverride None with AllowOverride All, then you need to enable rewrite mode in apache2 in the terminal:

sudo a2enmod rewrite

STEP 3 : Restart Apache

sudo service apache2 restart

STEP 4 : Then You can Edit .htaccess file.

RewriteEngine On
RewriteBase /
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s([^.]+)\.php [NC]
RewriteRule ^ %1 [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*?)/?$ $1.php [NC,L]
Shurvir Mori
  • 2,288
  • 1
  • 17
  • 29
-1
RewriteCond %{THE_REQUEST} "^[^ ]* .*?\.php[? ].*$"   
RewriteRule .* - [L,R=404]
jmoerdyk
  • 5,544
  • 7
  • 38
  • 49
  • 7
    While this code may solve the question, [including an explanation](//meta.stackexchange.com/q/114762) of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please [edit] your answer to add explanations and give an indication of what limitations and assumptions apply. – Yunnosch Aug 30 '22 at 17:29
  • This does not work. An explanation would be helpful if it did though. – ethry Nov 01 '22 at 07:45
  • Does not work .. – Mekey Salaria Apr 16 '23 at 08:31