5

几个小时后,

我确定了有关使用 https 请求下载图像的问题。当我使用硬路径访问图像时(https://mysite/tmp/file.jpg),apache 成功返回它,我可以在浏览器中查看它,无需任何额外操作。当我尝试使用另一条路径访问它时 (https://mysite/files/file.jpg),为了使用 php 控制它的访问,我从我的 php 代码中得到响应,但我无法在浏览器中查看图像。

  • 虚拟主机定义;mysite:设置为 /var/www/mysite
  • $app['controllers']->requireHttps();

环境描述:

mysite/tmp/file.jpg          
mysite/files/.htaccess
            //... no files; handled by Silex router. here is the .htaccess:
            ---
            <IfModule mod_rewrite.c>
                RewriteEngine On
                RewriteRule ^ ../web/index.php [L]
            </IfModule>
            ---
  • https://mysite/tmp/file.jpg,以 https:200 提供,并在浏览器中查看;好的
  • https://mysite/files/file.jpg 与 https:200 一起提供但未在浏览器中查看;?

以下是尝试的3种方法:

方法一:Silex sendFile() 直接方法 >

$app->get('/files/{onefile}', function ($onefile) use ($app) {    
    // Validate authorization;  if ok, then
    return $app->sendFile('/var/www/mysite/tmp/' . $onefile);
});

方法 2:Silex 流式传输 >

$app->get('/files/{onefile}', function ($onefile) use ($app) {   
    // Validate authorization;  if ok, then
   $stream = function () use ($file) {
       readfile($file);
   };
   return $app->stream($stream, 200, array('Content-Type' => 'image/jpeg'));

方法三:Symfony2 风格 >

$app->get('/files/{onefile}', function ($onefile) use ($app) {   
    // Validate authorization;  if ok, then
    $exactFile="/var/www/mysite/tmp/" . $onefile;
    $response = new StreamedResponse();
    $response->setCallback(function () use ($exactFile) {
        $fp = fopen($exactFile, 'rb');
        fpassthru($fp);
    });
    $response->headers->set('Content-Type', 'image/jpg');
    $response->headers->set('Content-length', filesize($exactFile));
    $response->headers->set('Connection', 'Keep-Alive');
    $response->headers->set('Accept-Ranges','bytes');
    $response->send();

这是 Chrome 呈现的内容:

在此处输入图像描述

使用此 Chrome 图像,这是 Http(是否为 Https,相同的结果)请求

Request URL:https://mysite/files/tmpphp0XkXn9.jpg
Request Method:GET
Status Code:200 OK

Request Headers:
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Cache-Control:no-cache
Connection:keep-alive
Cookie:XDEBUG_SESSION=netbeans-xdebug; _MYCOOKIE=u1k1vafhaqik2d4jknko3c94j1
Host:mysite
Pragma:no-cache
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36

Response Headers:
Accept-Ranges:bytes
Cache-Control:no-cache
Connection:Keep-Alive, Keep-Alive
Content-Length:39497
Content-Type:image/jpg
Date:Thu, 13 Jun 2013 13:44:55 GMT
Keep-Alive:timeout=15, max=99
Server:Apache/2.2.16 (Debian)
X-Powered-By:PHP/5.3.3-7+squeeze15

为消除可能的不良行为而进行的其他测试:

  • 我检查了 BOM 并确保响应请求的 php 代码是有效的,并且没有使用 Emacs ( ) 的不需要的字节顺序标记 (BOM set-buffer-file-coding-system utf-8)。此外,为了避免未知的 BOM 标记文件,我在 mysite 目录 ( grep -rl $'\xEF\xBB\xBF' .) 中执行了以下命令。没有出现任何异常。

更新:

查看浏览器收到的文件(图像)(save as在每个图像上),这是工具(Hex Friend)帮助我找到的,但我仍然不明白为什么:

比较两个文件

  • (一个成功的: mysite/tmp/file.jpg ;直接由 Apache提供服务)
  • (一个没有成功:mysite/files/file.jpg;由 PHP 脚本提供服务)。

在二进制文件的开头,我得到了这个区别: 在此处输入图像描述

在二进制文件的末尾,我得到了这个区别: 在此处输入图像描述

问题: 如何使用 php 代码返回图像(在流或其他技术中),并在浏览器中查看?所有 php 代码方法都返回相同的输出,我怀疑是环境问题。是否有可能产生我正在试验的错误的环境设置?

4

2 回答 2

4

我对这个解决方案(A PATCH )不满意,但是通过添加以下调用解决了问题:

$app->get('/files/{onefile}', function ($onefile) use ($app) {    
  ob_end_clean();  // ob_clean() gave me the same result.
...
}

好的,它已修复,但是,有人可以向我解释如何更智能地修复它吗?

更新

发生了什么 ?:

这就是我的解释:
额外的换行符保留在原始 php 原始文件中到一个无意的位置!事实证明,当你有一个 php 文件时

<?php
...
?>

在 之后留下一些换行符(或空格)的地方?>,这些换行符将在输出缓冲区中累加。然后尝试将文件流式传输到输出将采用这些加起来的换行符并将它们放在它们所属的位置:在标题流中或在页脚流中。具有固定大小的流(等于图像大小)将特别采用标题额外字符并相应地移动输出到浏览器的字节。我怀疑我正好添加了 5 个字符 ( 0A 0A 20 0A 0A),对应于linefeed linefeed space linefeed linefeed从浏览器接收到的图像中发现的 ()。现在浏览器无法识别图像结构,从偏移量 0 偏移 5 个二进制图像的非逻辑字符。因此,浏览器只能显示破碎的图像图标。

另请参阅:另一个帮助 SO 修复

给 PHP 框架开发者的建议:

如果您提供sendFile()等效方法,也许您应该在流式传输到输出之前抛出一个Exception, whenob_get_contents()不返回空缓冲区!

目前:

这个小的 linux 批处理文件至少可以让您找到应该清理代码的位置。使用它后,我能够ob_end_clean()在分析这个小脚本的输出后删除 ... 。它会告诉您可疑的 php 文件,这些文件可能在 php 文件的末尾包含额外的空格或换行符。只需执行并手动修复文件:

#!/bin/bash

for phpfiles in $(ls -1R *.php); do
   hexdump -e '1/1 "%.2x"' $phpfiles | tail -1 >endofphpfile;
   if [  `cat endofphpfile` = "3f3e" ]; then
      echo "OK.................File  $phpfiles"
   else 
      thisout=`cat endofphpfile`
      echo "File  $phpfiles: Suspucious. Check ($thisout) at the EOF; it should end with '?>' (in hex 3f3e) "
   fi
done

它肯定可以改进,但这至少应该对任何人都有帮助!

于 2013-06-13T21:25:37.540 回答
3

不要使用结束?> ...这违反了 symfony 编码标准。

反对PSR-2更具体。

所有 PHP 文件必须以一个空行结尾。

关闭 ?> 标记必须从仅包含 PHP 的文件中省略。

部分原因是你所经历的。

这种行为有时也是由BOM引起的。

检查您的文件都不包含字节顺序标记!

于 2013-06-14T06:26:53.253 回答