PluginProbe ʕ •ᴥ•ʔ
Backup Migration / 2.1.2
Backup Migration v2.1.2
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 / ajax_offline.php
backup-backup / includes Last commit date
banner 3 months ago bodies 3 months ago check 3 months ago cli 3 months ago cron 3 months ago dashboard 3 months ago database 3 months ago external 3 months ago extracter 3 months ago htaccess 3 months ago notices 3 months ago progress 3 months ago scanner 3 months ago staging 3 months ago traits 3 months ago uploader 3 months ago vendor 3 months ago zipper 3 months ago .htaccess 3 months ago activation.php 3 months ago ajax.php 3 months ago ajax_offline.php 3 months ago analyst.php 3 months ago backup-process.php 3 months ago class-backup-method-mananger.php 3 months ago cli-handler.php 3 months ago compatibility.php 3 months ago config.php 3 months ago constants.php 3 months ago file-explorer.php 3 months ago initializer.php 3 months ago logger.php 3 months ago offline.php 3 months ago
ajax_offline.php
855 lines
1 <?php
2
3 // Namespace
4 namespace BMI\Plugin;
5
6 // Uses
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\External\BMI_External_BackupBliss as BackupBliss;
13 use BMI\Plugin\External\BMI_External_Dropbox as Dropbox;
14 use BMI\Plugin\External\BMI_External_GDrive as GDrive;
15 use BMI\Plugin\External\BMI_External_FTP as FTP;
16 use BMI\Plugin\External\BMI_External_S3 as S3;
17 use BMI\Plugin\Dashboard as Dashboard;
18
19 // Exit on direct access
20 if (!defined('ABSPATH')) exit;
21
22 /**
23 * Ajax Offline (unauthorized) Handler for BMI
24 */
25 class BMI_Ajax_Offline
26 {
27
28 public $post;
29 public $backupbliss;
30 public $dropbox;
31 public $gdrive;
32 public $ftp;
33 public $aws;
34 public $wasabi;
35 public $proajax;
36
37
38 public $dropboxStatus = false;
39 public $gdriveStatus = false;
40 public $ftpStatus = false;
41 public $awsStatus = false;
42 public $wasabiStatus = false;
43
44 public function __construct($post)
45 {
46
47 // $POST is sanitized by BMI Basic Version
48 // Do not call this class anywhere else [!]
49 $this->post = $post;
50
51 // Active offline ajax premium side
52 if (defined('BMI_PRO_INC')) {
53 if (BMI_DEBUG)
54 Logger::error("PREMIUM CHECK");
55
56 require_once BMI_PRO_INC . 'ajax_offline.php';
57 $this->proajax = new BMI_Ajax_Offline_Premium($post);
58 }
59
60 $isDropboxEnabled = Dashboard\bmi_get_config('STORAGE::EXTERNAL::DROPBOX');
61 $isGDriveEnabled = Dashboard\bmi_get_config('STORAGE::EXTERNAL::GDRIVE');
62 $isFtpEnabled = Dashboard\bmi_get_config('STORAGE::EXTERNAL::FTP');
63 $isAWSEnabled = Dashboard\bmi_get_config('STORAGE::EXTERNAL::AWS');
64 $isWasabiEnabled = Dashboard\bmi_get_config('STORAGE::EXTERNAL::WASABI');
65
66 $isEnabledDropbox = ($isDropboxEnabled === true || $isDropboxEnabled === 'true') && $this->getDropboxConnectionStatus();
67 $isEnabledGdrive = ($isGDriveEnabled === true || $isGDriveEnabled === 'true') && $this->getGDriveConnectionStatus();
68 $isEnabledFtp = ($isFtpEnabled === true || $isFtpEnabled === 'true') && $this->getFtpConnectionStatus();
69 $isEnabledAWS = ($isAWSEnabled === true || $isAWSEnabled === 'true') && $this->getAWSConnectionStatus();
70 $isEnabledWasabi = ($isWasabiEnabled === true || $isWasabiEnabled === 'true') && $this->getWasabiConnectionStatus();
71
72 if ($isEnabledDropbox) {
73 require_once BMI_INCLUDES . '/external/dropbox.php';
74 $this->dropbox = new Dropbox();
75 }
76
77 if ($isEnabledGdrive) {
78 require_once BMI_INCLUDES . '/external/google-drive.php';
79 $this->gdrive = new GDrive();
80 }
81
82 if ($isEnabledFtp) {
83 require_once BMI_INCLUDES . '/external/ftp.php';
84 $this->ftp = new FTP();
85 }
86
87 if ($isEnabledAWS) {
88 require_once BMI_INCLUDES . '/external/s3.php';
89 $this->aws = new S3('aws');
90 }
91
92 if ($isEnabledWasabi) {
93 require_once BMI_INCLUDES . '/external/s3.php';
94 $this->wasabi = new S3('wasabi');
95 }
96
97 require_once BMI_INCLUDES . '/external/backupbliss.php';
98 $this->backupbliss = new BackupBliss();
99
100 if (is_user_logged_in() && current_user_can('manage_options')) {
101 if ($this->post['f'] == 'check-not-uploaded-backups') {
102
103 $this->checkForBackupsToUpload();
104
105 if ($this->proajax)
106 $this->proajax->checkForBackupsToUpload();
107
108 BMP::res(['status' => 'success']);
109 }
110 }
111
112 if ($this->post['f'] == 'refresh') {
113 BMP::res($this->keepAliveUnAuthorizedRefresh());
114 }
115
116 }
117
118 public function getWasabiConnectionStatus() {
119 require_once BMI_INCLUDES . '/external/s3.php';
120
121 $s3 = new S3('wasabi');
122 $status = $s3->verifyConnection();
123 if (isset($status['result']) && $status['result'] == 'connected') {
124 $this->wasabiStatus = true;
125 return true;
126 } else {
127 return false;
128 }
129 }
130
131
132 public function getDropboxConnectionStatus() {
133 require_once BMI_INCLUDES . '/external/dropbox.php';
134
135 $dropbox = new Dropbox();
136 $status = $dropbox->verifyConnection();
137 if (isset($status['result']) && $status['result'] == 'connected') {
138 $this->dropboxStatus = true;
139 return true;
140 } else {
141 return false;
142 }
143 }
144
145 /**
146 * getGDriveConnectionStatus - Returns Connection Status for PHP
147 *
148 * @return boolean true on connected | false on disconnected
149 */
150 public function getGDriveConnectionStatus()
151 {
152 require_once BMI_INCLUDES . '/external/google-drive.php';
153
154 $gdrive = new GDrive();
155 $status = $gdrive->verifyConnection();
156 if (isset($status['result']) && $status['result'] == 'connected') {
157 $this->gdriveStatus = true;
158 return true;
159 } else {
160 return false;
161 }
162 }
163
164 public function getAWSConnectionStatus() {
165 require_once BMI_INCLUDES . '/external/s3.php';
166
167 $s3 = new S3('aws');
168 $status = $s3->verifyConnection();
169 if (isset($status['result']) && $status['result'] == 'connected') {
170 $this->awsStatus = true;
171 return true;
172 } else {
173 return false;
174 }
175 }
176
177 public function getFtpConnectionStatus()
178 {
179 require_once BMI_INCLUDES . '/external/ftp.php';
180
181
182 $ftp = new FTP();
183 $status = $ftp->verifyConnection();
184 if (isset($status['result']) && $status['result'] == 'connected') {
185 $this->ftpStatus = true;
186 return true;
187 } else {
188 return false;
189 }
190 }
191
192
193 public function getBackupBlissConnectionStatus()
194 {
195 $status = $this->backupbliss->verifyConnection();
196 return isset($status['result']) && $status['result'] == 'connected';
197 }
198 public function checkForBackupsToUpload() {
199 $toBeUploaded = $this->fetchToBeUploaded();
200
201 $task = $toBeUploaded['current_upload'];
202 $queue = $toBeUploaded['queue'];
203
204 //If there's no task or queue present, then check for backups to upload
205 if (sizeof($task) == 0 && sizeof($queue) == 0) {
206 $this->backupbliss->checkForBackupsToUpload();
207 if ($this->dropbox && $this->dropboxStatus) $this->dropbox->checkForBackupsToUploadToDropbox();
208 if ($this->gdrive && $this->gdriveStatus) $this->gdrive->checkForBackupsToUpload();
209 if ($this->ftp && $this->ftpStatus) $this->ftp->checkForBackupsToUpload();
210 if ($this->aws && $this->awsStatus) $this->aws->checkForBackupsToUpload();
211 if ($this->wasabi && $this->wasabiStatus) $this->wasabi->checkForBackupsToUpload();
212
213 //Check for backups premium
214 if ($this->proajax)
215 $this->proajax->checkForBackupsToUpload();
216 }
217
218 //Remove failed tasks if the local backup is deleted
219 if (isset($toBeUploaded['failed'])) {
220 // Local Backups
221 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'scanner' . DIRECTORY_SEPARATOR . 'backups.php';
222 $backups = new Backups();
223 $backupsAvailable = $backups->getAvailableBackups("local");
224 $localBackups = $backupsAvailable['local'];
225 $localBackups = array_reverse($localBackups);
226
227 $failed = $toBeUploaded['failed'];
228 foreach($failed as $failed_task => $failed_count) {
229 $data = explode("_", $failed_task);
230
231
232 if (count($data) == 2) {
233 $cloudtype = $data[0];
234 $md5 = $data[1];
235
236 $md5s = array_map(function($backup) { return $backup[7]; }, $localBackups);
237
238 if (!in_array($md5, $md5s)) {
239 unset($toBeUploaded["failed"][$failed_task]);
240 update_option('bmip_to_be_uploaded', $toBeUploaded);
241 }
242 }
243 }
244 }
245 }
246
247 /**
248 * keepAliveUnAuthorizedRefresh - Unauthorized Keep Alive Request
249 * DO NOT RESPONSE WITH ANY SENSITIVE DATA, ONLY SUCCESS OR FAIL
250 * THIS CAN BE ACCESSED BY ANYONE WITHOUT ANY AUTH
251 *
252 * @return string[] success/fail
253 */
254 public function keepAliveUnAuthorizedRefresh()
255 {
256 //Atomic locking to prevent race conditions
257 $lock_file = BMI_CONFIG_DIR . DIRECTORY_SEPARATOR . '.keep_alive.lock';
258
259 // Open the lock file
260 $fp = fopen($lock_file, 'c');
261
262 // Try to acquire an exclusive lock
263 if (flock($fp, LOCK_EX | LOCK_NB)) {
264 if (BMI_DEBUG)
265 Logger::error("Lock acquired.");
266
267 $ret = $this->keepAliveUnAuthorizedRefreshExec();
268
269 // Release the lock
270 flock($fp, LOCK_UN);
271 if (BMI_DEBUG)
272 Logger::error("Lock released.");
273 return $ret;
274 } else {
275 return ['status' => 'success']; // Lock is already held
276 }
277 }
278
279 private function removeCurrentTask($toBeUploaded) {
280 $toBeUploaded["current_upload"] = []; //Removes the current ttask
281 update_option("bmip_to_be_uploaded", $toBeUploaded);
282
283 return ['status' => 'no_tasks'];
284 }
285
286 private function fetchToBeUploaded() {
287 //Get the option without any caching when used with get_option which prevvents stale data from being retreived.
288 //This is implemented after observing and debugging the issue that sometimes the same batch is uploaded again causing issues.
289 global $wpdb;
290 $bmip_to_be_uploaded = $wpdb->get_var( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s", 'bmip_to_be_uploaded' ) );
291 if ($bmip_to_be_uploaded !== null) {
292 $toBeUploaded = maybe_unserialize($bmip_to_be_uploaded);
293 if (!isset($toBeUploaded['current_upload']))
294 $toBeUploaded['current_upload'] = [];
295 } else {
296 $toBeUploaded = [
297 'current_upload' => [],
298 'queue' => [],
299 'failed' => []
300 ];
301 }
302
303 return $toBeUploaded;
304 }
305
306 private function checkIfBackupCanBeUploaded($type, $taskname) {
307
308 $backupPath = BMI_BACKUPS . DIRECTORY_SEPARATOR . $taskname;
309 $backupSize = file_exists($backupPath) ? filesize($backupPath) : -1;
310
311 switch($type) {
312
313 case "backupbliss": {
314 $storageInfo = $this->backupbliss->getStorageInfo();
315
316 if ($storageInfo["used_space_percent"] > 80 && $storageInfo["used_space_percent"] <= 100) {
317 $error_message_notice = 'It seems you already used more than 80% of your space. <a href="'.BMI_AUTHOR_URI . 'pricing'.'">Get more storage now.</a>';
318
319 $this->backupbliss->showNotice("storage_warn", $error_message_notice, 60 * 60);
320 } elseif($storageInfo["used_space_percent"] > 100) {
321 $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>. ';
322
323 $this->backupbliss->showNotice("upload_issue_space", $error_message_notice, 60 * 60);
324 } else {
325 $this->backupbliss->removeNotice("storage_warn");
326 $this->backupbliss->removeNotice("upload_issue_space");
327 }
328
329 if (!$this->getBackupBlissConnectionStatus()) {
330 return false;
331 }
332
333
334
335 if (!$this->backupbliss->getNotice("upload_issue_space")) {
336
337 if (isset($storageInfo["remaining_space"]))
338 {
339 $remaining = $storageInfo["remaining_space"];
340
341
342 if ($backupSize != -1)
343 {
344 if ($remaining < $backupSize)
345 {
346 $error_message_notice = 'Moving backups to your storage is failing or will fail because you don’t have enough space.';
347
348 add_option("bmip_backupbliss_required_space", $backupPath);
349 $this->backupbliss->showNotice("upload_issue_space", $error_message_notice, 60 * 60);
350 //Triggering the server, so that an alert also get sent
351 $this->backupbliss->initiateUploadSession($backupPath);
352 return false;
353 }
354 }
355
356 }
357 else {
358 Logger::error("[BMI] Couldn't fetch quota from BackupBliss!");
359 }
360 }
361
362 if ($this->backupbliss->getNotice("upload_issue_space")) {
363 return false;
364 }
365
366 break;
367 }
368
369 case "dropbox": {
370 if (!$this->dropbox || !$this->dropboxStatus) return false;
371 if (in_array(get_transient('bmip_dropbox_issue'), ['rate_limit', 'not_enough_memory', 'insufficient_space', 'auth_error_disconnected'])) {
372 $issue = get_transient('bmip_dropbox_issue');
373 switch($issue){
374 case 'auth_error_disconnected':
375 delete_option($this->dropbox->dropboxAuthCodeOption);
376 delete_option($this->dropbox->dropboxId);
377 delete_transient($this->dropbox->dropboxAccessToken);
378 return false;
379 case 'not_enough_memory':
380 if (BMP::getAvailableMemoryInBytes() >= 16 * 1024 * 1024) {
381 delete_transient('bmip_dropbox_issue');
382 return true;
383 }
384 break;
385 case 'insufficient_space':
386 $spaceUsage = $this->dropbox->getSpaceUsage();
387 if ($spaceUsage === false) {
388 return false;
389 }
390
391 $requiredSpace = get_option('bmip_dropbox_required_space', 0);
392 $requiredSpace = intval($requiredSpace);
393 $availableSpace = $spaceUsage['allocation']['allocated'] - $spaceUsage['used'];
394
395 if ($backupSize != -1 && $availableSpace >= $backupSize)
396 return true; //Allow backup to be uploaded if the backup size is within the storage limit
397
398
399 if ($availableSpace >= $requiredSpace) {
400 delete_transient('bmip_dropbox_issue');
401 return true;
402 }
403 break;
404 }
405
406 return false;
407 }
408
409 break;
410 }
411
412 case "gdrive": {
413 if (get_transient('bmip_gd_issue') === 'auth_error_disconnected') {
414 delete_option('bmi_pro_gd_client_id');
415 delete_option('bmi_pro_gd_token');
416 delete_transient('bmi_pro_access_token');
417 return false;
418 }
419 if (!$this->gdrive || !$this->gdriveStatus) return false;
420 if (get_transient('bmip_display_quota_issues')) {
421 $requiredSpace = get_option('bmip_gd_required_space', 0);
422 $gdriveStorage = $this->gdrive->getGoogleDriveAvailableStorage();
423
424 if ($backupSize != -1 && $gdriveStorage >= $backupSize)
425 return true; //Allow backup to be uploaded if the backup size is within the storage limit
426
427 if ($requiredSpace < $gdriveStorage && $requiredSpace != 0) {
428 delete_transient('bmip_display_quota_issues');
429 delete_option('bmip_gd_required_space');
430 delete_option('bmip_to_be_uploaded');
431 } else {
432 return false;
433 }
434 }
435
436 break;
437 }
438
439 case "ftp": {
440 if (!$this->ftp || !$this->ftpStatus) return false;
441
442 break;
443 }
444
445 case "aws": {
446 if (!$this->aws || !$this->awsStatus) return false;
447 $issue = $this->aws->getIssue()['issue'];
448 switch ($issue){
449 case 'rate_limit':
450 return false;
451 case 'disconnected':
452 case 'forbidden':
453 $this->aws->restartUploadProcess();
454 return false;
455 default:
456 return true;
457 }
458 }
459
460 case "wasabi": {
461 if (!$this->wasabi || !$this->wasabiStatus) return false;
462 $issue = $this->wasabi->getIssue()['issue'];
463 switch ($issue){
464 case 'rate_limit':
465 return false;
466 case 'disconnected':
467 case 'forbidden':
468 $this->wasabi->restartUploadProcess();
469 return false;
470 default:
471 return true;
472 }
473 }
474 }
475
476 if ($this->proajax)
477 return $this->proajax->checkIfBackupCanBeUploaded($type, $backupSize);
478
479 return true;
480 }
481
482 private function _removeTasksFromDeactivatedClouds($cltype, $toBeUploaded, $task, $queue, $failed) {
483 if (sizeof($task) > 0 && isset($task['task'])) {
484 $taskname = $task['task'];
485 $type = explode('_', $taskname)[0];
486 if ($type == $cltype)
487 $task = [];
488 }
489
490 if (sizeof($queue) > 0) {
491 $tasks = array_keys($queue);
492 foreach($tasks as $taskname) {
493 $type = explode('_', $taskname)[0];
494 if ($type == $cltype)
495 unset($queue[$taskname]);
496 }
497 }
498
499 if (sizeof($failed) > 0) {
500 $tasks = array_keys($failed);
501 foreach($tasks as $taskname) {
502 $type = explode('_', $taskname)[0];
503 if ($type == $cltype)
504 unset($failed[$taskname]);
505 }
506 }
507
508 $toBeUploaded['current_upload'] = $task;
509 $toBeUploaded['queue'] = $queue;
510 $toBeUploaded['failed'] = $failed;
511 update_option("bmip_to_be_uploaded", $toBeUploaded);
512 }
513
514 public function getDeactivatedClouds() {
515 $deactivatedClouds = [];
516 if (!$this->ftpStatus) $deactivatedClouds[] = "ftp";
517 if (!$this->getBackupBlissConnectionStatus()) $deactivatedClouds[] = "backupbliss";
518 if (!$this->dropboxStatus) $deactivatedClouds[] = "dropbox";
519 if (!$this->gdriveStatus) $deactivatedClouds[] = "gdrive";
520
521 if ($this->proajax)
522 $deactivatedClouds = array_merge($this->proajax->getDeactivatedClouds(), $deactivatedClouds);
523
524 return $deactivatedClouds;
525 }
526
527 public function keepAliveUnAuthorizedRefreshExec() {
528
529 $isOnGoing = get_transient('bmip_upload_ongoing');
530 if ($isOnGoing === '1') return ['status' => 'success']; //Returning success so that the auto pinger will keep on pinging
531
532
533 $toBeUploaded = $this->fetchToBeUploaded();
534
535
536
537 $task = $toBeUploaded['current_upload'];
538 $queue = $toBeUploaded['queue'];
539 $failed = isset($toBeUploaded['failed']) ? $toBeUploaded['failed'] : [];
540
541 foreach ($this->getDeactivatedClouds() as $cloudType)
542 $this->_removeTasksFromDeactivatedClouds($cloudType, $toBeUploaded, $task, $queue, $failed);
543
544
545 //Check for uploads
546 if (get_transient('bmip_check_for_backups_to_upload') !== "wait") {
547 set_transient("bmip_check_for_backups_to_upload", "wait", 10);
548 $this->checkForBackupsToUpload();
549 //Refresh variables after checking for backups to upload
550 $toBeUploaded = $this->fetchToBeUploaded();
551 $task = $toBeUploaded['current_upload'];
552 $queue = $toBeUploaded['queue'];
553 }
554
555 $shouldBeQueued = false;
556
557 if (sizeof($task) > 0 && isset($task['task'])) {
558 $taskname = $task['task'];
559 $type = explode('_', $taskname)[0];
560
561
562 if (!$this->checkIfBackupCanBeUploaded($type, $task['name'])) {
563 $this->removeCurrentTask($toBeUploaded);
564 $type = null; //Set type as null so that no actions will be taken
565 $shouldBeQueued = true; //Set it to queue the next task
566 }
567
568 // BackupBliss
569 if ($type == 'backupbliss') {
570
571 if (!isset($task['uploadSession'])) {
572
573 $backupPath = BMI_BACKUPS . DIRECTORY_SEPARATOR . $task['name'];
574 $manifestPath = BMI_BACKUPS . DIRECTORY_SEPARATOR . $task['json'];
575 $uploadSession = $this->backupbliss->initiateUploadSession($backupPath);
576 if (!$uploadSession)
577 {
578 $this->removeCurrentTask($toBeUploaded);
579 return ['status' => 'success'];
580 }
581
582 $availableMemory = BMP::getAvailableMemoryInBytes();
583 $bytesPerRequest = intval($availableMemory / 4);
584
585 $toBeUploaded['current_upload']['bytesPerRequest'] = $bytesPerRequest;
586 $toBeUploaded['current_upload']['uploadSession'] = $uploadSession;
587 $toBeUploaded['current_upload']['manifestPath'] = $manifestPath;
588 $toBeUploaded['current_upload']['backupPath'] = $backupPath;
589 $toBeUploaded['current_upload']['batch'] = 1;
590
591 update_option('bmip_to_be_uploaded', $toBeUploaded);
592
593 if (!file_exists($backupPath)) delete_option('bmip_to_be_uploaded');
594 return ['status' => 'success'];
595 } else {
596
597 if (!file_exists($task['backupPath'])) {
598 delete_option('bmip_to_be_uploaded');
599 return ['status' => 'success'];
600 }
601
602 $this->backupbliss->uploadFile($task['uploadSession'], $task['backupPath'], $task['manifestPath'], $task['md5'], $task['batch'], $task['bytesPerRequest']);
603 return ['status' => 'success'];
604 }
605 }
606 // Dropbox Process
607 elseif ($type == 'dropbox') {
608
609 $sessionId = isset($task['sessionId']) ? $task['sessionId'] : '';
610 $offset = isset($task['offset']) ? $task['offset'] : 0;
611 $backupName = isset($task['name']) ? $task['name'] : '';
612 $md5 = isset($task['md5']) ? $task['md5'] : '';
613
614 $dropbox = new Dropbox();
615 $result = $dropbox->uploadDropboxBackup($sessionId, $backupName, $offset, $md5);
616 switch ($result['status']) {
617 case 'success':
618 $uploadedBackupStatus = get_option('bmi_uploaded_backups_status', []);
619 if (!isset($uploadedBackupStatus[$md5])) {
620 $uploadedBackupStatus[$md5] = [];
621 }
622 $uploadedBackupStatus[$md5]['dropbox'] = true;
623 update_option('bmi_uploaded_backups_status', $uploadedBackupStatus);
624 $toBeUploaded['current_upload'] = [];
625 if (isset($toBeUploaded['failed']) && isset($toBeUploaded['failed'][$taskname])) unset($toBeUploaded['failed'][$taskname]);
626 break;
627 case 'error':
628 Logger::error('[BMI PRO] Could not upload ' . $backupName . ' to Dropbox as an error occurred: ' . $result['error']);
629
630 if ($result['error'] == 'internal_file_not_found') {
631 return $this->dropbox->restartUploadprocess();
632 }
633
634 if (!isset($toBeUploaded['failed'])) $toBeUploaded['failed'] = [];
635 if (isset($toBeUploaded['failed'][$taskname])) $toBeUploaded['failed'][$taskname]++;
636 else $toBeUploaded['failed'][$taskname] = 1;
637 break;
638 case 'continue':
639 $offset = isset($result['offset']) ? $result['offset'] : 0;
640 $sessionId = isset($result['sessionId']) ? $result['sessionId'] : '';
641 if ($offset != 0 ) $toBeUploaded['current_upload']['offset'] = $offset;
642 if ($sessionId != '') $toBeUploaded['current_upload']['sessionId'] = $sessionId;
643 $fileSize = filesize(BMI_BACKUPS . DIRECTORY_SEPARATOR . $backupName);
644 $toBeUploaded['current_upload']['progress'] = round(($offset / $fileSize) * 100) . '%';
645
646 // remove from failed
647 if (isset($toBeUploaded['failed']) && isset($toBeUploaded['failed'][$taskname])) unset($toBeUploaded['failed'][$taskname]);
648 break;
649 }
650
651 delete_transient("bmip_upload_ongoing");
652 update_option('bmip_to_be_uploaded', $toBeUploaded);
653 return ['status' => 'success'];
654 }
655 // Google Drive Process
656 elseif ($type == 'gdrive') {
657
658 if (!isset($task['uploadURL'])) {
659
660 $backupPath = BMI_BACKUPS . DIRECTORY_SEPARATOR . $task['name'];
661 $manifestPath = BMI_BACKUPS . DIRECTORY_SEPARATOR . $task['json'];
662 $uploadURL = $this->gdrive->createUploadGoogleDriveURL($backupPath, $manifestPath);
663
664 $availableMemory = BMP::getAvailableMemoryInBytes();
665 $bytesPerRequest = intval($availableMemory / 4);
666
667 $toBeUploaded['current_upload']['bytesPerRequest'] = $bytesPerRequest;
668 $toBeUploaded['current_upload']['uploadURL'] = $uploadURL['uploadURL'];
669 $toBeUploaded['current_upload']['manifestPath'] = $manifestPath;
670 $toBeUploaded['current_upload']['backupPath'] = $backupPath;
671 $toBeUploaded['current_upload']['batch'] = 1;
672
673 update_option('bmip_to_be_uploaded', $toBeUploaded);
674
675 if (!file_exists($backupPath)) delete_option('bmip_to_be_uploaded');
676 return ['status' => 'success'];
677 } else {
678
679 if (!file_exists($task['backupPath'])) {
680 delete_option('bmip_to_be_uploaded');
681 return ['status' => 'success'];
682 }
683
684 $this->gdrive->uploadGoogleDriveFile($task['uploadURL'], $task['backupPath'], $task['manifestPath'], $task['md5'], $task['batch'], $task['bytesPerRequest']);
685 return ['status' => 'success'];
686 }
687 }
688 // FTP Process
689 elseif ($type == 'ftp') {
690
691 if (!isset($task['uploadURL'])) {
692 $backupPath = BMI_BACKUPS . DIRECTORY_SEPARATOR . $task['name'];
693 $manifestPath = BMI_BACKUPS . DIRECTORY_SEPARATOR . $task['json'];
694 $availableMemory = BMP::getAvailableMemoryInBytes();
695
696 $bytesPerRequest = intval($availableMemory / 4);
697 $toBeUploaded['current_upload']['bytesPerRequest'] = $bytesPerRequest;
698 $toBeUploaded['current_upload']['uploadURL'] = get_option('bmi_pro_ftp_host');
699 $toBeUploaded['current_upload']['manifestPath'] = $manifestPath;
700 $toBeUploaded['current_upload']['backupPath'] = $backupPath;
701 $toBeUploaded['current_upload']['batch'] = 1;
702
703 update_option('bmip_to_be_uploaded', $toBeUploaded);
704
705 if (!file_exists($backupPath)) delete_option('bmip_to_be_uploaded');
706 return ['status' => 'success'];
707 } else {
708
709 if (!file_exists($task['backupPath'])) {
710 delete_option('bmip_to_be_uploaded');
711 return ['status' => 'success'];
712 }
713 $this->ftp->uploadFtpDriveFiles($task['uploadURL'], $task['backupPath'], $task['manifestPath'], $task['md5'], $task['batch'], $task['bytesPerRequest']);
714 return ['status' => 'success'];
715 }
716
717 }
718 // AWS
719 elseif ($type == 'aws') {
720
721 $uploadId = isset($task['uploadId']) ? $task['uploadId'] : '';
722 $offset = isset($task['offset']) ? $task['offset'] : 0;
723 $backupName = isset($task['name']) ? $task['name'] : '';
724 $md5 = isset($task['md5']) ? $task['md5'] : '';
725
726 $s3 = new S3('aws');
727
728 $result = $s3->uploadBackup($uploadId, $backupName, $offset, $md5);
729 switch ($result['status']) {
730 case 'success':
731 $uploadedBackupStatus = get_option('bmi_uploaded_backups_status', []);
732 if (!isset($uploadedBackupStatus[$md5])) {
733 $uploadedBackupStatus[$md5] = [];
734 }
735 $uploadedBackupStatus[$md5]['aws'] = true;
736 update_option('bmi_uploaded_backups_status', $uploadedBackupStatus);
737 $toBeUploaded['current_upload'] = [];
738 if (isset($toBeUploaded['failed']) && isset($toBeUploaded['failed'][$taskname])) unset($toBeUploaded['failed'][$taskname]);
739 break;
740 case 'error':
741 Logger::error('[BMI PRO] Could not upload ' . $backupName . ' to AWS S3 as an error occurred: ' . $result['error']);
742
743 $toBeUploaded['current_upload'] = [];
744 if (!isset($toBeUploaded['failed'])) $toBeUploaded['failed'] = [];
745 if (isset($toBeUploaded['failed'][$taskname])) $toBeUploaded['failed'][$taskname]++;
746 else $toBeUploaded['failed'][$taskname] = 1;
747 break;
748 case 'continue':
749 $offset = isset($result['offset']) ? $result['offset'] : 0;
750 $uploadId = isset($result['uploadId']) ? $result['uploadId'] : '';
751 if ($offset != 0 ) $toBeUploaded['current_upload']['offset'] = $offset;
752 if ($uploadId != '') $toBeUploaded['current_upload']['uploadId'] = $uploadId;
753 $fileSize = filesize(BMI_BACKUPS . DIRECTORY_SEPARATOR . $backupName);
754 $toBeUploaded['current_upload']['progress'] = round(($offset / $fileSize) * 100) . '%';
755
756 // remove from failed
757 if (isset($toBeUploaded['failed']) && isset($toBeUploaded['failed'][$taskname])) unset($toBeUploaded['failed'][$taskname]);
758 break;
759 }
760
761 delete_transient("bmip_upload_ongoing");
762 update_option('bmip_to_be_uploaded', $toBeUploaded);
763 return ['status' => 'success'];
764 }
765 //Wasabi
766 elseif ($type == 'wasabi') {
767
768 $uploadId = isset($task['uploadId']) ? $task['uploadId'] : '';
769 $offset = isset($task['offset']) ? $task['offset'] : 0;
770 $backupName = isset($task['name']) ? $task['name'] : '';
771 $md5 = isset($task['md5']) ? $task['md5'] : '';
772
773 $s3 = new S3('wasabi');
774
775 $result = $s3->uploadBackup($uploadId, $backupName, $offset, $md5);
776 switch ($result['status']) {
777 case 'success':
778 $uploadedBackupStatus = get_option('bmi_uploaded_backups_status', []);
779 if (!isset($uploadedBackupStatus[$md5])) {
780 $uploadedBackupStatus[$md5] = [];
781 }
782 $uploadedBackupStatus[$md5]['wasabi'] = true;
783 update_option('bmi_uploaded_backups_status', $uploadedBackupStatus);
784 $toBeUploaded['current_upload'] = [];
785 if (isset($toBeUploaded['failed']) && isset($toBeUploaded['failed'][$taskname])) unset($toBeUploaded['failed'][$taskname]);
786 break;
787 case 'error':
788 Logger::error('[BMI PRO] Could not upload ' . $backupName . ' to Wasabi as an error occurred: ' . $result['error']);
789
790 $toBeUploaded['current_upload'] = [];
791 if (!isset($toBeUploaded['failed'])) $toBeUploaded['failed'] = [];
792 if (isset($toBeUploaded['failed'][$taskname])) $toBeUploaded['failed'][$taskname]++;
793 else $toBeUploaded['failed'][$taskname] = 1;
794 break;
795 case 'continue':
796 $offset = isset($result['offset']) ? $result['offset'] : 0;
797 $uploadId = isset($result['uploadId']) ? $result['uploadId'] : '';
798 if ($offset != 0 ) $toBeUploaded['current_upload']['offset'] = $offset;
799 if ($uploadId != '') $toBeUploaded['current_upload']['uploadId'] = $uploadId;
800 $fileSize = filesize(BMI_BACKUPS . DIRECTORY_SEPARATOR . $backupName);
801 $toBeUploaded['current_upload']['progress'] = round(($offset / $fileSize) * 100) . '%';
802
803 // remove from failed
804 if (isset($toBeUploaded['failed']) && isset($toBeUploaded['failed'][$taskname])) unset($toBeUploaded['failed'][$taskname]);
805 break;
806 }
807
808 delete_transient("bmip_upload_ongoing");
809 update_option('bmip_to_be_uploaded', $toBeUploaded);
810 return ['status' => 'success'];
811 }
812 elseif ($this->proajax) {
813 $ret = $this->proajax->processClouds($type, $task, $toBeUploaded, $taskname);
814 if ($ret["status"] !== "no_tasks")
815 return $ret;
816 }
817
818 } else {
819 $shouldBeQueued = true;
820 }
821
822 if ($shouldBeQueued && sizeof($queue) > 0) {
823
824 $tasks = array_keys($queue);
825 if (sizeof($tasks) > 0) {
826
827 $selectedTask = $tasks[0];
828 $cloudType = explode("_", $selectedTask)[0];
829 $toBeProcessed = $queue[$selectedTask];
830
831 if ($this->checkIfBackupCanBeUploaded($cloudType, $toBeProcessed['name'])) {
832 $toBeUploaded['current_upload'] = [
833 'task' => $selectedTask,
834 'name' => $toBeProcessed['name'],
835 'md5' => $toBeProcessed['md5'],
836 'json' => $toBeProcessed['json'],
837 'progress' => '0%'
838 ];
839 } else {
840 if (isset($toBeUploaded['failed']))
841 $toBeUploaded['failed'][$selectedTask] = 1; //Mark the task as failed
842 }
843
844 unset($toBeUploaded['queue'][$selectedTask]);
845 update_option('bmip_to_be_uploaded', $toBeUploaded);
846
847 //Return success if there are more tasks in the queue, so auto pinger can ping rapidly
848 return ['status' => sizeof($queue) > 0 ? 'success' : 'no_tasks'];
849 } else return ['status' => 'no_tasks'];
850 } else return ['status' => 'no_tasks'];
851
852 return ['status' => 'no_tasks'];
853 }
854 }
855