Articles

How to Use Clean URLs

Many developers prefer to use clean URLs like these in their apps:

http://example.com/profiles/foo

rather than URLs like the following that include the PHP script filename in the URL:

http://example.com/index.php?section=profiles&name=foo

Clean URLs are sometimes called pretty URLs, search engine-friendly URLs, SEO-friendly URLs, user-friendly URLs, semantic URLs, or permalinks.

How Clean URLs Work

For your app to use clean URLs, two things must happen:

  1. The webserver must know that if a requested file does not exist, it should instead send the request to one of your app's PHP scripts (most often index.php).
  2. Your PHP scripts must expect to receive requests this way, so they can inspect the original request URL and determine the content to show.

Enabling Clean URLs

For WordPress apps, you do not need to modify your .htaccess file directly. WordPress will automatically make any necessary changes to your .htaccess file when you enable permalinks in WordPress.

Modern Apps

If your PHP app supports clean URLs, you can tell the webserver to send these requests to your PHP scripts by adding the following lines to your app's .htaccess file:

RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

The above approach will work as long as the app's PHP code looks at the original request path to determine the requested page. This is the most common approach and is used by apps like WordPress.

The most common variable for PHP scripts to use to determine the requested page is

$_SERVER['REQUEST_URI']

Legacy Apps

If your app wasn't written to look at the original request URL and instead needs the original request path appended to the internally rewritten URL, you can instead use the following rules in your app's .htaccess file:

RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php?/$1 [L]

If you get "File not found" errors when using these rules, check to make sure the last line is exactly as shown above. Specifically, the rule must be rewriting to /index.php?/$1 (with a question mark) rather than to just /index.php/$1, which some legacy apps may use by default.

Clean URLs for Specific Apps and Frameworks

WordPress

WordPress makes all changes necessary to your .htaccess file when you enable permalinks through the WordPress administration dashboard.

If you or a plugin has accidentally broken the WordPress rewrite rules and you'd like to make sure the contents of your .htaccess file are correct, this is what your .htaccess file should contain:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

[Source]

For WordPress Multisite, your .htaccess file contents should be:

RewriteRule ^index\.php$ - [L]

# add a trailing slash to /wp-admin
RewriteRule ^([_0-9a-zA-Z-]+/)?wp-admin$ $1wp-admin/ [R=301,L]

RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) $2 [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(.*\.php)$ $2 [L]
RewriteRule . index.php [L]

[Source]

Laravel

To use clean URLs with Laravel, add the following to your .htaccess file:

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

[Source]

Drupal

To use clean URLs with Drupal, add the following to your .htaccess file:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteRule ^ index.php [L] 

[Source]

CraftCMS

To use clean URLs with CraftCMS, add the following to your .htaccess file:

# Send would-be 404 requests to Craft
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/(favicon\.ico|apple-touch-icon.*\.png)$ [NC]
RewriteRule (.+) index.php?p=$1 [QSA,L]

[Source]

ExpressionEngine

To use clean URLs with ExpressionEngine, add the following to your .htaccess file:

# Removes index.php from ExpressionEngine URLs
RewriteCond %{THE_REQUEST} ^GET.*index\.php [NC]
RewriteCond %{REQUEST_URI} !/system/.* [NC]
RewriteRule (.*?)index\.php/*(.*) /$1$2 [R=301,NE,L]

# Directs all EE web requests through the site index file
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php?/$1 [L]

[Source]

CakePHP

To use clean URLs with CakePHP, add the following to your .htaccess file:

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

[Source]

Symphony

To use clean URLs with Symphony, add the following to your .htaccess file:

RewriteRule ^app.php - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /app.php [QSA,L]

[Source]

ZendFramework

To use clean URLs with ZendFramework, add the following to your .htaccess file:

RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]

[Source]

CodeIgniter

To use clean URLs with CodeIgniter, add the following to your .htaccess file:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?/$1 [L]
The CodeIgnitor documentation shows an outdated RewriteRule format. Do not use the RewriteRule example from the CodeIgniter documentation or you will get "File not found" errors when making requests to your app.

Last updated: January 12, 2017