S3 Compatible Storage

Làm thế nào để upload file từ local server lên S3 compatible storage bằng ngôn ngữ PHP

Upload file lên S3

Để tải tệp lên S3 thông qua API, bạn có thể sử dụng AWS SDK cho PHP. Dưới đây là ví dụ cách tải tệp lên S3 bằng PHP và sử dụng AWS SDK for PHP.

Cài đặt SDK

composer require aws/aws-sdk-php

Cấu hình tài khoản AWS

use Aws\S3\S3Client;

$s3 = new S3Client([
    'version' => 'latest',
    'region' => 'region-name',
    'credentials' => [
        'key' => 'ACCESS_KEY',
        'secret' => 'SECRET_KEY',
    ],
]);

Trong đó region-name, ACCESS_KEY, và SECRET_KEY là thông tin xác thực tài khoản AWS của bạn.

Tải file lên S3

use Aws\S3\Exception\S3Exception;

try {
    $s3->putObject([
        'Bucket' => 'bucket-name',
        'Key' => 'object-name',
        'SourceFile' => 'path/to/local/file',
    ]);
} catch (S3Exception $e) {
    echo $e->getMessage() . "\n";
}

Trong đó:

  • "bucket-name": tên bucket S3 mà bạn muốn tải tệp lên.
  • "object-name": tên đối tượng mà bạn muốn đặt cho tệp trên S3.
  • "path/to/local/file": đường dẫn đến tệp cần tải lên.

Bạn có thể thay đổi tên bucket và tên đối tượng theo ý của mình. Bây giờ file của bạn đã được tải lên S3.

Vậy để tải nhiều file lên hàng loạt thì phải làm sao?

Để tải lên hàng loạt files lên Amazon S3 bằng PHP thông qua API, bạn có thể sử dụng các phương thức trong AWS SDK để lặp lại các yêu cầu tải lên cho mỗi tệp. Dưới đây là một ví dụ về cách tải lên hàng loạt tệp bằng PHP và sử dụng AWS SDK for PHP.

use Aws\S3\S3Client;
use Aws\Exception\AwsException;

$bucketName = 'BUCKET_NAME';
$localDirectory = 'LOCAL_DIRECTORY';
$s3Directory = 'S3_DIRECTORY';

$s3 = new S3Client([
    'version' => 'latest',
    'region' => 'REGION_NAME',
    'credentials' => [
        'key' => 'ACCESS_KEY',
        'secret' => 'SECRET_KEY',
    ],
]);

try {
    $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($localDirectory));

    foreach ($iterator as $file) {
        if ($file->isFile()) {
            $relativePath = substr($file->getPathname(), strlen($localDirectory) + 1);
            $s3Path = $s3Directory . '/' . str_replace('\\', '/', $relativePath);
            $s3->putObject([
                'Bucket' => $bucketName,
                'Key' => $s3Path,
                'SourceFile' => $file->getPathname(),
            ]);
            echo 'File ' . $file->getPathname() . ' uploaded to S3 ' . $bucketName . '/' . $s3Path . PHP_EOL;
        }
    }
} catch (AwsException $e) {
    echo $e->getMessage();
}

Trong đó:

  • BUCKET_NAME là tên bucket S3 mà bạn muốn tải các tệp lên.
  • LOCAL_DIRECTORY là thư mục chứa các tệp cần tải lên.
  • S3_DIRECTORY là thư mục trên S3 mà bạn muốn lưu các tệp lên.
  • REGION_NAME, ACCESS_KEY và SECRET_KEY là thông tin xác thực tài khoản AWS của bạn.
    Đoạn code này sử dụng đối tượng RecursiveIteratorIterator để lặp lại tất cả các tệp trong thư mục LOCAL_DIRECTORY, sau đó đối tượng S3Client để tải lên từng tệp lên bucket S3. Bằng cách lặp lại yêu cầu tải lên cho mỗi tệp, đoạn code sẽ tải lên hàng loạt các tệp vào bucket S3.

Vậy để tối ưu đoạn code trên tránh tình trạng bị timeout thì phải làm sao?

