UpdraftPlus WordPress Backup Plugin - Version 0.8.36

Version Description

  • 03/10/2012 =
  • Support using sub-directories in Amazon S3
  • Some more debug logging for Amazon S3
Download this release

Release Info

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

Code changes from version 0.8.33 to 0.8.36

Files changed (2) hide show
  1. readme.txt +8 -4
  2. updraftplus.php +73 -61
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: David Anderson
3
  Tags: backup, restore, database, cloud, amazon, s3, Amazon S3, google drive, google, gdrive, ftp, cloud, updraft, back up
4
  Requires at least: 3.2
5
  Tested up to: 3.4.2
6
- Stable tag: 0.8.33
7
  Donate link: http://david.dw-perspective.org.uk/donate
8
  License: GPLv2 or later
9
 
@@ -12,7 +12,7 @@ License: GPLv2 or later
12
  UpdraftPlus simplifies backups (and restoration). Backup into the cloud (S3, Google Drive, FTP, and email) and restore with a single click. Backups of files and database can have separate schedules.
13
 
14
  == Upgrade Notice ==
15
- Some web hosts set safe_mode=Off, which is an invalid value and causes surprises
16
 
17
  == Installation ==
18
 
@@ -29,7 +29,7 @@ Standard WordPress plugin installation:
29
 
30
  You can check the changelog for changes; but the original Updraft, before I forked it, had two major problems. Firstly, it only backed up WP core tables from the database; if any of your plugins stored data in extra tables, then they were not backed up. Secondly, the database backup did not include charset information, which meant that you needed to know some SQL wizardry to actually be able to use the backup. I made UpdraftPlus out of my experience of trying to back up several sites with Updraft. Then, I added encryption for the database file for extra peace of mind, and future-proofed by getting rid of some deprecated aspects.
31
 
32
- = I like automating WordPress, and using the command-line. Please advertise to me. =
33
 
34
  That's very good of you, thank you. You are looking for WordShell, <a href="http://wordshell.net">http://wordshell.net</a>.
35
 
@@ -39,7 +39,7 @@ If you have the encryption key entered in your settings and you are restoring fr
39
 
40
  = I lost my encryption key - what can I do? =
41
 
42
- Nothing, probably. That's the point of an encryption key - people who don't have it can't get the data. Hire an encryption expert to build a super computer to try to break the encryption by brute force, at a tremendous price.
43
 
44
  = I found a bug. What do I do? =
45
 
@@ -47,6 +47,10 @@ Contact me! This is a complex plugin and the only way I can ensure it's robust i
47
 
48
  == Changelog ==
49
 
 
 
 
 
50
  = 0.8.33 - 09/19/2012 =
51
  * Work around some web hosts with invalid safe_mode configurations
52
 
3
  Tags: backup, restore, database, cloud, amazon, s3, Amazon S3, google drive, google, gdrive, ftp, cloud, updraft, back up
4
  Requires at least: 3.2
5
  Tested up to: 3.4.2
6
+ Stable tag: 0.8.36
7
  Donate link: http://david.dw-perspective.org.uk/donate
8
  License: GPLv2 or later
9
 
12
  UpdraftPlus simplifies backups (and restoration). Backup into the cloud (S3, Google Drive, FTP, and email) and restore with a single click. Backups of files and database can have separate schedules.
13
 
14
  == Upgrade Notice ==
15
+ Support using subdirectories in Amazon S3
16
 
17
  == Installation ==
18
 
29
 
30
  You can check the changelog for changes; but the original Updraft, before I forked it, had two major problems. Firstly, it only backed up WP core tables from the database; if any of your plugins stored data in extra tables, then they were not backed up. Secondly, the database backup did not include charset information, which meant that you needed to know some SQL wizardry to actually be able to use the backup. I made UpdraftPlus out of my experience of trying to back up several sites with Updraft. Then, I added encryption for the database file for extra peace of mind, and future-proofed by getting rid of some deprecated aspects.
31
 
32
+ = I like automating WordPress, and using the command-line. Please tell me more. =
33
 
34
  That's very good of you, thank you. You are looking for WordShell, <a href="http://wordshell.net">http://wordshell.net</a>.
35
 
39
 
40
  = I lost my encryption key - what can I do? =
41
 
42
+ Nothing, probably. That's the point of an encryption key - people who don't have it can't get the data. Hire an encryption expert to build a super computer to try to break the encryption by brute force, at a price.
43
 
44
  = I found a bug. What do I do? =
