UpdraftPlus WordPress Backup Plugin - Version 1.2.26

Version Description

  • 01/14/2013 =
  • Fixed bug with DropBox deletions
  • Fixed cases where DropBox failed to resume chunked uploading
  • Can now create uncreated zip files on a resumption attempt
Download this release

Release Info

Developer DavidAnderson
Plugin Icon 128x128 UpdraftPlus WordPress Backup Plugin
Version 1.2.26
Comparing to
See all releases

Code changes from version 1.2.25 to 1.2.26

Files changed (3) hide show
  1. methods/dropbox.php +1 -1
  2. readme.txt +4 -3
  3. updraftplus.php +75 -25
methods/dropbox.php CHANGED
@@ -153,7 +153,7 @@ class UpdraftPlus_BackupModule_dropbox {
153
  $dropbox->delete($dropbox_folder.'/'.$file);
154
  } catch (Exception $e) {
155
  $updraftplus->log('DropBox error: '.$e->getMessage().' (line: '.$e->getLine().', file: '.$e->getFile().')');
156
- $file_success = 1;
157
  }
158
  if ($file_success) $updraftplus->log('DropBox: delete succeeded (alternative path)');
159
  }
153
  $dropbox->delete($dropbox_folder.'/'.$file);
154
  } catch (Exception $e) {
155
  $updraftplus->log('DropBox error: '.$e->getMessage().' (line: '.$e->getLine().', file: '.$e->getFile().')');
156
+ $file_success = 0;
157
  }
158
  if ($file_success) $updraftplus->log('DropBox: delete succeeded (alternative path)');
159
  }
readme.txt CHANGED
@@ -3,12 +3,12 @@ Contributors: David Anderson
3
  Tags: backup, restore, database, cloud, amazon, s3, Amazon S3, DropBox, DropBox backup, google drive, google, gdrive, ftp, cloud, updraft, back up
4
  Requires at least: 3.2
5
  Tested up to: 3.5
6
- Stable tag: 1.2.25
7
  Donate link: http://david.dw-perspective.org.uk/donate
8
  License: GPLv3 or later
9
 
10
  == Upgrade Notice ==
11
- DropBox can now support larger, resumable uploads. Also improved DropBox help text.
12
 
13
  == Description ==
14
 
@@ -112,9 +112,10 @@ Thanks for asking - yes, I have. Check out my profile page - http://profiles.wor
112
 
113
  == Changelog ==
114
 
115
- = 1.2.25 - 01/14/2013 =
116
  * Fixed bug with DropBox deletions
117
  * Fixed cases where DropBox failed to resume chunked uploading
 
118
 
119
  = 1.2.20 - 01/12/2013 =
120
  * DropBox no longer limited to 150Mb uploads
3
  Tags: backup, restore, database, cloud, amazon, s3, Amazon S3, DropBox, DropBox backup, google drive, google, gdrive, ftp, cloud, updraft, back up
4
  Requires at least: 3.2
5
  Tested up to: 3.5
6
+ Stable tag: 1.2.26
7
  Donate link: http://david.dw-perspective.org.uk/donate
8
  License: GPLv3 or later
9
 
10
  == Upgrade Notice ==
11
+ DropBox can now support larger, resumable uploads. Also improved DropBox help text. Made file downloads resumable.
12
 
13
  == Description ==
14
 
112
 
113
  == Changelog ==
114
 
115
+ = 1.2.26 - 01/14/2013 =
116
  * Fixed bug with DropBox deletions
117
  * Fixed cases where DropBox failed to resume chunked uploading
118
+ * Can now create uncreated zip files on a resumption attempt
119
 
120
  = 1.2.20 - 01/12/2013 =
121
  * DropBox no longer limited to 150Mb uploads
updraftplus.php CHANGED
@@ -4,7 +4,7 @@ Plugin Name: UpdraftPlus - Backup/Restore
4
  Plugin URI: http://wordpress.org/extend/plugins/updraftplus
5
  Description: Backup and restore: All your content and your DB can be automatically backed up to Amazon S3, DropBox, Google Drive, FTP, or emailed, on separate schedules.
6
  Author: David Anderson.
7
- Version: 1.2.25
8
  Donate link: http://david.dw-perspective.org.uk/donate
9
  License: GPLv3 or later
10
  Author URI: http://wordshell.net
