XCloner – Backup and Restore - Version 4.4.2

Version Description

  • fix: https://github.com/watchfulli/XCloner-Wordpress/issues/227
  • fix: https://github.com/watchfulli/XCloner-Wordpress/issues/231
Download this release

Release Info

Developer watchful
Plugin Icon 128x128 XCloner – Backup and Restore
Version 4.4.2
Comparing to
See all releases

Code changes from version 4.4.1 to 4.4.2

README.txt CHANGED
@@ -5,7 +5,7 @@ Tags: backup, database backup, cloud backup, WordPress backup, WordPress migrati
5
  Requires at least: 5.1
6
  Requires PHP: 7.3
7
  Tested up to: 6.0
8
- Stable tag: 4.4.1
9
 
10
 
11
  XCloner is a backup plugin that allows you to safely back up and restore your WordPress sites. You can send site backups to SFTP, Dropbox, Amazon, Google Drive, Backblaze and other locations.
@@ -117,6 +117,11 @@ Of course, schedules can be adjusted accordingly to how often you update your si
117
 
118
  == Changelog ==
119
 
 
 
 
 
 
120
  = 4.4.1 =
121
  * minor code review
122
 
5
  Requires at least: 5.1
6
  Requires PHP: 7.3
7
  Tested up to: 6.0
8
+ Stable tag: 4.4.2
9
 
10
 
11
  XCloner is a backup plugin that allows you to safely back up and restore your WordPress sites. You can send site backups to SFTP, Dropbox, Amazon, Google Drive, Backblaze and other locations.
117
 
118
  == Changelog ==
119
 
120
+ = 4.4.2 =
121
+ * fix: https://github.com/watchfulli/XCloner-Wordpress/issues/227
122
+ * fix: https://github.com/watchfulli/XCloner-Wordpress/issues/231
123
+
124
+
125
  = 4.4.1 =
126
  * minor code review
127
 
admin/partials/remote_storage/backblaze.php CHANGED
@@ -28,6 +28,10 @@ if (!defined('WPINC')) {
28
  <p>
29
  <?php echo sprintf(__('Visit %s and get your KeyID and applicationKey.', 'xcloner-backup-and-restore'), '<a href="https://secure.backblaze.com/b2_buckets.htm" target="_blank">https://secure.backblaze.com/b2_buckets.htm</a>') ?>
30
  </p>
 
 
 
 
31
  </div>
32
  </div>
33
 
@@ -69,6 +73,18 @@ if (!defined('WPINC')) {
69
  </div>
70
  </div>
71
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  <?php echo common_cleanup_html('backblaze')?>
73
 
74
  <div class="row">
28
  <p>
29
  <?php echo sprintf(__('Visit %s and get your KeyID and applicationKey.', 'xcloner-backup-and-restore'), '<a href="https://secure.backblaze.com/b2_buckets.htm" target="_blank">https://secure.backblaze.com/b2_buckets.htm</a>') ?>
30
  </p>
31
+ <p>
32
+ If you specify <strong>only the bucket name</strong>, you must use the <strong>master key</strong>.<br>
33
+ However, if you specify <strong>both bucket name and bucket id</strong>, you do not need the master key and can use a <strong>single-bucket key</strong>.
34
+ </p>
35
  </div>
36
  </div>
37
 
73
  </div>
74
  </div>
75
 
76
+ <div class="row">
77
+ <div class="col s12 m3 label">
78
+ <label
79
+ for="backblaze_bucket_id"><?php echo __("Backblaze Bucket ID", 'xcloner-backup-and-restore') ?></label>
80
+ </div>
81
+ <div class=" col s12 m6">
82
+ <input placeholder="<?php echo __("Backblaze Bucket ID", 'xcloner-backup-and-restore') ?>"
83
+ id="backblaze_bucket_id" type="text" name="xcloner_backblaze_bucket_id" class="validate"
84
+ value="<?php echo esc_attr(get_option("xcloner_backblaze_bucket_id")) ?>" autocomplete="off">
85
+ </div>
86
+ </div>
87
+
88
  <?php echo common_cleanup_html('backblaze')?>
89
 
90
  <div class="row">
lib/Xcloner.php CHANGED
@@ -755,7 +755,7 @@ class Xcloner
755
  }
756
 
757
  /**
758
- * Run the loader to execute all of the hooks with WordPress.
759
  *
760
  * @since 1.0.0
761
  */
@@ -800,7 +800,7 @@ class Xcloner
800
  $data['id'] = $profile_id;
801
  }
802
 
803
- $this->xcloner_scheduler->xcloner_scheduler_callback($data['id'], $data, $this);
804
  }
805
 
806
  /**
755
  }
756
 
757
  /**
758
+ * Run the loader to execute all the hooks with WordPress.
759
  *
760
  * @since 1.0.0
761
  */
800
  $data['id'] = $profile_id;
801
  }
802
 
803
+ $this->xcloner_scheduler->xcloner_scheduler_callback($data['id'], $data);
804
  }
805
 
806
  /**
lib/Xcloner_Api.php CHANGED
@@ -646,10 +646,8 @@ class Xcloner_Api
646
  $this->send_response($data, 0);
647
  }
648
 
649
- /*
650
- *
651
- * Get schedule by id API
652
- *
653
  */
654
  public function get_schedule_by_id()
655
  {
@@ -670,11 +668,6 @@ class Xcloner_Api
670
  $this->send_response($data);
671
  }
672
 
673
- /*
674
- *
675
- * Get Schedule list API
676
- *
677
- */
678
  public function get_scheduler_list()
679
  {
680
  $return = array();
646
  $this->send_response($data, 0);
647
  }
