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

Перекладено ШІ 0 Laravel News 08 серпня, 2026

Laravel 13.24 отримав підтримку форматів HEIC та AVIF, що нарешті дозволяє безперешкодно приймати фото безпосередньо з iPhone. Оновлений функціонал спрощує валідацію таких зображень та їхню конвертацію у WebP для коректного відображення у браузерах.

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

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

# Що потрібно налаштувати на сервері

PHP не вміє декодувати HEIC самостійно. Для цього потрібен делегат 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 "як є", більшість користувачів побачать замість фото порожнє місце. Рішення — конвертувати зображення безпосередньо під час завантаження:

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 після конвертації збережеться як 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");

Тепер у Blade можна надати браузеру вибір через тег <picture>:

<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 при однаковій якості, але потребує більше часу на кодування. Якщо завантаження відбувається синхронно, користувач відчує затримку. У такому разі краще винести обробку в чергу (queued job).

# Запис у форматі HEIC

Laravel також дозволяє зберігати файли у HEIC за допомогою toHeic() або optimize('heic'):

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

Це специфічний кейс, але він корисний для створення архівів чи експорту даних, які будуть відкриватися переважно на пристроях Apple.

Аліас heif автоматично нормалізується до HEIC, тому optimize('heif') видасть той самий результат, що й optimize('heic'). Файли зберігаються з розширенням .heic, а mimeType() повертає image/heic.

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

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

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

Попередня валідація правилом image дозволяє уникнути більшості таких помилок. Проте це виключення також з'явиться, якщо ви спробуєте обробити HEIC на сервері, де Imagick не має потрібного делегата. Це проблема конфігурації сервера, а не користувача, тому її варто перевіряти під час деплою.

Для версій Laravel старіше 13.24 або для ручної обробки поза межами фреймворку можна скористатися іншими методами конвертації HEIC у JPEG через PHP.

# Що ще почитати

Популярні

Інше, що варто прочитати

32 Оновлено 26 червня, 2026

Інтеграція Laravel Socialite з бібліотекою Google Client PHP

Ви хочете навчитися, як інтегрувати Google OAuth у вашому проекті Laravel, використовуючи Socialite? Дізнайтеся, як налаштувати доступ до сервісів Google, таких як Календар, у нашій сьогоднішній статті

17 Оновлено 26 червня, 2026

Обробка геопросторових даних за допомогою Laravel Magellan

Ви готові відкрити нові горизонти у роботі з геопросторовими даними в Laravel? Дізнайтеся, як за допомогою PostGIS та пакету Laravel-Magellan можна легко зберігати, запитувати та маніпулювати інформацією про розташування, перетворюючи ваші проекти на вражаючі рішення у сфері картографії та геолокації!

27 Оновлено 26 червня, 2026

"SQLSTATE[HY000] [2002] Connection refused" у Laravel в GitHub Actions

Чи стикалися ви з помилкою «SQLSTATE[HY000] [2002] Connection refused» під час налаштування GitHub Actions для вашого додатку на Laravel? У нашій статті ми розглянемо три поширені причини цієї помилки та надамо рішення для їх усунення. Читайте далі, щоб дізнатися, як ваш CI/CD потік може працювати бездоганно!