Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти
Інше
Події Про нас
Новини 08 серпня 2026

Валідація та конвертація HEIC зображень у Laravel

Кожен iPhone, проданий за останні кілька років, знімає у форматі HEIC за замовчуванням. Файл приблизно вдвічі менший за еквівалентний JPEG тієї ж якості, саме тому Apple перейшла на цей формат. Проте Chrome та Firefox не вміють рендерити HEIC. Застосунок, що приймає завантаження фото з телефонів, має десь це обробляти, і до недавнього часу компонент зображень Laravel не був тим місцем: HEIC файли відхилялися ще до того, як потрапляли до драйвера.

Laravel 13.24 приймає HEIC, HEIF та AVIF як вхідні дані, додає метод toHeic() для виводу та навчає правило валідації image розпізнавати всі три формати. У цій статті розглянемо, як приймати фото з телефону та віддавати його у форматі, зрозумілому для браузерів.

Що потрібно вашому серверу

Декодування HEIC - це не те, що PHP робить самостійно. Воно надходить від HEIF делегата ImageMagick, побудованого на libheif, тому вам потрібне розширення Imagick з цим скомпільованим делегатом. Драйвер GD взагалі не може читати HEIC, незалежно від версії PHP.

Багато дистрибутивних пакетів постачають ImageMagick без HEIF делегата, тому перевірте, а не припускайте:

php -r "print_r(Imagick::queryFormats('HEI*'));"

Порожній масив означає, що розширення встановлено, але не може працювати з цими файлами. У Debian та Ubuntu делегат знаходиться в пакеті libheif1, а в macOS формула Homebrew imagemagick включає його. AVIF більш толерантний, оскільки GD теж може його декодувати, якщо PHP було зібрано з libavif.

Встановіть Intervention Image, якщо ще не зробили цього, оскільки він підтримує обидва драйвери:

composer require intervention/image:^4.0

Валідація завантаження

Правило image перевіряє файл на відповідність фіксованому списку типів зображень, і цей список тепер включає heic, heif та avif:

$request->validate([
    'photo' => ['required', 'image', 'max:12288'],
]);

Нічого налаштовувати не потрібно. Фото, зняте на iPhone і завантажене прямо з камери, тепер проходить валідацію там, де раніше видавало помилку "The photo field must be an image."

Якщо ви хочете бути явними щодо того, які формати приймаєте, правило mimes приймає ті ж розширення:

'photo' => ['required', 'mimes:jpg,png,webp,heic', 'max:12288'],

Зауважте, що HEIC завантаження надходять з різними MIME типами залежно від клієнта, найпоширеніші - image/heic та image/heif. Правила image та mimes визначають тип із вмісту файлу, а не довіряють браузеру, тому обидва варіанти обробляються однаково.

Конвертація під час завантаження

Прийняти файл - це лише половина справи. Якщо зберегти HEIC як є, більшість відвідувачів побачать зламане зображення. Рішення - конвертувати під час завантаження, що робиться кількома рядками через API зображень:

use App\Models\Photo;
use Illuminate\Http\Request;

public function store(Request $request)
{
    $request->validate([
        'photo' => ['required', 'image', 'max:12288'],
    ]);

    $path = $request->image('photo')
        ->usingImagick()
        ->orient()
        ->scale(width: 2000)
        ->toWebp()
        ->quality(80)
        ->store('photos');

    return Photo::create(['path' => $path]);
}

Два моменти варті уваги. usingImagick() тут тому, що драйвер за замовчуванням - GD, який не працює з HEIC. А orient() читає метадані орієнтації та повертає зображення відповідно, що важливіше для фото з телефонів, ніж для будь-чого іншого, оскільки портретний знімок зазвичай зберігається як горизонтальний кадр з прапорцем повороту.

Збережений файл автоматично отримує правильне розширення. store() будує хешоване ім'я файлу з вихідного формату, тому HEIC завантаження, конвертоване у WebP, потрапляє як photos/{hash}.webp.

Видача AVIF з WebP фолбеком

