Pragmatism in the real world

Remove index.php from your URL

One thing you may have noticed with Zend Framework projects that use the baseUrl() view helper to reference CSS and other static files is that it doesn’t work if the URL contains contains index.php.

Let’s explain, by using code from the tutorial.

In the layout.phtml file, we link to a CSS file like this:

<?php echo $this->headLink()->prependStylesheet($this->baseUrl().'/css/site.css'); ?>

This code uses a baseUrl() view helper that looks like this

<?php
class Zend_View_Helper_BaseUrl
{
function baseUrl()
{
$fc = Zend_Controller_Front::getInstance();
return $fc->getBaseUrl();
}
}

When you go to http://localhost/zf-tutorial/ you get an page that looks like this:

Screen short of Zend Framework tutorial

However, if you go to http://localhost/zf-tutorial/index.php, you get this:

zf-tutorial_no_css.jpg

This happens because the baseURL used in the href of the CSS link in the second case is /zf-tutorial/public/index.php/css/site.css rather than the correct /zf-tutorial/public/css/site.css.

Solution using mod_rewrite

One way to fix this is to use a mod_rewrite rule in your .htaccess file:


RewriteCond %{THE_REQUEST} ^[A-Z]{3,9} /([^/]+/)*index.php
RewriteRule ^index.php(.*)$ /zf-tutorial/public$1 [R=301,L]

I did have to put the full subdirectory into the rewrite rule to get it to work.

The quick and dirty solution

At the top of your index.php file take out the index.php from the REQUEST_URI:

$_SERVER["REQUEST_URI"] = str_replace('index.php','',$_SERVER["REQUEST_URI"]);

This obviously works, but feels a bit “hacky”! There’s probably other ways to solve it too, but once I found the rewrite rule, I stuck with it.

12 thoughts on “Remove index.php from your URL

  1. Thanks, was looking for this. The Rewrite didn't work for me the first time, got an internal server error (500). After using the following condition it worked correctly:

    RewriteCond %{THE_REQUEST} ^[A-Z]{3,9} /([^/]+/)*index.php

    The dirty hack works as well but it is not as SEO friendly as the htaccess solution. This because the url still contains 'index.php' and you end up with duplicate content (two different urls have the exact same content).

  2. Hey,

    I was wondering why not to remove the index.php in the baseUrl() helper as he is responsible, at least I think so, to return a 'valid' base url? Or go further and remove any filename at that point?

    Best regards

  3. Hi, example of other approach which I'm using would be:

    RewriteCond %{ENV:REDIRECT_STATUS} ^$
    RewriteRule ^index.php(.*)$ $1 [R=301,NE,L]

    Which basically says: rewrite everything after index.php to root unless not internal redirect (flags are important too)

    I have not tested it on project root other than "/" so, it may require some modification

  4. Just a follow up, the modification needed for "zf-tutorial" should be just:

    RewriteBase zf-tutorial

  5. Hello, good morning.
    I did the same example on my local server (WAMP).
    So I took the sample and sent it to production server (IIS6, PHP, and Windows) (www.celebrandodeus.com.br / zf-tutorial / public)
    Changing rules for re_write isapi_rewrite to debug in firebug gives 500 for the index to css but it does the normal request.

    Below is the rule re_write (this works) (apache)
    RewriteEngine On
    RewriteCond% {REQUEST_FILENAME}-s [OR]
    RewriteCond% {REQUEST_FILENAME}-l [OR]
    RewriteCond% {REQUEST_FILENAME}-d
    RewriteRule ^ .* $ – [NC, L]
    RewriteRule ^ .* $ index.php [NC, L]

    Under the rule of IIS6 (not working)
    RewriteEngine On
    RewriteCond% {REQUEST_FILENAME}-s
    RewriteCond% {REQUEST_FILENAME}-l
    RewriteCond% {REQUEST_FILENAME}-d
    RewriteRule ^(.*)$ – [NC, L]
    RewriteRule ^(.*)$ index.php [NC, L]

    Could help me with this? Thank you. Carlos

  6. Sure, Rob. I know it works in IIS6 module isapi_rewrite

    Could you help me configure isapi_rewrite IIS6.

    If you access the site (www.celebrandodeus.com.br / zf-tutorial / public) will see the error through the firebug.

    Look Rob, I researched a lot already but so far not come to any solution. Thank you again.

  7. Rob, what do you think about these things.

    Apache's default mod_rewrite module is build with performance, security and flexibility in mind. Even on average site it handles a big number of requests – each access to a css/image/php/etc. file from bot/human/webservice/etc. goes through a set of rules.

    It is executed as compiled binary code as a part of httpd process possibly with the highest possible speed on hardware architecture used (I don't mention special cases when external script is used to handle rewrites).

    But MVC approach implies single entry point for all 'code' URLs (e.g. *.php) redirecting all input to one script which parses it and performs appropriate actions like index.php. And such parsing is obviously much slower and less secure.

    Additionally, mod_rewrite can help with sanitizing URLs and their parameters and with doing some initial routing but in this case all these features are not used completely.

    Is there a balanced approach to use some mod_rewrite functionality along with ZF controllers to achieve better performance? What would you suggest?

    1. Alex,

      I minimally use mod_rewrite, so don't really have an opinion. As I also deploy to IIS, I don't like to complicate my life too much.

      Rob…

Comments are closed.