Чиним генерацию WEBP на PHP

На днях добавил к блогу поддержку формата WEBP. Работать начало всё сразу, но без костылей не обошлось.
Каналы передачи данных становятся всё шире, скорости растут, а дух оптимизатора все никак не унимается. WEBP обещает выигрыш до 30% на размер файла по сравнению с JPG при примерно одинаковом количестве деталей. Проверено, так и есть.
Реализация WEBP на этом блоге
Сегодня, из всех браузеров, полноценно поддерживают WEBP только Chromium-подобные браузеры. Не очень-то и обширно, но радует, что крупные игроки один за одним сообщают о внедрении технологии в ближайшее время. Тем не менее, реализуя поддержку WEBP уже сегодня, мы получаем ощутимый прирост скорости загрузки. А по данным comss.ru , мы покрываем более 60% всех пользователей. Браузер Покрытие, % webp Примечание Chromium 61,29 да все Chromium-подобные браузеры
(Chrome, Yandex-браузер, новая Opera и.т.д) Firefox 12,38 нет говорят, поддержку уже добавили в тестовую версию Edge 4,03 нет поддержку грозятся внести не только в Edge, но ещё и в Windows
Как же быть с браузерами, не поддерживающими WEBP? Умные головы придумали тег <picture>, а в нём теги <source> с указанием типа изображения и пути к файлу. Браузеры сами решают, какое изображение они будут показывать. Например, Chrome выбирает WEBP. Современные браузеры корректно обработают эту конструкцию, а старые пропустят неизвестные теги. Особое внимание нужно обратить на атрибут type, в нем указывается mime-тип изображения.
<picture>
<source type="image/webp" srcset="/images/coolimg.webp"/>
<source type="image/jpeg" srcset="/images/coolimg.jpg"/>
<img src="/images/coolimg.jpg"/>
</picture>Я был приятно удивлен, обнаружив поддержку WEBP в библиотеке php-gd. На стороне сервера за сохранение изображений отвечают следующие функции:
imagejpeg($imageObject, $jpgDestination, $quality); //в JPG
imagewebp($imageObject, $webpDestination, $quality); //в WEBPPHP ломает WEBP
Как и положено, у этого блога есть 2 сервера. На тесте стоит php 5.6.36, на проме php 5.6.37. Внеся все необходимые правки, я протестировал сайт на домашнем компьютере и обновил пром. Я был удивлен, изображения на проме не отображались, вообще, хотя на тестовом сервере работали без проблем.
В консоли хрома ошибок не было, более того Хром рапортовал о нормальной загрузке изображений.

Я скачал сгенерированный WEBP-файл с блога и... файл отлично открылся в ACDSee. Сравнивая файлы прома и теста, я обнаружил несоответствие размеров для сгенерированных WEBP-файлов на сервере и на домашнем компьютере. Размер файлов отличался всего лишь в 1 байт.

Вот эти 2 файла:Скачать 157.0 КБjcup-gen.webpСкачать 157.0 КБjcup-ru.webp
Сдул пыль с HEX-редактора и полез смотреть, чего там не хватает. Оказалось, что промовкий PHP не дописывает 1 байт в конец файла, файл оказывается не валидным и Chrome не может его отобразить. Обновление пакетовphp5.6 и php5.6-gd на проме не дало, ровным счётом, никаких результатов.

Немного поисследовав структуру WEBP, я пришел к выводу, что все живые файлы всегда заканчиваются байтом x00, кроме того WEBP продолжает нормально работать, если добавить любое количество x00 в конец. Можете проверить сами, всё отлично работает:Скачать 157.1 КБru-with-many-x00.webp
Так и появился на свет очередной костыль. Сразу после генерации изображения, дописываем x00 в конец файла.
//x00 webp generation fix
$fpr=fopen($webpDestination, "a+");
fwrite($fpr, chr(0x00));
fclose($fpr);


