PHP - Google App Engine Загрузка больших файлов на Google Диск в виде фрагментов (возобновляемая загрузка) - ошибка 500

Я загружаю файл из корзины облачного хранилища Google в папку Google Диска, используя php-код, который работает в фоновом режиме. Моя проблема в том, что когда размер файла увеличивается, Google Диск (или GAE) выдает ошибку 500.

Error: Server Error
The server encountered an error and could not complete your request.
Please try again in 30 seconds.

Я использую следующую зависимость.

нао-пон/flysystem-google-диск: ^1.1,

Ниже приведена часть моего кода, которая дает эту ошибку. Это отлично работает для небольших файлов:

$fileN = $this->clean($att->ATT_TITLE);

$fileData = file_get_contents("https://storage.googleapis.com/xxxxxx/".$att->ATT_FILE);

$dir = sys_get_temp_dir();
$tmp = tempnam($dir, $fileN);
file_put_contents($tmp, $fileData);
Storage::cloud()->putFileAs( $folderPath, new File($tmp),$fileN);

Я установил конфигурации в файле .env

FILESYSTEM_CLOUD=google
GOOGLE_DRIVE_CLIENT_ID=xxxxapps.googleusercontent.com
GOOGLE_DRIVE_CLIENT_SECRET=xxxxx
GOOGLE_DRIVE_REFRESH_TOKEN=xxxxxx
GOOGLE_DRIVE_FOLDER_ID=xxxx
#GOOGLE_DRIVE_TEAM_DRIVE_ID=xxx

Я настроил диск, как показано ниже, в файле system.php.

'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'),
    // 'teamDriveId' => env('GOOGLE_DRIVE_TEAM_DRIVE_ID'),
    ],

Я установил файл php.ini, как показано ниже.

upload_max_filesize = 300M
post_max_size = 300M
memory_limit = 3000M

App.yaml

runtime: php72
handlers: 
- url: /assets
  static_dir: public/assets
env_variables:
   APP_KEY: xxxxx
   APP_STORAGE: /tmp
   CACHE_DRIVER: file
   VIEW_COMPILED_PATH: /tmp
   SESSION_DRIVER: database
   DB_DATABASE: xxx
   DB_USERNAME: xx
   DB_PASSWORD: xxxx
   DB_SOCKET: "/cloudsql/xxxxx"
runtime_config:
    document_root: public

Может ли кто-нибудь дать мне подсказку или дать мне другой альтернативный способ сделать это? Мое требование в основном состоит в том, чтобы загрузить большой файл (например, 250 МБ) на Google Диск с помощью фонового задания в Google App Engine.


person Kusal Dissanayake    schedule 31.08.2020    source источник


Ответы (2)


Поскольку вы вызываете API облачного хранилища для загрузки больших файлов, загрузка может быть выполнена в течение 60 секунд, что является тайм-аутом по умолчанию для API облачного хранилища Google. Вы можете самостоятельно изменить время ожидания API. Вот клавиша stackoverflow, на которую вы можете ссылаться, чтобы установить тайм-аут API самостоятельно.

person Shawn Di Wu    schedule 01.09.2020

В этой ситуации загрузка фрагментами решает проблему.

См. следующий пример из PHP-клиента Google API https://github.com/googleapis/google-api-php-client/blob/master/examples/large-file-upload.php

Пример рабочего кода:

$fileData = file_get_contents("https://storage.googleapis.com/xxxx/".$att->ATT_FILE);

$dir = sys_get_temp_dir();
$tmp = tempnam($dir, $fileN);
file_put_contents($tmp, $fileData);       
     
$fileToUpload = new File($tmp);
$filename = $fileN;
$mimeType = mime_content_type($tmp);
                   
$driveService = Storage::cloud();
$client = new \Google_Client();
$client->setClientId('xxxx');
$client->setClientSecret('xxx');
$client->refreshToken('xxx');
$client->setApplicationName('xxx');

$service = new \Google_Service_Drive($client);


// Test 1
$file = new \Google_Service_Drive_DriveFile();
$file->title = $fileN;
$file->name = $fileN;
$file->parents = array($basePath);
$chunkSizeBytes = 1 * 1024 * 1024;

// Call the API with the media upload, defer so it doesn't immediately return.
$client->setDefer(true);
$request = $service->files->create($file);

// Create a media file upload to represent our upload process.
$media = new \Google_Http_MediaFileUpload(
  $client,
  $request,
  $mimeType,
  null,
  true,
  $chunkSizeBytes
);
$media->setFileSize(filesize($tmp));

// Upload the various chunks. $status will be false until the process is
// complete.
$status = false;
$handle = fopen($tmp, "rb");
while (!$status && !feof($handle)) {
  $chunk = fread($handle, $chunkSizeBytes);
  $status = $media->nextChunk($chunk);
 }

// The final value of $status will be the data from the API for the object
// that has been uploaded.
$result = false;
if($status != false) {
  $result = $status;
}

fclose($handle);
person Kusal Dissanayake    schedule 01.09.2020