Lưu trữ file với Google Drive trong Laravel

Giới thiệu

Khi các bạn phát triển 1 website chia sẻ tài nguyên cho người dùng (phim, tài liệu, ảnh, ...) thì hẳn các bạn sẽ phải tính toán việc lưu trữ tài nguyên của mình tại 1 nơi nào đó. Có rất nhiều nơi cho các bạn lưu trữ dữ liệu của mình như lưu tại chính server của bạn, Amazon S3, Google Drive, ... Theo mình, nếu website của bạn lớn và cần lưu trữ file có dung lượng lớn thì nên dùng dùng Amazon S3 (mất phí) để lưu trữ là tốt nhất. Hôm nay, mình xin chia sẻ việc upload file lên Google Drive với website code bằng Laravel. Với mỗi tài khoản, Google sẽ cung cấp cho bạn 15GB để sử dụng lưu trữ dữ liệu trên các dịch vụ của họ như Drive, Mail, Photos+, ... Do vậy, Google Drive chỉ phù hợp với nhu cầu lưu trữ file với dung lượng vừa phải và nhỏ. Nếu bạn muốn phát triển website lưu trữ trên Google Drive thì nên lưu ý điều này.

Cài đặt

Google cũng đã cung cấp API cho chúng ta tương tác, nhưng để sử dụng thuận tiện hơn, nhanh gọn hơn thì mình sử dụng package Flysystem Adapter for Google Drive

  • Cài đặt package cho Google Drive API V3
composer require nao-pon/flysystem-google-drive:~1.1
  • Cài đặt package cho Google Drive API V2
composer require nao-pon/flysystem-google-drive:~1.0.0

Sử dụng

  • Sau khi cài đặt package xong, chúng ta cần thêm GoogleDriveServiceProvider::class, vào providers trong file config/app.php:
'providers' => [
    // ...
    App\Providers\GoogleDriveServiceProvider::class,
    // ...
],
  • Thêm google disk vào config/filesystems.php:
'disks' => [
    // ...
    'google' => [
        'driver' => 'google',
        'clientId' => env('GOOGLE_DRIVE_CLIENT_ID'),
        'clientSecret' => env('GOOGLE_DRIVE_CLIENT_SECRET'),
        'refreshToken' => env('GOOGLE_DRIVE_REFRESH_TOKEN'),
        'folderId' => env('GOOGLE_DRIVE_FOLDER_ID'),
    ],
    // ...
],

Tạo Google Drive API keys

Để lưu trữ file trên Google Drive, bạn cần lấy đủ 4 thông tin bên trên. Để có thông tin chi tiết về cách lấy API ID, secret và refresh token, bạn tham khảo hướng dẫn sau:

Cập nhật file .env

Thêm các keys đã lấy được trong file .env và đặt google làm cloud storage mặc định của bạn.

FILESYSTEM_CLOUD=google
GOOGLE_DRIVE_CLIENT_ID=xxx.apps.googleusercontent.com
GOOGLE_DRIVE_CLIENT_SECRET=xxx
GOOGLE_DRIVE_REFRESH_TOKEN=xxx
GOOGLE_DRIVE_FOLDER_ID=null

Bây giờ bạn có thể truy cập google disk như sau:

$googleDisk = Storage::disk('google');

Do đã đặt google làm cloud storage mặc định, bạn có thể gọi:

Storage::cloud(); // refers to Storage::disk('google')

Coding

Giờ chúng ta bắt đầu thực hiện xem kết quả thực tế nó như thế nào nhé. Tạo file, download file, xóa file, ... lên Google Drive nó ra làm sao nào.

Tạo file mới

Đầu tiên, chúng ta thử tạo file trên Google Drive nhé.

Storage::cloud()->put(tên file,  nội dung file);

Ví dụ mình muốn tạo file 'test.txt' với nội dung 'Hello World':

Route::get('put', function() {
    Storage::cloud()->put('test.txt', 'Hello World');
    return 'File was saved to Google Drive';
});

Sau khi chạy link /put, chúng ta sẽ có kết quả là: File was saved to Google Drive Bạn mở thư mục mà bạn đã cài đặt lưu trữ file trên https://drive.google.com của mình sẽ thấy 1 file test.txt mới được tạo như thế này: Nội dung của nó sẽ là dòng chữ Hello World mà bạn đã tạo:

Tạo file có sẵn

Nếu bạn có sẵn 1 file trên hệ thống và muốn đẩy file đó lên Google Drive thì bạn get content của file đó và put lên thôi.

