Khi làm web chúng ta không thể tránh khỏi việc thao tác với các file. Ví dụ như upload file, hình ảnh, tạo file các kiểu,… Thì hôm nay hãy cũng mình tìm hiểu về File Storage trong Laravel.

Giới thiệu

Laravel cung cấp một hệ thống file mạnh mẽ trừu tượng nhờ gói Flysystem PHP tuyệt vời của Frank de Jonge. Laravel Flysystem cung cấp các driver đơn giản để sử dụng với local filesystem, SFTP, Amazon S3. Thậm chí còn tốt hơn khi dễ dàng chuyển đổi giữa các tùy chọn lưu trữ ở local development và production vì API vẫn giữ nguyễn không thay đổi.

Cấu hình

File cấu hình nằm ở config/filesystems.php. Trong này, bạn có thể cấu hình các “disk”. Mỗi disk là một driver lưu trữ và vị trí lưu trữ cụ thể. Các cấu hình mẫu cho từng driver để bạn có thể sửa đổi cấu hình và thông tin lưu trữ của bạn.

Bạn cấu hình bao nhiêu disk tùy thích và có thể có nhiều disk cũng một driver

The Local Driver

Khi sử dụng local driver, tất cả hoạt động của file đều liên quan đến thư mục root được định nghĩa trong file config. Mặc định storage/app. Ví dụ dưới sẽ lưu thành storage/app/example.txt:

use Illuminate\Support\Facades\Storage;

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

The Public Disk

Public Disk dành cho những tập tim được truy cập công khai. Mặc định sử dụng local driver và lưu trữ các file này trong storage/app/public. Để giúp người dùng có thể truy cập được web, bạn tạo liên kết biểu tượng (shortcut) từ public/storage sang storage/app/public. Việc sử dụng quy ước thư mục này sẽ giữ các file có thể truy cập công khai của bạn trong một thư mục có thể dễ dàng chia sẻ trên các lần triển khai khi sử dụng các hệ thống triển khai không tốn thời gian.

Để tạo liên kết, sử dụng Artisan command:

php artisan storage:link

Lưu trữ:

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

Sau khi lưu trữ file và liên kết đã được tạo, bạn có thể sử dụng aset helper để lấy URL của file:

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

Bạn cũng có thể thêm nhiều liên kết tượng trưng trong phần config filesystems. Mỗi phần tử trong mảng links sẽ tọa một liên kết khác nhau sau khi chạy command storage:link:

'links' => [
    public_path('storage') => storage_path('app/public'),
    public_path('images') => storage_path('app/images'),
],

Driver Prerequisites

Composer Packages

Trước khi dùng S3 và SFTP drivers, bạn phải cài các package phù hợp bằng Composer:
Amazon S3:

composer require --with-all-dependencies league/flysystem-aws-s3-v3 "^1.0"

SFTP:

composer require league/flysystem-sftp "~1.0"

Ngoài ra bạn có thể lưu trữ trong cache để tăng hiệu suất:
CachedAdapter:

composer require league/flysystem-cached-adapter "~1.0"

S3 Driver Configuration
Mặc định phần cấu hình đã được khai báo sẵn trong config/filesystems.php. Bạn có thể thay đổi tùy thích theo ý muốn miễn là nó hoạt động được.

FTP Driver Configuration
Flysystem của Laravel hoạt động tốt với FTP. Tuy nhiên nó không được cấu hình mặc định mà bạn phải tự tay cấu hình các thông số cho nó trong file config/filesystems.php. Nếu bạn sử dụng FTP driver, bạn có thể sử dụng cấu hình mẫu dưới đây:

'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 Driver Configuration
SFTP driver cũng không được cáu hình sẵn cho chúng ta, bạn thử cấu hình theo cách phía dưới nhá:

'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,
],

Caching
bạn có thể sử dụng caching cho một disk nào đó. Bạn cấu hình như sau:

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

    // Other Disk Options...

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

Obtaining Disk Instances

Storage facade được sử dụng để tương tác với bất kì disk nào được cấu hình trong hệ thống. Ví dụ bạn có thể sử dụng phương thức put để lưu trữ hình trên disk mặc định khi không gọi phương thức disk như các ví dụ trên:

use Illuminate\Support\Facades\Storage;

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

Nếu ứng dụng tương tác với nhiều disk, bạn có thể sử dụng phương thức disk của Storage facade để làm việc với từng file cụ thể:

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

