Routing hell with Apache and CodeIgniter

Taken by the frustration of a ridicolous amount of time wasted in understanding why this thing did not want to run as expected I will write down how finally it did it.

Admittedly I do not know anything about Apache, PHP and CodeIgniter as well as any viable alternative to them. However, I needed some tool for hosting personal contents and I gave them a go.

The goal was to get something extremely simple running in a robust manner. I'd like to:

  1. display friendly URLs
  2. do not use .htaccess files
  3. only use virtual hosts
  4. only use rewrite rules as URL manipulation mechanism

The first point above translates in CodeIgniter with routing and removing index.php from the requested URI. Google 'hide index.php CodeIgniter' to get a flavour of it. Once you have done that carry on reading this.

From the official docs1 this is what you've got to do:

1
2
3
4
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]

It assumes you are using a .htaccess file, it also assumes you are willing to scatter dot-hidden-files across the file system, which is also discouraged by Apache folks2.

I don't want to use it, I'll move it to the vhost. In order to get it right though there are a few caveats to be noted. .htaccess lives in a directory context, so make sure this will be replicated in the vhost, as:

1
2
3
<Directory "/var/www/html">
    Require all granted # This assumes that /var/www/html can be safely accessed
</Directory>

Then, RewriteEngine & Co. can be added, but one more thing must be clarified: DO NOT REDIRECT. This means, make sure R isn't one of the flags you are passing to the rewrite rule. This is because you want the rewrite engine to be silently manipulating the requested URI server side only, definitely you do not want the client to send a new request that includes index.php/whatever.

1
2
3
4
5
6
7
<Directory "/var/www/html">
    Require all granted
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ index.php/$1 [L]
</Directory>

Now you can tell CodeIgniter not to expect any prefix before the controller is invoked, in config/config.php remove index.php:

1
2
- $config['index_page'] = 'index.php';
+ $config['index_page'] = '';

Last thing to do is to set up some route in order to map a specific requested token to the right controller for your case. This is done in config/routes.php as follows3:

1
2
3
$route['blog/joe'] = 'blogs/users/34';
$route['product/(:any)'] = 'catalog/product_lookup';
$route['product/(:num)'] = 'catalog/product_lookup_by_id/$1';

HTH

Giggi.me. Built using Pelican. Theme is subtle by Carey Metcalfe. Based on svbhack by Giulio Fidente.