Imagick / imagick

🌈 The Imagick PHP extension 🌈
http://pecl.php.net/imagick
Other
536 stars 135 forks source link

readImageFile - Error seeking within stream #305

Open botzkobg opened 4 years ago

botzkobg commented 4 years ago

I'm experiencing a strange problem with readImageFile() when passing stream wrapped resource as a first parameter. The problem does not exits if I pass resource returned by fopen(). Also I can reproduce this problem only on the official php alpine docker machine (not on the Debian one).

The error message is

Fatal error: Uncaught Zend\Diactoros\Exception\UnseekableStreamException: Error seeking within stream in /srv/test/vendor/zendframework/zend-diactoros/src/Exception/UnseekableStreamException.php:28
Stack trace:
#0 /srv/test/vendor/zendframework/zend-diactoros/src/Stream.php(194): Zend\Diactoros\Exception\UnseekableStreamException::dueToPhpError()
#1 /srv/test/vendor/guzzlehttp/psr7/src/StreamWrapper.php(104): Zend\Diactoros\Stream->seek(140730958207224, 0)
#2 [internal function]: GuzzleHttp\Psr7\StreamWrapper->stream_seek(140730958207224, 0)
#3 /srv/test/test.php(18): Imagick->readimagefile(Resource id #27, 'test.jpg')
#4 {main}
  thrown in /srv/test/vendor/zendframework/zend-diactoros/src/Exception/UnseekableStreamException.php on line 28

The problem is with the value passed to GuzzleHttp\Psr7\StreamWrapper->stream_seek() - 140730958207224. This is way out of range. According my investigation readImageFile() is calling:

GuzzleHttp\Psr7\StreamWrapper::stream_open();
GuzzleHttp\Psr7\StreamWrapper::stream_seek();
GuzzleHttp\Psr7\StreamWrapper::stream_tell(); // This returns 0 as expected
GuzzleHttp\Psr7\StreamWrapper::stream_seek(); // This is the method getting 140730958207224 as first parameter

I'm attaching all files required to reproduce the problem (after download remove the .txt extension): image.jpg - The image used to create the stream composer.json.txt - the composer.json file required to install all required libraries composer.lock.txt - the composer.json file required to install all required libraries Dockerfile.txt - the Dockerfile required to build the docker container run.sh.txt - script to build the docker container and to run the test inside it test.php.txt - the test

Hope you can help me resolve this problem.

Danack commented 4 years ago

Thanks for the comprehensive report, but without looking at the issue in detail, my guess is that the only 'fix' I would be able to do would be to disable passing non-filehandle based streams to Imagick.

Imagick is only a thin wrapper around the C ImageMagick library. The streams wrapping that PHP allows is only understood by code that is written to be explicitly aware of those streams......and ImageMagick isn't aware of them. ImageMagick will handling the resource as if it is a file opened by fopen, but in your case it isn't, and so yes....it's almost guaranteed to fail.

I'll have a look when I can, but really the only viable workaround would be to download the file to a local filesystem first.

kynx commented 4 years ago

Similar problems occur when using PHP's built-in stream wrappers:

<?php
$imagick = new Imagick();
$contents = file_get_contents($file);
$resource = fopen('php://memory', 'r+');
fwrite($resource, $contents);
rewind($resource);
$imagick->readImageFile($resource, 'test.jpg');

On Alpine PHP7.3 this results in:

Fatal error: Uncaught ImagickException: no decode delegate for this image format `' @ error/constitute.c/ReadImage/556 in /srv/test/test.php:6
Stack trace:
#0 /srv/test/test.php(19): Imagick->readimagefile(Resource id #24, 'test.jpg')
#1 {main}

It works with Debian PHP7.1, 7.2 and 7.3.