On-Demand Disks
Đôi khi một số trường hợp bạn muốn phát sinh một disk trong thời gian chạy mà không phụ thuộc vào phần cấu hình filesystems. Hãy sử dụng phương thức build trong quá trình làm:

use Illuminate\Support\Facades\Storage;

$disk = Storage::build([
    'driver' => 'local',
    'root' => '/path/to/root',
]);

$disk->put('image.jpg', $content);

Retrieving Files

Phương thức get có thể được sử dụng để lấy nội dung của một file. Nội dung chuỗi thô của file sẽ được trả về. Lưu ý, các đường dẫn file phải được chỉ định liên quan đến vị trí “root”:

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

Tương tự putget cũng có thể sử dụng phương thức disk để xác định disk phù hợp.
Phương thức exists có thể sử dụng để kiểm tra file có tồn tại trên disk không:

if (Storage::disk('s3')->exists('file.jpg')) {
    // ...
    echo "exists";
}

Và trái lại, missing để kiểm tra file đó có “không tồn tại” hay không:

if (Storage::disk('s3')->missing('file.jpg')) {
    // ...
    echo "missing";
}

Downloading Files

Phương thức download dùng để tạo response buộc trình duyệt phải tải file xuống theo đường dẫn nhất định.

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

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

File URLs

Sử dụng phương thức url để lấy URL của file. và cũng có thể sử dụng disk để xác định disk chứa file:

use Illuminate\Support\Facades\Storage;

$url = Storage::url('file1.jpg');

Nếu trả về đường dẫn sai hoặc đường dẫn đúng nhưng vẫn không truy cập được, thì bạn kiểm tra lại đã chạy lệnh storage:link hay chưa, và kiểm tra trong file .env có APP_URL đúng hay chưa.

Temporary URLs
Bạn có thể tạo URL tạm thời cho một file sử dụng phương thức temporaryUrl khi sử dụng S3 driver. Phương thức này chấp nhận một đường dẫn và một path, một DateTime để xác định khi nào URL hết hạn:

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

Nếu bạn dùng s3 request parameters, bạn thử cách dưới đây:

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

URL Host Customization
Nếu bạn muốn xác định trước máy chủ lưu trữ các file được lưu trữ trên disk sử dụng trình điều khiển local, bạn có thể thêm tùy chọn url vào mảng cấu hình của disk:

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

File Metadata

Ngoài việc đọc và viết các file, Laravel cũng có thể cung cấp thông tin về các file về bản thân chúng. Ví dụ, phương thức size có thể được sử dụng để lấy kích thước của file theo byte:

use Illuminate\Support\Facades\Storage;

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

Phương thức lastModified trả về UNIX timestamp của lần cuối cùng file đã được sửa đổi:

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

File Paths
Bạn có thể sử dụng phương thức path để lấy được path (khác url) cho một file. Nếu sử dụng local driver, nó sẽ trả về đường dẫn tuyệt đối đến file. Còn sử dụng s3 driver, nó sẽ trả về đường dẫn tương đối đến file trong S3 bucket:

use Illuminate\Support\Facades\Storage;

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

Storing Files

Phương thức put có thể được sử dụng để lưu trữ nội dung file thô trên disk. Bạn cũng có thể truyền một PHP resource tới phương thức put, sẽ sử dụng hỗ trợ luồng cơ bản của Flysystem.

use Illuminate\Support\Facades\Storage;

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

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

Automatic Streaming
Nếu bạn muốn Laravel tự động quản lý streaming một file nhất định đến vị trí lưu trữ của bạn, bạn có thể sử dụng phương thức putFile hoặc putFileAs. Phương pháp này chấp nhận một yêu cầu Illuminate\Http\File hoặc Illuminate\Http\UploadedFile và sẽ tự động truyền file đến vị trí mong muốn của bạn:

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

// Automatically generate a unique ID for filename...
$path = Storage::putFile('photos', new File('/path/to/photo'));
// Storage::putFile('photos', new File($request->file('file')->path()));

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

Nó cũng chấp nhận thêm một đối số để xác định “visibility” của file lưu trữ. Điều này đặc biệt hữu ích nếu bạn đang lưu trữ file trên disk đám mây như S3 và muốn file được truy cập công cộng:

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

Prepending & Appending To Files
Phương thức prepend và append cho phép bạn ghi vào đầu hoặc cuối của một file:

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

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

Copying & Moving Files
Phương thức copy có thể được sử dụng để sao chép một file hiện có vào một vị trí mới trên disk, trong khi phương thức move có thể sử dụng để đổi tên hoặc di chuyển một file hiện có sang một vị trí mới:

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

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

