Laravel 5: Как скопировать локальный файл в Amazon S3?

Я пишу код в Laravel 5 для периодического резервного копирования базы данных MySQL. Мой код до сих пор выглядит так:

    $filename = 'database_backup_'.date('G_a_m_d_y').'.sql';
    $destination = storage_path() . '/backups/';

    $database = \Config::get('database.connections.mysql.database');
    $username = \Config::get('database.connections.mysql.username');
    $password = \Config::get('database.connections.mysql.password');

    $sql = "mysqldump $database --password=$password --user=$username --single-transaction >$destination" . $filename;

    $result = exec($sql, $output); // TODO: check $result

    // Copy database dump to S3

    $disk = \Storage::disk('s3');

    // ????????????????????????????????
    //  What goes here?
    // ????????????????????????????????

Я видел решения онлайн, которые предложили бы мне сделать что-то вроде:

$disk->put('my/bucket/' . $filename, file_get_contents($destination . $filename));

Однако, для больших файлов, не расточительно ли использовать file_get_contents()? Есть ли лучшие решения?

4 ответа

Решение

Глядя на документацию, единственный способ - использовать метод put который нуждается в содержании файла. Нет способа скопировать файл между двумя файловыми системами, поэтому, вероятно, решение, которое вы дали, на данный момент является единственным.

Если вы подумаете об этом, в конце концов, когда вы копируете файл из локальной файловой системы в s3, вам нужно иметь содержимое файла, чтобы поместить его в S3, так что, на мой взгляд, это не так расточительно.

Существует способ копирования файлов без необходимости загрузки содержимого файла в память.

Вам также нужно будет импортировать следующее:

use League\Flysystem\MountManager;

Теперь вы можете скопировать файл так:

$mountManager = new MountManager([
    's3' => \Storage::disk('s3')->getDriver(),
    'local' => \Storage::disk('local')->getDriver(),
]);
$mountManager->copy('s3://path/to/file.txt', 'local://path/to/output/file.txt');

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

Storage::disk('s3')->put('my/bucket/' . $filename, fopen('path/to/local/file', 'r+'));

Альтернативное предложение предлагается здесь. Он использует фасад хранилища Laravel для чтения потока. Основная идея примерно такая:

    $inputStream = Storage::disk('local')->getDriver()->readStream('/path/to/file');
    $destination = Storage::disk('s3')->getDriver()->getAdapter()->getPathPrefix().'/my/bucket/';
    Storage::disk('s3')->getDriver()->putStream($destination, $inputStream);

Вы можете попробовать этот код

$contents = Storage::get($file);
Storage::disk('s3')->put($newfile,$contents);

Как документ Laravel, я нашел простой способ скопировать данные между двумя дисками.

Laravel теперь putFile а также putFileAs метод, чтобы разрешить поток файла.

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

Если вы хотите, чтобы Laravel автоматически управлял потоковой передачей данного файла в ваше хранилище, вы можете использовать метод 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');

Ссылка на документ: https://laravel.com/docs/5.8/filesystem (автоматическая трансляция)

Надеюсь, это поможет

Я решил это следующим образом:

$contents = \File::get($destination);
\Storage::disk('s3')
    ->put($s3Destination,$contents);

Иногда мы не получаем данные, используя $contents = Storage::get($file); - функция хранения, поэтому мы должны указать корневой путь данных, используя Laravel File, а не путь хранения, используя Storage.

Другие вопросы по тегам