Хранилище файлов

Содержание:


Введение

Ларавел обеспечивает мощную файловую систему благодаря компоненту PHP Flysystem от Frank de Jonge. Интеграция компонента и Ларавел обеспечивает простой для использования драйвер для работы с локальной файловой системой и Amazon S3. Даже больше это невероятно просто переключаться между этими опциями хранения, так как API остаётся неизменным для каждой системы.


Конфигурация

Конфигурация файловой системы расположена в config/filesystems.php. Внутри файла вы можете настроить в ваши "диски". Каждый дист представляет драйвер и место для хранения. Пример конфигурации для каждого поддерживаемого диска включён в файл конфигруации. Поэтому измените конфигруацию, чтобы она отражала ваши предпочтения касательно хранилища данных.

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

Публичный диск

public диск предназначается для файлов, которые предназначены для публичного доступа. По умолчанию, диск public использует драйвер local и хранит эти файлы в директории storage/app/public. Чтобы их сделать доступными, необходимо создать символическую ссылку из public/storage в storage/app/public. Это сохранит публично-доступные файлы в одной директории, которую можно легко разделить между точками разработки при использовании систем нулового простая, таких как Envoyer.

Чтобы создать символическую ссылку, вы можете использовать команду Artisan storage:link:

php artisan storage:link

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

echo asset('storage/file.txt');

Локальный драйвер

При использовании драйвера local, все операции с файлами привязаны к директории root определённой в вашем файле конфигурации filesystems. По умолчанию, это значение установлено в директории storage/app. Таким образом, следующий метод должен сохранить файл в storage/app/file.txt:

Storage::disk('local')->put('file.txt', 'Contents');

Разрешения

Установлены разрешения 0755 для публичных папок и 0644 для файлов. Вы можете изменить разрешения в вашем файле конфигурации filesystems:

'local' => [
    'driver' => 'local',
    'root' => storage_path('app'),
    'permissions' => [
        'file' => [
            'public' => 0664,
            'private' => 0600,
        ],
        'dir' => [
            'public' => 0775,
            'private' => 0700,
        ],
    ],
],

Требования к драйверу

Компоненты Composer

Перед использованием SFTP или S3 драйверов вам необходимо установить соответсвующие компоненты через Composer:

  • SFTP: league/flysystem-sftp ~1.0
  • Amazon S3: league/flysystem-aws-s3-v3 ~1.0

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

  • CachedAdapter: league/flysystem-cached-adapter ~1.0

Конфигурация драйвера S3

Информация конфигурации драйвера S3 находится в файле конфигурации config/filesystems.php. Это файл содержит пример массива конфигурации для драйвера S3. Вы можете свободно модифицировать этот массив под ваши нужды. Для удобства переменные окружения соответсвуют названию переменных используемых AWS CLI.

Конфигурация драйвера FTP

Flysystem Ларавел может отлично работать с FTP; Однако, конфигурация по умолчанию не включена в базовую сборку фреймворка и конкретно в файл filesystems.php. Если вам необходимо настроить систему для работы с FTP, вы можете использовать пример конфигурации:

'ftp' => [
    'driver' => 'ftp',
    'host' => 'ftp.example.com',
    'username' => 'your-username',
    'password' => 'your-password',

    // Optional FTP Settings...
    // 'port' => 21,
    // 'root' => '',
    // 'passive' => true,
    // 'ssl' => true,
    // 'timeout' => 30,
],

Конфигурация драйвера SFTP

Как и в случае с FTP, конфигурации SFTP нет в файле filesystems.php. Ниже представлен пример конфигурации для настройки SFTP:

'sftp' => [
    'driver' => 'sftp',
    'host' => 'example.com',
    'username' => 'your-username',
    'password' => 'your-password',

    // Settings for SSH key based authentication...
    // 'privateKey' => '/path/to/privateKey',
    // 'password' => 'encryption-password',

    // Optional SFTP Settings...
    // 'port' => 22,
    // 'root' => '',
    // 'timeout' => 30,
],

Кэширование

Чтобы включить кэширование для данного диска, вы можете добавить опцию cache в конфигурацию диска. Эта опция должна быть массивом, содержащим следующие параметры: имя disk, время в секундах expire и префикс prefix:

's3' => [
    'driver' => 's3',

    // Other Disk Options...

    'cache' => [
        'store' => 'memcached',
        'expire' => 600,
        'prefix' => 'cache-prefix',
    ],
],

Получения экземпляра диска

