http://www.perlmonks.org?node_id=1085191

tbodine88 has asked for the wisdom of the Perl Monks concerning the following question:

OK so I wrote a cgi page that up loads an excel xls spread sheet, to convert to html, but when I call Spreadsheet::XLSX -> new ($fh,$converter) I always get the Cannot open data as Zip archive at Spreadsheet/XLSX.pm line 28

However if I ftp the file to the linux server then open it with Spreadsheet::XLSX -> new ($file, $converter), it works fine. Why?

First the web code:

my $converter = Text::Iconv->new("utf-8","windows-1251"); if ( !$excelFile ){ die "Need a file name to upload"; } # end if no file name open($fh, "+>", undef) or die "Failed to write tempFile \n"; binmode($fh); while ($bytesread = read($excelFile, $buffer, $num_bytes)) { print $fh $buffer; } # end while seek($fh,0,0); my $excel = Spreadsheet::XLSX -> new ($fh,$converter); #(convert to html here)

Now the command line version

my $file = shift @ARGV; my $converter = Text::Iconv->new("utf-8","windows-1251"); my $excel = Spreadsheet::XLSX -> new ($file, $converter); die "open failed" unless $excel; #(convert to html here)
I also tried uploading and copying to a file, then using its name as an argument to "Spreadsheet::XLSX -> new" Any ideas would be appreciated. Thanks & Regards Tom Bodine

Replies are listed 'Best First'.
Re: Spreadsheet::XLS chokes on CGI uploads
by kcott (Archbishop) on May 06, 2014 at 20:33 UTC

    G'day tbodine88,

    Welcome to the monastery.

    From Spreadsheet::XLSX's source code on CPAN:

    sub new { my ($class, $filename, $converter) = @_; my $self = {}; $self -> {zip} = Archive::Zip -> new (); if (ref $filename) { $self -> {zip} -> readFromFileHandle ($filename) == Archive::Z +ip::AZ_OK or die ("Cannot open data as Zip archive"); } else { $self -> {zip} -> read ($filename) == Archive::Zip::AZ_OK or d +ie ("Cannot open $filename as Zip archive"); }; ... }

    Line 28 is the one with the "Cannot open data as Zip archive" message you're getting. When you "tried uploading and copying to a file", did you get the line 33 error message?

    If this is working when you download via FTP, but not working when uploading via CGI, this suggests you may have a problem with your upload code (which you haven't shown).

    Not having seen your CGI code, these are just suggestions which may prove fruitful. Take a look at CGI: PROCESSING A FILE UPLOAD FIELD. There's a lot of useful information there including example code. Also, look at CGI: Avoiding Denial of Service Attacks. See what it says about uploads here and look at the information about the $CGI::POST_MAX and $CGI::DISABLE_UPLOADS variables.

    You may also want to consider using Spreadsheet::ParseXLSX instead of Spreadsheet::XLSX. The former is being actively maintained; the latter hasn't been touched in four years and has dozens of outstanding bugs.

    -- Ken

Re: Spreadsheet::XLS chokes on CGI uploads
by graff (Chancellor) on May 07, 2014 at 03:08 UTC
    I see that you are writing binary (excel) data to a temp file ($fh), and you used "binmode" on that file handle accordingly. But I don't see how the "$excelFile" file handle was opened. Is the input set to binary mode as well? If not, then that might be the problem.

    Also, it does seem odd that, when you check whether $excelFile is true, your error message implies that it's a file name, but it must be a file handle in order for the "read()" call to work.

Re: Spreadsheet::XLS chokes on CGI uploads
by Tux (Canon) on May 07, 2014 at 09:13 UTC

    Stop using Spreadsheet::XLSX. It is undermaintained (bugs are very unlikely to get fixed), buggy in some areas and may be considered dead. There is this new and shiny Spreadsheet::ParseXLSX with the same interface as Spreadsheet::ParseExcel, which is fully functional and if that has bugs, those are likely to get fixed.


    Enjoy, Have FUN! H.Merijn