Laravel 5 - Как получить доступ к изображению, загруженному в хранилище, в View?

172

Я загрузил аватары пользователя в хранилище Laravel. Как я могу получить к ним доступ и отобразить их в виде?

Сервер направляет все запросы /public, так как я могу показать их, если они находятся в /storageпапке?

Тадеаш Йилек
источник

Ответы:

349

Лучший подход заключается в создании символической ссылки , как @SlateEntropy очень хорошо указал в ответ ниже . Чтобы помочь с этим, начиная с версии 5.3, Laravel включает команду, которая делает это невероятно простым:

php artisan storage:link

Это создает символическую ссылку из public/storageк storage/app/publicвам и что все , что есть в ней. Теперь любой файл в /storage/app/publicможно получить по ссылке, например:

http://somedomain.com/storage/image.jpg

Если по какой-либо причине вы не можете создать символические ссылки (может быть, вы используете общий хостинг и т. Д.) Или вы хотите защитить некоторые файлы с помощью некоторой логики управления доступом, есть альтернатива иметь специальный маршрут, который читает и обслуживает изображение. Например, простой маршрут закрытия:

Route::get('storage/{filename}', function ($filename)
{
    $path = storage_path('public/' . $filename);

    if (!File::exists($path)) {
        abort(404);
    }

    $file = File::get($path);
    $type = File::mimeType($path);

    $response = Response::make($file, 200);
    $response->header("Content-Type", $type);

    return $response;
});

Теперь вы можете получить доступ к своим файлам так же, как если бы у вас была символическая ссылка:

http://somedomain.com/storage/image.jpg

Если вы используете библиотеку изображений Intervention, вы можете использовать ее встроенный responseметод, чтобы сделать вещи более лаконичными:

Route::get('storage/{filename}', function ($filename)
{
    return Image::make(storage_path('public/' . $filename))->response();
});

ПРЕДУПРЕЖДЕНИЕ

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

Богдан
источник
Это кажется хорошим. Я хотел бы задать еще один вопрос. Рекомендуется ли хранить такие файлы, как аватары, превью и т. Д. (Загруженные файлы от пользователей) в хранилище?
Тадеаш Йилек,
5
Вы можете хранить их где угодно, но если это не личные файлы, я думаю, вам лучше хранить их в publicкаталоге. Таким образом, вы избежите накладных расходов, связанных с составлением ответа на изображение, который HTTP-сервер может обработать намного быстрее.
Богдан
2
Лично я не буду хранить пользовательские файлы в общей папке, я нахожу вещи более аккуратными и более управляемыми, когда папка хранения используется для хранения.
SlateEntropy
2
Я бы не рекомендовал ни один из них, потому что тогда вы добавляете накладные расходы на загрузку Laravel снова и / или используете PHP для чтения каждого изображения. Использование символической ссылки, как описано в CmdSft, будет намного быстрее.
user1960364
4
@ user1960364 Вот почему в последнем абзаце настоятельно рекомендуется использовать символическую ссылку. Но сам ответ, хотя и не является лучшим решением с точки зрения производительности, по-прежнему действителен и может быть единственным подходом для людей, запускающих приложения на общих серверах, где символические ссылки могут быть невозможны для настройки. Ответ также показывает, как вы можете обслуживать файлы программно, если когда-либо возникнет такая необходимость, возможно, для обслуживания зашифрованных файлов, как это задано в этом вопросе .
Богдан
53

Одним из вариантов будет создание символической ссылки между подпапкой в ​​вашем каталоге хранения и публичным каталогом.

Например

ln -s /path/to/laravel/storage/avatars /path/to/laravel/public/avatars

Это также метод, используемый Envoyer , менеджером развертывания, созданным Taylor Otwell, разработчиком Laravel.

SlateEntropy
источник
Я немного новичок в этом. Это нужно запустить на терминале или определить в файле конфигурации где-нибудь в laravel?
Гаурав Мехта
да, вам нужно запустить это через командную строку. Он должен быть настроен везде, где вы развернете приложение.
SlateEntropy
Для пользователей Windows есть отдельный инструмент для этого, если вы не хотите использовать CMD: github.com/amd989/Symlinker#downloads
David
3
Был задан вопрос, как показать storageпубличные аватары пользователей , обычно аватары не требуют какого-либо контроля доступа. Если никакой безопасности не требуется, используя какое-либо промежуточное программное обеспечение или маршрут, это просто потерянный удар по вашим ресурсам. Стоит также отметить, что в Laravel 5.2 существует отдельный файл «диск» для открытых файлов ( laravel.com/docs/5.2/filesystem ), использующий символические ссылки .
SlateEntropy
6
Для этого в Laravel 5.3 есть команда ремесленников: $ php artisan storage: ссылка
Фил
22

