Загрузка изображений в Laravel с помощью UploadImage

Как можно легко загружать, получать и удалять изображения в Laravel для любого типа контента? UploadImage пакет, созданный для удобства работы с изображениями в Laravel. Мало какой сайт может обойтись без использования изображений. Поэтому при разработке веб-проекта, программист обязательно столкнётся с необходимостью сохранять изображения на диск и получать изображения с диска.

По большому счету, Laravel  даёт очень удобный инструментарий для этих целей. Но вот каким образом сделать автоматизированную систему сохранения изображений, в зависимости от разного типа контента, вот это уже большой вопрос.

Конечно же в природе есть ряд решений, которые помогают в вопросе сохранения изображений. Одним из таких пакетов является UploadImage. Установить его можно через composer.

Чем так хорош пакет UploadImage?

Во первых, в базе данных сохраняется только название файла, без пути к этому файлу на диске. Это даёт возможность в любой момент перенести уже сохранённые изображения куда угодно. Хоть в облако, хоть на другой сервер. Прописать путь к базовому хранилищу можно в едином файле настроек. Такой подход никогда не побьёт ссылки, а шаблоны всегда будут знать от куда подгружать изображения.

Следующий момент — это возможность располагать изображения автоматически в разные папки, в зависимости от типа контента. В контроллере вы можете вызывать метод сохранения/загрузки изображения, передавая в него, помимо самого файла изображения, ещё и название модели. Например:

// Upload and save image.
try {
// Upload and save image.
$input['image'] = UploadImage::upload($file, 'post', $watermark)->getImageName();
} catch (UploadImageException $e) {
return back()->withInput()->withErrors(['image', $e->getMessage()]);
}

В этом случае из файла настроек будет получен путь, куда нужно сохранять изображение. Изображение будет проверено и сохранено в папку posts. В конец текстовой строки всегда дописывается символ s. Как это, например, происходит с миграциями и таблицами в базе данных. При чём, произойдет ряд проверок изображения, согласно настройкам.

Например, чтобы файл был шириной не менее 500px. В папке posts будет создана папка original для оригинального изображения. Именно в ней и будет сохранено изображение под случайным именем. И это имя будет возвращено методом одним из значений массива. Как это видно из кода.

Таким образом, изображения для разного контента будут храниться в разных директориях. Также можно в настройках включить функцию миниатюр. И указать какого размера нужно делать превьюшки. В этом случае будут созданы миниатюры и помещены рядом с папкой original в свои каталоги, которые будут названы согласно размеру превьюшки с префиксом w, например w300.

Ещё можно в настройках включить использование водяных знаков и прописать к ним свои пути. Тогда водяной знак будет автоматически ставиться на оригинальные изображения. Для нанесения водяного знака есть третий параметр $watermark, по-умолчанию false. В нём можно указать true, для наклеивания водяного знака на изображение. Если эту переменную вообще не передавать, то на фото не будет наклеен водяной знак.

Это делает процесс нанесения водяных знаков более гибким. Может в одном типе контента нужны ватермарки, а в другом не нужны. А если вы еще видеоролики храните на сайте, например из Ютуб, то наверняка захотите на картинку в тизере наложить изображение видеоплеера. Для этого нужно передать в метод четвёртый параметр для наложения видео, который равен true.

// Upload and save image.
try {
// Upload and save image.
$input['image'] = UploadImage::upload($file, 'post', false, $video)->getImageName();
} catch (UploadImageException $e) {
return back()->withInput()->withErrors(['image', $e->getMessage()]);
}

Получить изображение с диска очень просто. Нужно вызвать метод загрузки и передать в него строку модели:

$path = UploadImage::load('post');

Таким образом вы получите путь к папке, где хранится изображение, а само имя файла хранится в базе. Если нужна миниатюра, то передайте в метод вторым параметром ширину миниатюры, просто цифрой.

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

UploadImage::delete($post->image, 'post');

Нужно передать в метод имя файла и название модели. Тогда алгоритм удалит и оригинальное изображение и все миниатюры, которые были для него сделаны.