45
 
47
 
48
  == Changelog ==
49
 
50
+ = 0.8.36 - 03/10/2012 =
51
+ * Support using sub-directories in Amazon S3
52
+ * Some more debug logging for Amazon S3
53
+
54
  = 0.8.33 - 09/19/2012 =
55
  * Work around some web hosts with invalid safe_mode configurations
56
 
updraftplus.php CHANGED
@@ -4,7 +4,7 @@ Plugin Name: UpdraftPlus - Backup/Restore
4
  Plugin URI: http://wordpress.org/extend/plugins/updraftplus
5
  Description: Uploads, themes, plugins, and your DB can be automatically backed up to Amazon S3, Google Drive, FTP, or emailed. Files and DB can be on separate schedules.
6
  Author: David Anderson.
7
- Version: 0.8.33
8
  Donate link: http://david.dw-perspective.org.uk/donate
9
  Author URI: http://wordshell.net
10
  */
@@ -18,6 +18,8 @@ Author URI: http://wordshell.net
18
  //pretty up return messages in admin area
19
  //check s3/ftp download
20
 
 
 
21
  /* More TODO:
22
  Are all directories in wp-content covered? No; only plugins, themes, content. We should check for others and allow the user the chance to choose which ones he wants
23
  Use only one entry in WP options database
@@ -54,7 +56,7 @@ if(!$updraft->memory_check(192)) {
54
 
55
  class UpdraftPlus {
56
 
57
- var $version = '0.8.33';
58
 
59
  var $dbhandle;
60
  var $errors = array();
@@ -606,7 +608,8 @@ class UpdraftPlus {
606
  $this->log("Retain: user setting: number to retain = $retain");
607
  // Returns an array, most recent first, of backup sets
608
  $backup_history = $this->get_backup_history();
609
- $db_backups_found = 0; $file_backups_found = 0;
 
610
  $this->log("Number of backup sets in history: ".count($backup_history));
611
  foreach ($backup_history as $backup_datestamp => $backup_to_examine) {
612
  // $backup_to_examine is an array of file names, keyed on db/plugins/themes/uploads
@@ -623,9 +626,23 @@ class UpdraftPlus {
623
  $fullpath = trailingslashit(get_option('updraft_dir')).$file;
624
  @unlink($fullpath); //delete it if it's locally available
625
  if ($updraft_service == "s3") {
626
- $this->log("$backup_datestamp: Delete remote: s3://$remote_path/$file");
627
- if (!$remote_object->deleteObject($remote_path, $file)) {
628
- $this->error("S3 Error: Failed to delete object $file. Error was ".$php_errormsg);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
629
  }
630
  } elseif ($updraft_service == "ftp") {
631
  $this->log("$backup_datestamp: Delete remote ftp: $remote_path/$file");
@@ -646,56 +663,37 @@ class UpdraftPlus {
646
  $file = isset($backup_to_examine['plugins']) ? $backup_to_examine['plugins'] : "";
647
  $file2 = isset($backup_to_examine['themes']) ? $backup_to_examine['themes'] : "";
648
  $file3 = isset($backup_to_examine['uploads']) ? $backup_to_examine['uploads'] : "";
649
- if ($file) {
650
- $this->log("$backup_datestamp: Delete this file: $file");
651
- $fullpath = trailingslashit(get_option('updraft_dir')).$file;
652
- @unlink($fullpath); //delete it if it's locally available
653
- if ($updraft_service == "s3") {
654
- $this->log("$backup_datestamp: Delete remote: s3://$remote_path/$file");
655
- if (!$remote_object->deleteObject($remote_path, $file)) {
656
- $this->error("S3 Error: Failed to delete object $file. Error was ".$php_errormsg);
657
- }
658
- } elseif ($updraft_service == "ftp") {
659
- $this->log("$backup_datestamp: Delete remote ftp: $remote_path/$file");
660
- @$remote_object->delete($remote_path.$file);
661
- } elseif ($updraft_service == "googledrive") {
662
- $this->log("$backup_datestamp: Delete remote file from Google Drive: $remote_path/$file");
663
- $this->googledrive_delete_file($remote_path.'/'.$file,$remote_object);
664
- }
665
- }
666
- if ($file2) {
667
- $this->log("$backup_datestamp: Delete this file: $file2");
668
- $fullpath = trailingslashit(get_option('updraft_dir')).$file2;
669
- @unlink($fullpath); //delete it if it's locally available
670
- if ($updraft_service == "s3") {
671
- $this->log("$backup_datestamp: Delete remote: s3://$remote_path/$file2");
672
- if (!$remote_object->deleteObject($remote_path, $file2)) {
673
- $this->error("S3 Error: Failed to delete object $file2. Error was ".$php_errormsg);
674
- }
675
- } elseif ($updraft_service == "ftp") {
676
- $this->log("$backup_datestamp: Delete remote ftp: $remote_path/$file2");
677
- @$remote_object->delete($remote_path.$file2);
678
- } elseif ($updraft_service == "googledrive") {
679
- $this->log("$backup_datestamp: Delete remote file from Google Drive: $remote_path/$file");
680
- $this->googledrive_delete_file($remote_path.'/'.$file,$remote_object);
681
- }
682
-
683
- }
684
- if ($file3) {
685
- $this->log("$backup_datestamp: Delete this file: $file3");
686
- $fullpath = trailingslashit(get_option('updraft_dir')).$file3;
687
- @unlink($fullpath); //delete it if it's locally available
688
- if ($updraft_service == "s3") {
689
- $this->log("$backup_datestamp: Delete remote: s3://$remote_path/$file3");
690
- if (!$remote_object->deleteObject($remote_path, $file3)) {
691
- $this->error("S3 Error: Failed to delete object $file3. Error was ".$php_errormsg);
692
  }
693
- } elseif ($updraft_service == "ftp") {
694
- $this->log("$backup_datestamp: Delete remote ftp: $remote_path/$file3");
695
- @$remote_object->delete($remote_path.$file3);
696
- } elseif ($updraft_service == "googledrive") {
697
- $this->log("$backup_datestamp: Delete remote file from Google Drive: $remote_path/$file");
698
- $this->googledrive_delete_file($remote_path.'/'.$file,$remote_object);
699
  }
700
  }
701
  unset($backup_to_examine['plugins']);
@@ -722,15 +720,24 @@ class UpdraftPlus {
722
  }
723
  $s3 = new S3(get_option('updraft_s3_login'), get_option('updraft_s3_pass'));
724
  $bucket_name = untrailingslashit(get_option('updraft_s3_remote_path'));
 
 
 
 
 
 
725
  if (@$s3->putBucket($bucket_name, S3::ACL_PRIVATE)) {
726
  foreach($backup_array as $file) {
727
  $fullpath = trailingslashit(get_option('updraft_dir')).$file;
728
- if (!$s3->putObjectFile($fullpath, $bucket_name, $file)) {
 
 
729
  $this->error("S3 Error: Failed to upload $fullpath. Error was ".$php_errormsg);
730
  }
731
  }
732
- $this->prune_retained_backups('s3',$s3,$bucket_name);
733
  } else {
 
734
  $this->error("S3 Error: Failed to create bucket $bucket_name. Error was ".$php_errormsg);
735
  }
736
  }
@@ -1335,9 +1342,14 @@ class UpdraftPlus {
1335
  }
1336
  $s3 = new S3(get_option('updraft_s3_login'), get_option('updraft_s3_pass'));
1337
  $bucket_name = untrailingslashit(get_option('updraft_s3_remote_path'));
 
 
 
 
 
1338
  if (@$s3->putBucket($bucket_name, S3::ACL_PRIVATE)) {
1339
  $fullpath = trailingslashit(get_option('updraft_dir')).$file;
1340
- if (!$s3->getObject($bucket_name, $file, $fullpath)) {
1341
  $this->error("S3 Error: Failed to download $fullpath. Error was ".$php_errormsg);
1342
  }
1343
  } else {
@@ -1957,12 +1969,12 @@ ENDHERE;
1957
  <td><input type="password" autocomplete="off" style="width:292px" name="updraft_s3_pass" value="<?php echo get_option('updraft_s3_pass'); ?>" /></td>
1958
  </tr>
1959
  <tr class="s3" <?php echo $s3_display?>>
1960
- <th>S3 bucket:</th>
1961
- <td><input type="text" style="width:292px" name="updraft_s3_remote_path" value="<?php echo get_option('updraft_s3_remote_path'); ?>" /></td>
1962
  </tr>
1963
  <tr class="s3" <?php echo $s3_display?>>
1964
  <th></th>
1965
- <td><p>Get your access key and secret key from your AWS page, then pick a (globally unique) bucket name (letters and numbers) to use for storage. (Do not enter the s3:// prefix).</p></td>
1966
  </tr>
1967
 
1968
  <!-- Google Drive -->
4
  Plugin URI: http://wordpress.org/extend/plugins/updraftplus
5
  Description: Uploads, themes, plugins, and your DB can be automatically backed up to Amazon S3, Google Drive, FTP, or emailed. Files and DB can be on separate schedules.
6
  Author: David Anderson.
7
+ Version: 0.8.36
8
  Donate link: http://david.dw-perspective.org.uk/donate
9
  Author URI: http://wordshell.net
10
  */
