Serve image from file
ruzam
created: 2006-04-28 17:33:54
# serve an image file
# 
# The file is read as chunks to avoid consuming memory

use strict;
use warnings;

foreach (qw(PATH ENV BASH_ENV CDPATH IFS TERM)) { $ENV{$_}='' }	# secure ENV

use CGI qw(:standard);
use Fcntl;

# this is specific, provide your own code to set the path
# Oh, and make sure your path is clean!!
my $path = 'path_to_some_image_file.gif';

# read the file as 2048 byte chunks to avoid
# sucking all into memory at once

my $buffer;
my $buffer_size = 2048;

die unless -e $path;
$path =~ m/\.(gif|jpg|png)$/ or die;

# here's the code in question
print header(-type => "image/$1", -expires => "now");

binmode STDOUT;
sysopen(my $fh, $path, O_RDONLY) or die "Failed to open $path: $!";

while (sysread($fh, $buffer, $buffer_size)) {
  print $buffer;
}

exit;

Re: Serve image from file
created: 2006-04-28 18:12:47
  • Securing those environment variables is not needed, since you don't spawn any kids.

  • You're using the wrong MIME type for "JPEG" images. It's should be image/jpeg.

  • die is not very appropriate for CGI scripts.

  • exit is not needed.

  • sysread is probably more appropriate, but I find $/ = \2048 and $/ = \$buffer_size neat:

    local $/ = \2048;
    open(my $fh, '<', $path) or die "Failed to open $path: $!";
    binmode($fh);
    binmode(STDOUT);
    print while <$fh>;
    
Re^2: Serve image from file
created: 2006-04-28 18:47:17
Sometimes I also do session verification, which is why the environment variables crept in, so I suppose that's best left to what ever external code needs to be called. I'd skip the use CGI alltogether, but depending on how I need to get the path, it's usually there anyway. Speaking of CGI, I suppose it would be faster to skip CGI as well and simply print the headers directly?

For an image dump, what would you suggest to end the script other than die? My thinking is the output of die never makes it to the client (at least not in any readable way, 'cause it's an image), but you at least get the results in the Apache error logs. I suppose that could be considered either good or bad.

Your $/ trick is very clever. I like it. But is it any better/worse on performance? Dumping images is such a lowly task for Perl. I'd hate to waste anymore cycles then absolutely necessary doing it :)

perlmonks.org content © perlmonks.org and ikegami, ruzam

prlmnks.org © 2006 edmund von der burg (eccles & toad)

v 0.03