How I PHP: X-SendFile
It’s time for a new article in the ‘How I PHP’ series, which are about methods I use, but aren’t commonly known. This time it is about an Apache module ‘mod_xsendfile’.
Normally when want to let a user download a file, you simply stick it in a dir under the document root and let Apache do the rest.
However in some cases that is not good enough. You might need to do some authenticate first or you need to lookup the actual file name. In that case you would use PHP, which would result in a script looking like this:
authenticate(); # authenticate and authorize, redirect/exit if failed $file = determine_file(); if (!file_exists($file)) trigger_error("File '$file' doesn't exist.", E_USER_ERROR); header("Content-type: application/octet-stream"); header('Content-Disposition: attachment; filename="' . basename($file) . '"'); header("Content-Length: ". filesize($file)); readfile($file);
This means PHP has to read in the file, which goes through the output buffer, is flushed to Apache and processed before send to client. In this small I didn’t specify any other headers Apache normally sends like last-modified. If I want to actually make the caching based on last-modified work, I need to check the if-modified-since request header, check the mtime of the file and send a 304 result header. (I’m to lazy right now to write a code example for that, sorry)
Wouldn’t it be nicer to tell Apache, please send that file, and be done with it. Well, you can. When you enable mod_xsendfile in Apache, you can send an X-SendFile header, which is processed by Apache.
authenticate(); # authenticate and authorize, redirect/exit if failed $file = determine_file(); header("X-Sendfile: $somefile"); header("Content-type: application/octet-stream"); header('Content-Disposition: attachment; filename="' . basename($file) . '"');
Note that this technique was copied from Lighttp, so if you’re using that it will also work.
07 Mar 2008 Arnold Daniels 10 comments




