Отдача файлов в Laravel с ограниченным доступом


На одном из текущих проектов появилась задача. Необходимо создать хранилище файлов (изображений) пользователя и разрешить скачивать из этого самого только ему по прямой ссылке. Фреймворк - Laravel 9. Давайте разберемся, как это сделать.



Предварительные мысли и ход решения

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

  • Создаем роут для скачивания документов
  • Создаем контроллер для скачивания документов
  • В контроллере создаем две функции
    1. Для принудительного скачивания файлов (чтобы браузер не показывал картинку) и потом удаления его
    2. Получающую на вход запрос как аргумент, проверяющую пользователя, копирующую файл из хранилища (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 - то есть могу доработать ваш сайт или помочь с веб-программированием. Пишите сюда.

тегизаметки, laravel, php




Отправляя сообщение я подтверждаю, что ознакомлен и согласен с политикой конфиденциальности данного сайта.




Поиск по сайту
Урок 22. Функции поиска в строках C#
Урок 3. Числовые типы данных в C#