[lug] perl question

Ralf Mattes rm at ns.aura.de
Sun Apr 9 17:12:29 MDT 2000

On Sun, 9 Apr 2000, Hugh Brown wrote:

> Thanks for all of the replies.
> Below follows the code that I am fiddling with.  I asked about this
> earlier but wasn't specific enough in my query.  This is a cgi-script to
> allow uploading to a server.  I think I need to look into the seek
> command that Michael wrote about.  My solution was to combine the two
> while loops.  I was curious to know how to read through a file again for
> my own benefit.

Seek is what you're looking for if you want to do random access to
a file. If you just want to read it twice a reopening of the file 
might be ok (unless you high speed is an issue).


> sub print_results {
>     my $length;
>     my $file = param('upload');

Ah, you get your $filename from L. Steins CGI module ...
CGI does a bit of black magic here (have a look at
CGI.pm, esp. the 'to_filehandle' function). You can use
the return value of this function both as a string or
as a file handle. Since the FileHandle object is inherits
from IO::File and IO::Seekable you can use the methods of
these modules to reset the file position.

>     if (!$file) {
>        print "No file uploaded.";
>        return;
>     }
>     print h2('File name'),$file;
>     print h2('File MIME type'),
>     uploadInfo($file)->{'Content-Type'};
>     open (OUTFILE,">/home/brownclan/tmp/$file")||die $!;

of course, in a real life script you would check the
name of the file, wouldn't you? :-)
Someone might send you a file with the name 'file.txt; rm -rf /*' 

>     while (<$file>) {
>        $length += length($_);
>     }

$file->seek(0, 0);

>     while (<$file>){
>        print OUTFILE $_;
>     }
>     print h2('File length'),$length;
>     close(OUTFILE);
> }

If you just need to find out the length of the transmited file 
there might be better ways to get what you want.
A simple 'stat' on the file returns an array of file information:

  my $length = (stat $file)[7];

As a matter of fact, your aproach might consume a lot of memory;
The while(<FD>) construct will read a line at a time, where line
is defined as 'everything to the next input-record-separator', 
usually a newline. If someone sends you a huge image file then
your script will probably load quite a lot of data in one bite.
If you run under Apache's mod_perl this would be deadly (perl
doesn't give back memory to the OS ...).
A construct like:
 open (OUTFILE,">>/usr/local/web/users/feedback");
 while ($bytesread=read($filename,$buffer,1024)) {
   print OUTFILE $buffer;
from the CGI docs seems more healthy.

Hope this helped


|                                     |                             |==
| Ralf Mattes                         | ralf.mattes at ns.aura.de      |==
| Programming, Administration         | rm at ns.aura.de               |==
|                                     |                             |==

More information about the LUG mailing list