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 | UpdraftPlus WordPress Backup Plugin |
Version | 0.8.36 |
Comparing to | |
See all releases |
Code changes from version 0.8.33 to 0.8.36
- readme.txt +8 -4
- 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.
|
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 |
-
|
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
|
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
|
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.
|
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.
|
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;
|
|
|
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 |
-
|
627 |
-
|
628 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
-
|
650 |
-
|
651 |
-
|
652 |
-
|
653 |
-
|
654 |
-
|
655 |
-
|
656 |
-
|
657 |
-
|
658 |
-
|
659 |
-
|
660 |
-
|
661 |
-
|
662 |
-
|
663 |
-
|
664 |
-
|
665 |
-
|
666 |
-
|
667 |
-
|
668 |
-
|
669 |
-
|
670 |
-
|
671 |
-
|
672 |
-
|
673 |
-
|
674 |
-
|
675 |
-
|
676 |
-
|
677 |
-
|
678 |
-
|
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 |
-
|
|
|
|
|
729 |
$this->error("S3 Error: Failed to upload $fullpath. Error was ".$php_errormsg);
|
730 |
}
|
731 |
}
|
732 |
-
$this->prune_retained_backups('s3',$s3,$
|
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
|
1961 |
-
<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
|
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 -->
|