/** * Uploads backup file from server to Google Drive. * * @param array $args arguments passed to the function * [task_name] -> Task name for wich we are uploading * [task_result_key] -> Result key that we are uploading * [google_drive_token] -> user's Google drive token in json form * [google_drive_directory] -> folder on user's Google Drive account which backup file should be upload to * [google_drive_site_folder] -> subfolder with site name in google_drive_directory which backup file should be upload to * [backup_file] -> absolute path of backup file on local server * * @return bool|array true is successful, array with error message if not */ public function google_drive_backup($args) { mwp_register_autoload_google(); $googleClient = new Google_ApiClient(); $googleClient->setAccessToken($args['google_drive_token']); $googleDrive = new Google_Service_Drive($googleClient); mwp_logger()->info('Fetching Google Drive root folder ID'); try { $about = $googleDrive->about->get(); $rootFolderId = $about->getRootFolderId(); } catch (Exception $e) { mwp_logger()->error('Error while fetching Google Drive root folder ID', array('exception' => $e)); return array('error' => 'Error while fetching Google Drive root folder ID: ' . $e->getMessage()); } mwp_logger()->info('Loading Google Drive backup directory'); try { $rootFiles = $googleDrive->files->listFiles(array("q" => "title='" . addslashes($args['google_drive_directory']) . "' and '{$rootFolderId}' in parents and trashed = false")); } catch (Exception $e) { mwp_logger()->error('Error while loading Google Drive backup directory', array('exception' => $e)); return array('error' => 'Error while loading Google Drive backup directory: ' . $e->getMessage()); } if ($rootFiles->offsetExists(0)) { $backupFolder = $rootFiles->offsetGet(0); } else { try { mwp_logger()->info('Creating Google Drive backup directory'); $newBackupFolder = new Google_Service_Drive_DriveFile(); $newBackupFolder->setTitle($args['google_drive_directory']); $newBackupFolder->setMimeType('application/vnd.google-apps.folder'); if ($rootFolderId) { $parent = new Google_Service_Drive_ParentReference(); $parent->setId($rootFolderId); $newBackupFolder->setParents(array($parent)); } $backupFolder = $googleDrive->files->insert($newBackupFolder); } catch (Exception $e) { mwp_logger()->info('Error while creating Google Drive backup directory', array('exception' => $e)); return array('error' => 'Error while creating Google Drive backup directory: ' . $e->getMessage()); } } if ($args['google_drive_site_folder']) { try { mwp_logger()->info('Fetching Google Drive site directory'); $siteFolderTitle = $this->site_name; $backupFolderId = $backupFolder->getId(); $driveFiles = $googleDrive->files->listFiles(array("q" => "title='" . addslashes($siteFolderTitle) . "' and '{$backupFolderId}' in parents and trashed = false")); } catch (Exception $e) { mwp_logger()->info('Error while fetching Google Drive site directory', array('exception' => $e)); return array('error' => 'Error while fetching Google Drive site directory: ' . $e->getMessage()); } if ($driveFiles->offsetExists(0)) { $siteFolder = $driveFiles->offsetGet(0); } else { try { mwp_logger()->info('Creating Google Drive site directory'); $_backup_folder = new Google_Service_Drive_DriveFile(); $_backup_folder->setTitle($siteFolderTitle); $_backup_folder->setMimeType('application/vnd.google-apps.folder'); if (isset($backupFolder)) { $_backup_folder->setParents(array($backupFolder)); } $siteFolder = $googleDrive->files->insert($_backup_folder, array()); } catch (Exception $e) { mwp_logger()->info('Error while creating Google Drive site directory', array('exception' => $e)); return array('error' => 'Error while creating Google Drive site directory: ' . $e->getMessage()); } } } else { $siteFolder = $backupFolder; } $file_path = explode('/', $args['backup_file']); $backupFile = new Google_Service_Drive_DriveFile(); $backupFile->setTitle(end($file_path)); $backupFile->setDescription('Backup file of site: ' . $this->site_name . '.'); if ($siteFolder != null) { $backupFile->setParents(array($siteFolder)); } $googleClient->setDefer(true); // Deferred client returns request object. /** @var Google_Http_Request $request */ $request = $googleDrive->files->insert($backupFile); $chunkSize = 1024 * 1024 * 4; $media = new Google_Http_MediaFileUpload($googleClient, $request, 'application/zip', null, true, $chunkSize); $fileSize = filesize($args['backup_file']); $media->setFileSize($fileSize); mwp_logger()->info('Uploading backup file to Google Drive; file size is {backup_size}', array('backup_size' => mwp_format_bytes($fileSize))); // Upload the various chunks. $status will be false until the process is // complete. $status = false; $handle = fopen($args['backup_file'], 'rb'); $started = microtime(true); $lastNotification = $started; $lastProgress = 0; $threshold = 1; $uploaded = 0; $started = microtime(true); while (!$status && !feof($handle)) { $chunk = fread($handle, $chunkSize); $newChunkSize = strlen($chunk); if (($elapsed = microtime(true) - $lastNotification) > $threshold) { $lastNotification = microtime(true); mwp_logger()->info('Upload progress: {progress}% (speed: {speed}/s)', array('progress' => round($uploaded / $fileSize * 100, 2), 'speed' => mwp_format_bytes(($uploaded - $lastProgress) / $elapsed))); $lastProgress = $uploaded; echo " "; flush(); } $uploaded += $newChunkSize; $status = $media->nextChunk($chunk); } fclose($handle); if (!$status instanceof Google_Service_Drive_DriveFile) { mwp_logger()->error('Upload to Google Drive failed', array('status' => $status)); return array('error' => 'Upload to Google Drive was not successful.'); } $this->tasks[$args['task_name']]['task_results'][$args['task_result_key']]['google_drive']['file_id'] = $status->getId(); mwp_logger()->info('Upload to Google Drive completed; average speed is {speed}/s', array('speed' => mwp_format_bytes(round($fileSize / (microtime(true) - $started))))); return true; }