Apache2 mod_rewrite and %{REQUEST_FILENAME}

Filed Under (Sysadmin, Tips) by Amandine on 23-02-2010

I’m trying to develop a new website to increase my php object oriented skills. For this new website, I want every request for any url that doesn’t match a actual file on the disk to be redirected to index.php (to handle parameters in fact). Easy with apache2 rewrite rules :

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

This means : if the requested file is not a real file, and isn’t a directory, and isn’t a symlink, then redirect to index.php.

I was really surprised to discover that it doesn’t work. Though, everybody seems to use this syntax ! I checked my apache version : Apache/2.2.9 (Debian), nothing special with this one I guess.
To understand what Apache was doing with my rewrites, I activated the rewrite log :

         RewriteLog /var/log/apache2/rewrite.log                                                                                                                                                                      
         RewriteLogLevel 5

Here’s what I got (the interesting part, cause I got a looot more !) :

[blah blah blah] (2) init rewrite engine with requested uri /toto.htm
[blah blah blah] (3) applying pattern '^/(.*)$' to uri '/toto.htm'
[blah blah blah] (4) RewriteCond: input='/toto.htm' pattern='!-f' => matched
[blah blah blah] (4) RewriteCond: input='/toto.htm' pattern='!-d' => matched
[blah blah blah] (4) RewriteCond: input='/toto.htm' pattern='!-l' => matched
[blah blah blah] (2) rewrite '/toto.htm' -> '/index.php?rt=toto.htm'

So apaches verifies only ‘/toto.htm’ and not the whole path for “%{REQUEST_FILENAME}”? I thought though it was the whole path… let’s verify in the doc.
From http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html, by habit (cause I used apache 2.0 a lot more than apache 2.2 from now on) :

REQUEST_FILENAME : The full local filesystem path to the file or script matching the request.

Hmm. But I use apache version 2.2, so what do they say here http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html :

REQUEST_FILENAME : The full local filesystem path to the file or script matching the request, if this has already been determined by the server at the time REQUEST_FILENAME is referenced. Otherwise, such as when used in virtual host context, the same value as REQUEST_URI.

Ow.

REQUEST_URI : The resource requested in the HTTP request line. (In the example above, this would be “/index.html”.)

Ok, I understand, I use virtual hosts (like everybody, uh?), so the real syntax for my needs is :

         RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
         RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d
         RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-l                                                                                                                                                                              
         RewriteRule ^/(.*)$         /index.php?rt=$1 [L,QSA]

This works even if it doubles the “/” between each variable (one / at the end of DOCUMENT_ROOT, and another at the beginning of REQUEST_FILENAME).

Here’s the rewrite log showing that it works :

[blah blah blah] (2) init rewrite engine with requested uri /toto.htm                                                                          
[blah blah blah] (3) applying pattern '^/(.*)$' to uri '/toto.htm'
[blah blah blah] (4) RewriteCond: input='/path/to/documentroot//toto.htm' pattern='!-f' => not-matched
[blah blah blah] (1) pass through /toto.htm

Now I can disable this log if I want to keep space on my disk.

I must admit I read the description for REQUEST_FILENAME in apache2.2 several times before noticing that it was just the answer… too used to read too fast! Thanks to this old post that made me re-read slower ! ;)

Time

Filed Under (Tips) by Amandine on 23-09-2009

Today I struggled with the time command.

I wanted to use it in a bash script, so I checked the man page, where I found interesting stuff :

$ man time
time - run programs and summarize system resource usage

SYNOPSIS
time   [ -apqvV ] [ -f FORMAT ] [ -o FILE ]
[ --append ] [ --verbose ] [ --quiet ] [ --portability ]
[ --format=FORMAT ] [ --output=FILE ] [ --version ]
[ --help ] COMMAND [ ARGS ]

[...]
OPTIONS
-o FILE, --output=FILE
-f FORMAT, --format FORMAT
--quiet
[...]

Ok great. So I wrote my command like this :

$ time -f %E  wget -q --timeout=60 --connect-timeout=60 -O - 'http://my-url' >>/dev/null
-su: -f: command not found

hm. Maybe I did something wrong. Let’s try the man page’s example to understand how things work :

$ time -f "%E real,%U user,%S sys" ls -Fs
-su: -f: command not found

wtf??! The example given didn’t work either !
And then

$ time --help
-su: --help: command not found

ok… so, searching a little bit further helped me find the explanation :

Your shell (apparently bash) provides a builtin time function. If you want to use time binary, call it by absolute path (/usr/bin/time)

let’s try :

$ /usr/bin/time -f %E  wget -q --timeout=60 --connect-timeout=60 -O - 'http://my-url' >>/dev/null
0:00.20

Finally! It was just a silly thing…

Just remember, when using the bash time, get the time in minutes/seconds:

$ TIMEFORMAT=$'%0lR'
$ time wget -q --timeout=60 --connect-timeout=60 -O - 'http://my-url' >>/dev/null
0m2s

and in seconds only :

$ TIMEFORMAT=$'%0R'
$ time wget -q --timeout=60 --connect-timeout=60 -O - 'http://my-url' >>/dev/null
2

:D

phpmyadmin & pagination

Filed Under (Tips) by Amandine on 23-09-2009

You’re crazy and you created more than 250 tables in your mysql server, and now you’re bored with this ugly and unergonomic pagination on phpmyadmin? I found the solution, and an easy one : just add this line at the bottom of your config.inc.php file :

$cfg['MaxTableList'] = 500;

And that’s it ! now you can display your 500 tables at once ! However be careful, the more tables you display, the more time it will take each time, and the more you risk the “500 Internal Error”…

Some more interesting options to put in the same config file :

$cfg['LeftDisplayServers']    = TRUE; // display server choice at top of left frame (server list from this file)
$cfg['DisplayServersList']    = TRUE; // server choice as links
$cfg['ThemePerServer']      = TRUE; // allow different theme for each configured server
$cfg['LightTabs'] = FALSE; //use graphically less intense menu tabs
$cfg['LoginCookieValidity'] = 7200; // validity of cookie login (in seconds)