3

I was recently had an nginx + php-fpm server that was serving images like so:

header('Content-Type: image/png');
echo file_get_contents('example_image.png');
exit();

What I am came to realize, whether the image was cached or not, there was a huge peformance hit on the server. CPU utilization was extremely high, 100% with a minimal amount of connections. So I started to offload the images to a CDN and there was an immediate performance improvement but in some cases I still do require the image to be served through a server, which has brought me to the idea of image/media server.

My question is, is there a specific type of server that I should be using? One that can communicate with a database to find the images location and serve it? File system type? Or am I better off keeping just firing up another nginx + php-fpm instance and create a cdn like structure implementation where:

media.example.com 

points only to that server, thus there is no performance impact on the web server?

Devin Dixon
  • 11,553
  • 24
  • 86
  • 167
  • Why not serve images directly by nginx? Do you really need PHP for that? – ivoszz Dec 07 '13 at 16:06
  • The example isn't totally accurate because the images are related to ids, thus it looks up where the image location stored in the db, and then serves it. – Devin Dixon Dec 07 '13 at 16:08

2 Answers2

4

Your problem is that you're treating your image like a string instead of a stream. There's absolutely no need to load it all up in php using file_get_contents() and proceeding to echo the mess. Look up things such as readfile() and PG-related LOB functionality:

header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
exit;

http://php.net/manual/en/function.readfile.php

$db = new PDO('pgsql:dbname=test host=localhost', $user, $pass);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->beginTransaction();
$stmt = $db->prepare("select oid from BLOBS where ident = ?");
$stmt->execute(array($some_id));
$stmt->bindColumn('oid', $oid, PDO::PARAM_STR);
$stmt->fetch(PDO::FETCH_BOUND);
$stream = $db->pgsqlLOBOpen($oid, 'r');
header("Content-type: application/octet-stream");
fpassthru($stream);

http://php.net/manual/en/pdo.pgsqllobopen.php

Along similar lines, look into cache-control related headers. There's no need to resend an image that is already in the browser's cache. Try to send 304 Not Modified when possible:

Make PHP page return "304 Not Modified" if it hasn't been modified

Community
  • 1
  • 1
Denis de Bernardy
  • 75,850
  • 13
  • 131
  • 154
  • I never thought an image as a stream. I will definitely give this a try and benchmark it against other implementations. – Devin Dixon Dec 07 '13 at 19:02
  • 1
    What you might want to add to your answer is information about the X-SendFile – Devin Dixon Dec 11 '13 at 02:03
  • I've never used it myself, so that wouldn't seem right. Looks neat though. Thanks for pointing it out. :-) (Feel very free to add your own answer, or to edit my own for completeness.) – Denis de Bernardy Dec 11 '13 at 08:56
-1

What are you serving the images for? Because I'd say if you're just serving images in PHP use a simple echo with HTML in it?

echo "<img src='image.png'>";

or if you want it to display from a variable, or whatever, just add "" inside of the '' after the IMG SRC= (like so)

echo "<img src='" . $this . "." . $extention . "'>";

It shouldn't really be impacting your server that much by displaying a image? But hey, I'm no expert.

Reverb
  • 953
  • 2
  • 12
  • 17