File Uploads

Trong các ứng dụng web, một trong những trường hợp sử dụng phổ biến nhất để lưu trữ các file là lưu trữ các file tải lên của người dùng như ảnh tiểu sử, ảnh và tài liệu. Laravel giúp bạn dễ dàng lưu các file được tải lên bằng cách sử dụng phương thức store trên file được tải lên. Đơn giản chỉ cần gọi phương thức store với đường dẫn mà bạn muốn lưu trữ file đã tải lên:

<?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  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request)
    {
        $path = $request->file('avatar')->store('avatars');

        return $path;
    }
}

Lưu ý: mặc định nó sẽ tạo một ID để lưu tên file và thư mục nơi lưu file. Đường dẫn tới file sẽ được trả lại theo phương thức store để bạn có thể lưu trữ đường dẫn, bao gồm tên file được tạo ra, trong cơ sở dữ liệu của bạn. Bạn có thể thử cách này tương tự kết quả như trên:

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

Specifying A File Name
Nếu bạn không thích tên file được tự động gán vào file lưu trữ của mình, bạn có thể sử dụng phương thức storeAs file này nhận đường dẫn, file và disk (tùy chọn) làm đối số của nó:

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

hoặc

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

Specifying A Disk
Theo mặc định, phương pháp này sẽ sử dụng disk mặc định của bạn. Nếu bạn muốn chỉ định một disk khác, truyền tên disk như là đối số thứ hai sang phương thức store:

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

Other Uploaded File Information

Sử dụng phương thức getClientOriginalName để lấy tên, và extension để lấy đuôi file:

$name = $request->file('avatar')->getClientOriginalName();
$extension = $request->file('avatar')->extension();

File Visibility

Trong tích hợp Hệ thống Flysystem của Laravel, “visibility” là sự trừu tượng của quyền truy cập file trên nhiều nền tảng. Các file có thể được khai báo public hoặc private. Khi một file được khai báo public, bạn đang chỉ ra rằng các file thường có thể truy cập cho người khác. Ví dụ, khi sử dụng trình điều khiển S3, bạn có thể lấy URL cho các file public.
Bạn có thể thiết lập chế độ hiển thị khi thiết lập file thông qua phương thức put :

use Illuminate\Support\Facades\Storage;

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

Nếu file đã được lưu trữ, khả năng hiển thị của nó có thể được lấy ra và thiết lập thông qua các phương thức getVisibility và setVisibility:

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

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

Có thể set “visibility” khi store file:

$path = $request->file('avatar')->storePublicly('avatars', 's3');

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

Local Files & Visibility
Khi sử dụng local driver, public “visibility” chuyển quyền thành 0755 cho thư mục và 0644 cho file. Bạn có thể thay đổi trong file config:

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

Deleting Files

Phương thức delete sẽ xóa một file hoặc array of files:

use Illuminate\Support\Facades\Storage;

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

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

Và cũng có chỉ định disk mà tệp sẽ bị xóa:

use Illuminate\Support\Facades\Storage;

Storage::disk('s3')->delete('path/file.jpg');

Directories

Get All Files Within A Directory
Phương thức files trả về một mảng của tất cả các tệp trong một thư mục nhất định. Nếu bạn muốn lấy một danh sách tất cả các tệp trong một thư mục nhất định bao gồm tất cả thư mục con, bạn có thể sử dụng phương thức allFiles:

use Illuminate\Support\Facades\Storage;

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

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

Get All Directories Within A Directory
Phương thức directories trả về một mảng của tất cả thư mục trong một thư mục nhất định. Ngoài ra, bạn có thể sử dụng phương thức allDirectories để nhận danh sách tất cả các thư mục trong một thư mục nhất định và tất cả thư mục phụ của nó:

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

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

Create A Directory
Phương thức makeDirectory sẽ tạo ra thư mục đã cho, bao gồm bất kỳ thư mục con cần thiết

Storage::makeDirectory($directory);

Kết luận

Tuy phần này lượng kiến thức không nhiều và cũng không khó, nhưng nó cực kỳ phổ biến và sử dụng nhiều trong ứng dụng của chúng ta. Hãy thực hành nhiều để hiểu rõ hơn từng chức năng của nó nhá.

Nguồn tham khảo:

Rất mong được sự ủng hộ của mọi người để mình có động lực ra những bài viết tiếp theo.
{\__/}
( ~.~ )
/ > ♥️ I LOVE YOU 3000

JUST DO IT!