views:

173

answers:

4

Firefox 3.6 introduced a [multiple attribute on regular type="file" input elements]( http://hacks.mozilla.org/2009/12/multiple-file-input-in-firefox-3-6/).

I cannot get Perl to process these fields. I can call the field in a list context like this:

 my @files = $CGIobject->param("File_Input");

Looping through that will give me the file names as strings but nothing else.

Any suggestions would be greatly welcome.

Here's the HTML:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
<html>

  <head>
    <title>Multiple file upload test</title>

  </head>

  <body>

    <form action="deliberately_obfuscated" 
          method="post" 
         enctype="multipart/form-data">

      <input type="file" 
             name="multiple_files" 
         multiple="true"/>

      <button type="submit">Submit</button>

    </form>

  </body>

</html>

Here is the Perl:

#!/usr/bin/perl

#use strict;
#use warnings;

use CGI;

my $CGIo = new CGI;

print $CGIo->header();

@lightweight_fh = $CGIo->upload('myfiles');

# undef may be returned 
# if it's not a 
# valid file handle

if (@lightweight_fh) {

  # Upgrade the handle to 
  # one compatible with IO::Handle:

  my $io_handle = $lightweight_fh->handle;

  open (OUTFILE,'>>','/hidden_deliberately/');

  while ($bytesread = $io_handle->read($buffer,1024)){

    print OUTFILE $buffer;

  }

}

The script does not enter the

if (@lightweight_fh) {

block.

I've tried Data:Dumper on @lightweight_fh before the if block and it literally prints absolutely nothing.

+4  A: 

Use the upload method in CGI.pm.

In a list context, upload() will return an array of filehandles. This makes it possible to process forms that use the same name for multiple upload fields.

daxim
Strictly speaking, the form is not sending "multiple upload fields". The form is sending a singular upload field with multiple values.Therefore does that excerpt from the CGI.pm documentation apply?
pd_au
+2  A: 

It doesn't look like you're following the documentation for Processing a file upload field with CGI.pm. Before we get too far into this, can you do it with one file using the documented method?

brian d foy
I was not following the documented method initially but as you can see I've tried with the above example I've edited in, that method does not seem to work either. Sorry the example is not well formatted but I'm new to posting on this site.
pd_au
A: 

Woohoo, got this working. The big handbrake issue? Old CGI.pm version! It's a shame the CGI.pm documentation does not include notes alongside features such as "Introduced in version X". Many other modules/libraries/packages do.

As it happens I had version 3.15 and the current is 3.49. I even got it working in strict mode. Anybody know why Stein uses non-strict examples?

Here's the XHTML:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
<html>

  <head>
    <title>Multiple file upload test</title>

  </head>

  <body>

    <form action="deliberately_hidden"
          method="post"
         enctype="multipart/form-data">

      <input type="file"
             name="multiple_files"
         multiple="true"/>

      <button type="submit">Submit</button>

    </form>

  </body>

</html>

Here's the Perl:

#!/usr/bin/perl

  use strict;
  use warnings;

  use CGI;

  my $CGIo = new CGI;

  print $CGIo->header();

  my @lightweight_fh = $CGIo->upload('multiple_files');

  foreach my $fh (@lightweight_fh) {

    # undef may be returned if it's not a valid file handle

    if (defined $fh) {

      # Upgrade the handle to one compatible with IO::Handle:

      my $io_handle = $fh->handle;

      open (OUTFILE,'>>','/deliberately_hidden/' . $fh);

      while (my $bytesread = $io_handle->read(my $buffer,1024)) {

        print OUTFILE $buffer

      }

    }

  }

Thanks for your help everyone.

pd_au
A: 

Yes, perl's CGI.pm can proess firefox's multiple file uploads

Want to see? Use this shortcut:

use Data::Dumper;
print '<pre>', $CGIo->escapeHTML( Dumper( $CGIo ) ),'</pre>';

You'll see something like:

$VAR1 = bless( {
         '.parameters' => [
                            'filename',
                            'submit'
                          ],
         'use_tempfile' => 1,
         '.tmpfiles' => {
                          '*Fh::fh00003temp-2.txt' => {
                                                        'info' => {
                                                                    'Content-Type' => 'text/plain',
                                                                    'Content-Disposition' => 'form-data; name="filename"; filename="temp-2.txt"'
                                                                  },
                                                        'name' => bless( do{\(my $o = 'C:\\WINDOWS\\TEMP\\CGItemp52869')}, 'CGITempFile' ),
                                                        'hndl' => bless( \*{'Fh::fh00003temp-2.txt'}, 'Fh' )
                                                      },
                          '*Fh::fh00001temp-1.txt' => {
                                                        'info' => {
                                                                    'Content-Type' => 'text/plain',
                                                                    'Content-Disposition' => 'form-data; name="filename"; filename="temp-1.txt"'
                                                                  },
                                                        'name' => bless( do{\(my $o = 'C:\\WINDOWS\\TEMP\\CGItemp52775')}, 'CGITempFile' ),
                                                        'hndl' => bless( \*{'Fh::fh00001temp-1.txt'}, 'Fh' )
                                                      }
                        },
         '.charset' => 'ISO-8859-1',
         'param' => {
                      'filename' => [
                                      $VAR1->{'.tmpfiles'}{'*Fh::fh00001temp-1.txt'}{'hndl'},
                                      $VAR1->{'.tmpfiles'}{'*Fh::fh00003temp-2.txt'}{'hndl'}
                                    ],
                      'submit' => [
                                    'Process File'
                                  ]
                    },
         'escape' => 1,
         '.header_printed' => 1
       }, 'CGI' );

First you call your file upload field File_Input, then you call it multiple_files, then you call it myfiles -- you have to use the same name, this important.

Also, $lightweight_fh and @lightweight_fh are two distinct variables, you'll need

for my $lightweight_fh ( $CGIo->upload('multiple_files') ){
    my $io_handle = $lightweight_fh->handle;
    ...
}

Also, you try to open a DIRECTORY '/hidden_deliberately/' as a file, and you don't check for errors

tago
Hi Tago. I assure naming of the fields was not applied in my testing. My answer uses "multiple_files" consistently. The different naming is just a mistake.The same with /hidden_directory/. Just trying to obfuscate the path for privacy reasons. I did have "or die $!" on the end of the open call but cut it due to stack overflow's stupid narrow column layout. Re @lightwight_fh vs $lightweight_fh I'm aware they they are being different vars but I was confused about the context and at one point was struggling just to get the first file of a multiple field uploaded using the doc'd method.
pd_au