Введение
Laravel предоставляет мощную абстракцию для работы с файловой системой благодаря восхитительному PHP-пакету Flysystem от Франка де Жонге. Laravel Flysystem содержит простые в использовании драйвера для работы с локальными файловыми системами, Amazon S3 и Rackspace Cloud Storage. Более того, можно очень просто переключаться между этими вариантами хранения файлов, поскольку у всех одинаковый API.
Настройка
Настройки файловой системы находятся в файле config/filesystems.php. В нём вы можете настроить все свои «disks». Каждый диск представляет определенный драйвер и место хранения. В конфигурационном файле имеются примеры для каждого поддерживаемого драйвера. Поэтому вы можете просто немного изменить конфигурацию под ваши нужды!
Конечно, вы можете сконфигурировать столько дисков, сколько вам будет угодно, и даже можете иметь несколько дисков, которые используют один драйвер.
Общий диск
Диск public предназначен для общего доступа к файлам. По умолчанию диск public использует драйвер local и хранит файлы в storage/app/public. Чтобы сделать их доступными через веб, вам надо создать символьную ссылку из public/storage на storage/app/public. При этом ваши общедоступные файлы будут храниться в одной папке, которую легко можно использовать в разных развёртываниях при использовании систем обновления на лету, таких как Envoyer.
Для создания символьной ссылки используйте Artisan-команду shstorage:link
:
shphp artisan storage:link
Само собой, когда файл сохранён и создана символьная ссылка, вы можете создать URL к файлу с помощью вспомогательной функции PHPasset()
:
echo asset('storage/file.txt');
Драйвер local
При использовании драйвера local все файловые операции выполняются относительно каталога root, определенного в вашем конфигурационном файле. По умолчанию это каталог storage/app. Поэтому следующий метод сохранит файл в storage/app/file.txt:
Storage::disk('local')->put('file.txt', 'Contents');
Требования к драйверам
Перед использованием S3 или Rackspace вы должны установить соответствующие пакеты при помощи Composer:
- Amazon S3: league/flysystem-aws-s3-v3 ~1.0
- Rackspace: league/flysystem-rackspace ~1.0
добавлено в 5.3 ()
Интеграция Flysystem отлично работает с FTP, но в стандартном файле настроек filesystems.php нет примера настройки FTP. Если вам надо настроить файловую систему FTP, вы можете использовать в качестве примера приведенные ниже настройки:
'ftp' => [
'driver' => 'ftp',
'host' => 'ftp.example.com',
'username' => 'ваш-логин',
'password' => 'ваш-пароль',
// Необязательные настройки FTP...
// 'port' => 21,
// 'root' => '',
// 'passive' => true,
// 'ssl' => true,
// 'timeout' => 30,
],
Интеграция Flysystem отлично работает с Rackspace, но в стандартном файле настроек filesystems.php нет примера настройки Rackspace. Если вам надо настроить файловую систему Rackspace, вы можете использовать в качестве примера приведенные ниже настройки:
'rackspace' => [
'driver' => 'rackspace',
'username' => 'ваш-логин',
'key' => 'ваш-ключ',
'container' => 'ваш-контейнер',
'endpoint' => 'https://identity.api.rackspacecloud.com/v2.0/',
'region' => 'IAD',
'url_type' => 'publicURL',
],
Получение экземпляров дисков
Для взаимодействия с любым из ваших сконфигурированных дисков можно использовать фасад Storage. Например, вы можете использовать метод этого фасада PHPput()
, чтобы сохранить аватар на диск по умолчанию. Если вы вызовите метод фасада Storage без предварительного вызова метода PHPdisk()
, то вызов метода будет автоматически передан диску по умолчанию:
добавлено в 5.3 ()
use Illuminate\Support\Facades\Storage;
Storage::put('avatars/1', $fileContents);
добавлено в 5.2 () 5.1 () 5.0 ()
<?php
namespace App\Http\Controllers;
use Storage;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class UserController extends Controller
{
/**
* Обновить аватар данного пользователя.
*
* @param Request $request
* @param int $id
* @return Response
*/
public function updateAvatar(Request $request, $id)
{
$user = User::findOrFail($id);
Storage::put(
'avatars/'.$user->id,
file_get_contents($request->file('avatar')->getRealPath())
);
}
}
При использовании нескольких дисков вы можете обращаться к нужному диску с помощью метода PHPdisk()
фасада Storage:
Storage::disk('s3')->put('avatars/1', $fileContents);
Чтение файлов
Методом PHPget()
можно получать содержимое файла. Он возвращает сырую строку содержимого файла. Не забывайте, все пути файлов необходимо указывать относительно настроенного для диска «корня»:
$contents = Storage::get('file.jpg');
добавлено в 5.1 ()
URL файла
При использовании драйвера local или s3 вы можете использовать метод PHPurl()
для получения URL для файла. При использовании драйвера local в начало пути к файлу будет просто подставлено /storage, и будет возвращён относительный URL. При использовании драйвера s3 будет возвращён полный удалённый URL:
use Illuminate\Support\Facades\Storage;
$url = Storage::url('file1.jpg');
При использовании драйвера local все файлы, которые должны быть общедоступны, необходимо помещать в каталог storage/app/public. Кроме того, вам надо создать символьную ссылку в public/storage, которая указывает на папку storage/app/public.
Метаданные файла
Помимо чтения и записи файлов Laravel может предоставить информацию о самих файлах. Например, для получения размера файла в байтах служит метод PHPsize()
:
use Illuminate\Support\Facades\Storage;
$size = Storage::size('file1.jpg');
Для получения времени последней модификации файла (отметка времени UNIX) служит метод PHPlastModified()
:
$time = Storage::lastModified('file1.jpg');
Запись файлов
Для записи файла на диск служит метод PHPput()
. Также вы можете передать в метод PHPput()
PHP-resource, чтобы использовать низкоуровневую поддержку потоков Flysystem. Очень рекомендуем использовать потоки при работе с большими файлами:
use Illuminate\Support\Facades\Storage;
Storage::put('file.jpg', $contents);
Storage::put('file.jpg', $resource);
добавлено в 5.3 ()
Автоматическая работа с потоками
Если вы хотите, чтобы Laravel автоматически использовал потоки для записи файла в хранилище, используйте методы PHPputFile()
или PHPputFileAs()
. Эти методы принимают объект Illuminate\Http\File или Illuminate\Http\UploadedFile, и автоматически используют потоки для размещения файла в необходимом месте:
use Illuminate\Http\File;
// Автоматическое генерирование UUID для имени файла...
Storage::putFile('photos', new File('/path/to/photo'));
// Ручное указание имени файла...
Storage::putFileAs('photos', new File('/path/to/photo'), 'photo.jpg');
У метода PHPputFile()
есть несколько важных нюансов. Заметьте, мы указали только название каталога без имени файла. По умолчанию метод PHPputFile()
генерирует UUID в качестве имени файла. Метод вернёт путь к файлу, поэтому вы можете сохранить в БД весь путь, включая сгенерированное имя.
Методы PHPputFile()
и PHPputFileAs()
принимают также аргумент «видимости» сохраняемого файла. Это полезно в основном при хранении файлов в облачном хранилище, таком как S3, когда необходим общий доступ к файлам:
Storage::putFile('photos', new File('/path/to/photo'), 'public');
Добавление контента в начало / конец файла
Для вставки контента в начало или конец файла служат методы PHPprepend()
и PHPappend()
:
Storage::prepend('file.log', 'Prepended Text');
Storage::append('file.log', 'Appended Text');
Копирование и перемещение файлов
Метод PHPcopy()
используется для копирования существующего файла в новое расположение на диске, а метод PHPmove()
— для переименования или перемещения существующего файла в новое расположение:
Storage::copy('old/file1.jpg', 'new/file1.jpg');
Storage::move('old/file1.jpg', 'new/file1.jpg');
добавлено в 5.3 ()
Загрузка файлов
Загрузка файлов в веб-приложениях — это чаще всего загрузка пользовательских файлов, таких как аватар, фотографии и документы. В Laravel очень просто сохранять загружаемые файлы методом PHPstore()
на экземпляре загружаемого файла. Просто вызовите метод PHPstore()
, указав путь для сохранения загружаемого файла:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class UserAvatarController extends Controller
{
/**
* Обновление аватара пользователя.
*
* @param Request $request
* @return Response
*/
public function update(Request $request)
{
$path = $request->file('avatar')->store('avatars');
return $path;
}
}
В этом примере есть несколько важных моментов. Заметьте, мы указали только название каталога без имени файла. По умолчанию метод PHPstore()
генерирует UUID в качестве имени файла. Метод вернёт путь к файлу, поэтому вы можете сохранить в БД весь путь, включая сгенерированное имя.
Также вы можете вызвать метод PHPputFile()
фасада Storage для выполнения этой же операции над файлом, как показано в примере:
$path = Storage::putFile('avatars', $request->file('avatar'));
Если вы не хотите, чтобы файлу автоматически было назначено имя, можете использовать метод PHPstoreAs()
, который принимает в виде аргументов путь, имя файла, и (необязательно) диск:
$path = $request->file('avatar')->storeAs(
'avatars', $request->user()->id
);
Конечно, вы также можете использовать метод PHPputFileAs()
фасада Storage, который выполняет такую же операцию:
$path = Storage::putFileAs(
'avatars', $request->file('avatar'), $request->user()->id
);
По умолчанию этот метод использует диск по умолчанию. Если необходимо указать другой диск, передайте имя диска в качестве второго аргумента в метод PHPstore()
:
$path = $request->file('avatar')->store(
'avatars/'.$request->user()->id, 's3'
);
Видимость файлов
В интеграции Flysystem в Laravel «видимость» — это абстракция разрешений на файлы для использования на нескольких платформах. Файлы могут быть обозначены как public или private. Если файл отмечен как public, значит он должен быть доступен остальным. Например, при использовании драйвера S3 вы можете получить URL для public-файлов.
Вы можете задать видимость при размещении файла методом PHPput()
:
use Illuminate\Support\Facades\Storage;
Storage::put('file.jpg', $contents, 'public');
Если файл уже был сохранён, то получить и задать его видимость можно методами PHPgetVisibility()
и PHPsetVisibility()
:
$visibility = Storage::getVisibility('file.jpg');
Storage::setVisibility('file.jpg', 'public')
Удаление файлов
Метод PHPdelete()
принимает имя одного файла или массив файлов для удаления с диска:
use Illuminate\Support\Facades\Storage;
Storage::delete('file.jpg');
Storage::delete(['file1.jpg', 'file2.jpg']);
Папки
Получение всех файлов из папки
Метод PHPfiles()
возвращает массив всех файлов из указанной папки. Если вы хотите получить массив всех файлов папки и её подпапок, используйте метод PHPallFiles()
:
use Illuminate\Support\Facades\Storage;
$files = Storage::files($directory);
$files = Storage::allFiles($directory);
Метод PHPdirectories()
возвращает массив всех папок из указанной папки. Вдобавок, вы можете использовать метод PHPallDirectories()
для получения списка всех папок в данной папке и во всех её подпапках:
$directories = Storage::directories($directory);
// рекурсивно...
$directories = Storage::allDirectories($directory);
Метод PHPmakeDirectory()
создаёт указанную папку, включая необходимые подпапки:
Storage::makeDirectory($directory);
И наконец, метод PHPdeleteDirectory()
удаляет папку и все её файлы с диска:
Storage::deleteDirectory($directory);
Пользовательские файловые системы
Laravel Flysystem предоставляет драйверы для нескольких «drivers» из коробки. Однако, Flysystem не ограничен ими и содержит в себе адаптеры для многих других систем хранения. Вы можете создать свой драйвер, если хотите использовать один из этих дополнительных адаптеров в вашем приложении Laravel.
Чтобы установить свою файловую систему, вы должны будете создать сервис-провайдер такой как DropboxServiceProvider. Для определения своего драйвера вы можете использовать метод PHPextend()
фасада Storage в методе PHPboot()
провайдера:
<?php
namespace App\Providers;
use Storage;
use League\Flysystem\Filesystem;
use Dropbox\Client as DropboxClient;
use Illuminate\Support\ServiceProvider;
use League\Flysystem\Dropbox\DropboxAdapter;
class DropboxServiceProvider extends ServiceProvider
{
/**
* Выполнение после-регистрационной загрузки сервисов.
*
* @return void
*/
public function boot()
{
Storage::extend('dropbox', function ($app, $config) {
$client = new DropboxClient(
$config['accessToken'], $config['clientIdentifier']
);
return new Filesystem(new DropboxAdapter($client));
});
}
/**
* Регистрация привязок в контейнере.
*
* @return void
*/
public function register()
{
//
}
}
Первый аргумент метода PHPextend()
— имя драйвера, второй — замыкание, которое получает переменные PHP$app
и PHP$config
. Замыкание должно возвратить экземпляр League\Flysystem\Filesystem. Переменная PHP$config
содержит значения, определенные в config/filesystems.php для указанного диска.
Когда вы создали сервис-провайдер для регистрации расширения, вы можете использовать драйвер dropbox в своём файле с настройками config/filesystems.php.
Комментарии (7)
Все это замечательно, но непонятно как вывести ссылку например на изображение, которое мы закачали в storage? В storage оно `images/img.jpg`, а что указывать в `<img src=?>`...
$path = $request->file('photo')->store('uploads');
В переменную сохранится ссылка на файл сохраняешь в базу ссылку и потом в src тэг вставляешь, ты куда полез в фреймворки, надо бы тебе сначала базу поднять, такие простые вопросы задаешь.
Заметил, что на русских форумах, блогах и так далее, очень часто вместо просто ответа на вопрос есть еще к нему кометарии вроде «ты куда полез в фреймворки» «задаешь простые вопросы». Зачем мы это делаем? Для поднятия собственной самооценки? Или есть другие причины включять в ответ нотки негатива? В en бордах такое встречается крайне редко. Даже на самые элементарные вопросы. А у нас прям на каждом 2 вопросе находится подобный комментарий.
Уважаемый, вместо того, чтобы хвастаться, лучше бы правильный совет дал. $path = $request->file('photo')->store('uploads'); возвращает не ссылку на файл, а путь к сохраненному файлу относительно «/сторож/апп». А для получения ссылки надо создать в «/паблик» ссылку на «/сторож/апп/паблик» и применить метод фасада «урл», который заменит «паблик» на «сторож» в пути и создаст путь относительно «/паблик/сторож». Здесь же (в документации) все понятно написано. Как то так...
КАКК как создать эту ссылку ?
создать в «/паблик» ссылку на «/сторож/апп/паблик»
Все, говорят о создании ссылки, где она создается? как она создается?
Команда php artisan storage:link
создаст символьную ссылку «/public/storage».
Это ссылка на «/storage/app/public».
Теперь при методе url у тебя создастся ссылка на «/public/storage/твой файл». Я тоже только начал изучать ларавел. Но все-же позволь тебе рекомендовать сохранять файлы именно в «/storage/app/public». Можно конечно и в другой папке, можно и настройки по умолчанию поменять или к методу url прописать изменение пути, но тебе наверное это еще рано. Хотя смотри сам.
Я не понял, нужно ли самому создавать структуру папок для файлов или за меня это сделает ларавел? Ну, допустим, у меня есть «большая картинка» и миниатюра и чтобы они не путались, надо, например, раскидать их по разным папкам.