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

Ala*_*ain 5 php ssl symfony 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>
            ---
Run Code Online (Sandbox Code Playgroud)
  • https:// mysite/tmp/file.jpg,使用https:200并在浏览器中查看; 好
  • https:// mysite/files/file.jpg以https:200提供,但未在浏览器中查看; ?

以下是尝试的3种方法:

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

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

方法2:Silex Streaming>

$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'));
Run Code Online (Sandbox Code Playgroud)

方法3: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();
Run Code Online (Sandbox Code Playgroud)

这就是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
Run Code Online (Sandbox Code Playgroud)

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

  • 我检查了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脚本提供服务).

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

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

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

Ala*_*ain 5

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

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

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

更新

发生了什么 ?:

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

<?php
...
?>
Run Code Online (Sandbox Code Playgroud)

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

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

给 PHP 框架开发者的建议:

如果您提供sendFile()等效的方法,也许您应该在流式传输到输出之前抛出一个,Exceptionob_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
Run Code Online (Sandbox Code Playgroud)

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

  • 先生,您是我的英雄!我花了一天时间才弄清楚这个问题。将“ob_end_clean();”添加到“StreamedResponse”回调的开头是我在代码中缺少的内容。我试图将 Postgres bytea 存储的图像返回给用户,但无论我做什么,都不起作用。感谢您分享这个答案! (2认同)