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

Dear Monks,

I have an odd thing happening that I've been trying to fix for two days. I have a script on a server that generates an Excel file using Excel::Writer::XLSX to create a file with an extension of .xlsx. It creates an excel file that, if I download with FTP, opens properly and with no issues.

The problem is that the user won't have FTP access and will need to use a download link. As the file is written to a location outside of normal web space, I have a script that facilitates the download. I've been using it with text files and there is no issue.

I've also used this same format in the past for other binary files (JPG, PDF, Word, etc) and have not had a problem.

What is happening is that when I click on the downloaded file to open it I get first a message that says:
"We found a problem with some content in FILENAME. Do you want us to try recover as much as we can? If you trust the source of the workbook, click Yes."

When I click YES I get the message that says it was trying to open and repair the file, but nothing happens.

I know the file is okay because I can retrieve it over FTP and it opens fine. So the problem must be in the download itself.

I'm using the mime-type "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" and I've also tried "application/vnd.ms-excel"

Here is the portion of the code that does the download. (It is used for both binary and text files.)

if(open(FH, "<$filepath")) { print "Content-Type:$mimetype; name = \"$filename\"\n"; print "Content-Disposition: attachment; filename = \"$filename\"\n +\n"; while( my $line = <FH>) { #I am chomping then adding new lines because the UNIX line fee +ds are not #recognized on some winderz computerz apps. This is why I stri +p the UNIX line #feed (\n) and then add a Windows line feed (\r\n) if($mimetype eq 'text/plain') { chomp($line); print $line, "\r\n"; } else { print $line; } } close(FH); print "EOF\n\n"; exit; } else { &error_page; }

Server Software: LiteSpeed
Operating System: Linux
Perl version: 5.016003

I've tried downloading this on a 2-year old Windows11 operating system in Chrome version 109.
I've tried downloading this on a 10-year old laptop with Windows 8 operating system in Chrome version 109.
I've also tried downloading from Microsoft Edge 109, Firefox 86

I'm really bugged by this (pun intended) because I've done this same thing with many file types in the past (but never Excel) and never had a problem, binary or text.

Does anyone have experience with this problem and know what it is I'm doing wrong?

Thank you for your time and wisdom.

Replies are listed 'Best First'.
Re: Download from Perl script corrupted for XLSX file.
by choroba (Cardinal) on Feb 09, 2023 at 15:43 UTC
    Have you tried comparing the original file to the downloaded one?

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
      The sizes are identical. My last test had both of them at 8.49 Kb. I can't open the one downloaded through the script to compare sheets and rows.
        Try comparing them as bytes. If you have a Linux machine, you can run diff on them, or maybe diff their xxd representation:
        diff <(xxd original.xlsx) <(xxd downloaded.xlsx)
        map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
Re: Download from Perl script corrupted for XLSX file.
by Anonymous Monk on Feb 10, 2023 at 02:40 UTC

    You should try putting the filehandle in binmode, as well as stdout in binmode when you print the file.

      if binmode fails, I'd try utf-16 decoding and encoding

Re: Download from Perl script corrupted for XLSX file.
by Anonymous Monk on Feb 11, 2023 at 23:00 UTC

    After you open the file handle FH, add

    binmode FH;

    Perl tries to be helpful by silently converting line endings in text files to/from \r\n to \n

    If your binary contains line ending sequences they will be broken.

    If you look at bytes, rather than kB with the last digit truncated you will see your assertion of the files being the same size is wrong.