Фасад Storage можно использовать для взаимодействия с любым из настроенных дисков. Например, вы можете ипользовать метод put для фасада, чтобы сохранить аватар на диск, указанный по умолчанию:

use Illuminate\Support\Facades\Storage;

Storage::put('avatars/1', $fileContents);

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

Storage::disk('s3')->put('avatars/1', $fileContents);

Извлечение файлов

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

$contents = Storage::get('file.jpg');

Метод exists может быть использован для определения того, что файл есть на диске:

$exists = Storage::disk('s3')->exists('file.jpg');

Загрузка файлов

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

return Storage::download('file.jpg');

return Storage::download('file.jpg', $name, $headers);

Файловые URL

Вы можете использовать метод url, чтобы получить URL для данного файла. Если вы используете драйвер local, тогда он просто доставить /storage в выбранный путь и вернут относительный URL для файла. Если вы используете драйвер s3, вернётся полный удалённый URL:

use Illuminate\Support\Facades\Storage;

$url = Storage::url('file.jpg');
Запомните, если вы используете драйвер local, все файлы, которые быть публично доступны должны быть размещены в папке storage/app/public. Даже более того, вам стоит создать символическу ссылку в public/storage, которая приведёт в папку storage/app/public.

Временные URLs

При использовании файлов s3 вы можете использовать временный URL для данного файла используя метод temporaryUrl. Эти методы принимают путь и экземпляр DateTime, уточняющий когда URL должен исчезнуть:

$url = Storage::temporaryUrl(
    'file.jpg', now()->addMinutes(5)
);

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

$url = Storage::temporaryUrl(
    'file.jpg',
    now()->addMinutes(5),
    ['ResponseContentType' => 'application/octet-stream']
);

Настройка локального URL хоста

Если вы хотите предопределить хост для файлов хранящихся на диске с использованием драйвера local, вы можете добавить опцию url в массив конфигурации диска:

'public' => [
    'driver' => 'local',
    'root' => storage_path('app/public'),
    'url' => env('APP_URL').'/storage',
    'visibility' => 'public',
],

Метаданные файла

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

use Illuminate\Support\Facades\Storage;

$size = Storage::size('file.jpg');

Метод lastModified возвращает дату последнего изменения в формате UNIX:

$time = Storage::lastModified('file.jpg');

Хранение файлов

Метод put может быть использована для того, чтобы сохранить контент файла на диске. Вы также можете передать PHP resource в метод put, который будет использовать базовую поддержку стрима Flysystem. При работе с большими файлами, настоятельно рекомендуется настроить работу именно с использованием стримов:

use Illuminate\Support\Facades\Storage;

Storage::put('file.jpg', $contents);

Storage::put('file.jpg', $resource);

Автоматическая потоковая передача

Если вы хотите чтобы Ларавел автоматически настроил управление потоковой передачей данного файла к вашему месту хранения, вы можете использовать метод putFile или putFileAs. Этот метод принимает как экземпляры Illuminate\Http\File так и Illuminate\Http\UploadedFile и автоматически начнёт стрим файла в нужную локацию:

use Illuminate\Http\File;
use Illuminate\Support\Facades\Storage;

// Automatically generate a unique ID for file name...
Storage::putFile('photos', new File('/path/to/photo'));

// Manually specify a file name...
Storage::putFileAs('photos', new File('/path/to/photo'), 'photo.jpg');

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

Методы putFile и putFileAs также принимают аргумент для указания видимости сохранённого файла. Это особенно полезно если вы храните файл на облачных дисках, таких как S3, а файл публично доступен:

Storage::putFile('photos', new File('/path/to/photo'), 'public');

Дописывание в файлы

Методы prepend и append позволяют вам дописать в начало или конец файла:

Storage::prepend('file.log', 'Prepended Text');

Storage::append('file.log', 'Appended Text');

Копирование и перемещение файлов

Метод copy можно использования для копирования существующих файлов в новую локация на диске. Метод move можно использовать для переименования или перемещения существующего файла в новую директорию:

Storage::copy('old/file.jpg', 'new/file.jpg');

Storage::move('old/file.jpg', 'new/file.jpg');

Загрузка файлов

В веб-приложения, один из наиболее распространённых случаем для хранения файлов это хранение загреженных файлов пользователя таких как картинки, фото и документы. Ларавел делает очень легким сохранение файлов используя метод store для экземпляра загруженного файла. Вызовите метод store с путём в который вы хотите, чтобы файл был сохранён:

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class UserAvatarController extends Controller
{
    /**
     * Update the avatar for the user.
     *
     * @param  Request  $request
     * @return Response
     */
    public function update(Request $request)
    {
        $path = $request->file('avatar')->store('avatars');

        return $path;
    }
}

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

