【问题标题】:Perl CGI display image to browser from filePerl CGI 从文件向浏览器显示图像
【发布时间】:2012-11-30 20:49:43
【问题描述】:

朋友们,
我一直在网上搜索使用 Perl 向 Web 浏览器显示图像的解决方案,但没有找到适合我的解决方案。
我已经尝试过可能的解决方案,例如:
How To Display an Image with Perl
Outputting Image Data
Return an Image From a Script
而且这些都不适用于我正在做的事情。我想拒绝客户端访问图像(或者甚至只是将图像文件放在 www 根目录之外)并将其发送到服务器端。
这是我正在做的一个例子:

在我的主要 perl 文件中:

...
my $query = CGI->new();

sub main {
### This grabs page content from a module, depending on the page name.
### The module returns the HTML.
my $html = get_page('page', 'session');

### Perform any special conditionals here before printing the header...

print $query->header(some cookie/session data here);
print $html

}

在其中一个模块中:

sub return_page_content {

return <<HTML;
<html>
  <body>
    <img src="GET IMAGE HERE..." />
  </body>
</html>
HTML
}

我曾考虑在临时目录位置创建图像的副本,但这似乎会破坏使图像不被客户端访问的整个目的。
可能的解决方案不会生成图像。我不确定从这里去哪里,所以我希望这里有人有想法。非常感谢!
如果我需要提供其他信息,请告诉我。我觉得这可能对很多人都有好处。我希望至少 ;-)

