How can I remove index.php from my URLs? Please provide rationale for why the specific method should be used.
-
Just for clarification, ExpressionEngine no longer "officially supports" the removal of index.php on its message boards. The only way to get support if you run into problems is if you pay for the support or get the help of someone generous on the community boards. I don't know for a fact, but I wonder if the new approach works with older versions of ExpressionEngine.– Scott S. BatemanCommented Jan 14, 2014 at 21:53
7 Answers
I use the officially supported method. Why? because it's officially supported and I haven't had any problems using it.
add the following to your .htaccess file.
<IfModule mod_rewrite.c>
RewriteEngine On
# Removes index.php from ExpressionEngine URLs
RewriteCond $1 !\.(gif|jpe?g|png)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php/$1 [L]
</IfModule>
-
7It's also better to leave out the
<IfModule>
lines. Ifmod_rewrite
isn't enabled on your server, you want to see an error message, not spend hours trying to figure out why your links don't work properly. Commented Nov 28, 2012 at 2:04 -
1They recently updated their docs to remove index.php when it's part of the requested URL, i.e. to prevent duplicate content, see: ellislab.com/expressionengine/user-guide/urls/… Commented Dec 27, 2013 at 2:00
I've created a new method that works well on all hosts I have tried it on, and allows the use of regular query/GET parameters in URLs (unlike the built in QUERY_STRING protocol).
This method is needed on some hosts where the other methods are not available (such as where PATH_INFO is not set properly by the server configuration).
I call this method protocol "QUERY_PARAM" since it uses a single query parameter named QSTR to pass the requested page URI into the index.php script, rather than replacing the entire query string.
Here are the changes you'd need to make to use this method:
.htaccess
#### Do our rewrites
# Don't rewrite requests for real files or directories
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Match the entire query string value, this gets put into %1
RewriteCond %{QUERY_STRING} ^(.*)$
# Create a new redirect that packs the requested URI into QSTR and preserves the existing query string
RewriteRule ^(.*)$ index.php?QSTR=$1&%1 [L]
config/config.php
Use the new URI protocol that we're about to create.
$config['uri_protocol'] = 'QUERY_PARAM';
manager/codeigniter/system/core/URI.php
Find this block, and insert the // IRAWAY // section as shown:
if ($uri == 'REQUEST_URI')
{
$this->uri_string = $this->_parse_request_uri();
return;
}
// IRAWAY: add query param support
if ($uri == 'QUERY_PARAM' && isset($_GET['QSTR']))
{
$this->uri_string = $_GET['QSTR'];
return;
}
// END IRAWAY
$this->uri_string = (isset($_SERVER[$uri])) ? $_SERVER[$uri] : @getenv($uri);
There are a few other notes on the gist where I originally posted this.
I have a fairly extensive .htaccess template at https://gist.github.com/3438705
This uses the official rewrite method with a few more bells and whistles too.
The standard method cited in the docs doesn't work in all hosting environment. This rule is specific to MediaTemple (dv) accounts, but may work elsewhere also. I host quite a few sites with them & this works everytime. Note the ?
in the last rewrite rule
## BEGIN ExpressionEngine Rewrite
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond $1 !\.(gif|jpe?g|png)$ [NC]
RewriteRule ^(.*)$ /index.php?/$1 [L]
## END ExpressionEngine Rewrite
Why? Because it simple and works every time.
-
This does not work if you use any analytics packages or custom code that needs to use a Query string parameter. Commented Nov 27, 2012 at 21:27
For nginx this is what I use in my virtual host configurations specifically for removing EE's index.php:
location / {
index index.php;
try_files $uri $uri/ @ee;
}
location @ee {
rewrite ^(.*) /index.php$1 last;
}
What that does is look for the files as the requested URI, with a /, then try the @ee directive instead of just going to a 404. That basically appends the not found uri to index.php.
I also include a separate configuration file for PHP which includes this:
location /index.php {
# Prevent duplicate content
if ($request_uri ~ "^/index\.php/") {
return 404;
}
#php config stuff here
...
}
(For older versions of nginx you'll need a separate config for PHP under SSL to add HTTPS
manually as a server variable. Later versions have the if_not_empty
directive, just google it you'll see.)
So nginx knows to hand off those requests to my choice of PHP, along with a whole bunch of environment stuff esp. for path_info, https, and "scheme_url" (so EE's "site" can be http or https dynamically), and the rest is all up to EE (it seems I neglected to include these, so if anyone ever needs just ask away).
For more details see: http://wiki.nginx.org/ExpressionEngine
Like CreateSean, I also use the officially supported method — and for the same reasons. I’ve seen plenty of support requests in the EE Forums where the poster has been using some other method of removing index.php and quite often the first thing that the person trying to help says is “disable your ‘Remove index.php’ code and see if the problem persists”. To be fair, they also sometimes say that if you're using the official method, but I think not so much, since it's more tried and tested.
In summary then: it’s official, it works, and you might have slightly less code unpicking to do if you ever have a problem.
I use an extended version of the 'official' rewrite which also redirects any index.php requests to the shortened URL. This basic rewrite introduces a situation whereby all of your content can be accessed both with and without index.php
in the URL. This is easily avoided with a few extra lines of code:
<IfModule mod_rewrite.c>
# Enable Rewrite Engine
# ------------------------------
RewriteEngine On
RewriteBase /
# Redirect index.php Requests
# ------------------------------
RewriteCond %{THE_REQUEST} ^GET.*index\.php [NC]
RewriteCond %{THE_REQUEST} !/system/.*
RewriteRule (.*?)index\.php/*(.*) /$1$2 [R=301,L]
# Standard ExpressionEngine Rewrite
# ------------------------------
RewriteCond $1 !\.(css|js|gif|jpe?g|png) [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php/$1 [L]
</IfModule>
Full credit for this goes to Kevin Thompson who posted it on his blog last year.