648
 
649
+ /**
650
+ * @throws Exception
 
 
651
  */
652
  public function get_schedule_by_id()
653
  {
668
  $this->send_response($data);
669
  }
670
 
 
 
 
 
 
671
  public function get_scheduler_list()
672
  {
673
  $return = array();
lib/Xcloner_Remote_Storage.php CHANGED
@@ -163,6 +163,7 @@ class Xcloner_Remote_Storage
163
  "backblaze_account_id" => "string",
164
  "backblaze_application_key" => "raw",
165
  "backblaze_bucket_name" => "string",
 
166
  "backblaze_cleanup_retention_limit_days" => "float",
167
  "backblaze_cleanup_exclude_days" => "string",
168
  "backblaze_cleanup_retention_limit_archives" => "int",
@@ -671,7 +672,14 @@ class Xcloner_Remote_Storage
671
  $this->xcloner_settings->get_xcloner_option("xcloner_backblaze_account_id"),
672
  $this->xcloner_settings->get_xcloner_option("xcloner_backblaze_application_key")
673
  );
674
- $adapter = new BackblazeAdapter($client, $this->xcloner_settings->get_xcloner_option("xcloner_backblaze_bucket_name"));
 
 
 
 
 
 
 
675
 
676
  $filesystem = new Filesystem($adapter, new Config([
677
  'disable_asserts' => true,
163
  "backblaze_account_id" => "string",
164
  "backblaze_application_key" => "raw",
165
  "backblaze_bucket_name" => "string",
166
+ "backblaze_bucket_id" => "string",
167
  "backblaze_cleanup_retention_limit_days" => "float",
168
  "backblaze_cleanup_exclude_days" => "string",
169
  "backblaze_cleanup_retention_limit_archives" => "int",
672
  $this->xcloner_settings->get_xcloner_option("xcloner_backblaze_account_id"),
673
  $this->xcloner_settings->get_xcloner_option("xcloner_backblaze_application_key")
674
  );
675
+
676
+ $bucket_id = $this->xcloner_settings->get_xcloner_option("xcloner_backblaze_bucket_id");
677
+
678
+ $adapter = new BackblazeAdapter(
679
+ $client,
680
+ $this->xcloner_settings->get_xcloner_option("xcloner_backblaze_bucket_name"),
681
+ empty($bucket_id) ? null : $bucket_id,
682
+ );
683
 
684
  $filesystem = new Filesystem($adapter, new Config([
685
  'disable_asserts' => true,
lib/Xcloner_Scheduler.php CHANGED
@@ -3,54 +3,32 @@
3
  namespace Watchfulli\XClonerCore;
4
 
5
  use Exception;
 
 
 
 
6
 
7
  class Xcloner_Scheduler
8
  {
9
- private $db;
10
  private $scheduler_table = "xcloner_scheduler";
11
 
12
- private $xcloner_remote_storage;
13
- private $archive_system;
14
- private $xcloner_database;
15
- private $xcloner_settings;
16
  private $logger;
17
- private $xcloner_file_system;
18
- private $xcloner_encryption;
19
  private $xcloner_container;
20
 
21
  private $allowed_schedules = array("hourly", "twicedaily", "daily", "weekly", "monthly");
22
 
23
- /*public function __call($method, $args) {
24
- echo "$method is not defined";
25
- }*/
26
-
27
  public function __construct(Xcloner $xcloner_container)
28
  {
29
- //global $wpdb;
30
-
31
  $this->xcloner_container = $xcloner_container;
32
- $this->xcloner_database = $this->get_xcloner_container()->get_xcloner_database();
33
- $this->xcloner_settings = $this->xcloner_container->get_xcloner_settings();
34
 
35
- $this->db = $this->xcloner_database;
36
- $this->db->show_errors = false;
37
 
38
- $this->scheduler_table = $this->xcloner_settings->get_table_prefix() . $this->scheduler_table;
39
- }
40
-
41
- private function get_xcloner_container()
42
- {
43
- return $this->xcloner_container;
44
- }
45
-
46
- private function set_xcloner_container(Xcloner $container)
47
- {
48
- $this->xcloner_container = $container;
49
  }
50
 
51
  public function get_scheduler_list($return_only_enabled = 0)
52
  {
53
- $list = $this->db->get_results("SELECT * FROM " . $this->scheduler_table);
54
 
55
  if (!$list) {
56
  return array();
@@ -61,7 +39,7 @@ class Xcloner_Scheduler
61
 
62
  foreach ($list as $res) {
63
  if ($res->status) {
64
- $res->next_run_time = wp_next_scheduled('xcloner_scheduler_' . $res->id, array($res->id)) + ($this->xcloner_settings->get_xcloner_option('gmt_offset') * HOUR_IN_SECONDS);
65
  if ($res->next_run_time) {
66
  $new_list[] = $res;
67
  }
@@ -75,14 +53,12 @@ class Xcloner_Scheduler
75
 
76
  public function get_next_run_schedule()
77
  {
78
- $list = $this->get_scheduler_list($return_only_enabled = 1);
79
-
80
- return $list;
81
  }
82
 
83
  public function get_schedule_by_id_object($id)
84
  {
85
- $data = $this->db->get_row("SELECT * FROM " . $this->scheduler_table . " WHERE id=" . $id);
86
 
87
  if (!$data) {
88
  return false;
@@ -92,39 +68,32 @@ class Xcloner_Scheduler
92
  }
93
 
94
  /**
95
- * Get schedule by id or name
96
- *
97
- * @param [type] $id
98
- * @return array
99
  */
100
  public function get_schedule_by_id_or_name($id)
101
  {
102
- $data = $this->db->get_row("SELECT * FROM " . $this->scheduler_table . " WHERE id='" . $id . "' or name='" . $id . "'", ARRAY_A);
103
 
104
  if (!$data) {
105
- return false;
106
  }
107
 
108
  return $data;
109
  }
110
 
111
  /**
112
- * Get schedule by id
113
- *
114
- * @param [type] $id
115
- * @return array
116
  */
117
  public function get_schedule_by_id($id)
118
  {
119
- $data = $this->db->get_row("SELECT * FROM " . $this->scheduler_table . " WHERE id=" . $id, ARRAY_A);
120
 
121
  if (!$data) {
122
- return false;
123
  }
124
 
125
  $params = json_decode($data['params']);
126
 
127
- //print_r($params);
128
  $data['params'] = "";
129
  $data['backup_params'] = $params->backup_params;
130
  $data['table_params'] = json_encode($params->database);
@@ -138,9 +107,7 @@ class Xcloner_Scheduler
138
  $hook = 'xcloner_scheduler_' . $id;
139
  wp_clear_scheduled_hook($hook, array($id));
140
 
141
- $data = $this->db->delete($this->scheduler_table, array('id' => $id));
142
-
143
- return $data;
144
  }
145
 
146
  public function deactivate_wp_cron_hooks()
@@ -164,9 +131,9 @@ class Xcloner_Scheduler
164
  $hook = 'xcloner_scheduler_' . $schedule->id;
165
 
166
  //adding the xcloner_scheduler hook with xcloner_scheduler_callback callback
167
- $this->xcloner_container->get_xcloner_loader()->add_action($hook, [$this, 'xcloner_scheduler_callback'], 10, 1);
168
 
169
- if (!wp_next_scheduled($hook, array($schedule->id)) and $schedule->status) {
170
  if ($schedule->recurrence == "single") {
171
  wp_schedule_single_event(strtotime($schedule->start_at), $hook, array($schedule->id));
172
  } else {
@@ -209,7 +176,7 @@ class Xcloner_Scheduler
209
 
210
  $schedule['status'] = 0;
211
 
212
- $update = $this->db->update(
213
  $this->scheduler_table,
214
  $schedule,
215
  array('id' => $schedule_id),
@@ -218,8 +185,6 @@ class Xcloner_Scheduler
218
  '%s'
219
  )
220
  );
221
-
222
- return $update;
223
  }
224
 
225
  public function update_hash($schedule_id, $hash)
@@ -228,7 +193,7 @@ class Xcloner_Scheduler
228
 
229
  $schedule['hash'] = $hash;
230
 
231
- $update = $this->db->update(
232
  $this->scheduler_table,
233
  $schedule,
234
  array('id' => $schedule_id),
@@ -237,8 +202,6 @@ class Xcloner_Scheduler
237
  '%s'
238
  )
239
  );
240
-
241
- return $update;
242
  }
243
 
244
  public function update_last_backup($schedule_id, $last_backup)
@@ -249,7 +212,7 @@ class Xcloner_Scheduler
249
 
250
  $schedule['last_backup'] = $last_backup;
251
 
252
- $update = $this->db->update(
253
  $this->scheduler_table,
254
  $schedule,
255
  array('id' => $schedule_id),
@@ -258,21 +221,14 @@ class Xcloner_Scheduler
258
  '%s'
259
  )
260
  );
261
-
262
- return $update;
263
  }
264
 
265
- private function _xcloner_scheduler_callback($id, $schedule, $xcloner = "")
266
  {
267
  set_time_limit(0);
268
 
269
  $start_time = time();
270
 
271
- if (!$xcloner) {
272
- $xcloner = new \XCloner();
273
- $xcloner->init();
274
- }
275
- $this->set_xcloner_container($xcloner);
276
  $return_encrypted = array();
277
  $return = array();
278
  $additional = array();
@@ -285,25 +241,14 @@ class Xcloner_Scheduler
285
  $schedule['name'] = 'standalone';
286
  }
287
 
288
- #$hash = $this->xcloner_settings->get_hash();
289
- #$this->get_xcloner_container()->get_xcloner_settings()->set_hash($hash);
290
-
291
- //$this->xcloner_settings = $this->get_xcloner_container()->get_xcloner_settings();
292
- $this->xcloner_file_system = $this->get_xcloner_container()->get_xcloner_filesystem();
293
- $this->xcloner_encryption = $this->get_xcloner_container()->get_xcloner_encryption();
294
- $this->xcloner_database = $this->get_xcloner_container()->get_xcloner_database();
295
- $this->archive_system = $this->get_xcloner_container()->get_archive_system();
296
- $this->logger = $this->get_xcloner_container()->get_xcloner_logger()->withName("xcloner_scheduler");
297
- $this->xcloner_remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
298
-
299
 
300
- $this->db = $this->xcloner_database;
301
- $this->db->show_errors = false;
302
 
303
- $this->logger->info(sprintf("New schedule hash is %s", $this->xcloner_settings->get_hash()));
304
 
305
  if (isset($schedule['backup_params']->diff_start_date) && $schedule['backup_params']->diff_start_date) {
306
- $this->xcloner_file_system->set_diff_timestamp_start($schedule['backup_params']->diff_start_date);
307
  }
308
 
309
 
@@ -317,21 +262,19 @@ class Xcloner_Scheduler
317
  return;
318
  }
319
 
320
- //echo $this->get_xcloner_container()->get_xcloner_settings()->get_hash(); exit;
321
- if (!$xcloner) {
322
- //we update this only in WP mode
323
- $this->update_hash($schedule['id'], $this->xcloner_settings->get_hash());
324
  }
325
 
326
  $this->logger->print_info(sprintf("Starting backup profile '%s'", $schedule['name']), array("CRON"));
327
 
328
- $this->xcloner_file_system->set_excluded_files(json_decode($schedule['excluded_files']));
329
 
330
  $init = 1;
331
  $continue = 1;
332
 
333
  while ($continue) {
334
- $continue = $this->xcloner_file_system->start_file_recursion($init);
335
 
336
  $init = 0;
337
  }
@@ -344,7 +287,7 @@ class Xcloner_Scheduler
344
  $return['finished'] = 0;
345
 
346
  while (!$return['finished']) {
347
- $return = $this->xcloner_database->start_database_recursion((array)json_decode($schedule['table_params']), $return, $init);
348
  $init = 0;
349
  }
350
 
@@ -357,15 +300,15 @@ class Xcloner_Scheduler
357
  $return['extra'] = array();
358
 
359
  while (!$return['finished']) {
360
- $return = $this->archive_system->start_incremental_backup((array)$schedule['backup_params'], $return['extra'], $init);
361
  $init = 0;
362
  }
363
  $this->logger->print_info(sprintf("File archive process FINISHED."), array("CRON"));
364
 
365
  //getting the last backup archive file
366
- $return['extra']['backup_parent'] = $this->archive_system->get_archive_name_with_extension();
367
- if ($this->xcloner_file_system->is_part($this->archive_system->get_archive_name_with_extension())) {
368
- $return['extra']['backup_parent'] = $this->archive_system->get_archive_name_multipart();
369
  }
370
 
371
  //Updating schedule last backup archive
@@ -384,13 +327,13 @@ class Xcloner_Scheduler
384
 
385
  $backup_file = $return['extra']['backup_parent'];
386
 
387
- if ($this->xcloner_file_system->is_multipart($return['extra']['backup_parent'])) {
388
- $backup_parts = $this->xcloner_file_system->get_multipart_files($return['extra']['backup_parent']);
389
  $backup_file = $backup_parts[$part];
390
  }
391
 
392
  while (!$return_encrypted['finished']) {
393
- $return_encrypted = $this->xcloner_encryption->encrypt_file(
394
  $backup_file,
395
  "",
396
  "",
@@ -411,17 +354,17 @@ class Xcloner_Scheduler
411
  }
412
  }
413
 
414
- $additional['backup_size'] = size_format($this->xcloner_file_system->get_backup_size($return['extra']['backup_parent']));
415
 
416
  //Sending backup to remote storage
417
- if (isset($schedule['remote_storage']) && $schedule['remote_storage'] && array_key_exists($schedule['remote_storage'], $this->xcloner_remote_storage->get_available_storages())) {
418
  $backup_file = $return['extra']['backup_parent'];
419
 
420
  $this->logger->print_info(sprintf("Transferring backup to remote storage %s", strtoupper($schedule['remote_storage'])), array("CRON"));
421
 
422
- if (method_exists($this->xcloner_remote_storage, "upload_backup_to_storage")) {
423
  call_user_func_array(array(
424
- $this->xcloner_remote_storage,
425
  "upload_backup_to_storage"
426
  ), array($backup_file, $schedule['remote_storage'], $schedule['backup_params']->backup_delete_after_remote_transfer));
427
  }
@@ -434,49 +377,55 @@ class Xcloner_Scheduler
434
  $additional['lines_total'] = $return['extra']['lines_total'];
435
  $subject = sprintf(__("%s - new backup generated %s"), $schedule['name'], $return['extra']['backup_parent']);
436
 
437
- $this->archive_system->send_notification($to, $from, $subject, $return['extra']['backup_parent'], $schedule, "", $additional);
438
  } catch (Exception $e) {
439
  $this->logger->error($e->getMessage());
440
  }
441
  }
442
 
443
  //Backup Storage Cleanup
444
- $this->xcloner_file_system->backup_storage_cleanup();
445
 
446
  //Filesystem Cleanup
447
- $this->xcloner_file_system->cleanup_tmp_directories();
448
 
449
  //Removing the tmp filesystem used for backup
450
- $this->xcloner_file_system->remove_tmp_filesystem();
451
 
452
  $this->logger->print_info(sprintf("Profile '%s' finished in %d seconds.", $schedule['name'], time() - $start_time), array("CRON"));
453
 
454
  return $return;
455
  }
456
 
457
- public function xcloner_scheduler_callback($id, $schedule = "", $xcloner = "")
 
 
 
 
 
 
458
  {
459
- if ($id) {
460
- $schedule = $this->get_schedule_by_id($id);
461
- }
462
-
463
  try {
464
- if ($this->xcloner_settings->get_xcloner_option('xcloner_disable_email_notification')) {
 
 
 
 
465
  //we disable email notifications
466
  $schedule['backup_params']->email_notification = "";
467
  }
468
 
469
- $this->_xcloner_scheduler_callback($id, $schedule, $xcloner);
470
  } catch (Exception $e) {
471
 
472
  //send email to site admin if email notification is not set in the scheduler
473
  if (!isset($schedule['backup_params']->email_notification) || !$schedule['backup_params']->email_notification) {
474
- $schedule['backup_params']->email_notification = $this->xcloner_settings->get_xcloner_option('admin_email');
475
  }
476
 
477
  if (isset($schedule['backup_params']->email_notification) && $to = $schedule['backup_params']->email_notification) {
478
  $from = "";
479
- $this->archive_system->send_notification($to, $from, $schedule['name'] . " - backup error", "", "", $e->getMessage());
480
  }
481
  }
482
  }
3
  namespace Watchfulli\XClonerCore;
4
 
5
  use Exception;
6
+ use splitbrain\PHPArchive\ArchiveCorruptedException;
7
+ use splitbrain\PHPArchive\ArchiveIllegalCompressionException;
8
+ use splitbrain\PHPArchive\ArchiveIOException;
9
+ use splitbrain\PHPArchive\FileInfoException;
10
 
11
  class Xcloner_Scheduler
12
  {
 
13
  private $scheduler_table = "xcloner_scheduler";
14
 
 
 
 
 
15
  private $logger;
 
 
16
  private $xcloner_container;
17
 
18
  private $allowed_schedules = array("hourly", "twicedaily", "daily", "weekly", "monthly");
19
 
 
 
 
 
20
  public function __construct(Xcloner $xcloner_container)
21
  {
 
 
22
  $this->xcloner_container = $xcloner_container;
 
 
23
 
24
+ $this->xcloner_container->get_xcloner_database()->show_errors = false;
 
25
 
26
+ $this->scheduler_table = $this->xcloner_container->get_xcloner_settings()->get_table_prefix() . $this->scheduler_table;
 
 
 
 
 
 
 
 
 
 
27
  }
28
 
29
  public function get_scheduler_list($return_only_enabled = 0)
30
  {
31
+ $list = $this->xcloner_container->get_xcloner_database()->get_results("SELECT * FROM " . $this->scheduler_table);
32
 
33
  if (!$list) {
34
  return array();
39
 
40
  foreach ($list as $res) {
41
  if ($res->status) {
42
+ $res->next_run_time = wp_next_scheduled('xcloner_scheduler_' . $res->id, array($res->id)) + ($this->xcloner_container->get_xcloner_settings()->get_xcloner_option('gmt_offset') * HOUR_IN_SECONDS);
43
  if ($res->next_run_time) {
44
  $new_list[] = $res;
45
  }
53
 
54
  public function get_next_run_schedule()
55
  {
56
+ return $this->get_scheduler_list($return_only_enabled = 1);
 
 
57
  }
58
 
59
  public function get_schedule_by_id_object($id)
60
  {
61
+ $data = $this->xcloner_container->get_xcloner_database()->get_row("SELECT * FROM " . $this->scheduler_table . " WHERE id=" . $id);
62
 
63
  if (!$data) {
64
  return false;
68
  }
69
 
70
  /**
71
+ * @throws Exception
 
 
 
72
  */
73
  public function get_schedule_by_id_or_name($id)
74
  {
75
+ $data = $this->xcloner_container->get_xcloner_database()->get_row("SELECT * FROM " . $this->scheduler_table . " WHERE id='" . $id . "' or name='" . $id . "'", ARRAY_A);
76
 
77
  if (!$data) {
78
+ throw new Exception("Schedule not found");
79
  }
80
 
81
  return $data;
82
  }
83
 
84
  /**
85
+ * @throws Exception
 
 
 
86
  */
87
  public function get_schedule_by_id($id)
88
  {
89
+ $data = $this->xcloner_container->get_xcloner_database()->get_row("SELECT * FROM " . $this->scheduler_table . " WHERE id=" . $id, ARRAY_A);
90
 
91
  if (!$data) {
92
+ throw new Exception("Schedule not found");
93
  }
94
 
95
  $params = json_decode($data['params']);
96
 
 
97
  $data['params'] = "";
98
  $data['backup_params'] = $params->backup_params;
99
  $data['table_params'] = json_encode($params->database);
107
  $hook = 'xcloner_scheduler_' . $id;
108
  wp_clear_scheduled_hook($hook, array($id));
109
 
110
+ return $this->xcloner_container->get_xcloner_database()->delete($this->scheduler_table, array('id' => $id));
 
 
111
  }
112
 
113
  public function deactivate_wp_cron_hooks()
131
  $hook = 'xcloner_scheduler_' . $schedule->id;
132
 
133
  //adding the xcloner_scheduler hook with xcloner_scheduler_callback callback
134
+ $this->xcloner_container->get_xcloner_loader()->add_action($hook, [$this, 'xcloner_scheduler_callback']);
135
 
136
+ if (!wp_next_scheduled($hook, array($schedule->id)) && $schedule->status) {
137
  if ($schedule->recurrence == "single") {
138
  wp_schedule_single_event(strtotime($schedule->start_at), $hook, array($schedule->id));
139
  } else {
176
 
177
  $schedule['status'] = 0;
178
 
179
+ return $this->xcloner_container->get_xcloner_database()->update(
180
  $this->scheduler_table,
181
  $schedule,
182
  array('id' => $schedule_id),
185
  '%s'
186
  )
187
  );
 
 
188
  }
189
 
190
  public function update_hash($schedule_id, $hash)
193
 
194
  $schedule['hash'] = $hash;
195
 
196
+ return $this->xcloner_container->get_xcloner_database()->update(
197
  $this->scheduler_table,
198
  $schedule,
199
  array('id' => $schedule_id),
202
  '%s'
203
  )
204
  );
 
 
205
  }
206
 
207
  public function update_last_backup($schedule_id, $last_backup)
212
 
213
  $schedule['last_backup'] = $last_backup;
214
 
215
+ return $this->xcloner_container->get_xcloner_database()->update(
216
  $this->scheduler_table,
217
  $schedule,
218
  array('id' => $schedule_id),
221
  '%s'
222
  )
223
  );
 
 
224
  }
225
 
226
+ private function _xcloner_scheduler_callback($id, $schedule)
227
  {
228
  set_time_limit(0);
229
 
230
  $start_time = time();
231
 
 
 
 
 
 
232
  $return_encrypted = array();
233
  $return = array();
234
  $additional = array();
241
  $schedule['name'] = 'standalone';
242
  }
243
 
244
+ $this->logger = $this->xcloner_container->get_xcloner_logger()->withName("xcloner_scheduler");
 
 
 
 
 
 
 
 
 
 
245
 
246
+ $this->xcloner_container->get_xcloner_database()->show_errors = false;
 
247
 
248
+ $this->logger->info(sprintf("New schedule hash is %s", $this->xcloner_container->get_xcloner_settings()->get_hash()));
249
 
250
  if (isset($schedule['backup_params']->diff_start_date) && $schedule['backup_params']->diff_start_date) {
251
+ $this->xcloner_container->get_xcloner_filesystem()->set_diff_timestamp_start($schedule['backup_params']->diff_start_date);
252
  }
253
 
254
 
262
  return;
263
  }
264
 
265
+ if (defined('DOING_CRON')) {
266
+ $this->update_hash($schedule['id'], $this->xcloner_container->get_xcloner_settings()->generate_new_hash());
 
 
267
  }
268
 
269
  $this->logger->print_info(sprintf("Starting backup profile '%s'", $schedule['name']), array("CRON"));
270
 
271
+ $this->xcloner_container->get_xcloner_filesystem()->set_excluded_files(json_decode($schedule['excluded_files']));
272
 
273
  $init = 1;
274
  $continue = 1;
275
 
276
  while ($continue) {
277
+ $continue = $this->xcloner_container->get_xcloner_filesystem()->start_file_recursion($init);
278
 
279
  $init = 0;
280
  }
287
  $return['finished'] = 0;
288
 
289
  while (!$return['finished']) {
290
+ $return = $this->xcloner_container->get_xcloner_database()->start_database_recursion((array)json_decode($schedule['table_params']), $return, $init);
291
  $init = 0;
292
  }
293
 
300
  $return['extra'] = array();
301
 
302
  while (!$return['finished']) {
303
+ $return = $this->xcloner_container->get_archive_system()->start_incremental_backup((array)$schedule['backup_params'], $return['extra'], $init);
304
  $init = 0;
305
  }
306
  $this->logger->print_info(sprintf("File archive process FINISHED."), array("CRON"));
307
 
308
  //getting the last backup archive file
309
+ $return['extra']['backup_parent'] = $this->xcloner_container->get_archive_system()->get_archive_name_with_extension();
310
+ if ($this->xcloner_container->get_xcloner_filesystem()->is_part($this->xcloner_container->get_archive_system()->get_archive_name_with_extension())) {
311
+ $return['extra']['backup_parent'] = $this->xcloner_container->get_archive_system()->get_archive_name_multipart();
312
  }
313
 
314
  //Updating schedule last backup archive
327
 
328
  $backup_file = $return['extra']['backup_parent'];
329
 
330
+ if ($this->xcloner_container->get_xcloner_filesystem()->is_multipart($return['extra']['backup_parent'])) {
331
+ $backup_parts = $this->xcloner_container->get_xcloner_filesystem()->get_multipart_files($return['extra']['backup_parent']);
332
  $backup_file = $backup_parts[$part];
333
  }
334
 
335
  while (!$return_encrypted['finished']) {
336
+ $return_encrypted = $this->xcloner_container->get_xcloner_encryption()->encrypt_file(
337
  $backup_file,
338
  "",
339
  "",
354
  }
355
  }
356
 
357
+ $additional['backup_size'] = size_format($this->xcloner_container->get_xcloner_filesystem()->get_backup_size($return['extra']['backup_parent']));
358
 
359
  //Sending backup to remote storage
360
+ if (isset($schedule['remote_storage']) && $schedule['remote_storage'] && array_key_exists($schedule['remote_storage'], $this->xcloner_container->get_xcloner_remote_storage()->get_available_storages())) {
361
  $backup_file = $return['extra']['backup_parent'];
362
 
363
  $this->logger->print_info(sprintf("Transferring backup to remote storage %s", strtoupper($schedule['remote_storage'])), array("CRON"));
364
 
365
+ if (method_exists($this->xcloner_container->get_xcloner_remote_storage(), "upload_backup_to_storage")) {
366
  call_user_func_array(array(
367
+ $this->xcloner_container->get_xcloner_remote_storage(),
368
  "upload_backup_to_storage"
369
  ), array($backup_file, $schedule['remote_storage'], $schedule['backup_params']->backup_delete_after_remote_transfer));
370
  }
377
  $additional['lines_total'] = $return['extra']['lines_total'];
378
  $subject = sprintf(__("%s - new backup generated %s"), $schedule['name'], $return['extra']['backup_parent']);
379
 
380
+ $this->xcloner_container->get_archive_system()->send_notification($to, $from, $subject, $return['extra']['backup_parent'], $schedule, "", $additional);
381
  } catch (Exception $e) {
382
  $this->logger->error($e->getMessage());
383
  }
384
  }
385
 
386
  //Backup Storage Cleanup
387
+ $this->xcloner_container->get_xcloner_filesystem()->backup_storage_cleanup();
388
 
389
  //Filesystem Cleanup
390
+ $this->xcloner_container->get_xcloner_filesystem()->cleanup_tmp_directories();
391
 
392
  //Removing the tmp filesystem used for backup
393
+ $this->xcloner_container->get_xcloner_filesystem()->remove_tmp_filesystem();
394
 
395
  $this->logger->print_info(sprintf("Profile '%s' finished in %d seconds.", $schedule['name'], time() - $start_time), array("CRON"));
396
 
397
  return $return;
398
  }
399
 
400
+ /**
401
+ * @throws ArchiveIOException
402
+ * @throws ArchiveCorruptedException
403
+ * @throws FileInfoException
404
+ * @throws ArchiveIllegalCompressionException
405
+ */
406
+ public function xcloner_scheduler_callback($id, $schedule = "")
407
  {
 
 
 
 
408
  try {
409
+ if ($id) {
410
+ $schedule = $this->get_schedule_by_id($id);
411
+ }
412
+
413
+ if ($this->xcloner_container->get_xcloner_settings()->get_xcloner_option('xcloner_disable_email_notification')) {
414
  //we disable email notifications
415
  $schedule['backup_params']->email_notification = "";
416
  }
417
 
418
+ $this->_xcloner_scheduler_callback($id, $schedule);
419
  } catch (Exception $e) {
420
 
421
  //send email to site admin if email notification is not set in the scheduler
422
  if (!isset($schedule['backup_params']->email_notification) || !$schedule['backup_params']->email_notification) {
423
+ $schedule['backup_params']->email_notification = $this->xcloner_container->get_xcloner_settings()->get_xcloner_option('admin_email');
424
  }
425
 
426
  if (isset($schedule['backup_params']->email_notification) && $to = $schedule['backup_params']->email_notification) {
427
  $from = "";
428
+ $this->xcloner_container->get_archive_system()->send_notification($to, $from, $schedule['name'] . " - backup error", "", "", $e->getMessage());
429
  }
430
  }
431
  }
vendor/autoload.php CHANGED
@@ -9,4 +9,4 @@ if (PHP_VERSION_ID < 50600) {
9
 
10
  require_once __DIR__ . '/composer/autoload_real.php';
11
 
12
- return ComposerAutoloaderInit33b98bd5608997f602482388b1d4d108::getLoader();
9
 
10
  require_once __DIR__ . '/composer/autoload_real.php';
11
 
12
+ return ComposerAutoloaderInit238ab22fb5f7b2c52596ccc9f2b13d04::getLoader();
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInit33b98bd5608997f602482388b1d4d108
6
  {
7
  private static $loader;
8
 
@@ -24,18 +24,18 @@ class ComposerAutoloaderInit33b98bd5608997f602482388b1d4d108
24
 
25
  require __DIR__ . '/platform_check.php';
26
 
27
- spl_autoload_register(array('ComposerAutoloaderInit33b98bd5608997f602482388b1d4d108', 'loadClassLoader'), true, true);
28
  self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
29
- spl_autoload_unregister(array('ComposerAutoloaderInit33b98bd5608997f602482388b1d4d108', 'loadClassLoader'));
30
 
31
  require __DIR__ . '/autoload_static.php';
32
- call_user_func(\Composer\Autoload\ComposerStaticInit33b98bd5608997f602482388b1d4d108::getInitializer($loader));
33
 
34
  $loader->register(true);
35
 
36
- $includeFiles = \Composer\Autoload\ComposerStaticInit33b98bd5608997f602482388b1d4d108::$files;
37
  foreach ($includeFiles as $fileIdentifier => $file) {
38
- composerRequire33b98bd5608997f602482388b1d4d108($fileIdentifier, $file);
39
  }
40
 
41
  return $loader;
@@ -47,7 +47,7 @@ class ComposerAutoloaderInit33b98bd5608997f602482388b1d4d108
47
  * @param string $file
48
  * @return void
49
  */
50
- function composerRequire33b98bd5608997f602482388b1d4d108($fileIdentifier, $file)
51
  {
52
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
53
  $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInit238ab22fb5f7b2c52596ccc9f2b13d04
6
  {
7
  private static $loader;
8
 
24
 
25
  require __DIR__ . '/platform_check.php';
26
 
27
+ spl_autoload_register(array('ComposerAutoloaderInit238ab22fb5f7b2c52596ccc9f2b13d04', 'loadClassLoader'), true, true);
28
  self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
29
+ spl_autoload_unregister(array('ComposerAutoloaderInit238ab22fb5f7b2c52596ccc9f2b13d04', 'loadClassLoader'));
30
 
31
  require __DIR__ . '/autoload_static.php';
32
+ call_user_func(\Composer\Autoload\ComposerStaticInit238ab22fb5f7b2c52596ccc9f2b13d04::getInitializer($loader));
33
 
34
  $loader->register(true);
35
 
36
+ $includeFiles = \Composer\Autoload\ComposerStaticInit238ab22fb5f7b2c52596ccc9f2b13d04::$files;
37
  foreach ($includeFiles as $fileIdentifier => $file) {
38
+ composerRequire238ab22fb5f7b2c52596ccc9f2b13d04($fileIdentifier, $file);
39
  }
40
 
41
  return $loader;
47
  * @param string $file
48
  * @return void
49
  */
50
+ function composerRequire238ab22fb5f7b2c52596ccc9f2b13d04($fileIdentifier, $file)
51
  {
52
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
53
  $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
vendor/composer/autoload_static.php CHANGED
@@ -4,7 +4,7 @@
4
 
5
  namespace Composer\Autoload;
6
 
7
- class ComposerStaticInit33b98bd5608997f602482388b1d4d108
8
  {
9
  public static $files = array (
10
  '7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
@@ -7957,10 +7957,10 @@ class ComposerStaticInit33b98bd5608997f602482388b1d4d108
7957
  public static function getInitializer(ClassLoader $loader)
7958
  {
7959
  return \Closure::bind(function () use ($loader) {
7960
- $loader->prefixLengthsPsr4 = ComposerStaticInit33b98bd5608997f602482388b1d4d108::$prefixLengthsPsr4;
7961
- $loader->prefixDirsPsr4 = ComposerStaticInit33b98bd5608997f602482388b1d4d108::$prefixDirsPsr4;
7962
- $loader->prefixesPsr0 = ComposerStaticInit33b98bd5608997f602482388b1d4d108::$prefixesPsr0;
7963
- $loader->classMap = ComposerStaticInit33b98bd5608997f602482388b1d4d108::$classMap;
7964
 
7965
  }, null, ClassLoader::class);
7966
  }
4
 
5
  namespace Composer\Autoload;
6
 
7
+ class ComposerStaticInit238ab22fb5f7b2c52596ccc9f2b13d04
8
  {
9
  public static $files = array (
10
  '7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
7957
  public static function getInitializer(ClassLoader $loader)
7958
  {
7959
  return \Closure::bind(function () use ($loader) {
7960
+ $loader->prefixLengthsPsr4 = ComposerStaticInit238ab22fb5f7b2c52596ccc9f2b13d04::$prefixLengthsPsr4;
7961
+ $loader->prefixDirsPsr4 = ComposerStaticInit238ab22fb5f7b2c52596ccc9f2b13d04::$prefixDirsPsr4;
7962
+ $loader->prefixesPsr0 = ComposerStaticInit238ab22fb5f7b2c52596ccc9f2b13d04::$prefixesPsr0;
7963
+ $loader->classMap = ComposerStaticInit238ab22fb5f7b2c52596ccc9f2b13d04::$classMap;
7964
 
7965
  }, null, ClassLoader::class);
7966
  }
vendor/composer/installed.php CHANGED
@@ -1,9 +1,9 @@
1
  <?php return array(
2
  'root' => array(
3
  'name' => 'watchfulli/xcloner-wordpress',
4
- 'pretty_version' => 'v4.4.1',
5
- 'version' => '4.4.1.0',
6
- 'reference' => '6142827737f994d3de8eb656f79a73795154db7d',
7
  'type' => 'library',
8
  'install_path' => __DIR__ . '/../../',
9
  'aliases' => array(),
@@ -404,9 +404,9 @@
404
  'dev_requirement' => false,
405
  ),
406
  'watchfulli/xcloner-wordpress' => array(
407
- 'pretty_version' => 'v4.4.1',
408
- 'version' => '4.4.1.0',
409
- 'reference' => '6142827737f994d3de8eb656f79a73795154db7d',
410
  'type' => 'library',
411
  'install_path' => __DIR__ . '/../../',
412
  'aliases' => array(),
1
  <?php return array(
2
  'root' => array(
3
  'name' => 'watchfulli/xcloner-wordpress',
4
+ 'pretty_version' => 'v4.4.2',
5
+ 'version' => '4.4.2.0',
6
+ 'reference' => '925987090a887d9d37cae7e5f8000a4c9037251f',
7
  'type' => 'library',
8
  'install_path' => __DIR__ . '/../../',
9
  'aliases' => array(),
404
  'dev_requirement' => false,
405
  ),
406
  'watchfulli/xcloner-wordpress' => array(
407
+ 'pretty_version' => 'v4.4.2',
408
+ 'version' => '4.4.2.0',
409
+ 'reference' => '925987090a887d9d37cae7e5f8000a4c9037251f',
410
  'type' => 'library',
411
  'install_path' => __DIR__ . '/../../',
412
  'aliases' => array(),
xcloner.php CHANGED
@@ -15,7 +15,7 @@
15
  * Plugin Name: XCloner - Site Backup and Restore
16
  * Plugin URI: https://xcloner.com/
17
  * Description: XCloner is a tool that will help you manage your website backups, generate/restore/move so your website will be always secured! With XCloner you will be able to clone your site to any other location with just a few clicks, as well as transfer the backup archives to remote FTP, SFTP, DropBox, Amazon S3, Google Drive, WebDAV, Backblaze, Azure accounts.
18
- * Version: 4.4.1
19
  * Author: watchful
20
  * Author URI: https://watchful.net/
21
  * License: GPL-2.0+
@@ -202,13 +202,13 @@ function do_cli_execution($args = array(), $opts = array())
202
 
203
  // start schedule based on profile name
204
  if (!empty($profile_name)) {
205
- $profile = ($xcloner_backup->get_xcloner_scheduler()->get_schedule_by_id_or_name($profile_name));
206
-
207
- if ($profile['id']) {
208
- $xcloner_backup->execute_backup($profile['id']);
209
- } else {
210
  die(sprintf('Could not find profile %s', $profile_name));
211
  }
 
 
212
  }
213
  }
214
 
15
  * Plugin Name: XCloner - Site Backup and Restore
16
  * Plugin URI: https://xcloner.com/
17
  * Description: XCloner is a tool that will help you manage your website backups, generate/restore/move so your website will be always secured! With XCloner you will be able to clone your site to any other location with just a few clicks, as well as transfer the backup archives to remote FTP, SFTP, DropBox, Amazon S3, Google Drive, WebDAV, Backblaze, Azure accounts.
18
+ * Version: 4.4.2
19
  * Author: watchful
20
  * Author URI: https://watchful.net/
21
  * License: GPL-2.0+
202
 
203
  // start schedule based on profile name
204
  if (!empty($profile_name)) {
205
+ try {
206
+ $profile = $xcloner_backup->get_xcloner_scheduler()->get_schedule_by_id_or_name($profile_name);
207
+ } catch (Exception $e) {
 
 
208
  die(sprintf('Could not find profile %s', $profile_name));
209
  }
210
+
211
+ $xcloner_backup->execute_backup($profile['id']);
212
  }
213
  }
214