imagecreatefrompng (и imagecreatefromstring) приводит к неустранимой фатальной ошибке


Когда я пытаюсь использовать функции php-gd на неверных изображениях png, у меня есть фатальная ошибка PHP. Похоже, это какая-то ошибка, потому что в соответствии с документацией функций (imagecreatefrompng, например):

* @return resource an image resource identifier on success, false on errors.

Но когда я пытаюсь сделать это с моим неверным образом, у меня получается:

Fatal error: imagecreatefrompng(): gd-png: fatal libpng error: Read Error: truncated data in /var/www/common/models/Utils.php on line 61

Код, который приводит к этой ошибке, прост:
$handle = imagecreatefrompng($fname);

После этой строки код не выполняется.

То же самое поведение для imagecreatefromstring при попытке создать образ из та же струна.

Я не могу "исправить" эту картинку, потому что она предоставляется пользователем, поэтому мне нужно обрабатывать эти случаи.

Я попытался использовать блок try...catch следующим образом:

echo 'start'."n";
try {
    imagecreatefromstring($result);
} catch (Throwable $e) {
    echo 'error'."n";
    return null;
}
echo 'success'."n";

Но скрипт выводит только "start", а затем умирает и показывает описание ошибки, которое я опубликовал выше.

Ubuntu 16.04.2, PHP 7.0, расширение php7.0-gd, обе последние версии.

Так что я не могу справиться с этим с помощью try...поймайте блок, и я не знаю, как с ним справиться или починить его вообще. Какой-нибудь идеи?

UPD: это кажется действительно странной ошибкой с окружением, потому что когда я запускаю тот же код под Windows (с PHP 7.0), он выдает правильную ошибку "предупреждение".

UPD2: похоже, что это свежий баг https://bugs.php.net/bug.php?id=73986

3 3

3 ответа:

Похоже, это свежий баг (и, возможно, не закрытый): https://bugs.php.net/bug.php?id=73986

Поэтому, пока я не найду лучший способ, я думаю, что это только один способ проверить изображение. Это плохой код, и я знаю это, но у меня нет других идей. Идея состоит в том, чтобы попытаться создать образ в другом потоке, и возвращаемое значение проверки зависит от его вывода.
$fname = tempnam('/tmp', 'test_');
$handle = fopen($fname, 'w');
fwrite($handle, $result);
fclose($handle);

$output = `php -r "imagecreatefrompng('$fname');" 2>&1`;
unlink($fname);

if (!empty($output)) {
    return null; // error
}
// good image

Оператор Backtrick выполнит команду в оболочке. Чем он выведет ошибку в stderr. 2>&1 используется для вывода потока stderr в stdout поток, чтобы к нему можно было получить доступ через оператор backtrick.

Немного опоздал на вечеринку, но я также столкнулся с этой проблемой и не могу дождаться исправления ошибки, которое будет включено в мою ubuntu LTS Единственный чистый обходной путь, который я нашел, на самом деле использовать Imagick::valid() проверить изображение является допустимым.

function imageIsValid($path)
{
    try
    {
        $imagick = new \Imagick($path);

        return $imagick->valid();
    }
    catch (\Exception $e)
    {
        return false;
    }
}

Конечно, на вашем сервере / хостинге должно быть установлено расширение php imagick...

Поскольку PHP7 все ошибки являются исключениями, вы можете просто обернуть хрупкую часть кода внутри блока try-catch, чтобы поймать исключение \Throwable и обработать его соответствующим образом.