Как работать с личными изображениями в laravel 5?

Я новичок в Laravel и пытаюсь хранить личные изображения, чтобы только аутентифицированные пользователи могли получить к ним доступ. Сначала я сохранил изображения в папке Public/UserImages. Но здесь все изображения доступны и для неавторизованных пользователей, перейдя в «Проверить элемент хрома» и затем изменив идентификаторы пользователей. Будь добр, помоги мне...


person Hassan Saqib    schedule 17.02.2015    source источник


Ответы (4)


Это действительно зависит от вас. Он должен находиться за пределами каталога public — я бы лично выбрал resources/uploads или storage/uploads или полностью сохранил их за пределами сервера, используя поддержка облачной файловой системы.

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

person ceejayoz    schedule 17.02.2015

Ниже показано, как я решил проблему хранения изображений в Laravel 5 таким образом, чтобы только аутентифицированные пользователи могли просматривать изображения. Пользователи, не прошедшие проверку подлинности, будут перенаправлены на страницу входа. Мой сервер — это сервер Ubuntu/Apache2.

  1. Создайте каталог /var/www/ВАШ ВЕБ-САЙТ/app/Assets/Images

  2. Добавьте маршрут в app/Http/routes.php.

    Route::get('/images/{file}','ImageController@getImage');

  3. Создайте приложение контроллера/Http/Controllers/ImageController.php

    <?php
    namespace App\Http\Controllers;
    
    use App\Http\Requests;
    
    use App\Http\Controllers\Controller;
    
    use Illuminate\Http\Request;
    
    use Auth;
    
    class ImageController extends Controller {
    
        public function __construct()
       {
            $this->middleware('auth');
       } 
        public function getImage($filename) {
           $path = '/var/www/YOURWEBSITE/app/Assets/Images/'.$filename;
           $type = "image/jpeg";
           header('Content-Type:'.$type);
           header('Content-Length: ' . filesize($path));
           readfile($path);
    
        }
    
     }
    
  4. На ваш взгляд, у вас есть теги img, которые имеют:

    src="{{ url('/images/test.jpg') }}"
    

Это, конечно, предполагает, что test.jpg является файлом в /var/www/ВАШ ВЕБ-САЙТ/приложение/Активы/Изображения/

Конечно, вы можете добавить больше логики, например, не указывать жестко путь к изображениям и т. д. Это всего лишь простой пример принудительной проверки подлинности. Обратите внимание на использование промежуточного программного обеспечения ('auth') в конструкторе контроллера.

person ken koehler    schedule 15.04.2015
comment
Было бы намного лучше и позволить коду перемещаться из одного места в другое, если бы base_path() использовался для создания начала абсолютного пути, а не для ввода всего этого. - person Andrew Killen; 02.10.2016
comment
Кто-нибудь знает, как сделать, чтобы эти файлы отображались в формате pdf? Благодарность - person Cutis; 03.06.2019

У меня возникла такая же проблема несколько дней назад, и я придумал это решение:

  1. Первое, что вам нужно сделать, это загрузить файл в закрытый каталог. Мое приложение хранит отсканированные счета-фактуры, поэтому я собираюсь поместить их в storage/app/invoices. Код для загрузки файла и создания URL-адреса будет таким:

    // This goes inside your controller method handling the POST request.
    
    $path = $request->file('invoice')->store('invoices');
    $url = env('APP_URL') . Illuminate\Support\Facades\Storage::url($path);
    

    Возвращаемый URL-адрес должен выглядеть примерно так: http://yourdomain.com/storage/invoices/uniquefilename.jpg

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

    <?php
    
    namespace App\Http\Controllers;
    
    use Illuminate\Support\Facades\Storage;
    
    class FileController extends Controller
    {
    
        public function __construct()
        {
            $this->middleware('auth');
        }
    
        public function __invoke($file_path)
        {
            if (!Storage::disk('local')->exists($file_path)) {
                abort(404);
            }
    
            $local_path = config('filesystems.disks.local.root') . DIRECTORY_SEPARATOR . $file_path;
    
            return response()->file($local_path);
        }
    }
    
  3. Последнее, что нужно сделать, это зарегистрировать маршрут в файле routes/web.php:

    Route::get('/storage/{file_name}', 'FileController')->where(['file_name' => '.*'])
    

Итак, у вас есть довольно многоразовый фрагмент для всех ваших проектов, связанных с личными файлами :)

person Franco Sarachu    schedule 31.03.2017
comment
Это лучшее решение, которое я нашел. Спасибо - person MrEduar; 30.03.2021
comment
'.*' небезопасно, разрешите использовать ../ и можете получить доступ к корневым файлам как .env и т. д. Используйте это безопасное регулярное выражение ^([A-z0-9-_+]+\/)*([A-z0 -9-\.]+)(\?\d+)?$ - person Elias Tutungi; 11.05.2021

Вот как это сделать в Laravel 5.7