@@ -19,6 +19,7 @@ TODO
19
  //Eventually, when everything can be resumed, we will no longer need the backup() routine; it can be replaced with the resume() routine
20
  //Remind user to look inside their 'apps' folder in DropBox
21
  // Should we resume if the only errors were upon deletion (i.e. the backup itself was fine?) Presently we do, but it displays errors for the user to confuse them.
 
22
  // Separate 'retain' settings for db + files (since they are on separate schedules)
23
  // Warn the user if their zip-file creation is slooowww...
24
  // Create a "Want Support?" button/console, that leads them through what is needed, and performs some basic tests...
@@ -65,7 +66,7 @@ define('UPDRAFT_DEFAULT_OTHERS_EXCLUDE','upgrade,cache,updraft,index.php');
65
 
66
  class UpdraftPlus {
67
 
68
- var $version = '1.2.25';
69
 
70
  // Choices will be shown in the admin menu in the order used here
71
  var $backup_methods = array (
@@ -153,7 +154,7 @@ class UpdraftPlus {
153
  function log($line) {
154
  if ($this->logfile_handle) fwrite($this->logfile_handle,date('r')." ".$line."\n");
155
  }
156
-
157
  function backup_resume($resumption_no) {
158
  @ignore_user_abort(true);
159
  // This is scheduled for 5 minutes after a backup job starts
@@ -179,9 +180,13 @@ class UpdraftPlus {
179
  }
180
  $this->backup_time = $btime;
181
 
 
 
 
 
182
  // Returns an array, most recent first, of backup sets
183
  $backup_history = $this->get_backup_history();
184
- if (!isset($backup_history[$btime])) $this->log("Error: Could not find a record in the database of a backup with this timestamp");
185
 
186
  $our_files=$backup_history[$btime];
187
  $undone_files = array();
@@ -215,7 +220,8 @@ class UpdraftPlus {
215
 
216
  foreach ($our_files as $key => $file) {
217
 
218
- if ($key == 'nonce') { continue; }
 
219
  $hash = md5($file);
220
  $fullpath = trailingslashit(get_option('updraft_dir')).$file;
221
  if (get_transient('updraft_'.$hash) === "yes") {
@@ -294,6 +300,32 @@ class UpdraftPlus {
294
  }
295
  }
296
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297
  function backup($backup_files, $backup_database) {
298
 
299
  @ignore_user_abort(true);
@@ -324,8 +356,8 @@ class UpdraftPlus {
324
  // Do not set the transient or schedule the resume event until now, when we know there is something to do - otherwise 'vacatated' runs (when the database is on the same schedule as the files, and they get combined, leading to an empty run) can over-write the resume event and prevent resumption (because it is 'successful' - there was nothing to do).
325
  // If we don't finish in 3 hours, then we won't finish
326
  // This transient indicates the identity of the current backup job (which can be used to find the files and logfile)
327
- set_transient("updraftplus_backup_job_nonce", $this->nonce,3600*3);
328
- set_transient("updraftplus_backup_job_time", $this->backup_time,3600*3);
329
 
330
  // Schedule the event to run later, which checks on success and can resume the backup
331
  // We save the time to a variable because it is needed for un-scheduling
@@ -340,17 +372,16 @@ class UpdraftPlus {
340
 
341
  $this->check_backup_race();
342
 
343
- //backup directories and return a numerically indexed array of file paths to the backup files
 
 
 
 
344
  if ($backup_files) {
345
- $this->log("Beginning backup of directories");
346
- $backup_array = $this->backup_dirs();
347
- $backup_contains = "Files only (no database)";
348
- // This can get over-written later
349
- set_transient("updraft_backupcontains_".$this->nonce, $backup_contains, 3600*3);
350
  }
351
 
352
- // Save what *should* be done, to make it resumable from this point on
353
- set_transient("updraft_backdb_".$this->nonce, "begun", 3600*3);
354
  // Save this to our history so we can track backups for the retain feature
355
  $this->log("Saving backup history");
356
  $this->save_backup_history($backup_array);
@@ -617,14 +648,21 @@ class UpdraftPlus {
617
  return true;
618
  }
619
 
620
- function create_zip($whichone, $backup_file_base, $create_from_dir) {
621
  // Note: $create_from_dir can be an array or a string
622
  @set_time_limit(900);
623
 
624
- if ($whichone != "others") $this->log("Beginning backup of $whichone");
 
 
 
 
 
 
 
625
 
626
- $full_path = $backup_file_base.'-'.$whichone.'.zip';
627
- $zip_object = new PclZip($full_path);
628
 
629
  $microtime_start = microtime(true);
630
  # The paths in the zip should then begin with '$whichone', having removed WP_CONTENT_DIR from the front
@@ -633,6 +671,7 @@ class UpdraftPlus {
633
  $this->log("ERROR: PclZip failure: Could not create $whichone zip");
634
  return false;
635
  } else {
 
636
  $timetaken = max(microtime(true)-$microtime_start, 0.000001);
637
  $kbsize = filesize($full_path)/1024;
638
  $rate = round($kbsize/$timetaken, 1);
@@ -642,7 +681,8 @@ class UpdraftPlus {
642
  return basename($full_path);
643
  }
644
 
645
- function backup_dirs() {
 
646
 
647
  if(!$this->backup_time) $this->backup_time_nonce();
648
 
@@ -660,7 +700,7 @@ class UpdraftPlus {
660
  $blog_name = preg_replace('/[^A-Za-z0-9_]/','', $blog_name);
661
  if(!$blog_name) $blog_name = 'non_alpha_name';
662
 
663
- $backup_file_base = $updraft_dir.'/backup_'.date('Y-m-d-Hi',$this->backup_time).'_'.$blog_name.'_'.$this->nonce;
664
 
665
  $backup_array = array();
666
 
@@ -674,8 +714,12 @@ class UpdraftPlus {
674
  # Plugins, themes, uploads
675
  foreach ($possible_backups as $youwhat => $whichdir) {
676
  if (get_option("updraft_include_$youwhat", true)) {
677
- $created = $this->create_zip($youwhat, $backup_file_base, $whichdir);
678
- if ($created) $backup_array[$youwhat] = $created;
 
 
 
 
679
  } else {
680
  $this->log("No backup of $youwhat: excluded by user's options");
681
  }
@@ -685,6 +729,10 @@ class UpdraftPlus {
685
  if (get_option('updraft_include_others', true)) {
686
  $this->log("Beginning backup of other directories found in the content directory");
687
 
 
 
 
 
688
  // http://www.phpconcept.net/pclzip/user-guide/53
689
  /* First parameter to create is:
690
  An array of filenames or dirnames,
@@ -719,11 +767,13 @@ class UpdraftPlus {
719
  }
720
 
721
  if (count($other_dirlist)>0) {
722
- $created = $this->create_zip('others', $backup_file_base, $other_dirlist);
723
  if ($created) $backup_array['others'] = $created;
724
  } else {
725
  $this->log("No backup of other directories: there was nothing found to back up");
726
  }
 
 
727
  } else {
728
  $this->log("No backup of other directories: excluded by user's options");
729
  }
@@ -1604,7 +1654,7 @@ ENDHERE;
1604
  <div style="float:left; width:200px; padding-top: 100px;">
1605
  <form method="post" action="">
1606
  <input type="hidden" name="action" value="updraft_backup" />
1607
- <p><input type="submit" <?php echo $backup_disabled ?> class="button-primary" value="Backup Now!" style="padding-top:3px;padding-bottom:3px;font-size:24px !important" onclick="return(confirm('This will schedule a one-time backup. To trigger the backup you should go ahead, then wait 10 seconds, then load a page on your site.'))" /></p>
1608
  </form>
1609
  <div style="position:relative">
1610
  <div style="position:absolute;top:0;left:0">
4
  Plugin URI: http://wordpress.org/extend/plugins/updraftplus
5
  Description: Backup and restore: All your content and your DB can be automatically backed up to Amazon S3, DropBox, Google Drive, FTP, or emailed, on separate schedules.
6
  Author: David Anderson.
7
+ Version: 1.2.26
8
  Donate link: http://david.dw-perspective.org.uk/donate
9
  License: GPLv3 or later
10
  Author URI: http://wordshell.net
19
  //Eventually, when everything can be resumed, we will no longer need the backup() routine; it can be replaced with the resume() routine
20
  //Remind user to look inside their 'apps' folder in DropBox
21
  // Should we resume if the only errors were upon deletion (i.e. the backup itself was fine?) Presently we do, but it displays errors for the user to confuse them.
22
+ // Make jobs *individually* resumable (i.e. all the state info must be keyed on the nonce; then call the resume event *specifying the nonce*)
23
  // Separate 'retain' settings for db + files (since they are on separate schedules)
24
  // Warn the user if their zip-file creation is slooowww...
25
  // Create a "Want Support?" button/console, that leads them through what is needed, and performs some basic tests...
66
 
67
  class UpdraftPlus {
68
 
69
+ var $version = '1.2.26';
70
 
71
  // Choices will be shown in the admin menu in the order used here
72
  var $backup_methods = array (
154
  function log($line) {
155
  if ($this->logfile_handle) fwrite($this->logfile_handle,date('r')." ".$line."\n");
156
  }
157
+
158
  function backup_resume($resumption_no) {
159
  @ignore_user_abort(true);
160
  // This is scheduled for 5 minutes after a backup job starts
180
  }
181
  $this->backup_time = $btime;
182
 
183
+ $backup_array = $this->resumable_backup_of_files(false);
184
+ // This save, if there was something, is then immediately picked up again
185
+ if (is_array($backup_array)) $this->save_backup_history($backup_array);
186
+
187
  // Returns an array, most recent first, of backup sets
188
  $backup_history = $this->get_backup_history();
189
+ if (!isset($backup_history[$btime])) $this->log("Could not find a record in the database of a backup with this timestamp");
190
 
191
  $our_files=$backup_history[$btime];
192
  $undone_files = array();
220
 
221
  foreach ($our_files as $key => $file) {
222
 
223
+ if ($key == 'nonce') continue;
224
+
225
  $hash = md5($file);
226
  $fullpath = trailingslashit(get_option('updraft_dir')).$file;
227
  if (get_transient('updraft_'.$hash) === "yes") {
300
  }
301
  }
302
 
303
+ // This uses a transient; its only purpose is to indicate *total* completion; there is no actual danger, just wasted time, in resuming when it was not needed. So the transient just helps save resources.
304
+ function resumable_backup_of_files($resumptionrun) {
305
+ //backup directories and return a numerically indexed array of file paths to the backup files
306
+ $transient_status = get_transient("updraft_backf_".$this->nonce);
307
+ if ($transient_status == "finished") {
308
+ $this->log("Creation of backups of directories: already finished");
309
+ } elseif ($transient_status == "begun") {
310
+ if ($resumptionrun) {
311
+ $this->log("Creation of backups of directories: had begun; will resume");
312
+ } else {
313
+ $this->log("Creation of backups of directories: beginning");
314
+ }
315
+ } else {
316
+ # This is not necessarily a backup run which is meant to contain files at all
317
+ $this->log("This backup run is not intended for files - skipping");
318
+ return null;
319
+ }
320
+ // We want this array, even if already finished
321
+ $backup_array = $this->backup_dirs($transient_status);
322
+ $backup_contains = "Files only (no database)";
323
+ // This can get over-written later
324
+ set_transient("updraft_backupcontains_".$this->nonce, $backup_contains, 3600*3);
325
+ set_transient("updraft_backf_".$this->nonce, "finished", 3600*3);
326
+ return $backup_array;
327
+ }
328
+
329
  function backup($backup_files, $backup_database) {
330
 
331
  @ignore_user_abort(true);
356
  // Do not set the transient or schedule the resume event until now, when we know there is something to do - otherwise 'vacatated' runs (when the database is on the same schedule as the files, and they get combined, leading to an empty run) can over-write the resume event and prevent resumption (because it is 'successful' - there was nothing to do).
357
  // If we don't finish in 3 hours, then we won't finish
358
  // This transient indicates the identity of the current backup job (which can be used to find the files and logfile)
359
+ set_transient("updraftplus_backup_job_nonce", $this->nonce, 3600*3);
360
+ set_transient("updraftplus_backup_job_time", $this->backup_time, 3600*3);
361
 
362
  // Schedule the event to run later, which checks on success and can resume the backup
363
  // We save the time to a variable because it is needed for un-scheduling
372
 
373
  $this->check_backup_race();
374
 
375
+ // Save what *should* be done, to make it resumable from this point on
376
+ set_transient("updraft_backdb_".$this->nonce, "begun", 3600*3);
377
+
378
+ // The function itself will set to 'finished' if relevant
379
+ // The presence of the transient indicates that files are supposed to be in this set
380
  if ($backup_files) {
381
+ set_transient("updraft_backf_".$this->nonce, "begun", 3600*3);
382
+ $backup_array = $this->resumable_backup_of_files(false);
 
 
 
383
  }
384
 
 
 
385
  // Save this to our history so we can track backups for the retain feature
386
  $this->log("Saving backup history");
387
  $this->save_backup_history($backup_array);
648
  return true;
649
  }
650
 
651
+ function create_zip($create_from_dir, $whichone, $create_in_dir, $backup_file_basename) {
652
  // Note: $create_from_dir can be an array or a string
653
  @set_time_limit(900);
654
 
655
+ if ($whichone != "others") $this->log("Beginning creation of dump of $whichone");
656
+
657
+ $full_path = $create_in_dir.'/'.$backup_file_basename.'-'.$whichone.'.zip';
658
+
659
+ if (file_exists($full_path)) {
660
+ $this->log("$backup_file_basename-$whichone.zip: this file has already been created");
661
+ return basename($full_path);
662
+ }
663
 
664
+ // Temporary file, to be able to detect actual completion (upon which, it is renamed)
665
+ $zip_object = new PclZip($full_path.'.tmp');
666
 
667
  $microtime_start = microtime(true);
668
  # The paths in the zip should then begin with '$whichone', having removed WP_CONTENT_DIR from the front
671
  $this->log("ERROR: PclZip failure: Could not create $whichone zip");
672
  return false;
673
  } else {
674
+ rename($full_path.'.tmp', $full_path);
675
  $timetaken = max(microtime(true)-$microtime_start, 0.000001);
676
  $kbsize = filesize($full_path)/1024;
677
  $rate = round($kbsize/$timetaken, 1);
681
  return basename($full_path);
682
  }
683
 
684
+ // This function is resumable
685
+ function backup_dirs($transient_status) {
686
 
687
  if(!$this->backup_time) $this->backup_time_nonce();
688
 
700
  $blog_name = preg_replace('/[^A-Za-z0-9_]/','', $blog_name);
701
  if(!$blog_name) $blog_name = 'non_alpha_name';
702
 
703
+ $backup_file_basename = 'backup_'.date('Y-m-d-Hi', $this->backup_time).'_'.$blog_name.'_'.$this->nonce;
704
 
705
  $backup_array = array();
706
 
714
  # Plugins, themes, uploads
715
  foreach ($possible_backups as $youwhat => $whichdir) {
716
  if (get_option("updraft_include_$youwhat", true)) {
717
+ if ($transient_status == 'finished') {
718
+ $backup_array[$youwhat] = $backup_file_basename.'-'.$youwhat.'.zip';
719
+ } else {
720
+ $created = $this->create_zip($whichdir, $youwhat, $updraft_dir, $backup_file_basename);
721
+ if ($created) $backup_array[$youwhat] = $created;
722
+ }
723
  } else {
724
  $this->log("No backup of $youwhat: excluded by user's options");
725
  }
729
  if (get_option('updraft_include_others', true)) {
730
  $this->log("Beginning backup of other directories found in the content directory");
731
 
732
+ if ($transient_status == 'finished') {
733
+ $backup_array['others'] = $backup_file_basename.'-others.zip';
734
+ } else {
735
+
736
  // http://www.phpconcept.net/pclzip/user-guide/53
737
  /* First parameter to create is:
738
  An array of filenames or dirnames,
767
  }
768
 
769
  if (count($other_dirlist)>0) {
770
+ $created = $this->create_zip('others', $other_dirlist, $updraft_dir, $backup_file_basename);
771
  if ($created) $backup_array['others'] = $created;
772
  } else {
773
  $this->log("No backup of other directories: there was nothing found to back up");
774
  }
775
+ # If we are not already finished
776
+ }
777
  } else {
778
  $this->log("No backup of other directories: excluded by user's options");
779
  }
1654
  <div style="float:left; width:200px; padding-top: 100px;">
1655
  <form method="post" action="">
1656
  <input type="hidden" name="action" value="updraft_backup" />
1657
+ <p><input type="submit" <?php echo $backup_disabled ?> class="button-primary" value="Backup Now!" style="padding-top:3px;padding-bottom:3px;font-size:24px !important" onclick="return(confirm('This will schedule a one-time backup. To trigger the backup you should go ahead, then wait 10 seconds, then load a page on your site. WordPress should then start the backup running in the background.'))" /></p>
1658
  </form>
1659
  <div style="position:relative">
1660
  <div style="position:absolute;top:0;left:0">