Để giải quyết vấn đề này, bạn có thể sử dụng một số thư viện PHP hỗ trợ cho việc tải lên hàng loạt các tệp tin đồng bộ và bất đồng bộ. Một trong số đó là thư viện "spatie/async" (https://github.com/spatie/async), cho phép tải lên hàng loạt các tệp tin theo chế độ bất đồng bộ và quản lý tải lên các tệp tin theo hàng đợi.

Để sử dụng thư viện "spatie/async", bạn cần cài đặt nó bằng Composer:

composer require spatie/async

Sau đó, bạn có thể sử dụng đoạn code sau để tải lên hàng loạt các tệp tin và cho phép chỉ tải lên tối đa 3 tệp tin cùng một lúc:

use Spatie\Async\Pool;

$pool = Pool::create();

$localPath = '/path/to/local/files';
$bucketName = 'my-bucket';

$files = scandir($localPath);

foreach ($files as $file) {
    if (in_array($file, ['.', '..'])) {
        continue;
    }

    $pool->add(function () use ($s3Client, $localPath, $file, $bucketName) {
        $s3Client->putObject([
            'Bucket' => $bucketName,
            'Key' => basename($file),
            'SourceFile' => $localPath . '/' . $file,
        ]);
    })->then(function () use ($file) {
        echo "File $file uploaded successfully.\n";
    });

    if ($pool->countActive() >= 3) {
        $pool->wait();
    }
}

$pool->wait();

Đoạn code trên sử dụng phương thức scandir để lấy danh sách tệp tin trong thư mục $localPath. Sau đó, với mỗi tệp tin, nó sử dụng phương thức add để thêm một công việc mới vào hàng đợi.

Phương thức add trả về một đối tượng Promise đại diện cho kết quả của công việc đó. Sau khi thêm một công việc vào hàng đợi, nó kiểm tra số lượng công việc đang hoạt động (được xác định bởi phương thức countActive) và nếu nó đạt tối đa (trong trường hợp này là 3), nó gọi phương thức wait để đợi cho tất cả các công việc đang hoạt động hoàn thành trước khi tiếp tục thêm công việc vào hàng đợi.

Điều này giúp bạn kiểm soát lượng tệp tin đang được tải lên cùng một lúc và tránh tình trạng quá tải tài nguyên của máy chủ và giảm thiểu tình trạng trễ trong quá trình tải lên. Khi tất cả các công việc được thêm vào hàng đợi, nó gọi phương thức wait để chờ tất cả các công việc hoàn thành trước khi kết thúc.

Nếu bạn muốn tải lên các tệp tin trong một thời gian nhất định, bạn có thể sử dụng một biến thời gian (ví dụ: $timeToRun) và kiểm tra xem thời gian đã trôi qua chưa. Ví dụ, bạn có thể sửa đoạn code trên như sau:

use Spatie\Async\Pool;

$pool = Pool::create();

$localPath = '/path/to/local/files';
$bucketName = 'my-bucket';

$files = scandir($localPath);

$timeToRun = time() + 60; // Run for 60 seconds

foreach ($files as $file) {
    if (in_array($file, ['.', '..'])) {
        continue;
    }

    $pool->add(function () use ($s3Client, $localPath, $file, $bucketName) {
        $s3Client->putObject([
            'Bucket' => $bucketName,
            'Key' => basename($file),
            'SourceFile' => $localPath . '/' . $file,
        ]);
    })->then(function () use ($file) {
        echo "File $file uploaded successfully.\n";
    });

    if ($pool->countActive() >= 3) {
        $pool->wait();
    }

    if (time() >= $timeToRun) {
        break;
    }
}

$pool->wait();

Trong đoạn code này, biến $timeToRun được sử dụng để đặt thời gian tối đa để tải lên các tệp tin là 60 giây.

Trong vòng lặp, sau khi thêm một công việc vào hàng đợi, nó kiểm tra xem thời gian đã trôi qua chưa bằng cách sử dụng hàm time.

Nếu thời gian đã trôi qua, nó sẽ thoát khỏi vòng lặp. Sau đó, nó gọi phương thức wait để chờ tất cả các công việc hoàn thành trước khi kết thúc.

Với cách tiếp cận này, bạn có thể quản lý tải lên hàng loạt các tệp tin một cách hiệu quả và tránh tình trạng quá tải tài nguyên của máy chủ.

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *

Back to top button
Close