2013-07-23 14 views
6

既存の安定したWebサイトを新しいサーバーに転送している間、Imagickを使用してイメージを動的に作成するコードで断続的な問題が発生しました。Imagickを使用した動的イメージの作成/ Apacheヘッダー

コードはGETクエリを解析し(例えばexample.com/image.php?ipid=75 R = 0 & H = 1000 750 & = W)、次いで、スケーリング及び回転サーバ上に格納された画像を、それを提供していクライアントに送信します。

ipid = id for an image stored on server 
r = degrees of rotation 
w = width to display 
h = height to display. 

コードはおそらく少なくとも5年間問題なく使用されています。

Debian SqueezeからDebian Squeezeを使って新しい(はるかに速い)サーバーに転送すると、画像が表示されない時間の約50%が問題になり、代わりにサーバーが 'pngファイル' 0バイト。 PHPエラーやサーバーエラーはありません。

は、画像が正常か送信されたかどうかに応じて、異なるヘッダが送信されます。

成功した画像ヘッダ:

Connection: Keep-Alive 
Content-Type: image/png 
Date: Tue, 23 Jul 2013 17:03:32 GMT 
Keep-Alive: timeout=5, max=76 
Server: Apache/2.2.22 (Ubuntu) 
Transfer-Encoding: chunked 
X-Powered-By: PHP/5.3.10-1ubuntu3.7 

失敗した画像ヘッダ:

Connection Keep-Alive 
Content-Length 0 
Content-Type image/png 
Date Tue, 23 Jul 2013 17:03:31 GMT 
Keep-Alive timeout=5, max=78 
Server Apache/2.2.22 (Ubuntu) 
X-Powered-By PHP/5.3.10-1ubuntu3.7 

を誰にもこれが起こっている理由を知っていますか?

問題の根本にあるのか疑問に思うので、チャンクされたpng画像を強制的に送信する方法はありますか?私はさまざまな回避策を試してみました。ここでは、PHPのheader()関数を使ってイメージサイズを送信するか、Transfer-Encoding:chunkedをヘッダとして使用しましたが、うまくいきませんでした。

<?php 

//Class used to connect to Imagick and do image manipulation: 
class Images 
{ 
    public $image = null; 

    public function loadImage($imagePath){ 

     $this->image = new Imagick(); 
     return $this->image->readImage($imagePath); 
    } 

    public function getImage(){ 

     $this->image->setImageFormat("png8"); 
     $this->image->setImageDepth(5); 
     $this->image->setCompressionQuality(90); 
     return $this->image; 
    } 

    //  Resize an image by given percentage. 
    //  percentage must be set as float between 0.01 and 1 
    public function resizeImage ($percentage = 1, $maxWidth = false, $maxHeight = false) 
    { 
     if(!$this->image){return false;} 
     if($percentage==1 && $maxWidth==false && $maxHeight == false){return true;} 

     $width = $this->image->getImageWidth(); 
     $height = $this->image->getImageHeight(); 

     $newWidth = $width; 
     $newHeight = $height; 

     if($maxHeight && $maxWidth){ 
      if($height > $maxHeight || $width > $maxWidth){ 

       $scale = ($height/$maxHeight > $width/$maxWidth) ? ($height/$maxHeight) : ($width/$maxWidth) ; 
       $newWidth = (int) ($width/$scale); 
       $newHeight = (int) ($height/$scale); 
      } 
     }else{ 

      $newWidth = $width * $percentage; 
      $newHeight = $height * $percentage; 
     } 
     return $this->image->resizeImage($newWidth,$newHeight,Imagick::FILTER_LANCZOS,1); 

    } 

    public function resizeImageByWidth ($newWidth) 
    { 
     if ($newWidth > 3000){ 
      $newWidth = 3000; //Safety measure - don't allow crazy sizes to break server. 
     } 

     if(!$this->image){return false;} 

     return $this->image->resizeImage($newWidth,0,Imagick::FILTER_LANCZOS,1); 

    } 

    public function rotateImage($degrees=0) 
    { 
     if(!$this->image){return false;} 
     return $this->image->rotateImage(new ImagickPixel(), $degrees); 
    } 

} 


//(simplified version of) procedural code that outputs the image to browser: 

