How to hide the .php file extension with IIS URL Rewrite Module

Sometimes it's important to remove (or hide) the file extension of scripts you use. Security by obscurity might be that reason, if you don't want others to know what script language you are using for your website, or for static site hosts.
Published on Friday, 23 May 2014

This example will hide the .php extension using IIS URL Rewrite Module, in a ready to use web.config & .htaccess example: extension less URLs in IIS.

Why the need to hide file extensions in URL's?

I am no fan of security by obscurity, and I have never encountered this as the result outcome of a security scan.

Security by obscurity is one reason to hide the file extension in URL's, if you don't want others to know what script language you are using for your website. Search Engine Optimization (SEO) is another valid reason, or perhaps you just want to hide the file extension for no apparent reason.

There is also no benefit for SEO, for as far as I know.

You can however, use this technique to shorten URL's a bit. It does shave off four to five characters from the URL (".php", ".html", ".aspx"). And some say a website performs faster because a web server can match URL's without extensions to folders (directories) faster than URL's with an extension to a file. Some say. I have no data or further information on this.

Hide .php extension with URL Rewrite Module on IIS

Here is an IIS URL Rewrite Module example for you to hide .php extension in URL's.

This technique is also known as Multiviews or Content Negotiation in Apache, and others call it extensionless URLs. See below for an example to use with .htaccess in IIS.

About MultiViews, or content negotiation:

The effect of MultiViews is as follows: if the server receives a request for /some/dir/foo, if /some/dir has MultiViews enabled, and /some/dir/foo does not exist, then the server reads the directory looking for files named foo.*, and effectively fakes up a type map which names all those files, assigning them the same media types and content-encodings it would have if the client had asked for one of them by name. It then chooses the best match to the client's requirements.

Put the following rewrite in a web.config file to hide the .php extension in your URL's. Well, the example doesn't really hide .php from the URL, but this allows you to use extension-less URL's like www.example.com/index.

IIS' URL Rewrite Module adds the .php part to the URL in the background.

<configuration>
  <system.webServer>
    <rewrite>
    <rules>
      <rule name="hide .php extension" stopProcessing="true">
        <match url="(.*)" />
        <conditions>
          <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
          <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
        </conditions>
        <action type="Rewrite" url="{R:1}.php" />
      </rule>
    </rewrite>
  </system.webServer>
</configuration>

Convert .htaccess to web.config
Disallow direct access to PHP files in wp-content/uploads/
SSL in WordPress: how to move WordPress to HTTPS? The definitive guide

For requests already containing a .php extension

A more extended example is to redirect all requests with .php in the URL to their extension-less variant. So when a visitor comes in through /index.php, the extension is stripped and he will be directed to /index.

Our Rewrite rule maps that final request back to index.php without displaying the extension.

<rewrite>
  <rules>
    <rule name="Redirect .php extension" stopProcessing="false">
      <match url="^(.*).php$" ignoreCase="true" />
    <conditions logicalGrouping="MatchAny">
      <add input="{URL}" pattern="(.*).php$" ignoreCase="false" />
    </conditions>
      <action type="Redirect" url="{R:1}" redirectType="Permanent" />
    </rule>
    <rule name="hide .php extension" stopProcessing="true">
      <match url="^(.*)$" ignoreCase="true" />
    <conditions>
      <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
      <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
      <add input="{REQUEST_FILENAME}.php" matchType="IsFile" />
    </conditions>
      <action type="Rewrite" url="{R:0}.php" />
    </rule>
  </rules>
</rewrite>

Always test such examples before putting it into production.

Emulate Apache Multiviews in IIS using a .htaccess file and Helicon Ape

If you use .htaccess in IIS you can create the same Multiviews effect to hide the .php extension. For this to happen you have to declare a few rewrite conditions and rewrite rules (RewriteCond and RewriteRule). The neat part is, this should also work with Linux, Apache and mod_rewrite, making this solution cross-platform!

Multiviews .htaccess example
In your .htaccess file, add the following rewrite configuration:

# Enable the Rewrite Engine
RewriteEngine On

# Match a folder name, www.example.com/dev/ in this case
RewriteBase /dev/

# SEO URL's for PHP files
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

# Hide the .php extension to prevent double content
RewriteRule ^(.+).php$ $1 [NC,L,R=301]

# Rewrite to, and present the contents of the .php files, 
# if there is no file extension in the URL.
#   For example: /foo shows /foo.php
RewriteRule ^([^/]+)(?:/(.+))?$ $1.php?(?2p=$2) [L]

.htaccess rules explanation The first code block uses two RewriteCond checks to verify whether or not the URL is a file or folder. This is more complete, clear and faster than to create an exception for every file type possible. The RewriteRule rewrites the URL - that mostly doesn't contain a file extension - to a PHP file with that name.

The pattern ^([^/]+)(?:/(.+))?$ is explained as follows:

  1. The enclosing characters ^ and $ mark the beginning and end of the string; which prevents the rule from sometimes matching only a portion of the URL
  2. The group ([^/]+) matches the name of the PHP file as $1. And it finds all the characters up to a slash, or the end of the string
  3. The block (?:/(+).)? tries to find a slash, followed by other characters, and saves it as $2

The replacement $1.php?(?2p=$2) uses a conditional reference:

  • The query string is filled with p=$2 if $2 exists.

Finally, a rule is added that hides the .php extension.

This prevents a search engine from finding duplicate content, and thus prevents a penalty for your site's position in the search results. There are other ways too.

RewriteProxy with .htaccess in IIS

Remove .php extension with .htaccess from URLs

To remove the .php extension from a URL with .htaccess, you can save the following in a new .htaccess file:

<IfModule mod_rewrite.c>
RewriteEngine on

# Redirects example.com/file.php to example.com/file properly
RewriteCond %{REQUEST_FILENAME} !-d         # is not directory
RewriteCond %{REQUEST_FILENAME}\.php -f     # is an existing html file
RewriteCond %{REQUEST_URI} ^(.+)\.php$      # request URI ends with .php
RewriteRule (.*)\.php$ /$1 [R=301,L]        # redirect from index.php to index
</IfModule>
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php

Or use MultiViews:

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

This removes the extension making the URLs more user and -some say- SEO search engine friendly. Use what works best for you, and add a canonical meta tag in your HTML head to avoid duplicate content (where appropriate).