如何使用PHP将图像返回到https请求

时间:2013-06-12 22:54:29

标签: php symfony ssl silex

几个小时后,

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

  • VirtualHost定义; mysite:设置为/ var / www / mysite
  • $应用程式['控制器'] - > 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种方法:

方法1:Silex sendFile()直接方法&gt;

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

方法2:Silex Streaming&gt;

$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'));

方法3:Symfony2样式&gt;

$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提供的内容:

enter image description here

使用此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(set-buffer-file-coding-system utf-8)的不需要的字节顺序标记(BOM)。此外,为了避免未知的BOM标记文件,我在mysite目录(grep -rl $'\xEF\xBB\xBF' .)中执行了以下命令。没有出现任何异常。

更新

查看浏览器收到的文件(图片)(每张图片上save as),这就是该工具(Hex Friend)帮我查找的内容,但我仍然不明白为什么:

比较两个文件

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

在二进制文件的开头,我得到了这个区别: enter image description here

在二进制文件的末尾,我得到了这个区别: enter image description here

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

2 个答案:

答案 0 :(得分:4)

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

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

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

<强>更新

发生了什么事?:

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

<?php
...
?>

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

另请参阅:Another helping SO fix

向PHP框架开发人员提供建议:

如果你提供了一个sendFile()等效方法,那么当Exception没有返回空缓冲区时,你可能会抛出一个ob_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

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

答案 1 :(得分:3)

不要使用结束?&gt; ...这是针对symfony编码标准的。

反对PSR-2更具体。

  

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

     

结束?&gt;必须从仅包含PHP的文件中省略标记。

原因部分是你所经历的。

此行为有时是由BOM引起的。

检查您的文件中是否包含字节顺序标记!