uiarts / proxy-image
Proxy images
1.3.5
2026-06-17 08:08 UTC
Requires
None
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Пакет для проксування та обробки зображень (resize, crop, optimize) через підписані URL.
Встановлення
1. Додати пакет через Composer
composer require uiarts/proxy-image
2. Опублікувати конфіг
php artisan vendor:publish --tag=proxy-image-config
3. Опублікувати entrypoint (images.php)
php artisan vendor:publish --tag=proxy-image-public
Після цього файл буде доступний:
public/images.php
Налаштування
В .env додай:
IMAGES_HMAC_SECRET=your-secret-key IMAGES_DEFAULT_DISK=your_disk IMAGES_LOCAL_DISK=your_disk IMAGES_LOCAL_PREFIX= IMAGES_S3_DISK=s3 IMAGES_S3_PREFIX= IMAGES_PICTURE_PLACEHOLDER_MODE=false IMAGES_RENDERER=gd IMAGES_LIBVIPS_BINARY=vipsthumbnail IMAGES_LIBVIPS_MODE=vipsthumbnail
Або відредагуй config/proxy-image.php.
Renderer
IMAGES_RENDERER=gd— поточний дефолтний рендерер через GD.IMAGES_RENDERER=libvips— рендерер черезlibvipsCLI.IMAGES_LIBVIPS_MODE=vipsthumbnail|thumbnail_source— режим роботи libvips.IMAGES_LIBVIPS_BINARY— шлях/назва бінарника для обраного режиму:vipsthumbnailдляIMAGES_LIBVIPS_MODE=vipsthumbnailvipsдляIMAGES_LIBVIPS_MODE=thumbnail_source
Placeholder mode (picsum)
Коли IMAGES_PICTURE_PLACEHOLDER_MODE=true, методи ProxyImage::picture(...) і ProxyImage::singleUrl(...) віддають лінки на https://picsum.photos/{width}/{height}.
Розміри беруться з sizes для кожного брейкпоінта. Якщо висота a, використовується width / 2.
Це зменшує навантаження на локальну машину під час розробки.
Налаштування Nginx
Додай у конфіг:
location ^~ /i/ { include fastcgi_params; fastcgi_pass php-fpm:9000; fastcgi_param SCRIPT_FILENAME $document_root/images.php; fastcgi_param SCRIPT_NAME /images.php; fastcgi_param REQUEST_URI $request_uri; fastcgi_param PHP_VALUE "error_log=/var/log/nginx/application_php_errors.log"; add_header X-Images-Entrypoint 1 always; } if (!-e $request_filename) { rewrite ^.*$ /index.php last; }
Формат URL
/i/{signature}/{ops}/{encoded}.{ext}
Приклад URL
https://example.com/i/{signature}/w:800/dXBsb2Fkcy90ZXN0LmpwZw.jpg
Приклад Використання
{!!
\UIArts\ProxyImage\Facades\ProxyImage::picture(
pictures: 'uploads/image.jpg',
sizes: [
'mobile' => [300, 'a'], // [(int)width, (int|string)height] height - може бути або int або стрінг, але тільки "a", що означає auto
'tablet' => [300, 'a'],
'desktop' => [800, 'a'],
],
class: 'picture-wrap', // class для <picture>
attributes: [
'mode' => 'fit', // fit, fill
'quality' => 85,
'densities' => [1, 2],
'alt' => 'Some alt',
'title' => 'Some title',
'class' => 'img-fluid', // class для <img>
'data-zoom' => 'uploads/image.jpg',
'data-error-src' => 'uploads/image.jpg',
'loading' => 'lazy',
'lazyStrategy' => 'observer', // observer, manual
'fetchPriority' => 'high', // high, low, auto
],
)
!!}
Headless JSON (picture data)
Структуровані дані для <picture> можна отримати без HTML:
\UIArts\ProxyImage\Facades\ProxyImage::pictureData( pictures: 'uploads/image.jpg', sizes: [ 'mobile' => [300, 'a'], 'tablet' => [300, 'a'], 'desktop' => [800, 'a'], ], attributes: [ 'mode' => 'fit', 'quality' => 85, 'densities' => [1, 2], 'formats' => ['avif', 'jpg'], 'alt' => 'Some alt', 'lazyStrategy' => 'observer', ], );
Lazy strategy
lazyStrategy=observer— дефолтна поведінка дляloading=lazy: пакет віддаєdata-src/data-srcsetі автоматично додає класlazy.lazyStrategy=manual— пакет віддає deferred markup (data-src,data-srcset, placeholder уsrc), але не додає класlazy. Це режим для кастомного тригера, наприклад hover, click, slider change або ручногоLazyLoad.load(...).
Формат відповіді:
[
'mode' => 'proxy', // proxy|bypass|placeholder
'img' => [
'src' => '/i/...',
'srcset' => '/i/... 1x, /i/... 2x',
'alt' => 'Some alt',
'title' => 'Some title',
'width' => 800,
'height' => 'auto',
],
'sources' => [
[
'type' => 'image/avif',
'media' => '(min-width: 1200px)',
'srcset' => '/i/... 1x, /i/... 2x',
],
],
]
Приклад для Vue:
<template> <picture v-if="data?.img?.src"> <source v-for="(source, i) in (data?.sources || [])" :key="i" :type="source.type || undefined" :media="source.media || undefined" :srcset="source.srcset || ''" /> <img :src="data.img.src" :srcset="data.img.srcset || undefined" :alt="data.img.alt || ''" :title="data.img.title || undefined" :width="data.img.width || undefined" :height="data.img.height !== 'auto' ? data.img.height : undefined" > </picture> </template> <script setup> defineProps({ data: { type: Object, required: true } }); </script>