18
  //pretty up return messages in admin area
19
  //check s3/ftp download
20
 
21
+ //If someone tries Google Drive then switches away, then they get a whinge about unauthenticated details
22
+
23
  /* More TODO:
24
  Are all directories in wp-content covered? No; only plugins, themes, content. We should check for others and allow the user the chance to choose which ones he wants
25
  Use only one entry in WP options database
56
 
57
  class UpdraftPlus {
58
 
59
+ var $version = '0.8.36';
60
 
61
  var $dbhandle;
62
  var $errors = array();
608
  $this->log("Retain: user setting: number to retain = $retain");
609
  // Returns an array, most recent first, of backup sets
610
  $backup_history = $this->get_backup_history();
611
+ $db_backups_found = 0;
612
+ $file_backups_found = 0;
613
  $this->log("Number of backup sets in history: ".count($backup_history));
614
  foreach ($backup_history as $backup_datestamp => $backup_to_examine) {
615
  // $backup_to_examine is an array of file names, keyed on db/plugins/themes/uploads
626
  $fullpath = trailingslashit(get_option('updraft_dir')).$file;
627
  @unlink($fullpath); //delete it if it's locally available
628
  if ($updraft_service == "s3") {
629
+ if (preg_match("#^([^/]+)/(.*)$#",$remote_path,$bmatches)) {
630
+ $s3_bucket=$bmatches[1];
631
+ $s3_uri = $bmatches[2]."/".$file;
632
+ } else {
633
+ $s3_bucket = $remote_path;
634
+ $s3_uri = $file;
635
+ }
636
+ $this->log("$backup_datestamp: Delete remote: bucket=$s3_bucket, URI=$s3_uri");
637
+ # Here we brought in the function deleteObject in order to get more direct access to any error
638
+ $rest = new S3Request('DELETE', $s3_bucket, $s3_uri);
639
+ $rest = $rest->getResponse();
640
+ if ($rest->error === false && $rest->code !== 204) {
641
+ $this->log("S3 Error: Expected HTTP response 204; got: ".$rest->code);
642
+ $this->error("S3 Error: Unexpected HTTP response code ".$rest->code." (expected 204)");
643
+ } elseif ($rest->error !== false) {
644
+ $this->log("S3 Error: ".$rest->error['code'].": ".$rest->error['message']);
645
+ $this->error("S3 delete error: ".$rest->error['code'].": ".$rest->error['message']);
646
  }
647
  } elseif ($updraft_service == "ftp") {
648
  $this->log("$backup_datestamp: Delete remote ftp: $remote_path/$file");
663
  $file = isset($backup_to_examine['plugins']) ? $backup_to_examine['plugins'] : "";
664
  $file2 = isset($backup_to_examine['themes']) ? $backup_to_examine['themes'] : "";
665
  $file3 = isset($backup_to_examine['uploads']) ? $backup_to_examine['uploads'] : "";
666
+ foreach (array($file,$file2,$file3) as $dofile) {
667
+ if ($dofile) {
668
+ $this->log("$backup_datestamp: Delete this file: $dofile");
669
+ $fullpath = trailingslashit(get_option('updraft_dir')).$dofile;
670
+ @unlink($fullpath); //delete it if it's locally available
671
+ if ($updraft_service == "s3") {
672
+ if (preg_match("#^([^/]+)/(.*)$#",$remote_path,$bmatches)) {
673
+ $s3_bucket=$bmatches[1];
674
+ $s3_uri = $bmatches[2]."/".$dofile;
675
+ } else {
676
+ $s3_bucket = $remote_path;
677
+ $s3_uri = $dofile;
678
+ }
679
+ $this->log("$backup_datestamp: Delete remote: bucket=$s3_bucket, URI=$s3_uri");
680
+ # Here we brought in the function deleteObject in order to get more direct access to any error
681
+ $rest = new S3Request('DELETE', $s3_bucket, $s3_uri);
682
+ $rest = $rest->getResponse();
683
+ if ($rest->error === false && $rest->code !== 204) {
684
+ $this->log("S3 Error: Expected HTTP response 204; got: ".$rest->code);
685
+ $this->error("S3 Error: Unexpected HTTP response code ".$rest->code." (expected 204)");
686
+ } elseif ($rest->error !== false) {
687
+ $this->log("S3 Error: ".$rest->error['code'].": ".$rest->error['message']);
688
+ $this->error("S3 delete error: ".$rest->error['code'].": ".$rest->error['message']);
689
+ }
690
+ } elseif ($updraft_service == "ftp") {
691
+ $this->log("$backup_datestamp: Delete remote ftp: $remote_path/$dofile");
692
+ @$remote_object->delete($remote_path.$dofile);
693
+ } elseif ($updraft_service == "googledrive") {
694
+ $this->log("$backup_datestamp: Delete remote file from Google Drive: $remote_path/$dofile");
695
+ $this->googledrive_delete_file($remote_path.'/'.$dofile,$remote_object);
 
 
 
 
 
 
 
 
 
 
 
 
 
696
  }
 
 
 
 
 
 
697
  }
698
  }
699
  unset($backup_to_examine['plugins']);
720
  }
721
  $s3 = new S3(get_option('updraft_s3_login'), get_option('updraft_s3_pass'));
722
  $bucket_name = untrailingslashit(get_option('updraft_s3_remote_path'));
723
+ $bucket_path = "";
724
+ $orig_bucket_name = $bucket_name;
725
+ if (preg_match("#^([^/]+)/(.*)$#",$bucket_name,$bmatches)) {
726
+ $bucket_name = $bmatches[1];
727
+ $bucket_path = $bmatches[2]."/";
728
+ }
729
  if (@$s3->putBucket($bucket_name, S3::ACL_PRIVATE)) {
730
  foreach($backup_array as $file) {
731
  $fullpath = trailingslashit(get_option('updraft_dir')).$file;
732
+ $this->log("S3 upload: $fullpath -> s3://$bucket_name/$bucket_path$file");
733
+ if (!$s3->putObjectFile($fullpath, $bucket_name, $bucket_path.$file)) {
734
+ $this->log("S3 upload: failed");
735
  $this->error("S3 Error: Failed to upload $fullpath. Error was ".$php_errormsg);
736
  }
737
  }
738
+ $this->prune_retained_backups('s3',$s3,$orig_bucket_name);
739
  } else {
740
+ $this->log("S3 Error: Failed to create bucket $bucket_name. Error was ".$php_errormsg);
741
  $this->error("S3 Error: Failed to create bucket $bucket_name. Error was ".$php_errormsg);
742
  }
743
  }
1342
  }
1343
  $s3 = new S3(get_option('updraft_s3_login'), get_option('updraft_s3_pass'));
1344
  $bucket_name = untrailingslashit(get_option('updraft_s3_remote_path'));
1345
+ $bucket_path = "";
1346
+ if (preg_match("#^([^/]+)/(.*)$#",$bucket_name,$bmatches)) {
1347
+ $bucket_name = $bmatches[1];
1348
+ $bucket_path = $bmatches[2]."/";
1349
+ }
1350
  if (@$s3->putBucket($bucket_name, S3::ACL_PRIVATE)) {
1351
  $fullpath = trailingslashit(get_option('updraft_dir')).$file;
1352
+ if (!$s3->getObject($bucket_name, $bucket_path.$file, $fullpath)) {
1353
  $this->error("S3 Error: Failed to download $fullpath. Error was ".$php_errormsg);
1354
  }
1355
  } else {
1969
  <td><input type="password" autocomplete="off" style="width:292px" name="updraft_s3_pass" value="<?php echo get_option('updraft_s3_pass'); ?>" /></td>
1970
  </tr>
1971
  <tr class="s3" <?php echo $s3_display?>>
1972
+ <th>S3 location:</th>
1973
+ <td>s3://<input type="text" style="width:292px" name="updraft_s3_remote_path" value="<?php echo get_option('updraft_s3_remote_path'); ?>" /></td>
1974
  </tr>
1975
  <tr class="s3" <?php echo $s3_display?>>
1976
  <th></th>
1977
+ <td><p>Get your access key and secret key from your AWS page, then pick a (globally unique) bucket name (letters and numbers) (and optionally a path) to use for storage.</p></td>
1978
  </tr>
1979
 
1980
  <!-- Google Drive -->