Вы можете также вызвать метод putFile для фасада Storage, чтобы выполнить такие же действия как и в примере выше:

$path = Storage::putFile('avatars', $request->file('avatar'));

Указание имение файла

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

$path = $request->file('avatar')->storeAs(
    'avatars', $request->user()->id
);

Вы можете также использовать метод putFileAs для фасада Storage, который выполнит такие же операции, как и примере выше:

$path = Storage::putFileAs(
    'avatars', $request->file('avatar'), $request->user()->id
);
Непечатные и неверные символы будут автоматически убраны из пути файла. Поэтому вы можете захотеть очистить путь файла до момента передачи в методы сохранения. Нормализация пути файла можно провести используя метод League\Flysystem\Util::normalizePath.

Указание диска

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

$path = $request->file('avatar')->store(
    'avatars/'.$request->user()->id, 's3'
);

Видимость файлов

В Ларавел в контексте компонента Flysystem, видимость — права и разрешения файла для различных платформ. Файлы могут быть быть задекларированны как public или private. Когда файл задекларированн как public, вы показываете что файл должен быть доступен для других. Еще, например, при использовании драйвера S3, вы можете получить URL для всех файлов public.

Вы можете установить видимость файла при сохранении для метода put:

use Illuminate\Support\Facades\Storage;

Storage::put('file.jpg', $contents, 'public');

А если файл уже сохранён, вы можете узнать их видимость или установить через методы getVisibility и setVisibility:

$visibility = Storage::getVisibility('file.jpg');

Storage::setVisibility('file.jpg', 'public')

Удаление файлов

Метод delete принимает имя файла или массив файлов, которые необходимо удалить из диска:

use Illuminate\Support\Facades\Storage;

Storage::delete('file.jpg');

Storage::delete(['file.jpg', 'file2.jpg']);

При необходимости, можно указать диск, с которого необходимо проводить удаление:

use Illuminate\Support\Facades\Storage;

Storage::disk('s3')->delete('folder_path/file_name.jpg');

Папки

Получение всех файлов внутри директории

Метод files возвращает массив файлов, которые находятся в данной директории. Если вы хотите получить все файлы как самой директории, так и вложенных папках, вы можете использовать метод allFiles:

use Illuminate\Support\Facades\Storage;

$files = Storage::files($directory);

$files = Storage::allFiles($directory);

Получить все папки внутри директории

Метод directories возвращает массив всех директрий внутри данной директории. Дополнитлеьно, вы можете использовать метод allDirectories для получения списка папок внутри директории включая те, которые находятся во вложенных папках:

$directories = Storage::directories($directory);

// Recursive...
$directories = Storage::allDirectories($directory);

Создание директрии

Метод makeDirectory создаст указанную директорнию, включая необходимоые вложенные директории:

Storage::makeDirectory($directory);

Удаление директории

Наконец, метод deleteDirectory удалит папку и все файлы внутри:

Storage::deleteDirectory($directory);

Пользовательская файловая система

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

Чтобы начать рабтать с пользовательской файловой системой вам будет необходимо адаптер Flysystem. Давайте добавим поддерживаемый сообществом адаптер Dropbox для нашего проекта:

composer require spatie/flysystem-dropbox

После чего, вам следует создать сервис провайдер, такой как DropboxServiceProvider. В методе провайдера boot вы можете использовать метод extend для фасада Storage для определения пользовательского драйвера:

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use League\Flysystem\Filesystem;
use Spatie\Dropbox\Client as DropboxClient;
use Spatie\FlysystemDropbox\DropboxAdapter;
use Storage;

class DropboxServiceProvider extends ServiceProvider
{
    /**
     * Register bindings in the container.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Storage::extend('dropbox', function ($app, $config) {
            $client = new DropboxClient(
                $config['authorization_token']
            );

            return new Filesystem(new DropboxAdapter($client));
        });
    }
}

Первый аргумент метода extend это название драйвер и второй аргумент это замыкание, кототрое получает переменные $app и $config. Должен вернуться экземпляр League\Flysystem\Filesystem. Переменная $config содержит значения, определённые в config/filesystems.php для указанного диска.

Следующим шагом необходимо добавить сервис провайдер в файл конфигурации config/app.php:

'providers' => [
    // ...
    App\Providers\DropboxServiceProvider::class,
];

После того как вы создали и зарегистрировали сервис провайдер, вы можете использовать драйвер dropbox в вашем файле конфигурации config/filesystems.php.