$img = new Images(); 

$imagePath = '/some/path/returned/by/DB/image.png'; 

if($imagePath){ 
    $img->loadImage($imagePath); 

    $width = $img->image->getImageWidth(); 
    $height = $img->image->getImageHeight(); 

    if (!$img->resizeImageByWidth($newWidth)) 
    { 
     die ("image_error: resizeImage() could not create image."); 
    } 

    if($rotation > 0){ 
     if (!$img->rotateImage($rotation)) 
     { 
      die ("image_error: rotateImage() could not create image."); 
     } 
    } 

}else{ 

    die("image_error: no image path specified"); 
} 

header('Content-type:image/png'); 
echo $img->getImage(); 

exit(0); 
?> 

UPDATE:ケースでは、問題の場所を特定するのに役立ちます:

私はその場しのぎの対策として、すべてのケースで動作cludgy回避策を作成しました。私がやることは、イメージを作成し、それを一時ファイルとしてディスクに保存することです。ファイルを開き、passthru()を使用してクライアントに送信し、ディスクからファイルを削除します。面倒で、私はむしろそれを「きちんとした」方法でやっていますが、問題は何とかこの2つの行に関連付けられています:header('Content-type:image/png'); echo $img->getImage();と、Apache、PHPまたはImagickによるリソースの処理に失敗しました。

+0

「0」のコンテンツ長ですか?チャンクエンコーディングは必要ありません。画像を生成するために使用している実際のコードを表示します。ヘッダー自体は役に立たない。 –

+0

現在のコード:http://phpfiddle.org/main/code/mkd-tjr – fred2

+0

明確にするために、同じ画像がコンテンツの長さ0で1度表示され、次にトランスファエンコーディング:チャンクで表示されます。それはランダムな振る舞いのようです。 – fred2

答えて

3

これまでと非常によく似た問題がありました。これは、301または302ステータスコードのヘッダーフォワードを持つ2番目のリクエストに関連していました。一部のブラウザはフォローしません

両方のイメージが200を返しますか、またはリダイレクトされた失敗したイメージですか?

+0

こんにちは、お返事ありがとうございます。いいえ、申し訳ありません。両方の画像が200を返しています。 – fred2

+0

私に画像へのリンクを送ることはできますか?それはパスワードで保護されたサイトにあるので、少し難しいですが、 – exussum

+0

ビットを助けるかもしれませんが、次の1時間ほどで他の提案が得られない場合、私は何ができるかを見ていきます。本質的に、あなたは私が信じる元の投稿の中の情報だけを見ていました。 – fred2

2

おそらく、エコー$img->getImage()が呼び出される前にいくつかの意図しない出力がありますか?これは出力イメージを破壊します。私はその前に、末尾の改行文字で、閉じ込めた後に?>タグをいくつかランダムに入れました。include()

コードを精査する前に簡単なテストを行うには、画像データ自体が出力される前に出力バッファリングを使用して何かをゴミ箱にすることがあります。しばらくして...

<?php 
    ob_clean(); //trash invalid data in the output buffer 
    //set proper headers for image output and browser caching if desired 
    echo $img->getImage(); 
    ob_end_flush(); //send the buffered image data to the browser 
?> 

は確か

<?php 
    ob_start(); //call this before executing ANY other php 
?> 

、あなたは安定したコードベースを言及しないが、WebサーバやPHPのバージョンが異なると、違ったもの意図しない空白を扱うことがあります。

EDIT:もう一つは、

が、それは新しいサーバーがPHPの出力キャッシュメカニズムのいくつかの種類を実行している可能性があると思いました。おそらく、最近生成されたイメージをどこかのキャッシュからリロードしようとしていて、その部分が失敗している可能性があります。これは、0バイトのコンテンツ長についてのより良い説明です。たぶん、新しいサーバーは単にライブラリがありません...各サーバーのphpinfo();の出力を比較してください。

+0

申し訳ありませんが、空白はありません。キャッシングは良いアイデアでした。新しいサーバーにまだキャッシングがないことを覚えておく前に、キャッシングを考えていたかもしれません。 – fred2

+0

コードベースにキャッシュに依存することはありますか?多分それが問題の根源です。 –

関連する問題