【问题讨论】:

    标签: perl cgi


    【解决方案1】:

    您找到的链接(第一个除外)描述了如何执行此操作,我认为您只是对 提供图像提供带有img 标签就可以了。请记住,当您的浏览器在解析 html 文件并遇到 img 标签时,它会获取标签中的 src url 并对其发出额外的 get 请求。

    尝试使用 curl、wireshark 等从图像请求中捕获原始输出。结果就是您想要尝试创建的结果。只需返回内容类型 http 标头,然后是二进制图像数据。

    再看this的例子,去掉random_file sub,替换掉这一行:

        my $image = random_file( IMAGE_DIRECTORY, '\\.(png|jpg|gif)$' );
    

    用这个:

        my $image = "path to an image file accessible by www-user";
    

    希望一旦你开始工作并了解它在做什么,你就会知道下一步需要做什么。

    【讨论】:

    • 我已经用随机文件名完成了你建议的操作。我会看看 Wireshark 告诉我的。感谢您的回复!
    • 嗯...它最终会删除图像(留下一个零 KB 文件)。我觉得这可能会开放一段时间。
    【解决方案2】:

    对于简单的“将文件发送到浏览器解决方案”,只需向浏览器发送正确的标题(让浏览器知道接下来会发生什么),然后打开您的图像并将内容打印到 STDOUT。

    select(STDOUT); $| = 1;   #unbuffer STDOUT
    print "Content-type: image/png\n\n";
    
    open (IMAGE, '<', '/image_outside_webroot/image.png');
    print <IMAGE>;
    close IMAGE;
    

    一旦成功,请查看ImageMagick。您可以进行各种即时、有趣的图像处理(调整大小、着色等)

    您的 cgi 脚本将包含如下所示的代码:

    select(STDOUT); $| = 1;   #unbuffer STDOUT
    
    my $image = Image::Magick->new();
    my $x = $image->Read(filename =>"/images_outside_web_root/image1.png");
    
    #some manipulation of the image here
    
    print "Content-type: image/png\n\n";
    binmode STDOUT;
    $x = $image->Write(.png:-');
    

    您可以在上面链接的网站上阅读更多相关信息。

    希望对您有所帮助。

    【讨论】:

    • Image::Magick 在此示例中不需要。只写内容。
    • 有机会我会看第一部分。使用 Macick 是不可能的,因为它有几 MB 大。我宁愿不在网络服务器上托管它
    【解决方案3】:

    还有一种方法是使用&lt;img src="data:image/...,base64,..."&gt; 格式嵌入图像。

    这会破坏浏览器缓存,并且不适用于非常大的图像。但是,如果在初始页面加载过程中构建图像更容易,或者您不希望通过文件系统管理/服务它们的麻烦,则很有用。

    #!/user/bin/perl
    use warnings; use strict;
    use MIME::Base64 qw();
    
    sub return_page_content {
        my $image_type = shift;
        my $image_data = shift;
    
        my $image_base64 = MIME::Base64::encode($image_data);
        $image_base64 =~ s{\n}{}g; # lose newlines
    
    return <<HTML;
    <html>
      <body>
        <img src="data:image/${image_type};base64,${image_base64}" />
      </body>
    </html>
    HTML
    }
    
    my $image_path =  "/tmp/test.jpg";
    open(my $fh, '<', $image_path)
        or die "unable to open file $image_path: $!";
    
    binmode($fh);
    my $image_data = do {local $/; <$fh>};
    close($fh);
    
    print return_page_content("jpeg", $image_data);
    

    【讨论】:

      【解决方案4】:

      好吧,事实证明这不起作用的原因是因为我完全忘记了我不使用标准 cgi_bin 目录之外的 CGI 进行操作。相反,我使用 .htaccess 文件告诉服务器如何以及何时将根目录中的文件解释为 cgi。

      所以,这就是我最终在图像处理脚本中使用的内容:

      imagedish.pm

      use CGI;
      
      my $cgi = new CGI;
      
      open (IMAGE, 'logo.png');
      my $size = -s "logo.png";
      my $data;
      read IMAGE, $data, $size;
      close (IMAGE);
      
      print $cgi->header(-type=>'image/png'), $data;
      

      这成功了,就像从一开始就应该做的那样,但是在我的 .htaccess 文件中,我添加了:

      <files imagedish.pm>
      SetHandler cgi-script
      </files>
      

      这就成功了(嗯,除了进入终端并运行 chmod +x imagedish.pm 以使其可执行)!当然,接下来的步骤是额外的安全措施,但至少它现在正在工作! :-)

      完整的解决方案: 主文件:

      !/usr/bin/perl 
      
      use CGI;
      use CGI::Carp qw(fatalsToBrowser);
      use CGI::Session qw/-ip-match/;
      use DBI;
      use strict;
      use warnings;
      
      # Variables
      my $query = CGI->new();
      my %vars = $query->Vars();
      
      sub main {
      
          my $p1 = $vars{p1};
      
          $p1 = 'Home' if (!$p1);
      
      
          my $html = get_page();
      
          #I use this method in case we have multiple sessions
          #I've omitted how I acquire the session, as this is not part of the solution ;-)
          print $query->header(-cookie=>[$query->cookie($vars{p1}=>$session->id)]);
          print $html;
      }
      
      sub get_page {
          return <<HTML;
      <!DOCTYPE HTML>
      <html>
          <head>
              <title>Image Disher</title>
              <link rel="shortcut icon" href="images/favicon.ico" />
              <link href="css/style.css" rel="stylesheet" type="text/css" />
          </head>
          <body>
              <div class="container">
                  <div class="addentry">
                      <div class="iaddentry">
                          <form name="client" action="" method="POST">
                              <div class="form-header" action="">
                                  <center>
                                      <img src="imagedish.pm" width="305" alt=""/><br>
                                  </center>
                                  <br>
                              </div>
                          </form>
                      </div>
                  </div>
              </div>
          </body>
      </html>
      HTML
      }
      
      
      main();
      

      在这里,img 标签查找源“imagedish.pm”,一旦找到,.htaccess 文件会告诉它作为 CGI 脚本执行。那时,它会适当地提供信息,而不是像以前那样。

      请注意,这不是最安全的方法,但它让我朝着正确的方向前进。

      【讨论】:

        猜你喜欢
        • 2012-08-05
        • 2013-02-24
        • 1970-01-01
        • 2011-09-27
        • 1970-01-01
        • 1970-01-01
        • 2011-10-24
        • 2021-06-13
        • 1970-01-01
        相关资源
        最近更新 更多