PluginProbe ʕ •ᴥ•ʔ
Backup Migration / 2.0.0
Backup Migration v2.0.0
2.1.7 2.1.6 2.1.5.2 trunk 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.6.1 1.4.7 1.4.8 1.4.9 1.4.9.1 2.0.0 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.5.1
backup-backup / includes / external / google-drive.php
backup-backup / includes / external Last commit date
backupbliss.php 10 months ago controller.php 10 months ago dropbox.php 10 months ago ftp.php 10 months ago google-drive.php 10 months ago s3.php 10 months ago
google-drive.php
746 lines
1 <?php
2
3 // Namespace
4 namespace BMI\Plugin\External;
5
6 // Use
7 use BMI\Plugin\Backup_Migration_Plugin as BMP;
8 use BMI\Plugin\BMI_Logger as Logger;
9 use BMI\Plugin\BMI_Pro_Core;
10 use BMI\Plugin\BMProAjax as BMProAjax;
11 use BMI\Plugin\Scanner\BMI_BackupsScanner as Backups;
12 use BMI\Plugin\Dashboard as Dashboard;
13
14 // Exit on direct access
15 if (!defined('ABSPATH')) {
16 exit;
17 }
18
19 /**
20 * BMI_External_GDrive
21 */
22 class BMI_External_GDrive {
23
24 private $gdrive_access_token = false;
25
26 public function __construct() {
27
28 add_action('bmi_premium_remove_backup_file', [&$this, 'deleteGoogleDriveBackup']);
29 add_action('bmi_premium_remove_backup_json_file', [&$this, 'deleteGoogleDriveJson']);
30
31 }
32
33 /**
34 * checkForBackupsToUpload - Will check for backups that requires to be in sync with cloud
35 *
36 * @return string[]
37 */
38 public function checkForBackupsToUpload() {
39
40 $isEnabled = Dashboard\bmi_get_config('STORAGE::EXTERNAL::GDRIVE');
41 if (!($isEnabled === true || $isEnabled === 'true')) {
42 return;
43 }
44
45 // Upload Object
46 $requiresUpload = get_option('bmip_to_be_uploaded', [
47 'current_upload' => [],
48 'queue' => [],
49 'failed' => []
50 ]);
51
52 // Local Backups
53 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'scanner' . DIRECTORY_SEPARATOR . 'backups.php';
54 $backups = new Backups();
55 $backupsAvailable = $backups->getAvailableBackups("local");
56 $localBackups = $backupsAvailable['local'];
57 $localBackups = array_reverse($localBackups);
58
59 // Google Drive
60 $gdriveFailed = false;
61 $googleDriveBackups = $this->getGoogleDriveBackups();
62 if ($googleDriveBackups && is_object($googleDriveBackups['data']) && isset($googleDriveBackups['data']->files)) {
63 $googleDriveParsed = $this->parseGoogleDriveFiles($googleDriveBackups['data']->files);
64 } else $gdriveFailed = true;
65
66 $uploadedBackupStatus = get_option('bmi_uploaded_backups_status', []);
67 foreach ($localBackups as $name => $details) {
68
69 $manifestName = $details[0];
70 $md5 = $details[7];
71 if (isset($uploadedBackupStatus[$md5]) && isset($uploadedBackupStatus[$md5]['gdrive'])) {
72 continue;
73 }
74
75 // Google Drive
76 if (!$gdriveFailed && !(isset($googleDriveParsed['md5_' . $md5]) && isset($googleDriveParsed['file_' . $md5 . '.json']))) {
77
78 // File is not uploaded action required
79 if (!isset($requiresUpload['queue']['gdrive_' . $md5])) {
80 $isAnyTaskATM = isset($requiresUpload['current_upload']['task']);
81 if (($isAnyTaskATM && $requiresUpload['current_upload']['task'] != 'gdrive_' . $md5) || !$isAnyTaskATM) {
82 $requiresUpload['queue']['gdrive_' . $md5] = [
83 'name' => $name,
84 'md5' => $md5,
85 'json' => $md5 . '.json'
86 ];
87 }
88 }
89 }
90 }
91
92 update_option('bmip_to_be_uploaded', $requiresUpload);
93 return [ 'status' => 'success' ];
94
95 }
96
97 /**
98 * parseGoogleDriveFiles - Parses Google Drive output files
99 *
100 * @param object $files Google Drive Files of Return
101 * @return array of parsed files
102 */
103 public function parseGoogleDriveFiles(&$files) {
104
105 $parsedFiles = [];
106 foreach ($files as $index => $file) {
107 $parsedFiles['file_' . $file->name] = [
108 'md5' => $file->md5Checksum,
109 'originalName' => $file->originalFilename,
110 'id' => $file->id,
111 'size' => $file->size
112 ];
113 $parsedFiles['md5_' . $file->md5Checksum] = [
114 'name' => $file->name,
115 'originalName' => $file->originalFilename,
116 'id' => $file->id,
117 'size' => $file->size
118 ];
119 }
120
121 return $parsedFiles;
122
123 }
124
125 /**
126 * getGoogleDriveAccessToken - Generates Access Token for API communication
127 *
128 * @return json status
129 */
130 private function getGoogleDriveAccessToken( $forceGetNewAccessToken = false ) {
131
132 $uri = home_url();
133 if (substr($uri, 0, 4) != 'http') {
134 if (is_ssl()) $uri = 'https://' . home_url();
135 else $uri = 'http://' . home_url();
136 }
137
138 if ($this->gdrive_access_token != false) {
139 return $this->gdrive_access_token;
140 }
141
142 $client_token = get_option('bmi_pro_gd_client_id', '');
143 $site_token = get_option('bmi_pro_gd_token', '');
144
145 if (strlen($site_token) < 60 || strlen($client_token) < 60) {
146 return false;
147 }
148
149 $savedAccessToken = get_transient('bmi_pro_access_token');
150 if ($savedAccessToken) return $savedAccessToken;
151
152 $url = 'https://authentication.backupbliss.com/v1/gdrive/token';
153 $response = wp_remote_post($url, array(
154 'method' => 'POST',
155 'timeout' => 15,
156 'redirection' => 2,
157 'httpversion' => '1.0',
158 'blocking' => true,
159 'body' => array(
160 'client_id' => get_option('bmi_pro_gd_client_id', ''),
161 'site_token' => get_option('bmi_pro_gd_token', ''),
162 'force_refresh' => $forceGetNewAccessToken,
163 'redirect_uri' => $uri
164 )
165 ));
166
167 if (is_wp_error($response)) {
168 $error_message = $response->get_error_message();
169 Logger::error('[BMI PRO] Something went wrong during getting token:' . $error_message);
170 return false;
171 } else {
172 $result = json_decode($response['body']);
173 if (isset($result->expiration) && isset($result->access_token)) {
174 $expiresInSeconds = intval($result->expiration) - intval(microtime(true));
175 $accessToken = $result->access_token;
176 set_transient('bmi_pro_access_token', $accessToken, $expiresInSeconds);
177 if (in_array(get_transient('bmip_gd_issue'), ['auth_error', 'auth_error_disconnected'])) {
178 delete_transient('bmip_gd_issue');
179 }
180
181 $this->gdrive_access_token = $accessToken;
182 return $this->gdrive_access_token;
183 }
184 return false;
185 }
186
187 }
188
189 /**
190 * makeGoogleDriveAPICall - Makes Call to the Google Drive API GET
191 *
192 * @return json status
193 */
194 private function makeGoogleDriveAPICall($uri, $range = false) {
195
196 $access_token = $this->getGoogleDriveAccessToken();
197
198 if ($access_token === false || $access_token === 'false') {
199 return 'error';
200 }
201
202 $headers = array(
203 'Authorization: Bearer ' . rawurlencode($access_token)
204 );
205
206 if ($range != false) $headers[] = 'Range: bytes=' . $range;
207 else $headers[] = 'Content-Type: application/json';
208
209 $url = 'https://www.googleapis.com/drive/v3/' . $uri;
210 $ch = curl_init();
211 curl_setopt($ch, CURLOPT_URL, $url);
212 curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
213 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
214 curl_setopt($ch, CURLOPT_TIMEOUT, 30);
215 curl_setopt($ch, CURLOPT_MAXREDIRS, 5);
216
217 $response = curl_exec($ch);
218
219 if (curl_errno($ch)) {
220 $error_message = curl_error($ch);
221 Logger::error('[BMI PRO] Something went wrong during getting file list/content/download:' . $error_message);
222 return 'error';
223 }
224
225 $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
226 if ($http_code == 401) {
227 if (get_transient('bmi_pro_access_token') && get_transient('bmip_gd_issue') != 'auth_error_disconnected') set_transient('bmip_gd_issue', 'auth_error', HOUR_IN_SECONDS);
228 }
229
230 // Close the cURL session
231 curl_close($ch);
232
233 if ($range != false) return $response;
234 else return json_decode($response);
235
236 }
237
238 /**
239 * makeGoogleDriveAPICallDelete - Makes Call to the Google Drive API DELETE
240 *
241 * @return json status
242 */
243 private function makeGoogleDriveAPICallDelete($fileId) {
244
245 $access_token = $this->getGoogleDriveAccessToken();
246
247 if ($access_token === false || $access_token === 'false') {
248 return 'error';
249 }
250
251 $url = 'https://www.googleapis.com/drive/v3/files/' . $fileId;
252 $response = wp_remote_get($url, array(
253 'method' => 'DELETE',
254 'timeout' => 15,
255 'redirection' => 5,
256 'httpversion' => '1.0',
257 'blocking' => true,
258 'headers' => array(
259 'Authorization' => 'Bearer ' . rawurlencode($access_token)
260 )
261 ));
262
263 $http_code = wp_remote_retrieve_response_code($response);
264 if ($http_code == 401) {
265 if (get_transient('bmi_pro_access_token') && get_transient('bmip_gd_issue') != 'auth_error_disconnected') set_transient('bmip_gd_issue', 'auth_error', HOUR_IN_SECONDS);
266 }
267
268 if (is_wp_error($response)) {
269 $error_message = $response->get_error_message();
270 Logger::error('[BMI PRO] Something went wrong during getting file list:' . $error_message);
271 return 'error';
272 } else return json_decode($response['body']);
273
274 }
275
276 /**
277 * makeGoogleDriveAPICallPost - Makes Call to the Google Drive API POST
278 *
279 * @return json status
280 */
281 private function makeGoogleDriveAPICallPost($uri, $postdata, $type = false) {
282
283 $access_token = $this->getGoogleDriveAccessToken();
284 if ($access_token === false || $access_token === 'false') {
285 return 'error';
286 }
287
288 if ($type == 'upload') $url = 'https://www.googleapis.com/upload/drive/v3/' . $uri;
289 else $url = 'https://www.googleapis.com/drive/v3/' . $uri;
290
291 $response = wp_remote_post($url, array(
292 'method' => 'post',
293 'timeout' => 15,
294 'redirection' => 5,
295 'httpversion' => '1.0',
296 'blocking' => true,
297 'headers' => array(
298 'Content-Type' => 'application/json',
299 'Authorization' => 'Bearer ' . rawurlencode($access_token)
300 ),
301 'body' => wp_json_encode($postdata)
302 ));
303
304 $http_code = wp_remote_retrieve_response_code($response);
305 if ($http_code == 401) {
306 if (get_transient('bmi_pro_access_token') && get_transient('bmip_gd_issue') != 'auth_error_disconnected') set_transient('bmip_gd_issue', 'auth_error', HOUR_IN_SECONDS);
307 }
308
309 if (is_wp_error($response)) {
310 $error_message = $response->get_error_message();
311 Logger::error('[BMI PRO] Something went wrong during getting file list:' . $error_message);
312 return 'error';
313 } else {
314 if ($type == 'upload') return $response['headers']['location'];
315 else return json_decode($response['body']);
316 }
317
318 }
319
320 /**
321 * makeGoogleDriveAPICallPutSingle - Makes Call to the Google Drive API PUT
322 * supports only single request upload
323 *
324 * @return json status
325 */
326 private function makeGoogleDriveAPICallPutSingle($url, &$data) {
327
328 $access_token = $this->getGoogleDriveAccessToken();
329 if ($access_token === false || $access_token === 'false') {
330 return 'error';
331 }
332
333 $response = wp_remote_post($url, array(
334 'method' => 'PUT',
335 'timeout' => 15,
336 'redirection' => 5,
337 'httpversion' => '1.0',
338 'blocking' => true,
339 'headers' => array(
340 'Content-Type' => 'text/plain',
341 'Content-Length' => strlen($data),
342 'Authorization' => 'Bearer ' . rawurlencode($access_token)
343 ),
344 'body' => $data
345 ));
346
347 $http_code = wp_remote_retrieve_response_code($response);
348 if ($http_code == 401) {
349 if (get_transient('bmi_pro_access_token') && get_transient('bmip_gd_issue') != 'auth_error_disconnected') set_transient('bmip_gd_issue', 'auth_error', HOUR_IN_SECONDS);
350 }
351
352 if (is_wp_error($response)) {
353 $error_message = $response->get_error_message();
354 Logger::error('[BMI PRO] Something went wrong during PUT upload (single):' . $error_message);
355 return 'error';
356 } else {
357 return $response;
358 }
359
360 }
361
362 /**
363 * makeGoogleDriveAPICallPut - Makes Call to the Google Drive API PUT
364 *
365 * @return json status
366 */
367 private function makeGoogleDriveAPICallPut($url, &$binaryData, $chunkSize, $chunkRange) {
368
369 $access_token = $this->getGoogleDriveAccessToken();
370 if ($access_token === false || $access_token === 'false') {
371 return 'error';
372 }
373
374 $max = ini_get('max_execution_time') - 2;
375 if ($max > 120) $max = 120;
376
377 $response = wp_remote_post($url, array(
378 'method' => 'PUT',
379 'timeout' => $max,
380 'redirection' => 5,
381 'httpversion' => '1.0',
382 'blocking' => true,
383 'headers' => array(
384 'Content-Type' => 'application/octet-stream',
385 'Authorization' => 'Bearer ' . rawurlencode($access_token),
386 'Content-Length' => $chunkSize,
387 'Content-Range' => $chunkRange
388 ),
389 'body' => $binaryData
390 ));
391
392 $http_code = wp_remote_retrieve_response_code($response);
393 if ($http_code == 401) {
394 if (get_transient('bmi_pro_access_token') && get_transient('bmip_gd_issue') != 'auth_error_disconnected') set_transient('bmip_gd_issue', 'auth_error', HOUR_IN_SECONDS);
395 }
396
397 if (is_wp_error($response)) {
398 $error_message = $response->get_error_message();
399 Logger::error('[BMI PRO] Something went wrong during file upload (resumable):' . $error_message);
400 return 'error';
401 } else {
402 return $response;
403 }
404
405 }
406
407 /**
408 * getBMIDirectoryID - Return list of Google Drive backups and their MD5s
409 *
410 * @return json status
411 */
412 private function getBMIDirectoryID() {
413
414 $dirname = esc_attr(sanitize_text_field(Dashboard\bmi_get_config('STORAGE::EXTERNAL::GDRIVE::DIRNAME')));
415
416 $search = rawurlencode("name = '" . $dirname . "' and trashed = false and mimeType = 'application/vnd.google-apps.folder'");
417 $uri = 'files?corpora=user&orderBy=folder&q=' . $search;
418 $api = $this->makeGoogleDriveAPICall($uri);
419
420 if ($api == 'error') return [ 'status' => 'error1' ];
421 if (!isset($api->files)) return [ 'status' => 'error2' ];
422
423 if (sizeof($api->files) <= 0 && !isset($api->files[0])) {
424
425 $directoryCreationData = [
426 'mimeType' => 'application/vnd.google-apps.folder',
427 'name' => $dirname,
428 'parents' => ['root'],
429 ];
430
431 $api = $this->makeGoogleDriveAPICallPost('files', $directoryCreationData);
432 $bmiAppDirectoryID = $api->id;
433
434 } else {
435
436 $bmiAppDirectoryID = $api->files[0]->id;
437
438 }
439
440 return $bmiAppDirectoryID;
441
442 }
443
444 /**
445 * getGoogleDriveBackups - Return list of Google Drive backups and their MD5s
446 *
447 * @return json status
448 */
449 public function getGoogleDriveBackups() {
450
451 $bmiAppDirectoryID = $this->getBMIDirectoryID();
452
453 if (is_array($bmiAppDirectoryID)) return false;
454
455 $search = rawurlencode("'" . $bmiAppDirectoryID . "'" . ' in parents and trashed = false');
456 $uri = 'files?corpora=user&orderBy=folder&fields=files(md5Checksum,+originalFilename,+size,+mimeType,+name,+id)&q=' . $search;
457 $api = $this->makeGoogleDriveAPICall($uri);
458
459 return [ 'status' => 'success', 'data' => $api ];
460
461 }
462
463 /**
464 * createUploadGoogleDriveURL - It will create resumable upload URL
465 *
466 * @return json status
467 */
468 public function createUploadGoogleDriveURL($backupPath, $manifestPath, $forManifest = false) {
469
470 $bmiAppDirectoryID = $this->getBMIDirectoryID();
471
472 $uri = 'files?uploadType=resumable';
473
474 // Make file LINK for RESUMABLE upload
475 $uploadBody = array();
476 if ($forManifest === true) $uploadBody['name'] = basename($manifestPath);
477 else $uploadBody['name'] = basename($backupPath);
478 $uploadBody['parents'] = [$bmiAppDirectoryID];
479 $uploadURL = $this->makeGoogleDriveAPICallPost($uri, $uploadBody, 'upload');
480
481 return [ 'status' => 'success', 'uploadURL' => $uploadURL ];
482
483 }
484
485 /**
486 * uploadManifestFile - It will upload manifest file into BMI directory on Google Drive
487 *
488 * @return array|false status
489 */
490 private function uploadManifestFile($manifestUploadURL, $manifestPath) {
491
492 if (!file_exists($manifestPath)) {
493 return false;
494 }
495
496 $contents = file_get_contents($manifestPath);
497 $api = $this->makeGoogleDriveAPICallPutSingle($manifestUploadURL, $contents);
498
499 return [ 'status' => 'success', 'data' => $api ];
500
501 }
502
503 /**
504 * getGoogleDriveFileContents - Gets file body by Google Drive file ID
505 *
506 * @return json status
507 */
508 public function getGoogleDriveFileContents($fileId, $range = false) {
509
510 $uri = 'files/' . sanitize_text_field($fileId) . '?alt=media';
511 $api = $this->makeGoogleDriveAPICall($uri, $range);
512
513 return [ 'status' => 'success', 'data' => $api ];
514
515 }
516
517 /**
518 * getGoogleDriveFileMeta - Gets file meta data by Google Drive file ID
519 *
520 * @return json status
521 */
522 public function getGoogleDriveFileMeta($fileId) {
523
524 $uri = 'files/' . sanitize_text_field($fileId) . '?fields=md5Checksum,originalFilename,size,mimeType,name,id';
525 $api = $this->makeGoogleDriveAPICall($uri);
526
527 return [ 'status' => 'success', 'data' => $api ];
528
529 }
530
531 /**
532 * deleteGoogleDriveBackup - Deletes Backup from Google Drive
533 *
534 * @return json status
535 */
536 public function deleteGoogleDriveBackup($md5) {
537
538 $files = $this->getGoogleDriveBackups();
539 if (isset($files['status']) && $files['status'] == 'success') {
540 $files = $files['data']->files;
541 foreach ($files as $index => $file) {
542 if ($file->md5Checksum == $md5) {
543 $fileId = $file->id;
544 $this->makeGoogleDriveAPICallDelete($fileId);
545 }
546 }
547 }
548
549 }
550
551 /**
552 * deleteGoogleDriveJson - Deletes JSON manifest from Google Drive
553 *
554 * @return json status
555 */
556 public function deleteGoogleDriveJson($fileName) {
557
558 $files = $this->getGoogleDriveBackups();
559 if (isset($files['status']) && $files['status'] == 'success') {
560 $files = $files['data']->files;
561 foreach ($files as $index => $file) {
562 if ($file->originalFilename == $fileName) {
563 $fileId = $file->id;
564 $this->makeGoogleDriveAPICallDelete($fileId);
565 }
566 }
567 }
568
569 }
570
571 /**
572 * uploadGoogleDriveFile - It will upload particular file into BMI directory on Google Drive
573 *
574 * @return json status
575 */
576 public function uploadGoogleDriveFile($uploadURL, $filePath, $manifestPath, $md5, $batch, $bytesPerRequest) {
577
578 if (!file_exists($filePath)) {
579
580 update_option('bmip_to_be_uploaded', [
581 'current_upload' => [],
582 'queue' => [],
583 'failed' => []
584 ]);
585
586 return ['status' => 'error'];
587
588 }
589
590 set_transient('bmip_upload_ongoing', '1', 31);
591
592 $batchNumber = intval($batch);
593 $maxLength = filesize($filePath);
594
595 $chunkSize = 256 * 1024 * 4 * intval($bytesPerRequest / 1024 / 1024);
596
597 $chunkOffset = (($batchNumber - 1) * $chunkSize);
598 $rangeEnd = (($chunkSize * $batchNumber) - 1);
599
600 if ($rangeEnd >= $maxLength) $rangeEnd = $maxLength - 1;
601 if (($chunkSize + $chunkOffset) >= $maxLength) $chunkSize = $rangeEnd - $chunkOffset + 1;
602 $range = 'bytes ' . $chunkOffset . '-' . $rangeEnd . '/' . $maxLength;
603 $nextShouldStartAt = $rangeEnd + 1;
604
605
606 if ($stream = fopen($filePath, 'r')) {
607 $binaryData = stream_get_contents($stream, $chunkSize, $chunkOffset);
608 fclose($stream);
609 }
610
611 $api = $this->makeGoogleDriveAPICallPut($uploadURL, $binaryData, $chunkSize, $range);
612 $toBeUploaded = get_option('bmip_to_be_uploaded', false);
613 if (isset($api['response']) && isset($api['response']['code'])) {
614 $code = intval($api['response']['code']);
615 if ($code == 308) {
616
617 $task = $toBeUploaded['current_upload']['task'];
618 if (!isset($toBeUploaded['failed'])) $toBeUploaded['failed'] = [];
619 if (isset($toBeUploaded['failed'][$task])) unset($toBeUploaded['failed'][$task]);
620
621 // All is good
622 if ($toBeUploaded) {
623 $toBeUploaded['current_upload']['batch'] = intval($batch) + 1;
624 $toBeUploaded['current_upload']['progress'] = number_format(($rangeEnd / $maxLength) * 100, 2) . '%';
625 update_option('bmip_to_be_uploaded', $toBeUploaded);
626 }
627
628 } else if ($code == 200) {
629
630 // Upload finished, upload manifest now
631 $manifestUploadURL = $this->createUploadGoogleDriveURL($filePath, $manifestPath, true);
632 $manifestRes = $this->uploadManifestFile($manifestUploadURL['uploadURL'], $manifestPath);
633 if ($manifestRes['status'] === 'success') {
634 $uploadedBackupStatus = get_option('bmi_uploaded_backups_status', []);
635 if (!isset($uploadedBackupStatus[$md5])) {
636 $uploadedBackupStatus[$md5] = [];
637 }
638 $uploadedBackupStatus[$md5]['gdrive'] = true;
639 update_option('bmi_uploaded_backups_status', $uploadedBackupStatus);
640 }
641
642 $task = $toBeUploaded['current_upload']['task'];
643 $toBeUploaded['current_upload'] = [];
644 if (!isset($toBeUploaded['failed'])) $toBeUploaded['failed'] = [];
645 if (isset($toBeUploaded['failed'][$task])) unset($toBeUploaded['failed'][$task]);
646
647 update_option('bmip_to_be_uploaded', $toBeUploaded);
648
649 } else if ($code == 403) {
650
651 $message = 'Backup file upload to Google Drive could not be completed due to insufficient free space on Google Drive.<br />';
652 $message .= 'The plugin will automatically retry uploading the backup file within an hour of this error message.<br />';
653 $message .= 'During this time, please try to resolve any issues, such as freeing up space on your Google Drive.<br />';
654
655 // Add required space option to check later
656 add_option('bmip_gd_required_space', filesize($filePath));
657 // Display message
658 set_transient('bmip_display_quota_issues', $message, HOUR_IN_SECONDS);
659 // Force to show the message again
660 delete_option('bmip_dismissed_quota_notice');
661
662 // Mark the backup as failed to upload
663 $task = $toBeUploaded['current_upload']['task'];
664 // Requeueing is handled globally
665 // $toBeUploaded['queue'][$task] = [
666 // 'name' => $toBeUploaded['current_upload']['name'],
667 // 'md5' => $toBeUploaded['current_upload']['md5'],
668 // 'json' => $toBeUploaded['current_upload']['json']
669 // ];
670
671 $toBeUploaded['current_upload'] = [];
672 if (!isset($toBeUploaded['failed'])) $toBeUploaded['failed'] = [];
673 if (isset($toBeUploaded['failed'][$task])) $toBeUploaded['failed'][$task]++;
674 else $toBeUploaded['failed'][$task] = 1;
675
676 update_option('bmip_to_be_uploaded', $toBeUploaded);
677
678 } else if ($code == 429) {
679
680 $message = 'Backup file upload to Google Drive could not be completed due to a limit error.<br />';
681 $message .= 'Received message: <i>Too Many Requests in a short amount of time.</i><br />';
682 $message .= 'The plugin will automatically retry uploading the backup file within 2 minutes of this error message.<br />';
683
684
685 set_transient('bmip_display_quota_issues', $message, 2 * MINUTE_IN_SECONDS);
686
687 } else {
688
689 Logger::error('[BMI PRO] Error during file upload (Google Drive) code:' . $code);
690 if (isset($api['body']) && is_string($api['body'])) {
691 Logger::error('[BMI PRO] Message received (body):' . print_r($api['body'], true));
692 }
693
694 $task = $toBeUploaded['current_upload']['task'];
695 // Requeueing is handled globally
696 // $toBeUploaded['queue'][$task] = [
697 // 'name' => $toBeUploaded['current_upload']['name'],
698 // 'md5' => $toBeUploaded['current_upload']['md5'],
699 // 'json' => $toBeUploaded['current_upload']['json']
700 // ];
701
702 $toBeUploaded['current_upload'] = [];
703 if (!isset($toBeUploaded['failed'])) $toBeUploaded['failed'] = [];
704 if (isset($toBeUploaded['failed'][$task])) $toBeUploaded['failed'][$task]++;
705 else $toBeUploaded['failed'][$task] = 1;
706
707 update_option('bmip_to_be_uploaded', $toBeUploaded);
708
709 }
710 } else {
711
712 $task = $toBeUploaded['current_upload']['task'];
713 // Requeueing is handled globally
714 // $toBeUploaded['queue'][$task] = [
715 // 'name' => $toBeUploaded['current_upload']['name'],
716 // 'md5' => $toBeUploaded['current_upload']['md5'],
717 // 'json' => $toBeUploaded['current_upload']['json']
718 // ];
719
720 $toBeUploaded['current_upload'] = [];
721 if (!isset($toBeUploaded['failed'])) $toBeUploaded['failed'] = [];
722 if (isset($toBeUploaded['failed'][$task])) $toBeUploaded['failed'][$task]++;
723 else $toBeUploaded['failed'][$task] = 1;
724
725 update_option('bmip_to_be_uploaded', $toBeUploaded);
726
727 }
728
729 delete_transient('bmip_upload_ongoing');
730 return [ 'status' => 'success', 'data' => $api ];
731
732 }
733
734 public function getGoogleDriveAvailableStorage() {
735 $uri = 'about?fields=storageQuota';
736 $api = $this->makeGoogleDriveAPICall($uri);
737 $quota = $api->storageQuota;
738 $totalStorage = $quota->limit;
739 $totalUsage = $quota->usage;
740 $availableStorage = $totalStorage - $totalUsage;
741
742 return $availableStorage;
743 }
744
745 }
746