Отдача файлов в Laravel с ограниченным доступом
На одном из текущих проектов появилась задача. Необходимо создать хранилище файлов (изображений) пользователя и разрешить скачивать из этого самого только ему по прямой ссылке. Фреймворк - Laravel 9. Давайте разберемся, как это сделать.
Предварительные мысли и ход решения
Загружать файлы в лару мы уже научились на вот этом уроке. Теперь нам надо научиться отдавать эти файлы, причем только тому пользователю, чьи они. Вообще говоря, мой план довольно прост:
- Создаем роут для скачивания документов
- Создаем контроллер для скачивания документов
- В контроллере создаем две функции
- Для принудительного скачивания файлов (чтобы браузер не показывал картинку) и потом удаления его
- Получающую на вход запрос как аргумент, проверяющую пользователя, копирующую файл из хранилища (storage) в общедоступную папку и вызывающую первую функцию.
Непосредственно код
В файл роутинга routes/web.php добавляем правило
Route::get('/docs/{idx}', [DocumentController::class, 'getFile'])->middleware(['auth'])->name('docs');Первая функция для скачивания файлов браузером посетителя
function file_force_download($file) { if (ob_get_contents()) ob_end_clean(); header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename=' . basename($file)); header('Content-Transfer-Encoding: binary'); header('Expires: 0'); header('Cache-Control: must-revalidate'); header('Pragma: public'); header('Content-Length: ' . filesize($file)); readfile($file); unlink($file); exit; }Вторая функция (обе находятся в классе DocumentController)
public function getFile(Request $request, String $idx = "" ) { if (!$idx){ return;//тут можно в принципе и сообщение об ошибке и abort(404) } $docname = DB::table('documents') ->where('id', $idx) ->where('user_id', Auth::user()->id) ->first(); if (!$docname){ return;//тут можно в принципе и сообщение об ошибке и abort(404) } //копируем файл $path = storage_path('app/docs/'. $idx); $newfile = "/home/каталог_сайта/public_html/tmp/". $idx; copy($path, $newfile); //отдаем его посетителю $this->file_force_download($newfile);Здесь мы сначала проверяем, есть ли вообще аргумент, потом предполагаем, что данный аргумент – это индекс документа в таблице documents и что владелец данного файла именно текущий, авторизованный пользователь – что именно он пытается осуществить скачивание. Теперь если зарегистрированный пользователь хочет скачать свой файл, то он переходит по адресу https://сайт/docs/ид_файла, ларавель копирует файл в папку https://сайт/tmp/ид_файла и дает скачать. Потом удаляет.
Итоги
Вот так несложно можно скачивать файлы с Laravel. Напоследок обращу внимание на один момент, на который стоит обратить внимание, если у вас на сервере-сайте будет храниться уж очень конфиденциальная информация. Можно дополнительно сделать так, чтобы файл копировался во временную папку со случайным названием из набора букв и цифр. Хотя и так он просуществует в доступном месте буквально пару секунд.
Автор этого материала - я - Пахолков Юрий. Я оказываю услуги по написанию программ на языках Java, C++, C# (а также консультирую по ним) и созданию сайтов. Работаю с сайтами на CMS OpenCart, WordPress, ModX и самописными. Кроме этого, работаю напрямую с JavaScript, PHP, CSS, HTML - то есть могу доработать ваш сайт или помочь с веб-программированием. Пишите сюда.
Отправляя сообщение я подтверждаю, что ознакомлен и согласен с политикой конфиденциальности данного сайта.