2
#!/usr/bin/perl 
use CGI ':standard';
use CGI::Carp qw(fatalsToBrowser); 
my $files_location; 
my $ID; 
my @fileholder;
$files_location = "C:\Users\user\Documents\hello\icon.png";
open(DLFILE, "<$files_location") ; 
@fileholder = <DLFILE>; 
close (DLFILE) ; 
print "Content-Type:application/x-download\n"; 
print "Content-Disposition:attachment;filename=$ID\n\n";
print @fileholder;

当我运行这个脚本时,它没有icon.png返回文件,而是返回download.pl(上面给出的脚本的名称),其中没有内容。问题是什么?

我目前正在使用的脚本。

#!C:\Perl64\bin\perl.exe -w 
use CGI qw(:standard);
use File::Copy qw( copy );
use File::Spec::Functions qw( catfile );
use constant IMG_DIR => catfile(qw(     D:\  ));
serve_logo(IMG_DIR);
sub serve_logo {
    my ($dir) = @_;

                my $cgi = CGI->new;

                my $file = "icon.png";
                #print $file;

                defined ($file)         or die "Invalid image name in CGI request\n";
                send_file($cgi, $dir, $file);


                return;
                }
sub send_file
  {
    my ($cgi, $dir, $file) = @_;
    my $path = catfile($dir, $file);
    open my $fh, '<:raw', $path         or die "Cannot open '$path': $!";
    print $cgi->header(         -type => 'application/octet-stream',         -attachment => $file,     ); 
    binmode STDOUT, ':raw';
     copy $fh => \*STDOUT, 8_192;      
    close $fh         or die "Cannot close '$path': $!";
    return;

} 
4

2 回答 2

7

有不少问题。@fileholder = <DLFILE>;第一个是您正在使用slurp 二进制文件的事实。在 Windows 上,行尾的自动转换会对该文件的内容造成严重破坏。

其他问题是:

  1. 您没有检查open. 我们甚至不知道是否open成功。

  2. 您永远不会为 分配值$ID,这意味着您正在发送"filename=\n\n"响应。

  3. 您正在使用二进制文件,使程序的内存占用与二进制文件的大小成正比。健壮的程序不会那样做。

  4. 您正在使用CGI.pmuse,但您既没有使用它,也没有阅读文档。

  5. 您使用的是裸字(即包全局)文件句柄。

然而,根本原因是open失败了。为什么会open失败?简单的:

C:\temp> 猫 uu.pl
#!/usr/bin/env perl

使用严格;使用警告;

我的 $files_location = "C:\Users\user\Documents\hello\icon.png";
打印 "$files_location\n";

让我们尝试运行它,好吗?

C:\temp> uu
无法识别的转义 \D 在 C:\temp\uu.pl 第 5 行通过。
无法识别的转义 \h 在 C:\temp\uu.pl 第 5 行通过。
无法识别的转义 \i 在 C:\temp\uu.pl 第 5 行通过。
C:SERSSERDOCUMENTSHELLOICON.PNG

这是一个简短的脚本,说明了一种更好的方法:

use CGI qw(:standard);
use File::Copy qw( copy );
use File::Spec::Functions qw( catfile );

use constant IMG_DIR => catfile(qw(
    E:\ srv localhost images
));

serve_logo(IMG_DIR);

sub serve_logo {
    my ($dir) = @_;

    my %mapping = (
        'big' => 'logo-1600x1200px.png',
        'medium' => 'logo-800x600.png',
        'small' => 'logo-400x300.png',
        'thumb' => 'logo-200x150.jpg',
        'icon' => 'logo-32x32.gif',
    );

    my $cgi = CGI->new;

    my $file = $mapping{ $cgi->param('which') };
    defined ($file)
        or die "Invalid image name in CGI request\n";

    send_file($cgi, $dir, $file);

    return;
}

sub send_file {
    my ($cgi, $dir, $file) = @_;

    my $path = catfile($dir, $file);

    open my $fh, '<:raw', $path
        or die "Cannot open '$path': $!";

    print $cgi->header(
        -type => 'application/octet-stream',
        -attachment => $file,
    );

    binmode STDOUT, ':raw';

    copy $fh => \*STDOUT, 8_192;

    close $fh
        or die "Cannot close '$path': $!";

    return;
}

我还在我的博客上发布了详细的解释

于 2012-05-12T11:48:12.320 回答
0

我花了一段时间才弄清楚出了什么问题,所以对于那些最终在这里(就像我一样)在提供大文件时遇到随机问题的人,这是我的建议:

避免使用 File::Copy,因为它为此目的存在错误。当通过 CGI 提供数据时,syswrite 可以在一段时间内返回 undef($! 是“资源暂时不可用”)。

File::Copy 在这种情况下停止(返回 0,设置 $!),无法传输整个文件(或流)。

许多不同的选项可以解决这个问题,重试系统写入或使用阻塞套接字,但不确定哪个是最好的!

于 2012-11-20T20:23:31.387 回答