Якщо ви хочете менший файл там, де це підтримується, згенеруйте обидва варіанти з одного джерела. Кожна трансформація повертає новий екземпляр, тому розгалуження не спричиняє витоку стану між ними:

$source = $request->image('photo')->usingImagick()->orient()->scale(width: 2000);

$avif = $source->toAvif()->quality(70)->storeAs('photos', "{$id}.avif");
$webp = $source->toWebp()->quality(80)->storeAs('photos', "{$id}.webp");

Потім дозвольте браузеру вибрати:

<picture>
    <source srcset="{{ Storage::url("photos/{$photo->id}.avif") }}" type="image/avif">
    <img src="{{ Storage::url("photos/{$photo->id}.webp") }}" alt="{{ $photo->caption }}">
</picture>

AVIF зазвичай на 20-30 відсотків менший за WebP при візуально порівнянній якості, ціною повільнішого кодування. Якщо ваші завантаження синхронні, цей час кодування з'являється в запиті, тому це гарний кандидат для черги завдань, коли ви обробляєте більше одного розміру.

Запис HEIC

Вивід теж працює через toHeic() або optimize('heic'):

Image::fromPath(storage_path('app/photo.jpg'))
    ->usingImagick()
    ->toHeic()
    ->quality(80)
    ->store('photos');

Це вужчий випадок використання, ніж читання HEIC, але він трапляється: архів або експорт, який відкриватиметься на Apple пристроях, або конвеєр, що зберігає оригінальний формат під час обробки.

Псевдонім heif нормалізується до HEIC скрізь, тому optimize('heif') створює той самий вивід, що й optimize('heic'), файли зберігаються з канонічним розширенням .heic, а mimeType() повідомляє image/heic. Image::extension() також розпізнає псевдоніми MIME типів image/x-heic та image/x-avif, які надсилають деякі клієнти, відображаючи їх на heic та avif замість пропуску.

Коли формат не підтримується

Якщо файл потрапляє до драйвера у форматі, який компонент не обробляє, ви отримуєте ImageException з типом у повідомленні:

The image format [image/tiff] is not supported.

Валідація спочатку правилом image ловить майже всі такі випадки, але виняток також з'явиться, коли HEIC файл потрапить до збірки Imagick без HEIF делегата. Це проблема розгортання, а не користувача, тому варто перевірити делегата на сервері як частину релізу, а не виявляти це зі звіту про помилку.

Для будь-чого старішого за 13.24 або коли вам потрібна конвертація поза Laravel, стаття про конвертацію HEIC у JPEG у PHP охоплює ручний підхід.

Додаткове читання

  • Практичний посібник з першокласної обробки зображень Laravel охоплює повний API трансформації та зберігання
  • Домінантний колір зображення в Laravel добре поєднується з цим, оскільки конвертоване фото може безкоштовно нести колір-заповнювач
  • Домінантний колір зображення та підтримка HEIC у Laravel 13.24 містить повні нотатки релізу
  • Підтримка HEIC та AVIF була внесена @riasvdv у #60922
0

Коментарі

Увійдіть, щоб залишити коментар

Будьте першим, хто залишить коментар!

Читайте також

array_keys
Новини 08 серпня 2026

Валідація ключів масиву в Laravel: нове правило array_keys

Laravel 13.24 додає правило валідації array_keys, яке дозволяє чітко визначити допустимі ключі масиву та відхиляти неочікувані. Це вирішує проблему тихих помилок у фільтрах API та запобігає запису зайвих даних у JSON-колонки.

Saga Lara Flow
Новини 08 серпня 2026

Saga Lara Flow: тривалі воркфлоу та компенсуючі транзакції на основі черг Laravel

Saga Lara Flow - пакет для Laravel, що дозволяє писати довготривалі бізнес-процеси як звичайні PHP-методи поверх черг Laravel. Підтримує автоматичні відкати транзакцій, сигнали, паралельні блоки та вкладені воркфлоу із записом кожного кроку до бази даних.