PluginProbe ʕ •ᴥ•ʔ
Backup Migration / 1.4.9
Backup Migration v1.4.9
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 / backupbliss.php
backup-backup / includes / external Last commit date
backupbliss.php 11 months ago controller.php 11 months ago
backupbliss.php
828 lines
1 <?php
2
3 // Namespace
4 namespace BMI\Plugin\External;
5
6 // Use
7 use BMI\Plugin\BMI_Logger as Logger;
8 use BMI\Plugin\Scanner\BMI_BackupsScanner as Backups;
9 use BMI\Plugin\Dashboard as Dashboard;
10
11 // Exit on direct access
12 if (!defined('ABSPATH')) {
13 exit;
14 }
15
16 class BMI_External_BackupBliss
17 {
18
19 public function __construct()
20 {
21
22 add_action('bmi_premium_remove_backup_file', [&$this, 'deleteBackup']);
23 add_action('bmi_premium_remove_backup_json_file', [&$this, 'deleteBackupManifest']);
24 }
25
26 public function process($action, $post) {
27
28 $uri = home_url();
29 if (substr($uri, 0, 4) != 'http') {
30 if (is_ssl()) $uri = 'https://' . home_url();
31 else $uri = 'http://' . home_url();
32 }
33
34 if ($action == "connect") {
35 $key = $this->getSecret($post['api_key']);
36 if($key !== false) {
37 update_option("bmi_pro_backupbliss_key", $key);
38 return ["status"=>'success'];
39 }
40
41 return ["status"=>'fail', "message"=>"Invalid API Key provided!"];
42 }
43
44 if ($action == "disconnect") {
45 $res = $this->_makeApiCall("plugin/disconnect", "POST", ["site_url"=>$uri]);
46 if ($res["status"])
47 if ($res["response_data"]["status"]) {
48 delete_option("bmi_pro_backupbliss_key");
49 return ["status"=>"success"];
50 }
51
52 return ["status"=>"fail", "message"=> "Error disconnecting from the backupbliss server."];
53 }
54
55 if ($action == "storage-info") {
56 $res = $this->_makeApiCall("file/storage-info");
57 if ($res["status"])
58 if ($res["response_data"]["status"]) {
59 return ["status"=>"success", "data"=>$res["response_data"]];
60 }
61
62 return ["status"=>"fail", "message"=>"Error fetching storage info from the backupbliss server."];
63 }
64 }
65
66 /**
67 * checkForBackupsToUpload - Will check for backups that requires to be in sync with cloud
68 *
69 * @return string[]
70 */
71 public function checkForBackupsToUpload()
72 {
73 // Upload Object
74 $requiresUpload = get_option('bmip_to_be_uploaded', [
75 'current_upload' => [],
76 'queue' => [],
77 'failed' => []
78 ]);
79
80 // Local Backups
81 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'scanner' . DIRECTORY_SEPARATOR . 'backups.php';
82 $backups = new Backups();
83 $backupsAvailable = $backups->getAvailableBackups("local");
84 $localBackups = $backupsAvailable['local'];
85 $localBackups = array_reverse($localBackups);
86
87 $files = $this->parseFiles($this->getAllFiles());
88 // if (BMI_DEBUG) {
89 // Logger::error( print_r($files, true));
90 // }
91
92
93 if (!$files) return;
94
95 foreach ($localBackups as $name => $details) {
96
97 $md5 = $details[7];
98
99 if (!(isset($files['manifests'][$md5 . '.json']) && isset($files['backups'][$name]))) {
100
101 $task = 'backupbliss_' . $md5;
102
103 // File is not uploaded action required
104 if (!isset($requiresUpload['queue'][$task])) {
105 $isAnyTaskATM = isset($requiresUpload['current_upload']['task']);
106
107
108 // if (isset($requiresUpload['failed'][$task])) unset($requiresUpload['failed'][$task]);
109
110 if (($isAnyTaskATM && $requiresUpload['current_upload']['task'] != $task) || !$isAnyTaskATM) {
111 $requiresUpload['queue'][$task] = [
112 'name' => $name,
113 'md5' => $md5,
114 'json' => $md5 . '.json'
115 ];
116 }
117 }
118 }
119 }
120
121 update_option('bmip_to_be_uploaded', $requiresUpload);
122 return ['status' => 'success'];
123 }
124
125 public function parseFiles($files)
126 {
127
128 $parsedFiles = ['backups' => [], 'manifests' => []];
129
130 if ($files === false) return false;
131
132 foreach ($files as $index => $file) {
133 if (isset($file['folder'])) {
134 continue; //Skip directories
135 }
136
137 $extension = pathinfo($file['name'], PATHINFO_EXTENSION);
138
139 if (BMI_DEBUG) {
140 // Logger::error("parseFiles - " . $file['name'] . " - " . print_r($file['file'], true));
141 // Logger::error("parseFiles - ext - $extension");
142 }
143
144 if (in_array($extension, ["zip", "tar", "gz"])) {
145 $type = 'backups';
146 }
147
148 if ($extension === 'json') {
149 $type = 'manifests';
150 }
151
152 if (isset($type)) {
153 $parsedFiles[$type][$file['name']] = [
154 'size' => $file['size']
155 ];
156 unset($type);
157 }
158 }
159
160
161 if (BMI_DEBUG) {
162 // Logger::error("parseFiles - " . print_r($parsedFiles, true));
163 }
164
165 return $parsedFiles;
166 }
167
168 public function getSecret($api_key = false)
169 {
170 $tempKeyBackupBlissFiles = BMI_TMP . DIRECTORY_SEPARATOR . 'backupblissKeys.php';
171 if (file_exists($tempKeyBackupBlissFiles)) {
172 $backupblissKeys = file_get_contents($tempKeyBackupBlissFiles);
173 if (strpos($backupblissKeys, "\n") !== false) {
174 $lines = explode("\n", $backupblissKeys);
175 if (sizeof($lines) == 3) {
176 $backupbliss_key = substr($lines[1], 2);
177 if (function_exists('wp_load_alloptions')) {
178 wp_load_alloptions(true);
179 }
180 delete_option("bmi_pro_backupbliss_key");
181 if (function_exists('wp_load_alloptions')) {
182 wp_load_alloptions(true);
183 }
184 update_option("bmi_pro_backupbliss_key", $backupbliss_key);
185 }
186 }
187 if (strpos(site_url(), 'tastewp') !== false) {
188 if (function_exists('wp_load_alloptions')) {
189 wp_load_alloptions(true);
190 }
191
192 update_option('__tastewp_redirection_performed', true);
193 update_option('auto_smart_tastewp_redirect_performed', 1);
194 update_option('tastewp_auto_activated', true);
195 update_option('__tastewp_sub_requested', true);
196 }
197
198 unlink($tempKeyBackupBlissFiles);
199 }
200
201 $uri = home_url();
202 if (substr($uri, 0, 4) != 'http') {
203 if (is_ssl()) $uri = 'https://' . home_url();
204 else $uri = 'http://' . home_url();
205 }
206
207 if (!$api_key)
208 $key = get_option('bmi_pro_backupbliss_key', false);
209 else
210 $key = $api_key;
211
212 if ($key === false) {
213 return false;
214 } elseif($api_key === false) {
215 return $key;
216 }
217
218 $url = BMI_BB_STORAGE_API_URI . '/plugin/verify';
219 $response = wp_remote_post($url, array(
220 'method' => 'POST',
221 'timeout' => 15,
222 'redirection' => 2,
223 'httpversion' => '1.0',
224 'blocking' => true,
225 'headers' => ["Content-Type"=>"application/json", "Authorization" => "Bearer ". $key],
226 'body' => json_encode([
227 "site_url" => $uri
228 ])
229 ));
230
231 if (is_wp_error($response)) {
232 $error_message = $response->get_error_message();
233 Logger::error('[BMI PRO] Something went wrong while authenticating the BackupBliss api key:' . $error_message);
234 return false;
235 } else {
236
237 $http_code = wp_remote_retrieve_response_code($response);
238 if (BMI_DEBUG) {
239 Logger::error("[BMI PRO] BackupBliss getSecret: $http_code - " . print_r($response['body'], true));
240 }
241 if ($http_code == 200) {
242 $this->removeNotice("invalid_key");
243 $result = json_decode($response['body']);
244
245
246 if ($result->status) {
247 return $key;
248 }
249 } else if ($http_code == 401) {
250 if ($api_key) //Authentication request so no need to show notice.
251 return false;
252 $this->_keyDeactivatedNotice();
253 }
254 return false;
255 }
256 }
257
258 public function showNotice($type, $message, $time = 0)
259 {
260 if (BMI_DEBUG) {
261 Logger::error("showNotice($type, $message, $time)");
262 }
263
264 set_transient('bmip_backupbliss_notice_' . $type, $message, $time);
265 $transients = [];
266 $current_trasients = get_transient('bmip_backupbliss_notices');
267 if ($current_trasients) $transients = $current_trasients;
268 $transients[$type] = $type;
269 set_transient('bmip_backupbliss_notices', $transients);
270 }
271
272 public function hideFailureWarnNotice($exp) {
273 set_transient('bmip_backupbliss_hide_failure_notice', true, $exp);
274 }
275
276 public function showFailureWarnNotice() {
277 delete_transient('bmip_backupbliss_hide_failure_notice');
278 }
279
280 public function canShowFailureWarnNotice() {
281 return !get_transient("bmip_backupbliss_hide_failure_notice", false);
282 }
283
284 public function removeNotice($type)
285 {
286 // if (BMI_DEBUG) {
287 // Logger::error("removeNotice($type)");
288 // }
289
290 delete_transient('bmip_backupbliss_notice_' . $type);
291 $current_trasients = get_transient('bmip_backupbliss_notices');
292 if (isset($current_trasients[$type])) {
293 unset($current_trasients[$type]);
294 set_transient('bmip_backupbliss_notices', $current_trasients);
295 }
296 }
297
298 public function hideNotice($type, $time = 0)
299 {
300 if (BMI_DEBUG) {
301 Logger::error("hideNotice($type, $time)");
302 }
303
304 set_transient('bmip_backupbliss_notice_hide_' . $type, true, $time);
305 }
306
307 public function canShowNotice($type)
308 {
309 return !get_transient('bmip_backupbliss_notice_hide_' . $type, false);
310 }
311
312 public function getNotice($type)
313 {
314 // if (BMI_DEBUG) {
315 // Logger::error("getNotice($type)");
316 // }
317
318 return get_transient("bmip_backupbliss_notice_" . $type);
319 }
320
321 public function getNotices()
322 {
323 $bmip_backupbliss_notices = get_transient("bmip_backupbliss_notices");
324 $temp_notices = $bmip_backupbliss_notices;
325 $notices = [];
326 if ($bmip_backupbliss_notices) {
327 foreach ($bmip_backupbliss_notices as $notice) {
328 $noticemessage = get_transient("bmip_backupbliss_notice_" . $notice);
329 if ($noticemessage) {
330 $notices[$notice] = $noticemessage;
331 } else {
332 unset($temp_notices[$notice]);
333 }
334 }
335 }
336
337 if ($bmip_backupbliss_notices !== $temp_notices) {
338 set_transient("bmip_backupbliss_notices", $temp_notices);
339 }
340
341 return $notices;
342 }
343
344
345 private function _makeApiCall($url, $req_type = "GET", $body = [], $custom_headers = null)
346 {
347 $url = BMI_BB_STORAGE_API_URI . $url;
348
349 if (BMI_DEBUG) {
350 $backtrace = debug_backtrace();
351 // Get the caller's function name
352 $callerFunction = isset($backtrace[1]['function']) ? $backtrace[1]['function'] : 'unknown';
353 }
354 if (BMI_DEBUG) {
355 Logger::error("[BMI PRO][BackupBliss] REQUEST FROM $callerFunction() in _makeApiCall($url, $req_type, " . ($req_type != "PUT" ? print_r($body, true) : "BINARYDATA") . ", " . print_r($custom_headers, true) . ")");
356 }
357
358 $secret = $this->getSecret();
359 if (!$secret) {
360 return ["status" => false];
361 }
362
363 $max_execution_time_pre_limit = ini_get('max_execution_time') - 2;
364
365 $headers = $custom_headers == null ? [
366 'Authorization: Bearer ' . $secret,
367 'Accept: application/json',
368 'Content-Type: application/json',
369 ] : $custom_headers;
370
371
372
373 $ch = curl_init();
374 curl_setopt($ch, CURLOPT_URL, $url);
375 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
376 curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
377 curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $req_type);
378 curl_setopt($ch, CURLOPT_TIMEOUT, $max_execution_time_pre_limit);
379
380 if ($req_type == "POST") {
381 curl_setopt($ch, CURLOPT_POST, true);
382 curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
383 } elseif ($req_type == "PUT") {
384 curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
385 }
386
387 $response = curl_exec($ch);
388 $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
389
390 if ($req_type == "DELETE") {
391 return $http_code;
392 }
393
394 if (curl_errno($ch)) {
395 Logger::error("[BMI PRO][BackupBliss] Error in _makeApiCall request: Type: $req_type HTTP Code: $http_code. Error: " . curl_error($ch));
396 return ["status" => false, "http_code" => $http_code, "response_data" => $response];
397 }
398
399 curl_close($ch);
400
401 if ($http_code >= 200 && $http_code <= 299) {
402 $response_data = $custom_headers == null ? json_decode($response, true) : $response;
403 if (BMI_DEBUG) {
404 //Logger::error("[BMI PRO] RESPONSE _makeApiCall - " . print_r($response_data, true));
405 }
406 return ["status" => true, "http_code" => $http_code, "response_data" => $response_data];
407 } else {
408 if ($http_code == 401) {
409 $this->_keyDeactivatedNotice();
410 } elseif ($http_code == 403) {
411 $response_data = json_decode($response, true);
412 $this->_accessPermissionNotice($response_data['message']);
413 }
414 Logger::error("[BMI PRO][BackupBliss] Error in _makeApiCall request: Type: $req_type HTTP Code: $http_code. Response: $response");
415 return ["status" => false, "http_code" => $http_code, "response_data" => $response];
416 }
417 }
418
419 private function _accessPermissionNotice($message) {
420 Logger::error("[BMI] " . $message);
421 $this->showNotice("invalid_permission", $message, 0);
422 }
423
424 private function _keyDeactivatedNotice() {
425 Logger::error("[BMI] The API key is either invalid or deactivated.");
426 $message = 'There was an error while authenticating the BackupBliss API key.<br />';
427 $message .= 'Your BackupBliss API key got deactivated, hence moving backups to the BackupBliss storage is failing or will fail.<br>';
428 $message .= 'Please connect with a new API key by accessing your <a target="_blank" href="' . BMI_BB_STORAGE_URI . '">backupbliss storage</a> account.';
429
430 $this->showNotice("invalid_key", $message);
431 delete_option('bmi_pro_backupbliss_key');
432 $this->removeNotice("storage_warn");
433 $this->removeNotice("upload_issue");
434 $this->removeNotice("upload_issue_space");
435 }
436
437 public function getFileDetailByName($file_name) {
438 $response_data = $this->_makeApiCall("file/file-info/$file_name");
439
440 if($response_data["status"] && $response_data["response_data"]["status"]) {
441 return $response_data["response_data"]["file_info"];
442 }
443
444 return false;
445 }
446
447 private function deleteFile($file_name)
448 {
449 if (BMI_DEBUG) {
450 Logger::error("deleteFile($file_name)");
451 }
452
453 $url = "file/delete/$file_name";
454
455 $http_code = $this->_makeApiCall($url, "DELETE");
456
457 // Handle the response based on the status code
458 if ($http_code == 200) {
459 // 'File deleted successfully'
460 return True;
461 } else {
462 //Logger::error("[BMI PRO] Error in deleteFile. HTTP Code: $http_code.");
463 return False;
464 }
465 }
466
467 public function deleteBackup($md5)
468 {
469
470 if (BMI_DEBUG) {
471 Logger::error("deleteBackup($md5)");
472 }
473
474 $manifest = $this->getManifest($md5);
475 if ($manifest) {
476 $this->deleteFile($manifest->name);
477 }
478 }
479
480 public function getManifest($md5)
481 {
482 $manifest = false;
483 $localManifest = BMI_BACKUPS . DIRECTORY_SEPARATOR . $md5 . '.json';
484
485 if (file_exists($localManifest)) {
486
487 $manifestData = file_get_contents($localManifest);
488 $manifest = json_decode($manifestData);
489 } else {
490
491 $manifestData = $this->getFile($md5 . '.json');
492 if (is_array($manifestData) && $manifestData["file_data"]) {
493
494 $manifest = json_decode($manifestData["file_data"]);
495 }
496 }
497 return $manifest;
498 }
499
500 public function deleteBackupManifest($md5_json)
501 {
502 if (BMI_DEBUG) {
503 Logger::error("deleteBackupManifest($md5_json)");
504 }
505
506 $this->deleteFile($md5_json);
507 }
508
509 public function initiateUploadSession($file_path)
510 {
511
512 $uri = home_url();
513 if (substr($uri, 0, 4) != 'http') {
514 if (is_ssl()) $uri = 'https://' . home_url();
515 else $uri = 'http://' . home_url();
516 }
517
518 $file_name = basename($file_path);
519
520 if (BMI_DEBUG) {
521 Logger::error("[BMI PRO][BackupBliss] initiateUploadSession - $file_path - $file_name");
522 }
523
524
525 $url = 'file/initiate-upload-session';
526 $body = [
527 'filename' => $file_name,
528 'site_url' => $uri,
529 'file_size' => filesize($file_path)
530 ];
531
532 $response = $this->_makeApiCall($url, "POST", $body);
533 if ($response["status"]) {
534 $session = $response["response_data"];
535 if ($session["status"] && isset($session['upload_id']) && !empty($session['upload_id'])) {
536 return $session;
537 } else {
538 Logger::error("[BMI PRO][BackupBliss] Failed to create upload session: " . json_encode($session));
539 return false;
540 }
541 } else {
542 Logger::error("[BMI PRO][BackupBliss] Failed to create upload session: " . $response);
543 return false;
544 }
545 }
546
547 private function uploadChunkWithSession($upload_session, $chunk_data, $start_byte, $end_byte, $total_size)
548 {
549 if (BMI_DEBUG) {
550 // Logger::error("[BMI PRO] BEFORE UPLOAD uploadChunkWithSession(" . $upload_session['uploadUrl'] . ", $start_byte, $end_byte, $total_size" . ")\n" . print_r($headers, true));
551 }
552
553 $response = $this->_makeApiCall("file/upload-chunk/".$upload_session['upload_id'], "PUT", $chunk_data);
554
555 if ($response["status"]) {
556 if (BMI_DEBUG) {
557 // Logger::error("[BMI PRO] AFTER UPLOAD uploadChunkWithSession\n" . print_r($response, true));
558 }
559 return $response;
560 }
561
562 Logger::error("[BMI PRO] Failed to upload chunks. Start byte: $start_byte. End byte: $end_byte. Total Size: $total_size");
563 return $response;
564 }
565
566 public function getAllFiles()
567 {
568 $response = $this->_makeApiCall('file/backups');
569 if (BMI_DEBUG) {
570 // Logger::error("[BMI PRO] getAllBackups " . print_r($response, true));
571 }
572 if ($response["status"] && $response["response_data"]["status"]) {
573 $files = $response["response_data"];
574 return $files['backups'];
575 }
576
577 return false;
578 }
579
580 private function downloadFile($file_details, $start_byte = 0, $end_byte = null)
581 {
582 if (BMI_DEBUG) {
583 //Logger::error("downloadFile(" . print_r($file_details, true) . ", $start_byte, $end_byte)");
584 }
585 if (!isset($file_details['download_hash'])) {
586 Logger::error('[BMI PRO] Download URL not available in the file details.');
587 return false;
588 }
589
590 $headers = [];
591
592 // Set the Range header for partial download
593 if ($end_byte !== null) {
594 $headers = [
595 'Range: bytes=' . $start_byte . '-' . $end_byte
596 ];
597 } else {
598 $headers = [
599 'Range: bytes=' . $start_byte . '-'
600 ];
601 }
602
603 $response = $this->_makeApiCall("file/download/".$file_details["download_hash"], "GET", [], $headers);
604
605 if ($response["status"]) {
606 return $response["response_data"];
607 }
608
609 return false;
610 }
611
612 public function getFile($file_name, $start_byte = 0, $end_byte = null)
613 {
614 if (BMI_DEBUG) {
615 Logger::error("getFile $file_name");
616 }
617 $file_detail = $this->getFileDetailByName($file_name);
618 if ($file_detail) {
619 return ["file_detail" => $file_detail, "file_data" => $this->downloadFile($file_detail, $start_byte, $end_byte)];
620 }
621 return false;
622 }
623
624 public function getStorageInfo()
625 {
626 $response = $this->_makeApiCall("file/storage-info");
627
628 if (BMI_DEBUG) {
629 // Logger::error("getStorageInfo - " . print_r($response, true));
630 }
631
632 if ($response["status"] && $response["response_data"]["status"]) {
633 return $response["response_data"]["storage_info"];
634 }
635
636 return false;
637 }
638
639
640 public function uploadFile($uploadSession, $filePath, $manifestPath, $md5, $batch, $bytesPerRequest)
641 {
642
643 if (!file_exists($filePath)) {
644
645 update_option('bmip_to_be_uploaded', [
646 'current_upload' => [],
647 'queue' => [],
648 'failed' => []
649 ]);
650
651 return ['status' => 'error'];
652 }
653
654 set_transient('bmip_upload_ongoing', '1', 31);
655
656 $batchNumber = intval($batch);
657 $maxLength = filesize($filePath);
658
659 # Microsoft recommended multiple value 320Kb
660 $chunkSize = 4 * 327680 * intval($bytesPerRequest / 1024 / 1024);
661
662 # Limit the chunk size to max of 50MB with multiple of recommended value
663 $maxChunkSize = 50 * 1024 * 1024;
664 $chunkSize = $chunkSize > $maxChunkSize ? $maxChunkSize : $chunkSize;
665
666 $chunkOffset = (($batchNumber - 1) * $chunkSize);
667 $rangeEnd = (($chunkSize * $batchNumber) - 1);
668
669 if ($rangeEnd >= $maxLength) $rangeEnd = $maxLength - 1;
670 if (($chunkSize + $chunkOffset) >= $maxLength) $chunkSize = $rangeEnd - $chunkOffset + 1;
671 $nextShouldStartAt = $rangeEnd + 1;
672
673
674 if ($stream = fopen($filePath, 'r')) {
675 $binaryData = stream_get_contents($stream, $chunkSize, $chunkOffset);
676 fclose($stream);
677 }
678
679
680 $toBeUploaded = get_option('bmip_to_be_uploaded', false);
681
682 if (BMI_DEBUG)
683 {
684 Logger::error("Before uploadFile - " . print_r($uploadSession, true));
685 Logger::error("Before uploadFile - " . print_r($toBeUploaded['current_upload']['batch'], true));
686 }
687
688 $response = $this->uploadChunkWithSession($uploadSession, $binaryData, $chunkOffset, $rangeEnd, $maxLength);
689
690 $code = intval($response['http_code']);
691
692 if ($response["status"]) {
693
694 if ($rangeEnd == $maxLength - 1) //Last chunk already uploaded so complete upload and upload manifest
695 {
696 if ($code != 201) //If upload is not already completed
697 {
698 $response = $this->_makeApiCall('file/complete-upload', "POST", ['upload_id'=>$uploadSession['upload_id']]);
699 $code = intval($response['http_code']);
700 if ($code != 201) { //Something failed while completing the upload
701 $task = $toBeUploaded['current_upload']['task'];
702 $toBeUploaded['current_upload'] = [];
703 if (!isset($toBeUploaded['failed'])) $toBeUploaded['failed'] = [];
704 $toBeUploaded['failed'][$task] = 1;
705
706 update_option('bmip_to_be_uploaded', $toBeUploaded);
707 return ['status' => 'fail', 'data' => $response];
708 }
709 }
710
711 $manifestUploadSession = $this->initiateUploadSession($manifestPath);
712
713 if (!$manifestUploadSession) { //Something failed while completing the upload
714 $task = $toBeUploaded['current_upload']['task'];
715 $toBeUploaded['current_upload'] = [];
716 if (!isset($toBeUploaded['failed'])) $toBeUploaded['failed'] = [];
717 $toBeUploaded['failed'][$task] = 1;
718
719 update_option('bmip_to_be_uploaded', $toBeUploaded);
720 return ['status' => 'fail', 'data' => $response];
721 }
722
723 if ($stream = fopen($manifestPath, 'r')) {
724 $binaryData = stream_get_contents($stream);
725 fclose($stream);
726 }
727
728 $size = strlen($binaryData);
729 $manifestRes = $this->uploadChunkWithSession($manifestUploadSession, $binaryData, 0, $size - 1, $size);
730
731 $task = $toBeUploaded['current_upload']['task'];
732 $toBeUploaded['current_upload'] = [];
733 if (!isset($toBeUploaded['failed'])) $toBeUploaded['failed'] = [];
734 if (isset($toBeUploaded['failed'][$task])) unset($toBeUploaded['failed'][$task]);
735
736 update_option('bmip_to_be_uploaded', $toBeUploaded);
737 return ['status' => 'success', 'data' => $response];
738 }
739
740
741 //Chunk accepted, let's continue uploading
742 if ($code == 202) {
743
744 $task = $toBeUploaded['current_upload']['task'];
745 if (!isset($toBeUploaded['failed'])) $toBeUploaded['failed'] = [];
746 if (isset($toBeUploaded['failed'][$task])) unset($toBeUploaded['failed'][$task]);
747
748 $toBeUploaded['current_upload']['batch'] = intval($batch) + 1;
749 $toBeUploaded['current_upload']['progress'] = number_format(($rangeEnd / $maxLength) * 100, 2) . '%';
750 update_option('bmip_to_be_uploaded', $toBeUploaded);
751
752 if (BMI_DEBUG)
753 Logger::error("After uploadFile - " . print_r($toBeUploaded['current_upload']['batch'], true));
754
755 $test = get_option('bmip_to_be_uploaded', false);
756
757 if (BMI_DEBUG)
758 Logger::error("After updating option uploadFile - " . print_r($test['current_upload']['batch'], true));
759 }
760 } elseif ($code == 507) {
761
762 $error_message_notice = 'Moving backups to your storage is failing or will fail because you don’t have enough space.';
763
764 add_option("bmip_backupbliss_required_space", $filePath);
765 $this->showNotice("upload_issue_space", $error_message_notice, 60 * 60);
766 } elseif ($code == 508) {
767
768 $error_message_notice = 'You’re using more space than allowed. No new backups will be moved to your storage and some of the <b>existing backups will be deleted very soon</b>. ';
769
770 $this->showNotice("upload_issue_space", $error_message_notice, 60 * 60);
771 } elseif ($code == 429) {
772
773 $error_message_notice = 'Upload to BackupBliss could not finish, due to rate limit error.<br />';
774 $error_message_notice .= 'Received message: <i>Too Many Requests in a short amount of time.</i><br />';
775 $error_message_notice .= 'Plugin will retry uploading automatically after 2 minutes.<br />';
776
777 $this->showNotice('upload_issue', $error_message_notice, 60 * 2);
778 } else {
779
780 Logger::error('[BMI PRO] Error during file upload (BackupBliss) code:' . $code);
781 if (isset($response['response_data']) && is_string($response['response_data'])) {
782 Logger::error('[BMI PRO] Message received (body):' . print_r($response['response_data'], true));
783 }
784
785 $error_message_notice = 'Upload to BackupBliss could not finish, due to an error.<br />';
786 if (is_string($response['response_data'])) {
787 $error = json_decode($response['response_data']);
788 if (isset($error->error->message)) {
789 $errorMessage = $error->error->message;
790 $error_message_notice .= "Code: $code - Received message:<i>" . $errorMessage . '</i><br />';
791 } else if ($error == null) {
792 $error_message_notice .= "HTTP Error Response - " . $response["response_data"];
793 }
794 }
795
796 if ($code == 0) {
797 $error_message_notice .= "Received Message: <i>Connection timed out. (This is most likely due to a connection issue in your server.)</i><br />";
798 }
799
800
801
802 $error_message_notice .= "Plugin will retry uploading automatically within a minute since this error.";
803 $this->showNotice("upload_issue", $error_message_notice, 60);
804 }
805
806
807 if (isset($error_message_notice)) {
808 $task = $toBeUploaded['current_upload']['task'];
809 // Requeueing is handled globally
810 // $toBeUploaded['queue'][$task] = [
811 // 'name' => $toBeUploaded['current_upload']['name'],
812 // 'md5' => $toBeUploaded['current_upload']['md5'],
813 // 'json' => $toBeUploaded['current_upload']['json']
814 // ];
815
816 $toBeUploaded['current_upload'] = [];
817 if (!isset($toBeUploaded['failed'])) $toBeUploaded['failed'] = [];
818 if (isset($toBeUploaded['failed'][$task])) $toBeUploaded['failed'][$task]++;
819 else $toBeUploaded['failed'][$task] = 1;
820
821 update_option('bmip_to_be_uploaded', $toBeUploaded);
822 }
823
824 delete_transient('bmip_upload_ongoing');
825 return ['status' => 'success', 'data' => $response];
826 }
827 }
828