Чтобы иметь личные файлы (изображения), вам необходимо обслуживать файлы через поток route => controller. И ваше промежуточное ПО аутентификации будет обрабатывать аутентификацию и разрешение. Если требуется дополнительная авторизация, вы обрабатываете ее в контроллере.

Итак, сначала мы устанавливаем маршрут:

Здесь у нас может быть один маршрут, который обрабатывает все наши файлы [лично я этого не предпочитаю]. Мы можем сделать это, используя такой маршрут (это как подстановочный знак).

Route::get('/storage/{filePath}', 'FileController@fileStorageServe')
->where(['filePath' => '.*'])

Вы также можете назвать это так:

Route::get('/storage/{fileName}', 'FileController@fileStorageServe')
->where(['fileName' => '.*'])->name('storage.gallery.file');

В противном случае мы создаем маршрут для каждого типа/категории файлов: (преимущество: вы сможете лучше контролировать доступность. (Каждый маршрут и тип ресурсов и его правила. Если вы хотите добиться этого с помощью маршрута с подстановочными знаками (позвольте мне назвать его так), вам нужно иметь условные блоки (если иначе, обрабатывать все разные ситуации. Это ненужные операции [идущие прямо вправо block, когда маршруты лучше разделены, плюс ко всему это позволяет лучше организовать обработку разрешений]).

Route::get('/storage/gallery/{file}', 'System\FileController@getGalleryImage')
->name('storage.gallery.image');

Наши маршруты были установлены СЕЙЧАС. Контроллер/Контроллеры

Подстановочный знак

  <?php
     public function fileStorageServe($file) {
                // know you can have a mapping so you dont keep the sme names as in local (you can not precsise the same structor as the storage, you can do anything)

                // any permission handling or anything else

                // we check for the existing of the file 
                if (!Storage::disk('local')->exists($filePath)){ // note that disk()->exists() expect a relative path, from your disk root path. so in our example we pass directly the path (/.../laravelProject/storage/app) is the default one (referenced with the helper storage_path('app')
                    abort('404'); // we redirect to 404 page if it doesn't exist
                } 
            //file exist let serve it 

// if there is parameters [you can change the files, depending on them. ex serving different content to different regions, or to mobile and desktop ...etc] // repetitive things can be handled through helpers [make helpers]

                return response()->file(storage_path('app'.DIRECTORY_SEPARATOR.($filePath))); // the response()->file() will add the necessary headers in our place (no headers are needed to be provided for images (it's done automatically) expected hearder is of form => ['Content-Type' => 'image/png'];

// big note here don't use Storage::url() // it's not working correctly.  
            }

Один на маршрут

(большая разница, это параметр, теперь он ссылается только на имя файла, а не на относительный путь к корню диска хранилища)

<?php
public function getCompaniesLogo($file) {
    // know you can have a mapping so you dont keep the sme names as in local (you can not precsise the same structor as the storage, you can do anything)

    // any permission handling or anything else

    $filePath =  config('fs.gallery').DIRECTORY_SEPARATOR.$file; // here in place of just using 'gallery', i'm setting it in a config file

    // here i'm getting only the path from the root  (this way we can change the root later) / also we can change the structor on the store itself, change in one place config.fs.

    // $filePath = Storage::url($file); <== this doesn't work don't use

     // check for existance
    if (!Storage::disk('local')->exists($file)){ // as mentionned precise relatively to storage disk root (this one work well not like Storage:url()
          abort('404');
    } 

    // if there is parameters [you can change the files, depending on them. ex serving different content to different regions, or to mobile and desktop ...etc] // repetitive things can be handled through helpers [make helpers]

    return response()->file(storage_path('app'.DIRECTORY_SEPARATOR.($file))); // the response()->file() will add the necessary headers in our place
}

Теперь вы можете проверить, сформировав правильный URL-адрес (перейдите в хранилище, скопируйте имя файла и сформируйте свой маршрут. Он должен показать вам изображение)

Осталось последнее:

Как показать это в поле зрения

подстановочный знак

<img src="{{route('routeName', ['fileParam' => $storageRelativePath])}}" />

Обратите внимание, что routeName здесь, в приведенном выше примере, будет storage.file, а fileParam будет filePath. $storageRelativePath например, вы получаете из базы данных (обычно это то, что будет).

За маршрут

<img src="{{route('routeName', ['fileName' => basename($storageRelativePath)])}}" />

То же самое, но мы предоставляем только имя файла.

Примечания. Лучший способ отправить такой ответ — использовать response()->file();. То, что вы найдете в документе 5.7. Эта производительность мудра против Image::make($storagePath)->response();. Если вам не нужно изменять его на лету.

Вы можете проверить мою статью в среде: https://medium.com/@allalmohamedlamine/how-to-serve-images-and-files-privatly-in-laravel-5-7-a4b469f0f706

person Mohamed Allal    schedule 15.11.2018