既存の安定した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」のコンテンツ長ですか?チャンクエンコーディングは必要ありません。画像を生成するために使用している実際のコードを表示します。ヘッダー自体は役に立たない。 –
現在のコード:http://phpfiddle.org/main/code/mkd-tjr – fred2
明確にするために、同じ画像がコンテンツの長さ0で1度表示され、次にトランスファエンコーディング:チャンクで表示されます。それはランダムな振る舞いのようです。 – fred2