Согласно документации Laravel 5.2, ваши общедоступные файлы должны быть помещены в каталог

storage/app/public

Чтобы сделать их доступными из Интернета, вы должны создать символическую ссылку с public/storageна storage/app/public.

ln -s /path/to/laravel/storage/app/public /path/to/laravel/public/storage

Теперь вы можете создать в своем представлении URL-адрес для файлов, используя помощник по активам:

echo asset('storage/file.txt');
Петр
источник
13

Прежде всего вам нужно создать символическую ссылку для каталога хранилища с помощью команды artisan

php artisan storage:link

Тогда в любом представлении вы можете получить доступ к своему изображению через URL-помощник, как это.

url('storage/avatars/image.png');
Хайдер Али
источник
4

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

Создайте маршрут / документацию и укажите любой метод контроллера:

public function docs() {

    //custom logic

    //check if user is logged in or user have permission to download this file etc

    return response()->download(
        storage_path('app/users/documents/4YPa0bl0L01ey2jO2CTVzlfuBcrNyHE2TV8xakPk.png'), 
        'filename.png',
        ['Content-Type' => 'image/png']
    );
}

Когда вы нажмете localhost:8000/docsфайл будет загружен, если таковой существует.

Файл должен находиться в root/storage/app/users/documentsкаталоге в соответствии с приведенным выше кодом, это было проверено на Laravel 5.4.

Сайед Шибли
источник
4

Если вы хотите загрузить небольшое количество личных изображений, вы можете кодировать изображения в base64 и выводить их <img src="{{$image_data}}">напрямую:

$path = image.png
$full_path = Storage::path($path);
$base64 = base64_encode(Storage::get($path));
$image_data = 'data:'.mime_content_type($full_path) . ';base64,' . $base64;

Я упомянул приватный, потому что вы должны использовать эти методы только в том случае, если вы не хотите хранить изображения, общедоступные через URL, вместо этого вы должны всегда использовать стандартный способ (связать хранилище / общую папку и обслуживать изображения с HTTP-сервером).

Остерегайтесь кодирования, чтобы base64()иметь две важные недостатки:

  1. Это увеличит размер изображения на ~ 30%.
  2. Вы объединяете все размеры изображений в одном запросе, вместо того, чтобы загружать их параллельно, это не должно быть проблемой для некоторых небольших миниатюр, но для многих изображений избегайте использования этого метода.
Араш Моосапур
источник
2

Если вы используете php, просто воспользуйтесь функцией php symlink, например:

symlink('/home/username/projectname/storage/app/public', '/home/username/public_html/storage')

измените имя пользователя и имя проекта на правильные имена.

dagogodboss
источник
1

без названия сайта

{{Storage::url($photoLink)}}

если вы хотите добавить имя сайта к нему, пример добавить в API JSON FELIDS

 public function getPhotoFullLinkAttribute()
{
    return env('APP_URL', false).Storage::url($this->attributes['avatar']) ;
}
Джехад Ахмад Джагуб
источник
0

Если вы похожи на меня и у вас каким-то образом есть полные пути к файлам (я сделал несколько шаблонов glob () на требуемых фотографиях, так что в итоге получаю полные пути к файлам), и ваши настройки хранилища хорошо связаны (то есть такие, что ваши пути есть строка storage/app/public/), тогда вы можете использовать мой маленький грязный хак ниже: р)

 public static function hackoutFileFromStorageFolder($fullfilePath) {
        if (strpos($fullfilePath, 'storage/app/public/')) {
           $fileParts = explode('storage/app/public/', $fullfilePath);
           if( count($fileParts) > 1){
               return $fileParts[1];
           }
        }

        return '';
    }
Дамилола Оловуокере
источник
0

Если у вас не работает локальный диск, попробуйте это:

  1. Изменить местный на общедоступный в 'default' => env('FILESYSTEM_DRIVER', 'public'),сproject_folder/config/filesystem.php
  2. Очистить кеш настроек php artisan config:clear
  3. Затем создайте сим-ссылку php artisan storage:link

Чтобы получить URL загруженного изображения, вы можете использовать это Storage::url('iamge_name.jpg');

Днянешвар Харер
источник