1

我目前输出这样的图像(在控制器类中):

    ob_start();
    header("Content-Type: image/gif");
    imagegif($image_resource);
    imagedestroy($image_resource);
    $content_string = ob_get_clean();
    $this->getResponse()->setContent($content_string);

有没有更好的方法而不实际捕获输出缓冲区?因为这不是很可测试...

4

1 回答 1

1

在没有输出缓冲区的情况下捕获图像的唯一方法是将图像写入文件:

$tmpFile = tmpfile();
$path = stream_get_meta_data($tmpFile)['uri'];
imagegif($image_resource, $tmpFile);
$content_string = file_get_contents($path);
imagedestroy($image_resource);
fclose($tmpFile);

$this->getResponse()->setContent($content_string);

我使用tmpfile()方法创建了一个临时文件,并通过stream_get_metadata()函数获取了文件名。然后我将文件的内容加载到字符串变量中,并关闭 tmpfile 的文件句柄,以便将其删除。

从建议写入php://memory文件的评论中获得了一种更优化的方式。这是关于何时使用 php://memory 和 php://temp的另一个问题的一个小解释

// open in memory file
$handle = fopen('php://memory', 'r+');
imagegif($im, $handle);
// reset file handle
fseek($handle, 0);

// get filesize
$stat = fstat($handle);
$size = $stat['size'];

// read the created file into variable
$fileContent = fread($handle, $size);
fclose($handle);

// write filecontent to the response object
$this->getResponse()->setContent($content_string);

我个人会使用输出缓冲区,但将代码移动到单独的函数或类中。这样您就可以隔离和模拟其行为以进行测试:

/** @var GDImage|resource $image */
function getImage($image): string
{
   ob_start();
   imagegif($image);
   $returnData = ob_get_contents();
   ob_end_clean();
   imagedestroy($image);
   return $returnData;
}
$content_string = getImage($image_resource);
$this->getResponse()->setContent($content_string);

无论如何,我建议您在响应对象上设置标头,而不是手动编写它:

$this->getResponse()->getHeaders()->addHeaders([
    'Content-Type' => 'image/gif',
]);
$this->getResponse()->setContent($content_string);

这样,框架在正确的时间将标头输出到浏览器,并且输出缓冲不会有任何问题。

于 2022-01-07T13:45:07.510 回答