Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

Serve image from file

by ruzam (Curate)
on Apr 28, 2006 at 21:33 UTC ( #546414=sourcecode: print w/replies, xml ) Need Help??
Category: CGI Programming
Author/Contact Info
Description: Here's snip of script I use to dump images from private (non-document path) file folders.

The source of the file path varies from application to application. Sometimes it comes from the cgi parms, othertimes it comes from a database, so I've simply included a path variable for reference.

Is there a leaner (performance wise, not elegant code wise) way to do this?
# 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{$_}='' }    # s
+ecure 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;
Replies are listed 'Best First'.
Re: Serve image from file
by ikegami (Pope) on Apr 28, 2006 at 22:12 UTC
    • 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>;
      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 :)

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: sourcecode [id://546414]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others lurking in the Monastery: (5)
As of 2021-01-20 09:42 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Notices?