Version Description
- 01/24/2013 =
- Fixed faulty assumptions in 'resume' code, now leading to more reliable resuming
- Removed some duplicate code; first attempt and resumptions now uses same code
- Added further parameters that should be removed on a wipe operation
Download this release
Release Info
Developer | DavidAnderson |
Plugin | UpdraftPlus WordPress Backup Plugin |
Version | 1.3.7 |
Comparing to | |
See all releases |
Code changes from version 1.3.2 to 1.3.7
- includes/Dropbox/OAuth/Storage/Encrypter.php +1 -1
- includes/updraft-restorer.php +4 -4
- methods/dropbox.php +5 -3
- readme.txt +8 -3
- updraftplus.php +158 -230
includes/Dropbox/OAuth/Storage/Encrypter.php
CHANGED
@@ -16,7 +16,7 @@ class Dropbox_Encrypter
|
|
16 |
const CIPHER = MCRYPT_RIJNDAEL_128;
|
17 |
const MODE = MCRYPT_MODE_CBC;
|
18 |
const KEY_SIZE = 32;
|
19 |
-
const IV_SIZE =
|
20 |
const IV_SOURCE = MCRYPT_DEV_URANDOM;
|
21 |
|
22 |
/**
|
16 |
const CIPHER = MCRYPT_RIJNDAEL_128;
|
17 |
const MODE = MCRYPT_MODE_CBC;
|
18 |
const KEY_SIZE = 32;
|
19 |
+
const IV_SIZE = 16;
|
20 |
const IV_SOURCE = MCRYPT_DEV_URANDOM;
|
21 |
|
22 |
/**
|
includes/updraft-restorer.php
CHANGED
@@ -14,13 +14,13 @@ class Updraft_Restorer extends WP_Upgrader {
|
|
14 |
|
15 |
function restore_backup($backup_file, $type) {
|
16 |
|
17 |
-
if ($type
|
18 |
|
19 |
global $wp_filesystem;
|
20 |
$this->init();
|
21 |
$this->backup_strings();
|
22 |
|
23 |
-
$res = $this->fs_connect(
|
24 |
if(!$res) exit;
|
25 |
|
26 |
$wp_dir = trailingslashit($wp_filesystem->abspath());
|
@@ -80,10 +80,10 @@ class Updraft_Restorer extends WP_Upgrader {
|
|
80 |
|
81 |
switch($type) {
|
82 |
case 'uploads':
|
83 |
-
|
84 |
break;
|
85 |
default:
|
86 |
-
|
87 |
}
|
88 |
}
|
89 |
|
14 |
|
15 |
function restore_backup($backup_file, $type) {
|
16 |
|
17 |
+
if ($type != 'plugins' && $type != 'themes' && $type != 'others' && $type != 'uploads') continue;
|
18 |
|
19 |
global $wp_filesystem;
|
20 |
$this->init();
|
21 |
$this->backup_strings();
|
22 |
|
23 |
+
$res = $this->fs_connect(array(ABSPATH, WP_CONTENT_DIR) );
|
24 |
if(!$res) exit;
|
25 |
|
26 |
$wp_dir = trailingslashit($wp_filesystem->abspath());
|
80 |
|
81 |
switch($type) {
|
82 |
case 'uploads':
|
83 |
+
@$wp_filesystem->chmod($wp_dir . "wp-content/$type", 0777, true);
|
84 |
break;
|
85 |
default:
|
86 |
+
@$wp_filesystem->chmod($wp_dir . "wp-content/$type", FS_CHMOD_DIR);
|
87 |
}
|
88 |
}
|
89 |
|
methods/dropbox.php
CHANGED
@@ -336,7 +336,7 @@ class UpdraftPlus_BackupModule_dropbox {
|
|
336 |
// This basically reproduces the relevant bits of bootstrap.php from the SDK
|
337 |
function bootstrap() {
|
338 |
|
339 |
-
require_once(UPDRAFTPLUS_DIR.'/includes/Dropbox/API.php');
|
340 |
require_once(UPDRAFTPLUS_DIR.'/includes/Dropbox/Exception.php');
|
341 |
require_once(UPDRAFTPLUS_DIR.'/includes/Dropbox/API.php');
|
342 |
require_once(UPDRAFTPLUS_DIR.'/includes/Dropbox/OAuth/Consumer/ConsumerAbstract.php');
|
@@ -346,8 +346,8 @@ class UpdraftPlus_BackupModule_dropbox {
|
|
346 |
require_once(UPDRAFTPLUS_DIR.'/includes/Dropbox/OAuth/Consumer/Curl.php');
|
347 |
// require_once(UPDRAFTPLUS_DIR.'/includes/Dropbox/OAuth/Consumer/WordPress.php');
|
348 |
|
349 |
-
$sec = UpdraftPlus_Options::get_updraft_option('updraft_dropbox_appkey');
|
350 |
$key = UpdraftPlus_Options::get_updraft_option('updraft_dropbox_secret');
|
|
|
351 |
|
352 |
// Set the callback URL
|
353 |
$callback = admin_url('options-general.php?page=updraftplus&action=updraftmethod-dropbox-auth');
|
@@ -359,7 +359,9 @@ class UpdraftPlus_BackupModule_dropbox {
|
|
359 |
$storage = new Dropbox_WordPress($encrypter, "updraft_dropboxtk_");
|
360 |
|
361 |
// WordPress consumer does not yet work
|
362 |
-
// $OAuth = new Dropbox_ConsumerWordPress($
|
|
|
|
|
363 |
list($d2, $d1) = self::defaults();
|
364 |
if (empty($sec)) { $sec = base64_decode($d1); }; if (empty($key)) { $key = base64_decode($d2); }
|
365 |
$OAuth = new Dropbox_Curl($sec, $key, $storage, $callback);
|
336 |
// This basically reproduces the relevant bits of bootstrap.php from the SDK
|
337 |
function bootstrap() {
|
338 |
|
339 |
+
require_once(UPDRAFTPLUS_DIR.'/includes/Dropbox/API.php' );
|
340 |
require_once(UPDRAFTPLUS_DIR.'/includes/Dropbox/Exception.php');
|
341 |
require_once(UPDRAFTPLUS_DIR.'/includes/Dropbox/API.php');
|
342 |
require_once(UPDRAFTPLUS_DIR.'/includes/Dropbox/OAuth/Consumer/ConsumerAbstract.php');
|
346 |
require_once(UPDRAFTPLUS_DIR.'/includes/Dropbox/OAuth/Consumer/Curl.php');
|
347 |
// require_once(UPDRAFTPLUS_DIR.'/includes/Dropbox/OAuth/Consumer/WordPress.php');
|
348 |
|
|
|
349 |
$key = UpdraftPlus_Options::get_updraft_option('updraft_dropbox_secret');
|
350 |
+
$sec = UpdraftPlus_Options::get_updraft_option('updraft_dropbox_appkey');
|
351 |
|
352 |
// Set the callback URL
|
353 |
$callback = admin_url('options-general.php?page=updraftplus&action=updraftmethod-dropbox-auth');
|
359 |
$storage = new Dropbox_WordPress($encrypter, "updraft_dropboxtk_");
|
360 |
|
361 |
// WordPress consumer does not yet work
|
362 |
+
// $OAuth = new Dropbox_ConsumerWordPress($sec, $key, $storage, $callback);
|
363 |
+
|
364 |
+
// Get the DropBox API access details
|
365 |
list($d2, $d1) = self::defaults();
|
366 |
if (empty($sec)) { $sec = base64_decode($d1); }; if (empty($key)) { $key = base64_decode($d2); }
|
367 |
$OAuth = new Dropbox_Curl($sec, $key, $storage, $callback);
|
readme.txt
CHANGED
@@ -1,9 +1,9 @@
|
|
1 |
=== UpdraftPlus Backup ===
|
2 |
Contributors: David Anderson
|
3 |
-
Tags: backup, restore, database, cloud, amazon, s3, dropbox, google drive,
|
4 |
Requires at least: 3.2
|
5 |
Tested up to: 3.5
|
6 |
-
Stable tag: 1.3.
|
7 |
Donate link: http://david.dw-perspective.org.uk/donate
|
8 |
License: GPLv3 or later
|
9 |
|
@@ -113,7 +113,7 @@ You can check the changelog for changes; but the original Updraft, before I fork
|
|
113 |
|
114 |
= Any known bugs ? =
|
115 |
|
116 |
-
Not a bug as such, but one issue to be aware of is that backups of very large sites (lots of uploaded media)
|
117 |
|
118 |
= I encrypted my database - how do I decrypt it? =
|
119 |
|
@@ -141,6 +141,11 @@ Thanks for asking - yes, I have. Check out my profile page - http://profiles.wor
|
|
141 |
|
142 |
== Changelog ==
|
143 |
|
|
|
|
|
|
|
|
|
|
|
144 |
= 1.3.2 - 01/23/2013 =
|
145 |
* Internal reorganisation, enabling UpdraftPlus Premium
|
146 |
|
1 |
=== UpdraftPlus Backup ===
|
2 |
Contributors: David Anderson
|
3 |
+
Tags: backup, restore, database, cloud, amazon, s3, dropbox, google drive, ftp, cloud, back up, multisite
|
4 |
Requires at least: 3.2
|
5 |
Tested up to: 3.5
|
6 |
+
Stable tag: 1.3.7
|
7 |
Donate link: http://david.dw-perspective.org.uk/donate
|
8 |
License: GPLv3 or later
|
9 |
|
113 |
|
114 |
= Any known bugs ? =
|
115 |
|
116 |
+
Not a bug as such, but one issue to be aware of is that backups of very large sites (lots of uploaded media) are quite complex matters, given the limits of running inside WordPress on a huge variety of different web hosting setups. With large sites, you need to use Amazon S3, which UpdraftPlus supports (since 0.9.20) or Google Drive (since 0.9.21) or Dropbox (since 1.2.19), because these support chunked, resumable uploads. Other backup methods have code (since 0.9.0) to retry failed uploads of an archive, but the upload cannot be chunked, so if an archive is enormous (i.e. cannot be completely uploaded in the time that PHP is allowed for running on your web host) it cannot work.
|
117 |
|
118 |
= I encrypted my database - how do I decrypt it? =
|
119 |
|
141 |
|
142 |
== Changelog ==
|
143 |
|
144 |
+
= 1.3.7 - 01/24/2013 =
|
145 |
+
* Fixed faulty assumptions in 'resume' code, now leading to more reliable resuming
|
146 |
+
* Removed some duplicate code; first attempt and resumptions now uses same code
|
147 |
+
* Added further parameters that should be removed on a wipe operation
|
148 |
+
|
149 |
= 1.3.2 - 01/23/2013 =
|
150 |
* Internal reorganisation, enabling UpdraftPlus Premium
|
151 |
|
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: your content and database can be automatically backed up to Amazon S3, Dropbox, Google Drive, FTP or email, on separate schedules.
|
6 |
Author: David Anderson.
|
7 |
-
Version: 1.3.
|
8 |
Donate link: http://david.dw-perspective.org.uk/donate
|
9 |
License: GPLv3 or later
|
10 |
Author URI: http://wordshell.net
|
@@ -13,19 +13,25 @@ Author URI: http://wordshell.net
|
|
13 |
/*
|
14 |
TODO
|
15 |
//Add SFTP, Box.Net, SugarSync and Microsoft Skydrive support??
|
|
|
|
|
|
|
|
|
16 |
//improve error reporting / pretty up return messages in admin area. One thing: have a "backup is now finished" flag. Otherwise with the resuming things get ambiguous/confusing. See http://wordpress.org/support/topic/backup-status - user was not aware that backup completely failed. Maybe a "backup status" field for each nonce that gets updated? (Even via AJAX?)
|
17 |
//?? On 'backup now', open up a Lightbox, count down 5 seconds, then start examining the log file (if it can be found)
|
18 |
//Should make clear in dashboard what is a non-fatal error (i.e. can be retried) - leads to unnecessary bug reports
|
19 |
-
//
|
20 |
// 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. Perhaps better to make pruning a separate scheuled task??
|
21 |
// Make jobs *individually* resumable (i.e. all the state info must be keyed on the nonce; then call the resume event *specifying the nonce*)
|
22 |
// Warn the user if their zip-file creation is slooowww...
|
23 |
// Create a "Want Support?" button/console, that leads them through what is needed, and performs some basic tests...
|
24 |
// Resuming partial FTP uploads
|
25 |
// Turn expert options into a jQuery toggle
|
26 |
-
// Provide backup/restoration for UpdraftPlus's settings, to allow 'bootstrap' on a fresh WP install
|
27 |
// Multiple jobs
|
28 |
-
//
|
|
|
|
|
29 |
|
30 |
Encrypt filesystem, if memory allows (and have option for abort if not); split up into multiple zips when needed
|
31 |
// Does not delete old custom directories upon a restore?
|
@@ -72,7 +78,7 @@ if (!class_exists('UpdraftPlus_Options')) require_once(UPDRAFTPLUS_DIR.'/options
|
|
72 |
|
73 |
class UpdraftPlus {
|
74 |
|
75 |
-
var $version = '1.3.
|
76 |
var $plugin_title = 'UpdraftPlus Backup/Restore';
|
77 |
|
78 |
// Choices will be shown in the admin menu in the order used here
|
@@ -88,7 +94,6 @@ class UpdraftPlus {
|
|
88 |
var $dbhandle_isgz;
|
89 |
var $errors = array();
|
90 |
var $nonce;
|
91 |
-
var $cronrun_type = "none";
|
92 |
var $logfile_name = "";
|
93 |
var $logfile_handle = false;
|
94 |
var $backup_time;
|
@@ -96,6 +101,8 @@ class UpdraftPlus {
|
|
96 |
var $opened_log_time;
|
97 |
var $backup_dir;
|
98 |
|
|
|
|
|
99 |
function __construct() {
|
100 |
// Initialisation actions - takes place on plugin load
|
101 |
# Create admin page
|
@@ -105,7 +112,7 @@ class UpdraftPlus {
|
|
105 |
# backup_all is used by the manual "Backup Now" button
|
106 |
add_action('updraft_backup_all', array($this,'backup_all'));
|
107 |
# this is our runs-after-backup event, whose purpose is to see if it succeeded or failed, and resume/mom-up etc.
|
108 |
-
add_action('updraft_backup_resume', array($this,'backup_resume'));
|
109 |
add_action('wp_enqueue_scripts', array($this, 'ajax_enqueue') );
|
110 |
add_action('wp_ajax_updraft_download_backup', array($this, 'updraft_download_backup'));
|
111 |
add_action('wp_ajax_updraft_ajax', array($this, 'updraft_ajax_handler'));
|
@@ -155,8 +162,6 @@ class UpdraftPlus {
|
|
155 |
$this->backup_time = time();
|
156 |
$nonce = substr(md5(time().rand()), 20);
|
157 |
$this->nonce = $nonce;
|
158 |
-
// Short-lived, as we only use this for detecting a race condition
|
159 |
-
set_transient("updraftplus_runtype_$nonce", $this->cronrun_type, 300);
|
160 |
}
|
161 |
|
162 |
function logfile_open($nonce) {
|
@@ -176,58 +181,65 @@ class UpdraftPlus {
|
|
176 |
UpdraftPlus_Options::update_updraft_option("updraft_lastmessage", $line." (".date('M d H:i:s').")");
|
177 |
}
|
178 |
|
179 |
-
function backup_resume($resumption_no) {
|
|
|
180 |
@ignore_user_abort(true);
|
181 |
// This is scheduled for 5 minutes after a backup job starts
|
182 |
-
|
183 |
-
|
184 |
-
$
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
if (!$btime) {
|
189 |
-
$this->log("Did not find stored time setting - aborting");
|
190 |
-
return;
|
191 |
}
|
192 |
-
|
|
|
|
|
193 |
// Schedule again, to run in 5 minutes again, in case we again fail
|
194 |
$resume_delay = 300;
|
195 |
// A different argument than before is needed otherwise the event is ignored
|
196 |
$next_resumption = $resumption_no+1;
|
197 |
if ($next_resumption < 10) {
|
198 |
-
|
|
|
199 |
} else {
|
200 |
-
$this->log("The current run is our tenth attempt - will not
|
201 |
}
|
202 |
-
$this->backup_time = $btime;
|
203 |
|
204 |
-
|
|
|
205 |
// This save, if there was something, is then immediately picked up again
|
206 |
if (is_array($backup_array)) $this->save_backup_history($backup_array);
|
207 |
|
208 |
// Returns an array, most recent first, of backup sets
|
209 |
$backup_history = $this->get_backup_history();
|
210 |
-
if (!isset($backup_history[$btime]))
|
|
|
|
|
211 |
|
212 |
$our_files=$backup_history[$btime];
|
213 |
if (!is_array($our_files)) $our_files = array();
|
214 |
|
215 |
$undone_files = array();
|
216 |
|
217 |
-
$backup_database =
|
218 |
|
219 |
// The transient is read and written below (instead of using the existing variable) so that we can copy-and-paste this part as needed.
|
220 |
-
if ($backup_database == "begun" || $backup_database == "finished") {
|
221 |
if ($backup_database == "begun") {
|
222 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
223 |
} else {
|
224 |
$this->log("Database dump: Creation was completed already");
|
225 |
}
|
226 |
$db_backup = $this->backup_db($backup_database);
|
227 |
if(is_array($our_files) && is_string($db_backup)) $our_files['db'] = $db_backup;
|
228 |
-
$
|
229 |
-
$backup_contains = (substr($backup_contains,0,10) == "Files only") ? "Files and database" : "Database only (no files)";
|
230 |
-
set_transient("updraft_backupcontains_".$this->nonce, $backup_contains, 3600*3);
|
231 |
} else {
|
232 |
$this->log("Unrecognised data when trying to ascertain if the database was backed up ($backup_database)");
|
233 |
}
|
@@ -241,18 +253,20 @@ class UpdraftPlus {
|
|
241 |
if (isset($our_files['db']) && !preg_match("/\.crypt$/", $our_files['db'])) {
|
242 |
$our_files['db'] = $this->encrypt_file($our_files['db']);
|
243 |
$this->save_backup_history($our_files);
|
|
|
244 |
}
|
245 |
|
246 |
foreach ($our_files as $key => $file) {
|
247 |
|
248 |
-
if
|
|
|
249 |
|
250 |
$hash = md5($file);
|
251 |
$fullpath = $this->backups_dir_location().'/'.$file;
|
252 |
-
if (
|
253 |
-
$this->log("$file: $key: This file has been successfully uploaded
|
254 |
} elseif (is_file($fullpath)) {
|
255 |
-
$this->log("$file: $key: This file has
|
256 |
$undone_files[$key] = $file;
|
257 |
} else {
|
258 |
$this->log("$file: Note: This file was not marked as successfully uploaded, but does not exist on the local filesystem");
|
@@ -262,68 +276,58 @@ class UpdraftPlus {
|
|
262 |
|
263 |
if (count($undone_files) == 0) {
|
264 |
$this->log("There were no more files that needed uploading; backup job is complete");
|
|
|
|
|
265 |
return;
|
266 |
}
|
267 |
|
268 |
$this->log("Requesting backup of the files that were not successfully uploaded");
|
269 |
$this->cloud_backup($undone_files);
|
270 |
|
271 |
-
$this->log("Resume backup ($resumption_no): finish run");
|
272 |
-
|
273 |
$this->backup_finish($next_resumption, true, true, $resumption_no);
|
274 |
|
275 |
}
|
276 |
|
277 |
function backup_all() {
|
278 |
-
$this->
|
279 |
}
|
280 |
|
281 |
function backup_files() {
|
282 |
# Note that the "false" for database gets over-ridden automatically if they turn out to have the same schedules
|
283 |
-
$this->
|
284 |
-
$this->backup(true,false);
|
285 |
}
|
286 |
|
287 |
function backup_database() {
|
288 |
# Note that nothing will happen if the file backup had the same schedule
|
289 |
-
$this->
|
290 |
-
$this->backup(false,true);
|
291 |
}
|
292 |
|
293 |
-
function
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
if (is_array($to_delete)) {
|
307 |
-
foreach ($to_delete as $key => $file) {
|
308 |
-
if (is_file($bdir.'/'.$file)) {
|
309 |
-
$this->log("Deleting the file we created: ".$file);
|
310 |
-
@unlink($bdir.'/'.$file);
|
311 |
-
}
|
312 |
-
}
|
313 |
-
}
|
314 |
-
exit;
|
315 |
-
}
|
316 |
}
|
|
|
317 |
}
|
318 |
|
319 |
// 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.
|
320 |
-
function resumable_backup_of_files($
|
321 |
//backup directories and return a numerically indexed array of file paths to the backup files
|
322 |
-
$transient_status =
|
323 |
if ($transient_status == "finished") {
|
324 |
$this->log("Creation of backups of directories: already finished");
|
325 |
} elseif ($transient_status == "begun") {
|
326 |
-
if ($
|
327 |
$this->log("Creation of backups of directories: had begun; will resume");
|
328 |
} else {
|
329 |
$this->log("Creation of backups of directories: beginning");
|
@@ -335,24 +339,23 @@ class UpdraftPlus {
|
|
335 |
}
|
336 |
// We want this array, even if already finished
|
337 |
$backup_array = $this->backup_dirs($transient_status);
|
338 |
-
$backup_contains = "Files only (no database)";
|
339 |
// This can get over-written later
|
340 |
-
|
341 |
-
set_transient("updraft_backf_".$this->nonce, "finished", 3600*3);
|
342 |
return $backup_array;
|
343 |
}
|
344 |
|
345 |
-
|
|
|
346 |
|
347 |
@ignore_user_abort(true);
|
|
|
348 |
//generate backup information
|
349 |
$this->backup_time_nonce();
|
350 |
-
|
351 |
$this->logfile_open($this->nonce);
|
352 |
|
353 |
// Log some information that may be helpful
|
354 |
global $wp_version;
|
355 |
-
$this->log("Tasks: Backup files: $backup_files (schedule: ".UpdraftPlus_Options::get_updraft_option('updraft_interval','unset').") Backup DB: $backup_database (schedule: ".UpdraftPlus_Options::get_updraft_option('updraft_interval_database','unset').")");
|
356 |
|
357 |
# If the files and database schedules are the same, and if this the file one, then we rope in database too.
|
358 |
# On the other hand, if the schedules were the same and this was the database run, then there is nothing to do.
|
@@ -362,87 +365,18 @@ class UpdraftPlus {
|
|
362 |
|
363 |
$this->log("Processed schedules. Tasks now: Backup files: $backup_files Backup DB: $backup_database");
|
364 |
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
$clear_nonce_transient = true;
|
371 |
-
|
372 |
-
// 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).
|
373 |
-
// If we don't finish in 3 hours, then we won't finish
|
374 |
-
// This transient indicates the identity of the current backup job (which can be used to find the files and logfile)
|
375 |
-
set_transient("updraftplus_backup_job_nonce", $this->nonce, 3600*3);
|
376 |
-
set_transient("updraftplus_backup_job_time", $this->backup_time, 3600*3);
|
377 |
-
|
378 |
-
// Schedule the event to run later, which checks on success and can resume the backup
|
379 |
-
// We save the time to a variable because it is needed for un-scheduling
|
380 |
-
$resume_delay = 300;
|
381 |
-
wp_schedule_single_event(time()+$resume_delay, 'updraft_backup_resume', array(1));
|
382 |
-
$this->log("In case we run out of time, scheduled a resumption at: $resume_delay seconds from now");
|
383 |
-
|
384 |
-
$backup_contains = "";
|
385 |
-
set_transient("updraft_backupcontains_".$this->nonce, "");
|
386 |
-
|
387 |
-
$backup_array = array();
|
388 |
-
|
389 |
-
$this->check_backup_race();
|
390 |
-
|
391 |
-
// Save what *should* be done, to make it resumable from this point on
|
392 |
-
set_transient("updraft_backdb_".$this->nonce, "begun", 3600*3);
|
393 |
-
|
394 |
-
// The function itself will set to 'finished' if relevant
|
395 |
-
// The presence of the transient indicates that files are supposed to be in this set
|
396 |
-
if ($backup_files) {
|
397 |
-
set_transient("updraft_backf_".$this->nonce, "begun", 3600*3);
|
398 |
-
$backup_array = $this->resumable_backup_of_files(false);
|
399 |
-
}
|
400 |
-
|
401 |
-
// Save this to our history so we can track backups for the retain feature
|
402 |
-
$this->log("Saving backup history");
|
403 |
-
$this->save_backup_history($backup_array);
|
404 |
-
|
405 |
-
$this->check_backup_race($backup_array);
|
406 |
-
|
407 |
-
// The transient is read and written below (instead of using the existing variable) so that we can copy-and-paste this part as needed.
|
408 |
-
if ($backup_database) {
|
409 |
-
$this->log("Beginning backup of database");
|
410 |
-
$db_backup = $this->backup_db();
|
411 |
-
if ($db_backup) $backup_array['db'] = $db_backup;
|
412 |
-
$backup_contains = get_transient("updraft_backupcontains_".$this->nonce);
|
413 |
-
$backup_contains = (substr($backup_contains,0,10) == "Files only") ? "Files and database" : "Database only (no files)";
|
414 |
-
set_transient("updraft_backupcontains_".$this->nonce, $backup_contains, 3600*3);
|
415 |
-
set_transient("updraft_backdb_".$this->nonce, "finished", 3600*3);
|
416 |
-
}
|
417 |
-
|
418 |
-
$this->check_backup_race($backup_array);
|
419 |
-
|
420 |
-
// Save this to our history so we can track backups for the retain feature
|
421 |
-
$this->log("Saving backup history");
|
422 |
-
// This is done before cloud despatch, because we want a record of what *should* be in the backup. Whether it actually makes it there or not is not yet known.
|
423 |
-
$this->save_backup_history($backup_array);
|
424 |
-
|
425 |
-
// Now encrypt the database, and re-save
|
426 |
-
if ($backup_database && isset($backup_array['db'])) {
|
427 |
-
$backup_array['db'] = $this->encrypt_file($backup_array['db']);
|
428 |
-
// Re-save with the possibly-altered database filename
|
429 |
-
$this->save_backup_history($backup_array);
|
430 |
-
}
|
431 |
-
|
432 |
-
//cloud operations (S3,Google Drive,FTP,email,nothing)
|
433 |
-
//this also calls the retain (prune) feature at the end (done in this method to reuse existing cloud connections)
|
434 |
-
if(is_array($backup_array) && count($backup_array) >0) {
|
435 |
-
$this->cloud_backup($backup_array);
|
436 |
-
}
|
437 |
-
|
438 |
-
//save the last backup info, including errors, if any
|
439 |
-
$this->log("Saving last backup information into WordPress db");
|
440 |
-
$this->save_last_backup($backup_array);
|
441 |
-
|
442 |
}
|
443 |
|
444 |
-
//
|
445 |
-
$this->
|
|
|
|
|
|
|
|
|
446 |
|
447 |
}
|
448 |
|
@@ -458,15 +392,7 @@ class UpdraftPlus {
|
|
458 |
$rijndael->setKey($encryption);
|
459 |
$updraft_dir = $this->backups_dir_location();
|
460 |
$file_size = @filesize($updraft_dir.'/'.$file)/1024;
|
461 |
-
|
462 |
-
$buffer = "";
|
463 |
-
while (!feof ($in_handle)) {
|
464 |
-
$buffer .= fread($in_handle, 16384);
|
465 |
-
}
|
466 |
-
fclose ($in_handle);
|
467 |
-
$out_handle = @fopen($updraft_dir.'/'.$file.'.crypt','w');
|
468 |
-
if (!fwrite($out_handle, $rijndael->encrypt($buffer))) {$encryption_error = 1;}
|
469 |
-
fclose ($out_handle);
|
470 |
if (0 == $encryption_error) {
|
471 |
$time_taken = max(0.000001, microtime(true)-$microstart);
|
472 |
$this->log("$file: encryption successful: ".round($file_size,1)."Kb in ".round($time_taken,1)."s (".round($file_size/$time_taken, 1)."Kb/s)");
|
@@ -489,9 +415,8 @@ class UpdraftPlus {
|
|
489 |
if (empty($this->errors)) {
|
490 |
if ($clear_nonce_transient) {
|
491 |
$this->log("There were no errors in the uploads, so the 'resume' event is being unscheduled");
|
492 |
-
wp_clear_scheduled_hook('updraft_backup_resume', array($cancel_event));
|
493 |
-
|
494 |
-
delete_transient("updraftplus_backup_job_time");
|
495 |
}
|
496 |
} else {
|
497 |
$this->log("There were errors in the uploads, so the 'resume' event is remaining scheduled");
|
@@ -554,7 +479,12 @@ class UpdraftPlus {
|
|
554 |
|
555 |
$append_log = ($debug_mode && $this->logfile_name != "") ? "\r\nLog contents:\r\n".file_get_contents($this->logfile_name) : "" ;
|
556 |
|
557 |
-
|
|
|
|
|
|
|
|
|
|
|
558 |
|
559 |
}
|
560 |
|
@@ -568,10 +498,9 @@ class UpdraftPlus {
|
|
568 |
|
569 |
// This should be called whenever a file is successfully uploaded
|
570 |
function uploaded_file($file, $id = false) {
|
571 |
-
# We take an MD5 hash because set_transient wants a name of 45 characters or less
|
572 |
$hash = md5($file);
|
573 |
$this->log("Recording as successfully uploaded: $file ($hash)");
|
574 |
-
|
575 |
if ($id) {
|
576 |
$ids = UpdraftPlus_Options::get_updraft_option('updraft_file_ids', array() );
|
577 |
$ids[$file] = $id;
|
@@ -752,7 +681,7 @@ class UpdraftPlus {
|
|
752 |
$rate = round($kbsize/$timetaken, 1);
|
753 |
$this->log("Created $whichone zip - file size is ".round($kbsize,1)." Kb in ".round($timetaken,1)." s ($rate Kb/s)");
|
754 |
}
|
755 |
-
|
756 |
return basename($full_path);
|
757 |
}
|
758 |
|
@@ -802,51 +731,51 @@ class UpdraftPlus {
|
|
802 |
|
803 |
# Others
|
804 |
if (UpdraftPlus_Options::get_updraft_option('updraft_include_others', true)) {
|
805 |
-
$this->log("Beginning backup of other directories found in the content directory");
|
806 |
|
807 |
if ($transient_status == 'finished') {
|
808 |
$backup_array['others'] = $backup_file_basename.'-others.zip';
|
809 |
} else {
|
810 |
-
|
811 |
-
|
812 |
-
|
813 |
-
|
814 |
-
|
815 |
-
|
816 |
-
|
817 |
-
|
818 |
-
|
819 |
-
|
820 |
-
|
821 |
-
|
822 |
-
|
823 |
-
|
824 |
-
|
825 |
-
|
826 |
-
|
827 |
-
|
828 |
-
|
829 |
-
|
830 |
-
$
|
831 |
-
|
832 |
-
|
833 |
-
|
834 |
-
|
835 |
-
|
836 |
-
|
837 |
-
|
|
|
|
|
|
|
|
|
|
|
838 |
}
|
839 |
-
} else {
|
840 |
-
$this->log('ERROR: Could not read the content directory: '.WP_CONTENT_DIR);
|
841 |
-
$this->error('Could not read the content directory: '.WP_CONTENT_DIR);
|
842 |
-
}
|
843 |
|
844 |
-
|
845 |
-
|
846 |
-
|
847 |
-
|
848 |
-
|
849 |
-
|
850 |
# If we are not already finished
|
851 |
}
|
852 |
} else {
|
@@ -874,7 +803,7 @@ class UpdraftPlus {
|
|
874 |
global $wpdb;
|
875 |
$backup_history = @unserialize($wpdb->get_var($wpdb->prepare("SELECT option_value from $wpdb->options WHERE option_name='updraft_backup_history'")));
|
876 |
if(is_array($backup_history)) {
|
877 |
-
krsort($backup_history); //reverse sort so earliest backup is last on the array.
|
878 |
} else {
|
879 |
$backup_history = array();
|
880 |
}
|
@@ -935,6 +864,7 @@ class UpdraftPlus {
|
|
935 |
$backup_file_base = $updraft_dir.'/'.$file_base;
|
936 |
|
937 |
if ("finished" == $already_done) return basename($backup_file_base.'-db.gz');
|
|
|
938 |
|
939 |
$total_tables = 0;
|
940 |
|
@@ -1072,10 +1002,7 @@ class UpdraftPlus {
|
|
1072 |
}
|
1073 |
|
1074 |
// Comment in SQL-file
|
1075 |
-
$this->stow("\n\n");
|
1076 |
-
$this->stow("#\n");
|
1077 |
-
$this->stow('# ' . sprintf(__('Data contents of table %s','wp-db-backup'),$this->backquote($table)) . "\n");
|
1078 |
-
$this->stow("#\n");
|
1079 |
}
|
1080 |
|
1081 |
// In UpdraftPlus, segment is always 'none'
|
@@ -1091,19 +1018,16 @@ class UpdraftPlus {
|
|
1091 |
}
|
1092 |
}
|
1093 |
|
1094 |
-
// Batch by $row_inc
|
1095 |
-
if ( ! defined('ROWS_PER_SEGMENT') ) define('ROWS_PER_SEGMENT', 100);
|
1096 |
-
|
1097 |
if($segment == 'none') {
|
1098 |
$row_start = 0;
|
1099 |
-
$row_inc =
|
1100 |
} else {
|
1101 |
-
$row_start = $segment *
|
1102 |
-
$row_inc =
|
1103 |
}
|
1104 |
-
do {
|
1105 |
|
1106 |
-
|
|
|
1107 |
$table_data = $wpdb->get_results("SELECT * FROM $table LIMIT {$row_start}, {$row_inc}", ARRAY_A);
|
1108 |
$entries = 'INSERT INTO ' . $this->backquote($table) . ' VALUES (';
|
1109 |
// \x08\\x09, not required
|
@@ -1521,6 +1445,7 @@ class UpdraftPlus {
|
|
1521 |
}
|
1522 |
|
1523 |
function wordshell_random_advert($urls) {
|
|
|
1524 |
$rad = rand(0,6);
|
1525 |
switch ($rad) {
|
1526 |
case 0:
|
@@ -1727,16 +1652,21 @@ class UpdraftPlus {
|
|
1727 |
$dir_info = '<span style="color:red">Backup directory specified is <b>not</b> writable, or does not exist. <span style="font-size:110%;font-weight:bold"><a href="options-general.php?page=updraftplus&action=updraft_create_backup_dir">Click here</a></span> to attempt to create the directory and set the permissions. If that is unsuccessful check the permissions on your server or change it to another directory that is writable by your web server process.</span>';
|
1728 |
}
|
1729 |
|
1730 |
-
echo $dir_info ?> This is where
|
1731 |
</tr>
|
1732 |
<tr>
|
1733 |
<td></td>
|
1734 |
<td>
|
1735 |
-
<p style="margin: 10px 0; padding: 10px; font-size: 140%; background-color: lightYellow; border-color: #E6DB55; border: 1px solid; border-radius: 4px;">
|
1736 |
<?php
|
1737 |
-
|
|
|
1738 |
?>
|
|
|
|
|
1739 |
</p>
|
|
|
|
|
|
|
1740 |
</td>
|
1741 |
</tr>
|
1742 |
<tr>
|
@@ -1818,10 +1748,10 @@ class UpdraftPlus {
|
|
1818 |
echo '</div>';
|
1819 |
}
|
1820 |
|
1821 |
-
if(isset($_POST['action']) && $_POST['action'] == 'updraft_backup_debug_all') { $this->
|
1822 |
elseif (isset($_POST['action']) && $_POST['action'] == 'updraft_backup_debug_db') { $this->backup_db(); }
|
1823 |
elseif (isset($_POST['action']) && $_POST['action'] == 'updraft_wipesettings') {
|
1824 |
-
$settings = array('updraft_interval', 'updraft_interval_database', 'updraft_retain', 'updraft_retain_db', 'updraft_encryptionphrase', 'updraft_service', 'updraft_s3_login', 'updraft_s3_pass', 'updraft_s3_remote_path', 'updraft_dropbox_appkey', 'updraft_dropbox_secret', 'updraft_dropbox_folder', 'updraft_googledrive_clientid', 'updraft_googledrive_secret', 'updraft_googledrive_remotepath', 'updraft_ftp_login', 'updraft_ftp_pass', 'updraft_ftp_remote_path', 'updraft_server_address', 'updraft_dir', 'updraft_email', 'updraft_delete_local', 'updraft_debug_mode', 'updraft_include_plugins', 'updraft_include_themes', 'updraft_include_uploads', 'updraft_include_others', 'updraft_include_others_exclude', 'updraft_lastmessage');
|
1825 |
foreach ($settings as $s) {
|
1826 |
UpdraftPlus_Options::delete_updraft_option($s);
|
1827 |
}
|
@@ -1832,7 +1762,7 @@ class UpdraftPlus {
|
|
1832 |
<div class="wrap">
|
1833 |
<h1><?php echo $this->plugin_title; ?></h1>
|
1834 |
|
1835 |
-
Maintained by <b>David Anderson</b> (<a href="http://david.dw-perspective.org.uk">Homepage</a
|
1836 |
<br>
|
1837 |
<?php
|
1838 |
if(isset($_GET['updraft_restore_success'])) {
|
@@ -1840,9 +1770,7 @@ class UpdraftPlus {
|
|
1840 |
}
|
1841 |
|
1842 |
$ws_advert = $this->wordshell_random_advert(1);
|
1843 |
-
echo
|
1844 |
-
<div class="updated fade" style="max-width: 800px; font-size:140%; line-height: 140%; padding:14px; clear:left;">${ws_advert}</div>
|
1845 |
-
ENDHERE;
|
1846 |
|
1847 |
if($deleted_old_dirs) echo '<div style="color:blue">Old directories successfully deleted.</div>';
|
1848 |
|
4 |
Plugin URI: http://wordpress.org/extend/plugins/updraftplus
|
5 |
Description: Backup and restore: your content and database can be automatically backed up to Amazon S3, Dropbox, Google Drive, FTP or email, on separate schedules.
|
6 |
Author: David Anderson.
|
7 |
+
Version: 1.3.7
|
8 |
Donate link: http://david.dw-perspective.org.uk/donate
|
9 |
License: GPLv3 or later
|
10 |
Author URI: http://wordshell.net
|
13 |
/*
|
14 |
TODO
|
15 |
//Add SFTP, Box.Net, SugarSync and Microsoft Skydrive support??
|
16 |
+
//The restorer has a hard-coded wp-content - fix
|
17 |
+
//Read safe-mode only once, remembering it will be totally removed from PHP
|
18 |
+
//Button for wiping files. Also auto-wipe on de-activate/de-install.
|
19 |
+
//Change DB encryption to not require whole gzip in memory (twice)
|
20 |
//improve error reporting / pretty up return messages in admin area. One thing: have a "backup is now finished" flag. Otherwise with the resuming things get ambiguous/confusing. See http://wordpress.org/support/topic/backup-status - user was not aware that backup completely failed. Maybe a "backup status" field for each nonce that gets updated? (Even via AJAX?)
|
21 |
//?? On 'backup now', open up a Lightbox, count down 5 seconds, then start examining the log file (if it can be found)
|
22 |
//Should make clear in dashboard what is a non-fatal error (i.e. can be retried) - leads to unnecessary bug reports
|
23 |
+
// Move the inclusion, cloud and retention data into the backup job (i.e. don't read current config, make it an attribute of each job). In fact, everything should be. So audit all code for where get_option is called inside a backup run: it shouldn't happen.
|
24 |
// 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. Perhaps better to make pruning a separate scheuled task??
|
25 |
// Make jobs *individually* resumable (i.e. all the state info must be keyed on the nonce; then call the resume event *specifying the nonce*)
|
26 |
// Warn the user if their zip-file creation is slooowww...
|
27 |
// Create a "Want Support?" button/console, that leads them through what is needed, and performs some basic tests...
|
28 |
// Resuming partial FTP uploads
|
29 |
// Turn expert options into a jQuery toggle
|
30 |
+
// Provide backup/restoration for UpdraftPlus's settings, to allow 'bootstrap' on a fresh WP install - some kind of single-use code which a remote UpdraftPlus can use to authenticate
|
31 |
// Multiple jobs
|
32 |
+
// When looking for files to delete, is the current encryption setting used? Should not be.
|
33 |
+
// Create single zip, containing even WordPress itself
|
34 |
+
// When a new backup starts, AJAX-update the 'Last backup' display in the admin page.
|
35 |
|
36 |
Encrypt filesystem, if memory allows (and have option for abort if not); split up into multiple zips when needed
|
37 |
// Does not delete old custom directories upon a restore?
|
78 |
|
79 |
class UpdraftPlus {
|
80 |
|
81 |
+
var $version = '1.3.7';
|
82 |
var $plugin_title = 'UpdraftPlus Backup/Restore';
|
83 |
|
84 |
// Choices will be shown in the admin menu in the order used here
|
94 |
var $dbhandle_isgz;
|
95 |
var $errors = array();
|
96 |
var $nonce;
|
|
|
97 |
var $logfile_name = "";
|
98 |
var $logfile_handle = false;
|
99 |
var $backup_time;
|
101 |
var $opened_log_time;
|
102 |
var $backup_dir;
|
103 |
|
104 |
+
var $jobdata;
|
105 |
+
|
106 |
function __construct() {
|
107 |
// Initialisation actions - takes place on plugin load
|
108 |
# Create admin page
|
112 |
# backup_all is used by the manual "Backup Now" button
|
113 |
add_action('updraft_backup_all', array($this,'backup_all'));
|
114 |
# this is our runs-after-backup event, whose purpose is to see if it succeeded or failed, and resume/mom-up etc.
|
115 |
+
add_action('updraft_backup_resume', array($this,'backup_resume'), 10, 3);
|
116 |
add_action('wp_enqueue_scripts', array($this, 'ajax_enqueue') );
|
117 |
add_action('wp_ajax_updraft_download_backup', array($this, 'updraft_download_backup'));
|
118 |
add_action('wp_ajax_updraft_ajax', array($this, 'updraft_ajax_handler'));
|
162 |
$this->backup_time = time();
|
163 |
$nonce = substr(md5(time().rand()), 20);
|
164 |
$this->nonce = $nonce;
|
|
|
|
|
165 |
}
|
166 |
|
167 |
function logfile_open($nonce) {
|
181 |
UpdraftPlus_Options::update_updraft_option("updraft_lastmessage", $line." (".date('M d H:i:s').")");
|
182 |
}
|
183 |
|
184 |
+
function backup_resume($resumption_no, $bnonce, $btime) {
|
185 |
+
|
186 |
@ignore_user_abort(true);
|
187 |
// This is scheduled for 5 minutes after a backup job starts
|
188 |
+
|
189 |
+
// Restore state
|
190 |
+
if ($resumption_no > 0) {
|
191 |
+
$this->nonce = $bnonce;
|
192 |
+
$this->backup_time = $btime;
|
193 |
+
$this->logfile_open($bnonce);
|
|
|
|
|
|
|
194 |
}
|
195 |
+
|
196 |
+
$this->log("Backup run: resumption=$resumption_no, nonce=$bnonce, begun at=$btime");
|
197 |
+
|
198 |
// Schedule again, to run in 5 minutes again, in case we again fail
|
199 |
$resume_delay = 300;
|
200 |
// A different argument than before is needed otherwise the event is ignored
|
201 |
$next_resumption = $resumption_no+1;
|
202 |
if ($next_resumption < 10) {
|
203 |
+
$this->log("Scheduling a resumption ($next_resumption) in case this run gets aborted");
|
204 |
+
wp_schedule_single_event(time()+$resume_delay, 'updraft_backup_resume', array($next_resumption, $bnonce, $btime));
|
205 |
} else {
|
206 |
+
$this->log("The current run is our tenth attempt - will not schedule a further attempt");
|
207 |
}
|
|
|
208 |
|
209 |
+
// This should be always called; if there were no files in this run, it returns us an empty array
|
210 |
+
$backup_array = $this->resumable_backup_of_files($resumption_no);
|
211 |
// This save, if there was something, is then immediately picked up again
|
212 |
if (is_array($backup_array)) $this->save_backup_history($backup_array);
|
213 |
|
214 |
// Returns an array, most recent first, of backup sets
|
215 |
$backup_history = $this->get_backup_history();
|
216 |
+
if (!isset($backup_history[$btime])) {
|
217 |
+
$this->log("Could not find a record in the database of a backup with this timestamp");
|
218 |
+
}
|
219 |
|
220 |
$our_files=$backup_history[$btime];
|
221 |
if (!is_array($our_files)) $our_files = array();
|
222 |
|
223 |
$undone_files = array();
|
224 |
|
225 |
+
$backup_database = $this->jobdata_get('backup_database');
|
226 |
|
227 |
// The transient is read and written below (instead of using the existing variable) so that we can copy-and-paste this part as needed.
|
228 |
+
if ($backup_database == "begun" || $backup_database == "finished" || $backup_database == "encrypted") {
|
229 |
if ($backup_database == "begun") {
|
230 |
+
if ($resumption_no > 0) {
|
231 |
+
$this->log("Resuming creation of database dump");
|
232 |
+
} else {
|
233 |
+
$this->log("Beginning creation of database dump");
|
234 |
+
}
|
235 |
+
} elseif ($backup_database == 'encrypted') {
|
236 |
+
$this->log("Database dump: Creation and encryption were completed already");
|
237 |
} else {
|
238 |
$this->log("Database dump: Creation was completed already");
|
239 |
}
|
240 |
$db_backup = $this->backup_db($backup_database);
|
241 |
if(is_array($our_files) && is_string($db_backup)) $our_files['db'] = $db_backup;
|
242 |
+
if ($backup_database != 'encrypted') $this->jobdata_set("backup_database", 'finished');
|
|
|
|
|
243 |
} else {
|
244 |
$this->log("Unrecognised data when trying to ascertain if the database was backed up ($backup_database)");
|
245 |
}
|
253 |
if (isset($our_files['db']) && !preg_match("/\.crypt$/", $our_files['db'])) {
|
254 |
$our_files['db'] = $this->encrypt_file($our_files['db']);
|
255 |
$this->save_backup_history($our_files);
|
256 |
+
$this->jobdata_set("backup_database", "encrypted");
|
257 |
}
|
258 |
|
259 |
foreach ($our_files as $key => $file) {
|
260 |
|
261 |
+
// Only continue if the stored info was about a dump
|
262 |
+
if ($key != 'plugins' && $key != 'themes' && $key != 'others' && $key != 'uploads' && $key != 'db') continue;
|
263 |
|
264 |
$hash = md5($file);
|
265 |
$fullpath = $this->backups_dir_location().'/'.$file;
|
266 |
+
if ($this->jobdata_get("uploaded_$hash") === "yes") {
|
267 |
+
$this->log("$file: $key: This file has already been successfully uploaded");
|
268 |
} elseif (is_file($fullpath)) {
|
269 |
+
$this->log("$file: $key: This file has not yet been successfully uploaded: will queue");
|
270 |
$undone_files[$key] = $file;
|
271 |
} else {
|
272 |
$this->log("$file: Note: This file was not marked as successfully uploaded, but does not exist on the local filesystem");
|
276 |
|
277 |
if (count($undone_files) == 0) {
|
278 |
$this->log("There were no more files that needed uploading; backup job is complete");
|
279 |
+
// No email, as the user probably already got one if something else completed the run
|
280 |
+
$this->backup_finish($next_resumption, true, false, $resumption_no);
|
281 |
return;
|
282 |
}
|
283 |
|
284 |
$this->log("Requesting backup of the files that were not successfully uploaded");
|
285 |
$this->cloud_backup($undone_files);
|
286 |
|
287 |
+
$this->log("Resume backup ($bnonce, $resumption_no): finish run");
|
|
|
288 |
$this->backup_finish($next_resumption, true, true, $resumption_no);
|
289 |
|
290 |
}
|
291 |
|
292 |
function backup_all() {
|
293 |
+
$this->boot_backup(true,true);
|
294 |
}
|
295 |
|
296 |
function backup_files() {
|
297 |
# Note that the "false" for database gets over-ridden automatically if they turn out to have the same schedules
|
298 |
+
$this->boot_backup(true,false);
|
|
|
299 |
}
|
300 |
|
301 |
function backup_database() {
|
302 |
# Note that nothing will happen if the file backup had the same schedule
|
303 |
+
$this->boot_backup(false,true);
|
|
|
304 |
}
|
305 |
|
306 |
+
function jobdata_set($key, $value) {
|
307 |
+
if (is_array($this->jobdata)) {
|
308 |
+
$this->jobdata[$key] = $value;
|
309 |
+
} else {
|
310 |
+
$this->jobdata = array($key => $value);
|
311 |
+
}
|
312 |
+
set_transient("updraft_jobdata_".$this->nonce, $this->jobdata, 14400);
|
313 |
+
}
|
314 |
+
|
315 |
+
function jobdata_get($key) {
|
316 |
+
if (!is_array($this->jobdata)) {
|
317 |
+
$this->jobdata = get_transient("updraft_jobdata_".$this->nonce);
|
318 |
+
if (!is_array($this->jobdata)) return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
319 |
}
|
320 |
+
return (isset($this->jobdata[$key])) ? $this->jobdata[$key] : false;
|
321 |
}
|
322 |
|
323 |
// 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.
|
324 |
+
function resumable_backup_of_files($resumption_no) {
|
325 |
//backup directories and return a numerically indexed array of file paths to the backup files
|
326 |
+
$transient_status = $this->jobdata_get("backup_files");
|
327 |
if ($transient_status == "finished") {
|
328 |
$this->log("Creation of backups of directories: already finished");
|
329 |
} elseif ($transient_status == "begun") {
|
330 |
+
if ($resumption_no>0) {
|
331 |
$this->log("Creation of backups of directories: had begun; will resume");
|
332 |
} else {
|
333 |
$this->log("Creation of backups of directories: beginning");
|
339 |
}
|
340 |
// We want this array, even if already finished
|
341 |
$backup_array = $this->backup_dirs($transient_status);
|
|
|
342 |
// This can get over-written later
|
343 |
+
$this->jobdata_set('backup_files', 'finished');
|
|
|
344 |
return $backup_array;
|
345 |
}
|
346 |
|
347 |
+
// This procedure initiates a backup run
|
348 |
+
function boot_backup($backup_files, $backup_database) {
|
349 |
|
350 |
@ignore_user_abort(true);
|
351 |
+
|
352 |
//generate backup information
|
353 |
$this->backup_time_nonce();
|
|
|
354 |
$this->logfile_open($this->nonce);
|
355 |
|
356 |
// Log some information that may be helpful
|
357 |
global $wp_version;
|
358 |
+
$this->log("Tasks: Backup files: $backup_files (schedule: ".UpdraftPlus_Options::get_updraft_option('updraft_interval', 'unset').") Backup DB: $backup_database (schedule: ".UpdraftPlus_Options::get_updraft_option('updraft_interval_database', 'unset').")");
|
359 |
|
360 |
# If the files and database schedules are the same, and if this the file one, then we rope in database too.
|
361 |
# On the other hand, if the schedules were the same and this was the database run, then there is nothing to do.
|
365 |
|
366 |
$this->log("Processed schedules. Tasks now: Backup files: $backup_files Backup DB: $backup_database");
|
367 |
|
368 |
+
# If nothing to be done, then just finish
|
369 |
+
if (!$backup_files && !$backup_database) {
|
370 |
+
$this->backup_finish(1, false, false, 0);
|
371 |
+
return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
372 |
}
|
373 |
|
374 |
+
// Save what *should* be done, to make it resumable from this point on
|
375 |
+
if ($backup_database) $this->jobdata_set("backup_database", "begun");
|
376 |
+
if ($backup_files) $this->jobdata_set("backup_files", "begun");
|
377 |
+
|
378 |
+
// Everthing is now set up; now go
|
379 |
+
$this->backup_resume(0, $this->nonce, $this->backup_time);
|
380 |
|
381 |
}
|
382 |
|
392 |
$rijndael->setKey($encryption);
|
393 |
$updraft_dir = $this->backups_dir_location();
|
394 |
$file_size = @filesize($updraft_dir.'/'.$file)/1024;
|
395 |
+
if (false === file_put_contents($updraft_dir.'/'.$file.'.crypt' , $rijndael->encrypt(file_get_contents($updraft_dir.'/'.$file)))) {$encryption_error = 1;}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
396 |
if (0 == $encryption_error) {
|
397 |
$time_taken = max(0.000001, microtime(true)-$microstart);
|
398 |
$this->log("$file: encryption successful: ".round($file_size,1)."Kb in ".round($time_taken,1)."s (".round($file_size/$time_taken, 1)."Kb/s)");
|
415 |
if (empty($this->errors)) {
|
416 |
if ($clear_nonce_transient) {
|
417 |
$this->log("There were no errors in the uploads, so the 'resume' event is being unscheduled");
|
418 |
+
wp_clear_scheduled_hook('updraft_backup_resume', array($cancel_event, $this->nonce, $this->backup_time));
|
419 |
+
// TODO: Delete the job transient (is presently useful for debugging, and only lasts 4 hours)
|
|
|
420 |
}
|
421 |
} else {
|
422 |
$this->log("There were errors in the uploads, so the 'resume' event is remaining scheduled");
|
479 |
|
480 |
$append_log = ($debug_mode && $this->logfile_name != "") ? "\r\nLog contents:\r\n".file_get_contents($this->logfile_name) : "" ;
|
481 |
|
482 |
+
$backup_files = $this->jobdata_get("backup_files");
|
483 |
+
$backup_db = $this->jobdata_get("backup_database");
|
484 |
+
|
485 |
+
$backup_contains = (substr($backup_contains,0,10) == "Files only") ? "Files and database" : "Database only (no files)";
|
486 |
+
|
487 |
+
wp_mail($sendmail_to,'Backed up: '.get_bloginfo('name').' (UpdraftPlus '.$this->version.') '.date('Y-m-d H:i',time()),'Site: '.site_url()."\r\nUpdraftPlus WordPress backup is complete.\r\nBackup contains: ".$backup_contains."\r\n\r\n".$this->wordshell_random_advert(0)."\r\n".$append_log);
|
488 |
|
489 |
}
|
490 |
|
498 |
|
499 |
// This should be called whenever a file is successfully uploaded
|
500 |
function uploaded_file($file, $id = false) {
|
|
|
501 |
$hash = md5($file);
|
502 |
$this->log("Recording as successfully uploaded: $file ($hash)");
|
503 |
+
$this->jobdata_set("uploaded_$hash", "yes");
|
504 |
if ($id) {
|
505 |
$ids = UpdraftPlus_Options::get_updraft_option('updraft_file_ids', array() );
|
506 |
$ids[$file] = $id;
|
681 |
$rate = round($kbsize/$timetaken, 1);
|
682 |
$this->log("Created $whichone zip - file size is ".round($kbsize,1)." Kb in ".round($timetaken,1)." s ($rate Kb/s)");
|
683 |
}
|
684 |
+
|
685 |
return basename($full_path);
|
686 |
}
|
687 |
|
731 |
|
732 |
# Others
|
733 |
if (UpdraftPlus_Options::get_updraft_option('updraft_include_others', true)) {
|
|
|
734 |
|
735 |
if ($transient_status == 'finished') {
|
736 |
$backup_array['others'] = $backup_file_basename.'-others.zip';
|
737 |
} else {
|
738 |
+
$this->log("Beginning backup of other directories found in the content directory");
|
739 |
+
|
740 |
+
// http://www.phpconcept.net/pclzip/user-guide/53
|
741 |
+
/* First parameter to create is:
|
742 |
+
An array of filenames or dirnames,
|
743 |
+
or
|
744 |
+
A string containing the filename or a dirname,
|
745 |
+
or
|
746 |
+
A string containing a list of filename or dirname separated by a comma.
|
747 |
+
*/
|
748 |
+
|
749 |
+
# Initialise
|
750 |
+
$other_dirlist = array();
|
751 |
+
|
752 |
+
$others_skip = preg_split("/,/",UpdraftPlus_Options::get_updraft_option('updraft_include_others_exclude', UPDRAFT_DEFAULT_OTHERS_EXCLUDE));
|
753 |
+
# Make the values into the keys
|
754 |
+
$others_skip = array_flip($others_skip);
|
755 |
+
|
756 |
+
$this->log('Looking for candidates to back up in: '.WP_CONTENT_DIR);
|
757 |
+
if ($handle = opendir(WP_CONTENT_DIR)) {
|
758 |
+
while (false !== ($entry = readdir($handle))) {
|
759 |
+
$candidate = WP_CONTENT_DIR.'/'.$entry;
|
760 |
+
if ($entry == "." || $entry == "..") { ; }
|
761 |
+
elseif ($candidate == $updraft_dir) { $this->log("others: $entry: skipping: this is the updraft directory"); }
|
762 |
+
elseif ($candidate == $wp_themes_dir) { $this->log("others: $entry: skipping: this is the themes directory"); }
|
763 |
+
elseif ($candidate == $wp_upload_dir) { $this->log("others: $entry: skipping: this is the uploads directory"); }
|
764 |
+
elseif ($candidate == $wp_plugins_dir) { $this->log("others: $entry: skipping: this is the plugins directory"); }
|
765 |
+
elseif (isset($others_skip[$entry])) { $this->log("others: $entry: skipping: excluded by options"); }
|
766 |
+
else { $this->log("others: $entry: adding to list"); array_push($other_dirlist, $candidate); }
|
767 |
+
}
|
768 |
+
} else {
|
769 |
+
$this->log('ERROR: Could not read the content directory: '.WP_CONTENT_DIR);
|
770 |
+
$this->error('Could not read the content directory: '.WP_CONTENT_DIR);
|
771 |
}
|
|
|
|
|
|
|
|
|
772 |
|
773 |
+
if (count($other_dirlist)>0) {
|
774 |
+
$created = $this->create_zip($other_dirlist, 'others', $updraft_dir, $backup_file_basename);
|
775 |
+
if ($created) $backup_array['others'] = $created;
|
776 |
+
} else {
|
777 |
+
$this->log("No backup of other directories: there was nothing found to back up");
|
778 |
+
}
|
779 |
# If we are not already finished
|
780 |
}
|
781 |
} else {
|
803 |
global $wpdb;
|
804 |
$backup_history = @unserialize($wpdb->get_var($wpdb->prepare("SELECT option_value from $wpdb->options WHERE option_name='updraft_backup_history'")));
|
805 |
if(is_array($backup_history)) {
|
806 |
+
krsort($backup_history); //reverse sort so earliest backup is last on the array. Then we can array_pop.
|
807 |
} else {
|
808 |
$backup_history = array();
|
809 |
}
|
864 |
$backup_file_base = $updraft_dir.'/'.$file_base;
|
865 |
|
866 |
if ("finished" == $already_done) return basename($backup_file_base.'-db.gz');
|
867 |
+
if ("encrypted" == $already_done) return basename($backup_file_base.'-db.gz.crypt');
|
868 |
|
869 |
$total_tables = 0;
|
870 |
|
1002 |
}
|
1003 |
|
1004 |
// Comment in SQL-file
|
1005 |
+
$this->stow("\n\n#\n# " . sprintf(__('Data contents of table %s','wp-db-backup'),$this->backquote($table)) . "\n#\n");
|
|
|
|
|
|
|
1006 |
}
|
1007 |
|
1008 |
// In UpdraftPlus, segment is always 'none'
|
1018 |
}
|
1019 |
}
|
1020 |
|
|
|
|
|
|
|
1021 |
if($segment == 'none') {
|
1022 |
$row_start = 0;
|
1023 |
+
$row_inc = 100;
|
1024 |
} else {
|
1025 |
+
$row_start = $segment * 100;
|
1026 |
+
$row_inc = 100;
|
1027 |
}
|
|
|
1028 |
|
1029 |
+
do {
|
1030 |
+
if ( !@ini_get('safe_mode') || strtolower(@ini_get('safe_mode')) == "off") @set_time_limit(15*60);
|
1031 |
$table_data = $wpdb->get_results("SELECT * FROM $table LIMIT {$row_start}, {$row_inc}", ARRAY_A);
|
1032 |
$entries = 'INSERT INTO ' . $this->backquote($table) . ' VALUES (';
|
1033 |
// \x08\\x09, not required
|
1445 |
}
|
1446 |
|
1447 |
function wordshell_random_advert($urls) {
|
1448 |
+
if (defined('UPDRAFTPLUS_PREMIUM')) return "";
|
1449 |
$rad = rand(0,6);
|
1450 |
switch ($rad) {
|
1451 |
case 0:
|
1652 |
$dir_info = '<span style="color:red">Backup directory specified is <b>not</b> writable, or does not exist. <span style="font-size:110%;font-weight:bold"><a href="options-general.php?page=updraftplus&action=updraft_create_backup_dir">Click here</a></span> to attempt to create the directory and set the permissions. If that is unsuccessful check the permissions on your server or change it to another directory that is writable by your web server process.</span>';
|
1653 |
}
|
1654 |
|
1655 |
+
echo $dir_info ?> This is where UpdraftPlus will write the zip files it creates initially. This directory must be writable by your web server. Typically you'll want to have it inside your wp-content folder (this is the default). <b>Do not</b> place it inside your uploads dir, as that will cause recursion issues (backups of backups of backups of...).</td>
|
1656 |
</tr>
|
1657 |
<tr>
|
1658 |
<td></td>
|
1659 |
<td>
|
|
|
1660 |
<?php
|
1661 |
+
$ws_ad = $this->wordshell_random_advert(1);
|
1662 |
+
if ($ws_ad) {
|
1663 |
?>
|
1664 |
+
<p style="margin: 10px 0; padding: 10px; font-size: 140%; background-color: lightYellow; border-color: #E6DB55; border: 1px solid; border-radius: 4px;">
|
1665 |
+
<?php echo $ws_ad; ?>
|
1666 |
</p>
|
1667 |
+
<?php
|
1668 |
+
}
|
1669 |
+
?>
|
1670 |
</td>
|
1671 |
</tr>
|
1672 |
<tr>
|
1748 |
echo '</div>';
|
1749 |
}
|
1750 |
|
1751 |
+
if(isset($_POST['action']) && $_POST['action'] == 'updraft_backup_debug_all') { $this->boot_backup(true,true); }
|
1752 |
elseif (isset($_POST['action']) && $_POST['action'] == 'updraft_backup_debug_db') { $this->backup_db(); }
|
1753 |
elseif (isset($_POST['action']) && $_POST['action'] == 'updraft_wipesettings') {
|
1754 |
+
$settings = array('updraft_interval', 'updraft_interval_database', 'updraft_retain', 'updraft_retain_db', 'updraft_encryptionphrase', 'updraft_service', 'updraft_s3_login', 'updraft_s3_pass', 'updraft_s3_remote_path', 'updraft_dropbox_appkey', 'updraft_dropbox_secret', 'updraft_dropbox_folder', 'updraft_googledrive_clientid', 'updraft_googledrive_secret', 'updraft_googledrive_remotepath', 'updraft_ftp_login', 'updraft_ftp_pass', 'updraft_ftp_remote_path', 'updraft_server_address', 'updraft_dir', 'updraft_email', 'updraft_delete_local', 'updraft_debug_mode', 'updraft_include_plugins', 'updraft_include_themes', 'updraft_include_uploads', 'updraft_include_others', 'updraft_include_others_exclude', 'updraft_lastmessage', 'updraft_googledrive_clientid', 'updraft_googledrive_token', 'updraft_googledrive_secret', 'updraft_dropboxtk_request_token', 'updraft_dropboxtk_access_token', 'updraft_dropbox_folder', '');
|
1755 |
foreach ($settings as $s) {
|
1756 |
UpdraftPlus_Options::delete_updraft_option($s);
|
1757 |
}
|
1762 |
<div class="wrap">
|
1763 |
<h1><?php echo $this->plugin_title; ?></h1>
|
1764 |
|
1765 |
+
Maintained by <b>David Anderson</b> (<a href="http://david.dw-perspective.org.uk">Homepage</a><?php if (!defined('UPDRAFTPLUS_PREMIUM')) { ?> | <a href="http://updraftplus.com">Premium</a> | <a href="http://wordshell.net">WordShell - WordPress command line</a> | <a href="http://david.dw-perspective.org.uk/donate">Donate</a><?php } ?> | <a href="http://wordpress.org/extend/plugins/updraftplus/faq/">FAQs</a> | <a href="http://profiles.wordpress.org/davidanderson/">My other WordPress plugins</a>). Version: <?php echo $this->version; ?>
|
1766 |
<br>
|
1767 |
<?php
|
1768 |
if(isset($_GET['updraft_restore_success'])) {
|
1770 |
}
|
1771 |
|
1772 |
$ws_advert = $this->wordshell_random_advert(1);
|
1773 |
+
if ($ws_advert) { echo '<div class="updated fade" style="max-width: 800px; font-size:140%; line-height: 140%; padding:14px; clear:left;">'.$ws_advert.'</div>'; }
|
|
|
|
|
1774 |
|
1775 |
if($deleted_old_dirs) echo '<div style="color:blue">Old directories successfully deleted.</div>';
|
1776 |
|