Route::get('put-existing', function() {
    $filePath = public_path('logo.png');
    $fileData = File::get($filePath);
    Storage::cloud()->put($filename, $fileData);
    return 'File was saved to Google Drive';
});

File ảnh ví dụ của mình cũng đã được có mặt trên Google Drive rồi:

Lấy danh sách thư mục con hoặc file trong thư mục

Lấy danh sách file

Mình muốn lấy danh sách file trong thư mục lưu trữ của mình.

Route::get('list', function() {
    $dir = '/';
    $recursive = false; // Có lấy file trong các thư mục con không?
    $contents = collect(Storage::cloud()->listContents($dir, $recursive));
    return $contents->where('type', '=', 'file');
});

Kết quả lấy được là chuỗi JSON như sau: Và khi parse JSON ra thì chúng ta sẽ thấy nó trả về đầy đủ các thông tin về các file:

Lưu ý: Thuộc tính path mà bạn tìm thấy là rất quan trọng, bạn có thể coi nó như ID của mỗi file để thao tác với từng file riêng biệt dù có thể các file trùng tên.

Lấy danh sách thư mục con

Để lấy danh sách các thư mục con trong thư mục lưu trữ, cũng tương tự như lấy danh sách file, chỉ khác ở điều kiện lấy ra là where('type', '=', 'dir') chứ không phải where('type', '=', 'file')

Route::get('list', function() {
    $dir = '/';
    $recursive = false; // Có lấy file trong các thư mục con không?
    $contents = collect(Storage::cloud()->listContents($dir, $recursive));
    return $contents->where('type', '=', 'dir'); // thư mục
});

Download file từ Google Drive

Ở ví dụ bên trên, mình đã tạo 1 file test.txt. Giờ thử download nó về xem sao. Mấu chốt để download file về đó là từ thuộc tính path của file (có thể tham khảo file path ở phần Lấy danh sách file) ta lấy được nội dung file rồi truyền thêm các thông số cần thiết vào header làContent-TypeContent-Disposition`.

Route::get('get', function() {
    $filename = 'test.txt';
    $dir = '/';
    $recursive = false; // Có lấy file trong các thư mục con không?
    $contents = collect(Storage::cloud()->listContents($dir, $recursive));
    $file = $contents
        ->where('type', '=', 'file')
        ->where('filename', '=', pathinfo($filename, PATHINFO_FILENAME))
        ->where('extension', '=', pathinfo($filename, PATHINFO_EXTENSION))
        ->first(); // có thể bị trùng tên file với nhau!
    //return $file; // array with file info
    $rawData = Storage::cloud()->get($file['path']);
    return response($rawData, 200)
        ->header('Content-Type', $file['mimetype'])
        ->header('Content-Disposition', "attachment; filename='$filename'");
});

Mình đã download được file từ Google Drive về máy:

Xóa file

Để xóa file, bạn cần lấy được path của file sau đó sử dụng Storage::cloud()->delete($path); là xong.

Route::get('delete', function() {
    $filename = 'test.txt';
    // Tìm file và sử dụng ID (path) của nó để xóa
    $dir = '/';
    $recursive = false; //  Có lấy file trong các thư mục con không?
    $contents = collect(Storage::cloud()->listContents($dir, $recursive));
    $file = $contents
        ->where('type', '=', 'file')
        ->where('filename', '=', pathinfo($filename, PATHINFO_FILENAME))
        ->where('extension', '=', pathinfo($filename, PATHINFO_EXTENSION))
        ->first(); // có thể bị trùng tên file với nhau!
    Storage::cloud()->delete($file['path']);
    return 'File was deleted from Google Drive';
});

Sau khi xóa, bạn sẽ thấy dòng chữ 'File was deleted from Google Drive và không tìm thấy file đó trên Google Drive của mình nữa.

Kết luận

Trên đây, mình đã giới thiệu với các bạn 1 vài thao tác cơ bản để lưu trữ file với Google Drive như: tạo file, xóa file, download file, lấy danh sách file. Để có thể tìm hiểu về các thao tác khác như: tạo thư mục, tạo file trong thư mục, đổi tên thư mục, xóa thư mục, ... bạn có thể tham khảo thêm tại đây.

Hy vọng, bài viết này của mình sẽ giúp ích cho các bạn với giải pháp lưu trữ trên Google Drive cho các website có dung lượng lưu trữ vừa và nhỏ. Và như mình đã nhấn mạnh bên trên, nếu nhu cầu lưu trữ cao ví dụ như website xem phim thì dùng Amazon S3 cho chuyên nghiệp nhé.

Cám ơn các bạn đã đọc bài viết.

Tham khảo