Помимо всего прочего, очень хочется, чтобы при начальном заполнении формы была возможность увидеть загруженное изображение. Например, на сайте есть возможность добавлять новости. Пользователь начинает заполнять форму добавления новости, выбирает фотографию, она загружается на диск. Пользователю сразу же показывается превьюшка, ещё до того, как он закончил заполнение формы.

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

<div class="image-preview-block">
<div class="image-preview-image"></div>
{!! Form::file('image', ['class' => 'image-preview-input']) !!}
</div>

Больше ни о чём думать не нужно, всё произойдет автоматически. В форме должна быть включена поддержка файлов, например:

{!! Form::open(['route' => 'post.store', 'files' => true]) !!}
Старайтесь использовать не пути, а имена роутов. Это лучше тем, что если нужно будет поменять путь, вы поменяете только у роута, а везде он подхватится уже автоматом.

Но есть один момент, достаточно любопытный. Представим, что по каким-то причинам, пользователь решил не создавать новость и бросит эту затею. Просто закрыл страницу и всё. При этом изображение уже было загружено на диск. Что же делать? Теперь это изображение будет похоронено в виде мусора.

Проблема решается достаточно просто. Когда пользователь загружает изображение, то функционал его получает от пользователя, сохраняет на диск, потом получает из диска и перекодирует в текстовый формат Base64 и отдает его в виде превьюшки назад пользователю. А оригинальное изображение удаляет с диска. Вот и всё. Если пользователь не засабмитит форму, то ничего страшного не произойдёт. А если засабмитит, то изображение опять загрузится на диск.

В новом релизе заменён алгоритм. Теперь превью изображения загружается средствами браузера. Единственное что будет получено от сервера, то это только настройка для ширины превьюшки.

Но и это еще не всё! Как нельзя представить современный сайт без изображений, так и нельзя, на сегодняшний день, представить сайт без WYSIWYG редактора. Никто, в здравом уме, не пишет контент в простом текстовом поле. И просто огромное количество пользователей знает лично, какая головная боль вставлять изображения в текст в самом редакторе! Для разных редакторов придуманы десятки всевозможных загрузчиков изображений, как платных, так и бесплатных.

Если вы всегда мечтали о том, чтобы просто нажать на кнопку вставить изображение прямо в редакторе, выбрать файл на компьютере, и изображение просто вставилось в текст, без вообще каких-либо дополнительных телодвижений. Чтобы при удалении статьи, куда вставилось много изображений из редактора, ненужно ничего было бы делать. Все фотографии автоматически бы удалились с диска вместе со статьёй.

В технической документации к пакету вы найдете пример, как это можно сделать. В настройках вы указываете, какая JS функция должна загружать изображения, а какая удалять. После этого, нажав на кнопку загрузки изображения, оно будет загружено в специальную папку, которую можно настроить в файле конфигурации. Если включены водяные знаки, то на изображение он будет нанесён, а изображение будет масштабировано и сжато, согласно настроек в конфиге.

И когда вы передаете изображение из текстового редактора, то вы можете передать сразу массив изображений. Все они автоматически будут загружены и возвращены в редактор. Когда вы находитесь в редакторе текста и нажмете на кнопку удаления изображения, то обработчик в финале вызовет метод, который удалит изображение с диска.

Все изображения в вашей статье будут содержать только относительные ссылки, поэтому переезд с сервера на сервер не побьёт их. Если же вы захотите удалить статью и все изображения в ней, то вам нужно всего-навсего вызвать следующий метод:

UploadImage::deleteBody($post->body);

Вы просто передаёте в метод текст, где содержаться ссылки на фотографии или изображения. Метод распарсит весь текст, найдет только относительные изображения и удалит их с вашего диска легко и просто.

В метод сохранения изображений, вы можете передать не только само изображение, но и ссылку на изображение, которое хранится на каком-то сайте. Метод автоматически распознаёт что вы передаёте. Тогда изображение будет закачено и превращено в обычное изображение на диске.