Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

file_get_contents or readfile for displaying filesystem image

Tags:

function

php

Can anyone advise on what is the best PHP function for displaying an image stored in a filesystem - file_get_contents or readfile. We are switching from displaying images stored in the database so we still need to call the images through a PHP file and cannot link directly to the filesystem. I've seen people recommending both functions but I'm inclined towards using readfile. Would appreciate any input on this.

like image 502
robjmills Avatar asked May 26 '09 08:05

robjmills


2 Answers

If you don't need to manipulate the images (resizing, adding watermarks,...) readfile() will be the best choice as it writes the file directly to the output buffer. file_get_contents() will read the file into memory instead - requiring a lot of memory with large files.

like image 73
Stefan Gehrig Avatar answered Oct 03 '22 05:10

Stefan Gehrig


Be sure to take caching into account when writing scripts like this!

A webserver serving a static image will do negotiation with the client when the image is re-requested on the next page visit, and if the server determines that the cached copy of the image at the client side is still valid, the image will not be retransmitted.

Since the naive script does not do this negotiation, the image will be retransmitted to the client on every page request, costing you a lot more bandwidth than necessary.

There are three mechanisms for this. I can't tell you exactly how to write the optimal script, as I've never had to do this before and I'm not sure how the different caching headers interoperate and on what HTTP version, but I encourage you to research into this further.

The three mechanisms that I know of:

Expires (HTTP/1.0)

The simplest one. This header tells the client that the image will definitely be valid until the given moment in time. The client will not even do a request to the script until this time has passed, so setting this appropriately can save you (some) CPU cycles on the server and image loading latency in your web app.

How you should set this depends entirely on your application; are your images changing rapidly or rarely? If the image changes before the Expires time you've sent to the client, the client will not see the new image.

Example:

header("Expires: " . gmdate('D, d-M-Y H:i:s \G\M\T', time() + 60)); // Valid for a minute

(Note: Expires seems to have been superseded by Cache-Control in HTTP/1.1)

If-Modified-Since (HTTP/1.1)

An HTTP/1.1 client can send this header if it already has a copy of the image, and notes what time the copy dates from. You can then determine in your database if the current version of the image was changed at an earlier or later time. If the version of the client is still the right one, simply send a "304 Not Modified" response and quit (thereby preventing having to transfer the image).

Example:

$cache_time   = parse_browsers_date_time_format($_SERVER["IF-MODIFIED-SINCE"]);
$actual_time  = get_current_resource_time_from_db();

if ($actual_time <= $cache_time) {
    header("HTTP/1.1 304 Not Modified");
    die;
}

// ... Produce and output resource here

(Note: clients may only actually send the If-Modified-Since if you also send Last-Modified in the original response. I'm not sure about that, research for yourself.)

ETag/If-None-Match (HTTP/1.1)

This method is similar to the If-Modified-Since negotiation, but instead of times it uses a hash of the image as to see if the content has changed. It works as follows: the server calculates some hash for the image, and sends this hash the first time the image is requested in the ETag header.

On subsequent requests, the server will send the hash back in the request field If-None-Match. If the hash of the client is the same as the current hash of the image, the image was not changed in between and the script can suffice by simply sending "304 Not Modified".

Since ETags seem to be actually intended to be used to prevent concurrency issues in client requests with side effects (i.e., POST and PUT), and because calculating a hash is a costly operation, I think the If-Modified-Since approach will be a better fit for most file-serving applications.

like image 33
rix0rrr Avatar answered Oct 03 '22 05:10

rix0rrr