App Engine PHP生成图片缩略图

4

我想使用 imagick 和 PHP 为存储在 Google Bucket 上的 PDF 文件 生成缩略图。
我在 Google App Engine(GAE)标准环境 上部署我的应用程序。
问题是我一直收到以下错误:

Fatal error: Uncaught exception 'ImagickException' with message  
'UnableToWriteBlob `magick--1noB3XBwJhgfn': Read-only file system

我知道应用程序部署的文件系统不可写,但我需要一种实现方式...
这是我的代码。
<?php
putenv('MAGICK_TEMPORARY_PATH='.sys_get_temp_dir());

$imagick = new Imagick();

// get the content of pdf url
$imagenblob=file_get_contents('http://www.pdf995.com/samples/pdf.pdf');      

// read the content and load it inn imagick instance
$imagick->readimageblob($imagenblob);                                        

// point to the first page, because I want thumbnail for first page
$imagick->setIteratorIndex(0);        

// set image format
$imagick->setImageFormat('png');       

// resize image
$imagick->resizeImage(320,320,Imagick::FILTER_LANCZOS,1,1);

// return the result
header("Content-Type: image/png");          
$base64 = 'data:image/png;base64,' . base64_encode($imagick);
exit($base64);

也许如果我可以更改imagick用于写入的目录,但是我无法实现这一点!!

如果该目录是“只读”的,换句话说,如果您没有权限执行该操作,则无法在该目录中写入任何数据。解决方法有四种:1-设置正确的权限;2-将缩略图保存到另一个您具有写入权限的目录中;3-将缩略图存储在云端(某些API或其他外部存储);4-将其保存到数据存储中,如MYSQL(不是一个好选择)。 - hassan
我无法更改添加写入权限...在我的情况下不允许这样做,我尝试更改imagick的写入目录,但未能实现... - Hamzeh Hirzallah
4个回答

1
ImageMagick需要一个临时目录来在委托解码/编码过程中写入工件。我不熟悉,但文档建议使用tempnam()sys_get_temp_dir()
putenv('MAGICK_TEMPORARY_PATH='.sys_get_temp_dir());
$imagick = new Imagick(); 
// ...

请注意,ImageMagick使用Ghostscript进行PDF解码。如果要处理PDF文件,请确认已安装并可用gs二进制文件。

我尝试了你的解决方案,但很抱歉它抛出了这个错误Uncaught exception 'ImagickException' with message 'UnableToWriteBlob `magick--1lFkoxwYxJHF4': Read-only file system @ error/blob.c/BlobToFile/266' - Hamzeh Hirzallah
顺便说一句,我可以成功地为JPG图像生成缩略图,问题只出现在PDF文件中... - Hamzeh Hirzallah

1

您正在遇到标准环境沙箱的限制之一:

App Engine 应用程序无法执行以下操作:

  • 写入文件系统。PHP 应用程序可以使用Google Cloud 存储存储持久文件。允许读取文件系统,并且上传到应用程序的所有应用程序文件都可用。

一个选项(花费更高)是使用灵活的环境,它没有这样的限制。

另一种方法是尝试配置imagick不使用中间/临时文件(不知道是否支持),或者使用内存文件模拟(我不知道 PHP 是否支持),并通过Imagick::setFilename指定。

尝试另一种方法是使用setFormat而不是setImageFormatsetImageFormat的注释表明在写入文件之前/之外进行转换可能是可能的

要设置整个对象的格式,请使用Imagick::setFormat方法。例如,加载TIFF文件,然后在Imagick对象上使用setFormat('pdf'),然后writeImagesFile('foo.pdf')或getImagesBlob()。


转移到Flex环境对我来说不是一个选择...而且异常是在这一行抛出的"$imagick->readimageblob($imagenblob);"....就在setFormat之前...我已经尝试了过去三天去配置imagick以不使用中间/临时文件,但没有成功... - Hamzeh Hirzallah
如果有使用Python的完整解决方案,我可以使用它来代替PHP。 - Hamzeh Hirzallah
很遗憾,我只能指出一种可能有用的方法,即使用内存中的StringIO文件处理程序来避免写入文件系统:https://stackoverflow.com/questions/38885764/how-to-zip-or-tar-a-static-folder-without-writing-anything-to-the-filesystem-in/38888667#38888667 - Dan Cornilescu
一个写入GCS文件的例子:https://stackoverflow.com/questions/35708725/how-to-open-gzip-file-on-gae-cloud/35709022#35709022 - Dan Cornilescu

1

由于两个相互对立的力量存在,没有真正的方法可以使其工作:

1)Google App Engine标准版的沙箱限制

2)显然需要临时访问本地文件系统才能工作。

因此,如果您无法更改Imagick的工作方式,则唯一剩下的解决方案是不使用GAE Standard。您可以使用GAE Flex或Google Compute Engine。我不知道为什么Flex对您来说不是一个选项;您不需要将整个项目迁移。您只需将此部分作为microservice移植到同一项目中的GAE Flex上。服务的唯一功能是处理图像并获取缩略图。然后,您可以将缩略图放置在Google Cloud Storage存储桶中,供应用程序的其余部分(在GAE Standard中)使用。


我尝试了你的解决方案,并将thumbnailGenerator文件移动到Flex环境中...现在我面临以下错误:"Uncaught ImagickException: Unable to read image blob in /app/thumpnailGenerator.php:31 Stack trace: #0 /app/thumpnailGenerator.php(31): Imagick->readimageblob('%PDF-1.3\n%\xC7\xEC\x8F\xA2\n...')" - Hamzeh Hirzallah
展示一下抛出这个错误的代码?我猜这是你的GAE标准应用程序读取GCS图像(后处理缩略图)引起的? - Ying Li

0
对于任何遇到相同问题的人,我通过创建一个安装了PHP的新Google Compute Engine解决了我的问题。我创建了一个函数来使用Imagick将pdf转换为图像,并将响应作为base64流返回。
在GAE上,Imagick无法很好地处理pdf文件。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接