5

何時間も経った後、

httpsリクエストで画像をダウンロードすることに関する問題を突き止めました。hard path で画像にアクセスすると(https://mysite/tmp/file.jpg)、apache は正常にそれを返し、余分な操作をしなくてもブラウザーで表示できます。別のパスでアクセスしようとすると (https://mysite/files/file.jpg)、php でアクセスを制御するために、php コードから応答が返されますが、ブラウザで画像を表示できません。

  • VirtualHost が定義されています。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つの方法は次のとおりです。

方法 1: 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'));

方法 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();

これは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) が見つけるのに役立つものですが、その理由はまだわかりません:

2 つのファイルの比較

  • (成功したもの: 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 rawファイルに意図しない位置に残っています! あなたがphpファイルを持っているとき

<?php
...
?>

の後にいくつかの改行 (またはスペース) を残した場合?>、それらの改行は出力バッファーに追加されます。次に、ファイルを出力にストリーミングしようとすると、これらの追加改行が取得され、それらが属する場所 (ヘッダー ストリームまたはフッター ストリーム) に配置されます。ストリームの固定サイズ (画像サイズと同じ) を使用すると、特別にヘッダーの余分な文字が取り込まれ、それに応じてブラウザーに出力されるバイトがシフトされます。ブラウザーから受信した画像で見つかった0A 0A 20 0A 0A( ) に対応する5 文字 ( ) を正確に追加したのではないかと疑っています。linefeed linefeed space linefeed linefeed現在、ブラウザーは、バイナリ イメージの 5 つの非論理文字のオフセット 0 からシフトされているイメージ構造を認識しません。したがって、ブラウザは壊れた画像のアイコンしか表示できません。

また見てください:別の役立つSO修正

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

それは確かに改善される可能性がありますが、それは少なくとも誰にとっても役立つはずです!

于 2013-06-13T21:25:37.540 に答える