views:

38

answers:

4

I have a lot of images on my website, they are pulled from an image server onto the main server when requested to save disk space at my hosting server.

To achieve this I have an entry in my .htaccess file that basically internally redirects people from /images/image.jpg to download.php which checks to see if the file exists. If the file exists it serves it up (code below) else it'll use CURL to pull in the remote file then redirect to itself header("Location: ".$_SERVER['REQUEST_URI']); so that it then shows the image.

Is it inefficient to serve images to the browser in such a manner? Is it faster to let the web server do it naturally? The code for reading and showing the file is below.

$file_extension = strtolower(substr(strrchr($filename,"."),1));

header("Pragma: public");
header("Content-Type: image/jpg");
header("Content-length: ".filesize($filename));
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($filename));
readfile("$filename");

Would I be better off (read: more efficient) NOT using a htaccess redirect but actually modifying my 404 page to check for image specific 404's and then download them?

Here is the .htaccess that defines the redirect to download.php

^images/([0-9]+)_([a-z0-9_]+).jpg$ /download.php?id=$1
A: 

I think directly serve images would always be faster than your code which wouldn't let to use the browser cache but I'm not sure.

MatTheCat
As far as the browser is concerned once loaded the image never changes as it's filesize and filename hasn't changed. At least browsers seem to cache it!
Chris
Yeah but the image is loaded trough a php file so I don't know if it works ?
MatTheCat
+2  A: 

It's a little unclear what you mean by 'redirect to itself'. Is there any reason your download.php can't use CURL to grab the image from the remote server and then serve it up using your code sample in the same way? Why would it need to redirect?

It's best not to use the PHP engine to serve images if it can be avoided, as Apache can do this much more efficiently by itself. You also lose some of Apache's default behaviour, e.g. your code example isn't sending last modified headers or handling etags, so if a user revisits the same page they're going to end up downloading the image again instead of using a cached version.

Your suggested alternative approach would be a little better, as once your script had downloaded the image the first time, all subsequent requests would be served by Apache directly. Just make sure you're not sending 404 headers along with the image.

Alternatively it is possible to check whether files exist using htaccess, so you could only redirect requests for non existent images to download.php and not have to modify your 404 script. Something like this (untested):

RewriteEngine On
RewriteCond %{REQUEST_URI} ^/images
RewriteCond %{REQUEST_FILENAME} !-s
RewriteRule ^.*$ download.php [NC,L]

this means: if the REQUEST_URI starts with /images, and the filename does not match an existing file on the file system, rewrite it to download.php.

I'd also recommend looking into X-Sendfile, an Apache module which makes it very easy to serve images (and other binary data). Using it in PHP is as simple as sending a header containing the path to the file:

header("X-Sendfile: /home/whatever/public/images/something.jpg");

Apache then does all the rest of the work for you - reading and outputting the file contents and sending all the appropriate headers. The module isn't usually enabled by default so you might need to install it or check with your host.

Tim Fountain
Checking for file existence in .htaccess is a pretty good idea, any thoughts on where to start on that? What is X-SendFile?
Chris
I tried to use X-Sendfile (which seems awesome btw!) but it didn't work lol
Chris
I've edited my answer with a htaccess example and X-Sendfile explanation. If you have any problems with X-Sendfile, check phpinfo() to ensure it's enabled, and check the Apache error log if it still doesn't work.
Tim Fountain
Thanks, the htaccess seems to work a treat and it does seem noticeably faster... I'll try benchmark it soon to make sure. And yes your right my server doesnt have `x-sendfile` but the htaccess stuff has made the need for that redundant - Thanks!
Chris
A: 

As far as the connection from client to browser, it's exactly as quick as serving the data normally. Apache doesn't care where the information came from, it just sends the data it's handed. If the data is the result of reading a file or the result of a 10-million like C++ program, it's all just bits.

Where your method is slower is when it's pulling the image from the image server. This essentially means that the image is being sent twice. Once from image server -> host server, then again from host server -> client. If your image server and host server are on the same Local Area Network with relatively few nodes and a very fast connection then this may not be a noticeable difference. If the image server is located on a different network or if the image file is very large, the difference can be dramatic, and may not be worth the cost to disk space.

steven_desu
+1  A: 

You'd be better of with just prefixing your rewrite with:

RewriteCOnd %{REQUEST_FILENAME} !-f

... and if you download the file in download.php, why not just show it to the user? No need for a redirect.

Wrikken
@Wrikken I originally did that but figured it'd be faster doing it that way? Also what does that specific RewriteCond do? How would I incorporate it into my htaccess? (ill update question)
Chris
It would only redirect to your download.php if the file doesn't exist yet.
Wrikken