Version Description
- 02/23/2013 =
- Now remembers what cloud service you used for historical backups, if you later switch
- Now performs user downloads from the settings page asynchronously, meaning that enormous backups can be fetched this way
- Fixed bug which forced GoogleDrive users to re-authenticate unnecessarily
- Fixed apparent race condition that broke some backups
- Include disk free space warning
- More intelligent scheduling of resumptions, leading to faster completion on hosts with low max_execution_time values
- Polls and updates in-page backup history status (no refresh required)
Download this release
Release Info
Developer | DavidAnderson |
Plugin | UpdraftPlus WordPress Backup Plugin |
Version | 1.4.27 |
Comparing to | |
See all releases |
Code changes from version 1.4.14 to 1.4.27
- includes/Dropbox/API.php +13 -3
- includes/Dropbox/OAuth/Consumer/Curl.php +1 -0
- includes/S3.php +16 -6
- includes/class-gdocs.php +15 -4
- includes/updraft-restorer.php +2 -1
- methods/dropbox.php +5 -2
- methods/ftp.php +1 -0
- methods/googledrive.php +3 -2
- methods/s3.php +4 -3
- options.php +1 -0
- readme.txt +11 -1
- updraftplus.php +509 -170
includes/Dropbox/API.php
CHANGED
@@ -202,19 +202,30 @@ class Dropbox_API
|
|
202 |
* @param string $file Path to file, relative to root, including path
|
203 |
* @param string $outFile Filename to write the downloaded file to
|
204 |
* @param string $revision The revision of the file to retrieve
|
|
|
205 |
* @return array
|
206 |
*/
|
207 |
-
public function getFile($file, $outFile = false, $revision = null)
|
208 |
{
|
209 |
// Only allow php response format for this call
|
210 |
if ($this->responseFormat !== 'php') {
|
211 |
throw new Exception('This method only supports the `php` response format');
|
212 |
}
|
|
|
|
|
213 |
|
214 |
$handle = null;
|
215 |
if ($outFile !== false) {
|
216 |
// Create a file handle if $outFile is specified
|
217 |
-
if (
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
218 |
throw new Exception("Unable to open file handle for $outFile");
|
219 |
} else {
|
220 |
$this->OAuth->setOutFile($handle);
|
@@ -223,7 +234,6 @@ class Dropbox_API
|
|
223 |
|
224 |
$file = $this->encodePath($file);
|
225 |
$call = 'files/' . $this->root . '/' . $file;
|
226 |
-
$params = array('rev' => $revision);
|
227 |
$response = $this->fetch('GET', self::CONTENT_URL, $call, $params);
|
228 |
|
229 |
// Close the file handle if one was opened
|
202 |
* @param string $file Path to file, relative to root, including path
|
203 |
* @param string $outFile Filename to write the downloaded file to
|
204 |
* @param string $revision The revision of the file to retrieve
|
205 |
+
* @param boolean $allow_resume - append to the file if it already exists
|
206 |
* @return array
|
207 |
*/
|
208 |
+
public function getFile($file, $outFile = false, $revision = null, $allow_resume = false)
|
209 |
{
|
210 |
// Only allow php response format for this call
|
211 |
if ($this->responseFormat !== 'php') {
|
212 |
throw new Exception('This method only supports the `php` response format');
|
213 |
}
|
214 |
+
|
215 |
+
$params = array('rev' => $revision);
|
216 |
|
217 |
$handle = null;
|
218 |
if ($outFile !== false) {
|
219 |
// Create a file handle if $outFile is specified
|
220 |
+
if ($allow_resume && file_exists($outFile)) {
|
221 |
+
if (!$handle = fopen($outFile, 'a')) {
|
222 |
+
throw new Exception("Unable to open file handle for $outFile");
|
223 |
+
} else {
|
224 |
+
$this->OAuth->setOutFile($handle);
|
225 |
+
$params['headers'] = array('Range: bytes='.filesize($outFile).'-');
|
226 |
+
}
|
227 |
+
}
|
228 |
+
elseif (!$handle = fopen($outFile, 'w')) {
|
229 |
throw new Exception("Unable to open file handle for $outFile");
|
230 |
} else {
|
231 |
$this->OAuth->setOutFile($handle);
|
234 |
|
235 |
$file = $this->encodePath($file);
|
236 |
$call = 'files/' . $this->root . '/' . $file;
|
|
|
237 |
$response = $this->fetch('GET', self::CONTENT_URL, $call, $params);
|
238 |
|
239 |
// Close the file handle if one was opened
|
includes/Dropbox/OAuth/Consumer/Curl.php
CHANGED
@@ -70,6 +70,7 @@ class Dropbox_Curl extends Dropbox_ConsumerAbstract
|
|
70 |
$options[CURLOPT_HEADER] = false;
|
71 |
$options[CURLOPT_FILE] = $this->outFile;
|
72 |
$options[CURLOPT_BINARYTRANSFER] = true;
|
|
|
73 |
$this->outFile = null;
|
74 |
} elseif ($method == 'POST') { // POST
|
75 |
$options[CURLOPT_POST] = true;
|
70 |
$options[CURLOPT_HEADER] = false;
|
71 |
$options[CURLOPT_FILE] = $this->outFile;
|
72 |
$options[CURLOPT_BINARYTRANSFER] = true;
|
73 |
+
if (isset($additional['headers'])) $options[CURLOPT_HTTPHEADER] = $additional['headers'];
|
74 |
$this->outFile = null;
|
75 |
} elseif ($method == 'POST') { // POST
|
76 |
$options[CURLOPT_POST] = true;
|
includes/S3.php
CHANGED
@@ -753,9 +753,10 @@ class S3
|
|
753 |
* @param string $bucket Bucket name
|
754 |
* @param string $uri Object URI
|
755 |
* @param mixed $saveTo Filename or resource to write to
|
|
|
756 |
* @return mixed
|
757 |
*/
|
758 |
-
public static function getObject($bucket, $uri, $saveTo = false)
|
759 |
{
|
760 |
$rest = new S3Request('GET', $bucket, $uri, self::$endpoint);
|
761 |
if ($saveTo !== false)
|
@@ -763,14 +764,23 @@ class S3
|
|
763 |
if (is_resource($saveTo))
|
764 |
$rest->fp =& $saveTo;
|
765 |
else
|
766 |
-
if (
|
767 |
-
$rest->
|
768 |
-
|
769 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
770 |
}
|
771 |
if ($rest->response->error === false) $rest->getResponse();
|
772 |
|
773 |
-
if ($rest->response->error === false && $rest->response->code
|
774 |
$rest->response->error = array('code' => $rest->response->code, 'message' => 'Unexpected HTTP status');
|
775 |
if ($rest->response->error !== false)
|
776 |
{
|
753 |
* @param string $bucket Bucket name
|
754 |
* @param string $uri Object URI
|
755 |
* @param mixed $saveTo Filename or resource to write to
|
756 |
+
* @param boolean resume, if possible
|
757 |
* @return mixed
|
758 |
*/
|
759 |
+
public static function getObject($bucket, $uri, $saveTo = false, $resume = false)
|
760 |
{
|
761 |
$rest = new S3Request('GET', $bucket, $uri, self::$endpoint);
|
762 |
if ($saveTo !== false)
|
764 |
if (is_resource($saveTo))
|
765 |
$rest->fp =& $saveTo;
|
766 |
else
|
767 |
+
if ($resume && file_exists($saveTo)) {
|
768 |
+
if (($rest->fp = @fopen($saveTo, 'ab')) !== false) {
|
769 |
+
$rest->setHeader('Range', "bytes=".filesize($saveTo).'-');
|
770 |
+
$rest->file = realpath($saveTo);
|
771 |
+
} else {
|
772 |
+
$rest->response->error = array('code' => 0, 'message' => 'Unable to open save file for writing: '.$saveTo);
|
773 |
+
}
|
774 |
+
} else {
|
775 |
+
if (($rest->fp = @fopen($saveTo, 'wb')) !== false)
|
776 |
+
$rest->file = realpath($saveTo);
|
777 |
+
else
|
778 |
+
$rest->response->error = array('code' => 0, 'message' => 'Unable to open save file for writing: '.$saveTo);
|
779 |
+
}
|
780 |
}
|
781 |
if ($rest->response->error === false) $rest->getResponse();
|
782 |
|
783 |
+
if ($rest->response->error === false && ( !$resume && $rest->response->code != 200) || ( $resume && $rest->response->code != 206 && $rest->response->code != 200))
|
784 |
$rest->response->error = array('code' => $rest->response->code, 'message' => 'Unexpected HTTP status');
|
785 |
if ($rest->response->error !== false)
|
786 |
{
|
includes/class-gdocs.php
CHANGED
@@ -611,17 +611,28 @@ class UpdraftPlus_GDocs {
|
|
611 |
|
612 |
}
|
613 |
|
614 |
-
public function download_data( $link, $saveas ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
615 |
|
616 |
-
$result = $this->request(
|
617 |
|
618 |
if ( is_wp_error( $result ) )
|
619 |
return $result;
|
620 |
|
621 |
-
if ( $result['response']['code'] != '200' )
|
622 |
return new WP_Error( 'bad_response', "Received response code '" . $result['response']['code'] . " " . $result['response']['message'] . "' while trying to get '" . $url . "'." );
|
623 |
|
624 |
-
|
|
|
|
|
|
|
625 |
|
626 |
}
|
627 |
|
611 |
|
612 |
}
|
613 |
|
614 |
+
public function download_data( $link, $saveas, $allow_resume = false ) {
|
615 |
+
|
616 |
+
if ($allow_resume && is_file($saveas)) {
|
617 |
+
$headers = array('Range' => 'bytes='.filesize($saveas).'-');
|
618 |
+
$put_flag = FILE_APPEND;
|
619 |
+
} else {
|
620 |
+
$headers = array();
|
621 |
+
$put_flag = NULL;
|
622 |
+
}
|
623 |
|
624 |
+
$result = $this->request($link, 'GET', $headers);
|
625 |
|
626 |
if ( is_wp_error( $result ) )
|
627 |
return $result;
|
628 |
|
629 |
+
if ( $result['response']['code'] != '200' && (!$allow_resume || 206 !== $result['response']['code']))
|
630 |
return new WP_Error( 'bad_response', "Received response code '" . $result['response']['code'] . " " . $result['response']['message'] . "' while trying to get '" . $url . "'." );
|
631 |
|
632 |
+
global $updraftplus;
|
633 |
+
$updraftplus->log("Google Drive downloaded bytes: ".strlen($result['body']));
|
634 |
+
|
635 |
+
file_put_contents($saveas, $result['body'], $put_flag);
|
636 |
|
637 |
}
|
638 |
|
includes/updraft-restorer.php
CHANGED
@@ -14,6 +14,7 @@ class Updraft_Restorer extends WP_Upgrader {
|
|
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;
|
@@ -34,7 +35,7 @@ class Updraft_Restorer extends WP_Upgrader {
|
|
34 |
$working_dir = $this->unpack_package($download , $delete);
|
35 |
if (is_wp_error($working_dir)) return $working_dir;
|
36 |
|
37 |
-
if ($type ==
|
38 |
|
39 |
// In this special case, the backup contents are not in a folder, so it is not simply a case of moving the folder around, but rather looping over all that we find
|
40 |
|
14 |
|
15 |
function restore_backup($backup_file, $type) {
|
16 |
|
17 |
+
// Various keys can get stored in the data - but only some represent actual data entities
|
18 |
if ($type != 'plugins' && $type != 'themes' && $type != 'others' && $type != 'uploads') continue;
|
19 |
|
20 |
global $wp_filesystem;
|
35 |
$working_dir = $this->unpack_package($download , $delete);
|
36 |
if (is_wp_error($working_dir)) return $working_dir;
|
37 |
|
38 |
+
if ($type == 'others' ) {
|
39 |
|
40 |
// In this special case, the backup contents are not in a folder, so it is not simply a case of moving the folder around, but rather looping over all that we find
|
41 |
|
methods/dropbox.php
CHANGED
@@ -185,7 +185,7 @@ class UpdraftPlus_BackupModule_dropbox {
|
|
185 |
|
186 |
$try_the_other_one = false;
|
187 |
try {
|
188 |
-
$get = $dropbox->getFile($file, $updraft_dir.'/'.$file);
|
189 |
} catch (Exception $e) {
|
190 |
// TODO: Remove this October 2013 (we stored in the wrong place for a while...)
|
191 |
$try_the_other_one = true;
|
@@ -197,7 +197,10 @@ class UpdraftPlus_BackupModule_dropbox {
|
|
197 |
$dropbox_folder = trailingslashit(UpdraftPlus_Options::get_updraft_option('updraft_dropbox_folder'));
|
198 |
$updraftplus->error('Dropbox error: '.$e);
|
199 |
try {
|
200 |
-
$get = $dropbox->getFile($file, $updraft_dir.'/'.$file);
|
|
|
|
|
|
|
201 |
} catch (Exception $e) {
|
202 |
$updraftplus->error($possible_error);
|
203 |
$updraftplus->error($e->getMessage());
|
185 |
|
186 |
$try_the_other_one = false;
|
187 |
try {
|
188 |
+
$get = $dropbox->getFile($file, $updraft_dir.'/'.$file, null, true);
|
189 |
} catch (Exception $e) {
|
190 |
// TODO: Remove this October 2013 (we stored in the wrong place for a while...)
|
191 |
$try_the_other_one = true;
|
197 |
$dropbox_folder = trailingslashit(UpdraftPlus_Options::get_updraft_option('updraft_dropbox_folder'));
|
198 |
$updraftplus->error('Dropbox error: '.$e);
|
199 |
try {
|
200 |
+
$get = $dropbox->getFile($file, $updraft_dir.'/'.$file, null, true);
|
201 |
+
if (isset($get['response']['body'])) {
|
202 |
+
$updraftplus->log("Dropbox: downloaded ".round(strlen($get['response']['body'])/1024,1).' Kb');
|
203 |
+
}
|
204 |
} catch (Exception $e) {
|
205 |
$updraftplus->error($possible_error);
|
206 |
$updraftplus->error($e->getMessage());
|
methods/ftp.php
CHANGED
@@ -72,6 +72,7 @@ class UpdraftPlus_BackupModule_ftp {
|
|
72 |
|
73 |
$ftp_remote_path = trailingslashit(UpdraftPlus_Options::get_updraft_option('updraft_ftp_remote_path'));
|
74 |
$fullpath = trailingslashit(UpdraftPlus_Options::get_updraft_option('updraft_dir')).$file;
|
|
|
75 |
$ftp->get($fullpath, $ftp_remote_path.$file, FTP_BINARY);
|
76 |
}
|
77 |
|
72 |
|
73 |
$ftp_remote_path = trailingslashit(UpdraftPlus_Options::get_updraft_option('updraft_ftp_remote_path'));
|
74 |
$fullpath = trailingslashit(UpdraftPlus_Options::get_updraft_option('updraft_dir')).$file;
|
75 |
+
|
76 |
$ftp->get($fullpath, $ftp_remote_path.$file, FTP_BINARY);
|
77 |
}
|
78 |
|
methods/googledrive.php
CHANGED
@@ -270,10 +270,11 @@ class UpdraftPlus_BackupModule_googledrive {
|
|
270 |
return false;
|
271 |
}
|
272 |
// Actually download the thing
|
|
|
273 |
$download_to = trailingslashit(UpdraftPlus_Options::get_updraft_option('updraft_dir')).$file;
|
274 |
-
$gdocs_object->download_data($content_link, $download_to);
|
275 |
|
276 |
-
if (filesize($download_to) >0) {
|
277 |
return true;
|
278 |
} else {
|
279 |
$updraftplus->error("Google Drive error: zero-size file was downloaded");
|
270 |
return false;
|
271 |
}
|
272 |
// Actually download the thing
|
273 |
+
|
274 |
$download_to = trailingslashit(UpdraftPlus_Options::get_updraft_option('updraft_dir')).$file;
|
275 |
+
$gdocs_object->download_data($content_link, $download_to, true);
|
276 |
|
277 |
+
if (filesize($download_to) > 0) {
|
278 |
return true;
|
279 |
} else {
|
280 |
$updraftplus->error("Google Drive error: zero-size file was downloaded");
|
methods/s3.php
CHANGED
@@ -85,9 +85,8 @@ class UpdraftPlus_BackupModule_s3 {
|
|
85 |
$s3->setExceptions(true);
|
86 |
try {
|
87 |
$uploadId = $s3->initiateMultipartUpload($bucket_name, $filepath);
|
88 |
-
} catch
|
89 |
$updraftplus->log('S3 error whilst trying initiateMultipartUpload: '.$e->getMessage().' (line: '.$e->getLine().', file: '.$e->getFile().')');
|
90 |
-
$s3->setExceptions(false);
|
91 |
$uploadId = false;
|
92 |
}
|
93 |
$s3->setExceptions(false);
|
@@ -207,10 +206,12 @@ class UpdraftPlus_BackupModule_s3 {
|
|
207 |
if (!empty($region)) {
|
208 |
$this->set_endpoint($s3, $region);
|
209 |
$fullpath = trailingslashit(UpdraftPlus_Options::get_updraft_option('updraft_dir')).$file;
|
210 |
-
if (!$s3->getObject($bucket_name, $bucket_path.$file, $fullpath)) {
|
|
|
211 |
$updraftplus->error("S3 Error: Failed to download $file. Check your permissions and credentials.");
|
212 |
}
|
213 |
} else {
|
|
|
214 |
$updraftplus->error("S3 Error: Failed to access bucket $bucket_name. Check your permissions and credentials.");
|
215 |
}
|
216 |
|
85 |
$s3->setExceptions(true);
|
86 |
try {
|
87 |
$uploadId = $s3->initiateMultipartUpload($bucket_name, $filepath);
|
88 |
+
} catch (Exception $e) {
|
89 |
$updraftplus->log('S3 error whilst trying initiateMultipartUpload: '.$e->getMessage().' (line: '.$e->getLine().', file: '.$e->getFile().')');
|
|
|
90 |
$uploadId = false;
|
91 |
}
|
92 |
$s3->setExceptions(false);
|
206 |
if (!empty($region)) {
|
207 |
$this->set_endpoint($s3, $region);
|
208 |
$fullpath = trailingslashit(UpdraftPlus_Options::get_updraft_option('updraft_dir')).$file;
|
209 |
+
if (!$s3->getObject($bucket_name, $bucket_path.$file, $fullpath, true)) {
|
210 |
+
$updraftplus->log("S3 Error: Failed to download $file. Check your permissions and credentials.");
|
211 |
$updraftplus->error("S3 Error: Failed to download $file. Check your permissions and credentials.");
|
212 |
}
|
213 |
} else {
|
214 |
+
$updraftplus->log("S3 Error: Failed to access bucket $bucket_name. Check your permissions and credentials.");
|
215 |
$updraftplus->error("S3 Error: Failed to access bucket $bucket_name. Check your permissions and credentials.");
|
216 |
}
|
217 |
|
options.php
CHANGED
@@ -52,6 +52,7 @@ class UpdraftPlus_Options {
|
|
52 |
register_setting('updraft-options-group', 'updraft_googledrive_clientid', array($updraftplus, 'googledrive_clientid_checkchange') );
|
53 |
register_setting('updraft-options-group', 'updraft_googledrive_secret' );
|
54 |
register_setting('updraft-options-group', 'updraft_googledrive_remotepath' );
|
|
|
55 |
register_setting('updraft-options-group', 'updraft_ftp_login' );
|
56 |
register_setting('updraft-options-group', 'updraft_ftp_pass' );
|
57 |
register_setting('updraft-options-group', 'updraft_ftp_remote_path' );
|
52 |
register_setting('updraft-options-group', 'updraft_googledrive_clientid', array($updraftplus, 'googledrive_clientid_checkchange') );
|
53 |
register_setting('updraft-options-group', 'updraft_googledrive_secret' );
|
54 |
register_setting('updraft-options-group', 'updraft_googledrive_remotepath' );
|
55 |
+
|
56 |
register_setting('updraft-options-group', 'updraft_ftp_login' );
|
57 |
register_setting('updraft-options-group', 'updraft_ftp_pass' );
|
58 |
register_setting('updraft-options-group', 'updraft_ftp_remote_path' );
|
readme.txt
CHANGED
@@ -3,7 +3,7 @@ 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.1
|
6 |
-
Stable tag: 1.4.
|
7 |
Author URI: http://updraftplus.com
|
8 |
Donate link: http://david.dw-perspective.org.uk/donate
|
9 |
License: GPLv3 or later
|
@@ -21,6 +21,7 @@ Clean-up old rubbish, and display more status in final email
|
|
21 |
* Files and databases can have separate schedules
|
22 |
* Failed uploads are automatically resumed/retried
|
23 |
* Select which files to backup (plugins, themes, content, other)
|
|
|
24 |
* Database backups can be encrypted for security
|
25 |
* Debug mode that gives full logging of the backup
|
26 |
* Thousands of users: widely tested and reliable
|
@@ -100,6 +101,15 @@ Thanks for asking - yes, I have. Check out my profile page - http://profiles.wor
|
|
100 |
|
101 |
== Changelog ==
|
102 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
103 |
= 1.4.14 - 02/19/2013 =
|
104 |
* Display final status message in email
|
105 |
* Clean-up any old temporary files detected
|
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.1
|
6 |
+
Stable tag: 1.4.27
|
7 |
Author URI: http://updraftplus.com
|
8 |
Donate link: http://david.dw-perspective.org.uk/donate
|
9 |
License: GPLv3 or later
|
21 |
* Files and databases can have separate schedules
|
22 |
* Failed uploads are automatically resumed/retried
|
23 |
* Select which files to backup (plugins, themes, content, other)
|
24 |
+
* Download backup archives direct from your WordPress dashboard
|
25 |
* Database backups can be encrypted for security
|
26 |
* Debug mode that gives full logging of the backup
|
27 |
* Thousands of users: widely tested and reliable
|
101 |
|
102 |
== Changelog ==
|
103 |
|
104 |
+
= 1.4.27 - 02/23/2013 =
|
105 |
+
* Now remembers what cloud service you used for historical backups, if you later switch
|
106 |
+
* Now performs user downloads from the settings page asynchronously, meaning that enormous backups can be fetched this way
|
107 |
+
* Fixed bug which forced GoogleDrive users to re-authenticate unnecessarily
|
108 |
+
* Fixed apparent race condition that broke some backups
|
109 |
+
* Include disk free space warning
|
110 |
+
* More intelligent scheduling of resumptions, leading to faster completion on hosts with low max_execution_time values
|
111 |
+
* Polls and updates in-page backup history status (no refresh required)
|
112 |
+
|
113 |
= 1.4.14 - 02/19/2013 =
|
114 |
* Display final status message in email
|
115 |
* Clean-up any old temporary files detected
|
updraftplus.php
CHANGED
@@ -4,19 +4,18 @@ Plugin Name: UpdraftPlus - Backup/Restore
|
|
4 |
Plugin URI: http://updraftplus.com
|
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.4.
|
8 |
Donate link: http://david.dw-perspective.org.uk/donate
|
9 |
License: GPLv3 or later
|
10 |
Author URI: http://wordshell.net
|
11 |
-
*/
|
12 |
|
13 |
/*
|
14 |
-
TODO
|
15 |
-
//
|
|
|
16 |
//Add SFTP, Box.Net, SugarSync and Microsoft Skydrive support??
|
17 |
//The restorer has a hard-coded wp-content - fix
|
18 |
-
//Change DB encryption to not require whole gzip in memory (twice)
|
19 |
-
//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?)
|
20 |
//?? On 'backup now', open up a Lightbox, count down 5 seconds, then start examining the log file (if it can be found)
|
21 |
//Should make clear in dashboard what is a non-fatal error (i.e. can be retried) - leads to unnecessary bug reports
|
22 |
// 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,17 +23,19 @@ TODO
|
|
24 |
// Warn the user if their zip-file creation is slooowww...
|
25 |
// Create a "Want Support?" button/console, that leads them through what is needed, and performs some basic tests...
|
26 |
// Resuming partial FTP uploads
|
|
|
|
|
27 |
// 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
|
28 |
// Multiple jobs
|
|
|
|
|
29 |
// Change FTP to use SSL by default
|
30 |
-
//
|
31 |
-
// Disk free-space display
|
32 |
// Multisite add-on should allow restoring of each blog individually
|
33 |
// When looking for files to delete, is the current encryption setting used? Should not be.
|
34 |
// Create single zip, containing even WordPress itself
|
35 |
// When a new backup starts, AJAX-update the 'Last backup' display in the admin page.
|
36 |
// Remove the recurrence of admin notices when settings are saved due to _wp_referer
|
37 |
-
// Auto-detect what the real execution time is (max_execution_time is just one of the upper limits, there can be others, some insivible directly), and tweak our resumption time accordingly
|
38 |
|
39 |
Encrypt filesystem, if memory allows (and have option for abort if not); split up into multiple zips when needed
|
40 |
// Does not delete old custom directories upon a restore?
|
@@ -236,12 +237,20 @@ class UpdraftPlus {
|
|
236 |
$logline .= (method_exists('ZipArchive', 'addFile')) ? "Y" : "N";
|
237 |
}
|
238 |
$this->log($logline);
|
|
|
|
|
239 |
}
|
240 |
|
241 |
# Logs the given line, adding (relative) time stamp and newline
|
242 |
function log($line) {
|
243 |
if ($this->logfile_handle) fwrite($this->logfile_handle, sprintf("%08.03f", round(microtime(true)-$this->opened_log_time, 3))." ".$line."\n");
|
244 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
245 |
}
|
246 |
|
247 |
// This function is used by cloud methods to provide standardised logging, but more importantly to help us detect that meaningful activity took place during a resumption run, so that we can schedule further resumptions if it is worthwhile
|
@@ -258,7 +267,7 @@ class UpdraftPlus {
|
|
258 |
|
259 |
if ($this->current_resumption >= 9 && $this->newresumption_scheduled == false && $percent > ( $this->current_resumption - 9)) {
|
260 |
$resume_interval = $this->jobdata_get('resume_interval');
|
261 |
-
if (!is_numeric($resume_interval) || $resume_interval
|
262 |
$schedule_for = time()+$resume_interval;
|
263 |
$this->newresumption_scheduled = $schedule_for;
|
264 |
$this->log("This is resumption ".$this->current_resumption.", but meaningful uploading is still taking place; so a new one will be scheduled");
|
@@ -266,6 +275,12 @@ class UpdraftPlus {
|
|
266 |
}
|
267 |
}
|
268 |
|
|
|
|
|
|
|
|
|
|
|
|
|
269 |
function backup_resume($resumption_no, $bnonce) {
|
270 |
|
271 |
@ignore_user_abort(true);
|
@@ -280,18 +295,22 @@ class UpdraftPlus {
|
|
280 |
|
281 |
$btime = $this->backup_time;
|
282 |
|
283 |
-
$this->
|
|
|
|
|
|
|
|
|
284 |
$this->current_resumption = $resumption_no;
|
285 |
|
286 |
// Schedule again, to run in 5 minutes again, in case we again fail
|
287 |
// The actual interval can be increased (for future resumptions) by other code, if it detects apparent overlapping
|
288 |
$resume_interval = $this->jobdata_get('resume_interval');
|
289 |
-
if (!is_numeric($resume_interval) || $resume_interval
|
290 |
|
291 |
// A different argument than before is needed otherwise the event is ignored
|
292 |
$next_resumption = $resumption_no+1;
|
293 |
if ($next_resumption < 10) {
|
294 |
-
$this->log("Scheduling a resumption ($next_resumption) in case this run gets aborted");
|
295 |
$schedule_for = time()+$resume_interval;
|
296 |
wp_schedule_single_event($schedule_for, 'updraft_backup_resume', array($next_resumption, $bnonce));
|
297 |
$this->newresumption_scheduled = $schedule_for;
|
@@ -301,16 +320,15 @@ class UpdraftPlus {
|
|
301 |
|
302 |
// This should be always called; if there were no files in this run, it returns us an empty array
|
303 |
$backup_array = $this->resumable_backup_of_files($resumption_no);
|
304 |
-
// This save, if there was something, is then immediately picked up again
|
305 |
-
if (is_array($backup_array)) $this->save_backup_history($backup_array);
|
306 |
|
307 |
-
//
|
308 |
-
|
309 |
-
|
310 |
-
$this->
|
311 |
}
|
312 |
|
313 |
-
|
|
|
314 |
if (!is_array($our_files)) $our_files = array();
|
315 |
|
316 |
$undone_files = array();
|
@@ -330,8 +348,13 @@ class UpdraftPlus {
|
|
330 |
} else {
|
331 |
$this->log("Database dump: Creation was completed already");
|
332 |
}
|
|
|
333 |
$db_backup = $this->backup_db($backup_database);
|
334 |
-
|
|
|
|
|
|
|
|
|
335 |
if ($backup_database != 'encrypted') $this->jobdata_set("backup_database", 'finished');
|
336 |
} else {
|
337 |
$this->log("Unrecognised data when trying to ascertain if the database was backed up ($backup_database)");
|
@@ -345,10 +368,15 @@ class UpdraftPlus {
|
|
345 |
// Potentially encrypt the database if it is not already
|
346 |
if (isset($our_files['db']) && !preg_match("/\.crypt$/", $our_files['db'])) {
|
347 |
$our_files['db'] = $this->encrypt_file($our_files['db']);
|
348 |
-
|
349 |
if (preg_match("/\.crypt$/", $our_files['db'])) $this->jobdata_set("backup_database", 'encrypted');
|
350 |
}
|
351 |
|
|
|
|
|
|
|
|
|
|
|
352 |
foreach ($our_files as $key => $file) {
|
353 |
|
354 |
// Only continue if the stored info was about a dump
|
@@ -397,15 +425,30 @@ class UpdraftPlus {
|
|
397 |
$this->boot_backup(false,true);
|
398 |
}
|
399 |
|
400 |
-
|
401 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
402 |
$this->jobdata[$key] = $value;
|
403 |
-
} else {
|
404 |
-
$this->jobdata = array($key => $value);
|
405 |
}
|
406 |
-
set_transient("updraft_jobdata_".$this->nonce, $this->jobdata,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
407 |
}
|
408 |
|
|
|
409 |
function jobdata_get($key) {
|
410 |
if (!is_array($this->jobdata)) {
|
411 |
$this->jobdata = get_transient("updraft_jobdata_".$this->nonce);
|
@@ -455,7 +498,7 @@ class UpdraftPlus {
|
|
455 |
|
456 |
# If the files and database schedules are the same, and if this the file one, then we rope in database too.
|
457 |
# On the other hand, if the schedules were the same and this was the database run, then there is nothing to do.
|
458 |
-
if (UpdraftPlus_Options::get_updraft_option('updraft_interval') == UpdraftPlus_Options::get_updraft_option('updraft_interval_database') || UpdraftPlus_Options::get_updraft_option('updraft_interval_database','xyz') == 'xyz' ) {
|
459 |
$backup_database = ($backup_files == true) ? true : false;
|
460 |
}
|
461 |
|
@@ -467,15 +510,23 @@ class UpdraftPlus {
|
|
467 |
return;
|
468 |
}
|
469 |
|
470 |
-
|
471 |
-
|
472 |
-
if ($
|
473 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
474 |
|
475 |
-
//
|
476 |
-
$
|
|
|
477 |
|
478 |
-
|
|
|
479 |
|
480 |
// Everthing is now set up; now go
|
481 |
$this->backup_resume(0, $this->nonce);
|
@@ -703,6 +754,7 @@ class UpdraftPlus {
|
|
703 |
unset($backup_to_examine['db']);
|
704 |
}
|
705 |
}
|
|
|
706 |
if (isset($backup_to_examine['plugins']) || isset($backup_to_examine['themes']) || isset($backup_to_examine['uploads']) || isset($backup_to_examine['others'])) {
|
707 |
$file_backups_found++;
|
708 |
$this->log("$backup_datestamp: this set includes files; fileset count is now $file_backups_found");
|
@@ -721,8 +773,10 @@ class UpdraftPlus {
|
|
721 |
unset($backup_to_examine['others']);
|
722 |
}
|
723 |
}
|
|
|
724 |
// Delete backup set completely if empty, o/w just remove DB
|
725 |
-
|
|
|
726 |
$this->log("$backup_datestamp: this backup set is now empty; will remove from history");
|
727 |
unset($backup_history[$backup_datestamp]);
|
728 |
if (isset($backup_to_examine['nonce'])) {
|
@@ -759,7 +813,7 @@ class UpdraftPlus {
|
|
759 |
// Reschedule - remove presently scheduled event
|
760 |
wp_clear_scheduled_hook('updraft_backup_resume', array($this->current_resumption + 1, $this->nonce));
|
761 |
// Add new event
|
762 |
-
if ($how_far_ahead <
|
763 |
$schedule_for = time() + $how_far_ahead;
|
764 |
wp_schedule_single_event($schedule_for, 'updraft_backup_resume', array($this->current_resumption + 1, $this->nonce));
|
765 |
$this->newresumption_scheduled = $schedule_for;
|
@@ -767,7 +821,7 @@ class UpdraftPlus {
|
|
767 |
|
768 |
function increase_resume_and_reschedule($howmuch = 120) {
|
769 |
$resume_interval = $this->jobdata_get('resume_interval');
|
770 |
-
if (!is_numeric($resume_interval) || $resume_interval
|
771 |
if ($this->newresumption_scheduled != false) $this->reschedule($resume_interval+$howmuch);
|
772 |
$this->jobdata_set('resume_interval', $resume_interval+$howmuch);
|
773 |
$this->log("To decrease the likelihood of overlaps, increasing resumption interval to: ".($resume_interval+$howmuch));
|
@@ -852,9 +906,13 @@ class UpdraftPlus {
|
|
852 |
if (UpdraftPlus_Options::get_updraft_option("updraft_include_$youwhat", true)) {
|
853 |
if ($transient_status == 'finished') {
|
854 |
$backup_array[$youwhat] = $backup_file_basename.'-'.$youwhat.'.zip';
|
|
|
855 |
} else {
|
856 |
$created = $this->create_zip($whichdir, $youwhat, $updraft_dir, $backup_file_basename);
|
857 |
-
if ($created)
|
|
|
|
|
|
|
858 |
}
|
859 |
} else {
|
860 |
$this->log("No backup of $youwhat: excluded by user's options");
|
@@ -866,6 +924,7 @@ class UpdraftPlus {
|
|
866 |
|
867 |
if ($transient_status == 'finished') {
|
868 |
$backup_array['others'] = $backup_file_basename.'-others.zip';
|
|
|
869 |
} else {
|
870 |
$this->log("Beginning backup of other directories found in the content directory");
|
871 |
|
@@ -905,7 +964,10 @@ class UpdraftPlus {
|
|
905 |
|
906 |
if (count($other_dirlist)>0) {
|
907 |
$created = $this->create_zip($other_dirlist, 'others', $updraft_dir, $backup_file_basename);
|
908 |
-
if ($created)
|
|
|
|
|
|
|
909 |
} else {
|
910 |
$this->log("No backup of other directories: there was nothing found to back up");
|
911 |
}
|
@@ -922,8 +984,9 @@ class UpdraftPlus {
|
|
922 |
$backup_history = UpdraftPlus_Options::get_updraft_option('updraft_backup_history');
|
923 |
$backup_history = (is_array($backup_history)) ? $backup_history : array();
|
924 |
$backup_array['nonce'] = $this->nonce;
|
|
|
925 |
$backup_history[$this->backup_time] = $backup_array;
|
926 |
-
UpdraftPlus_Options::update_updraft_option('updraft_backup_history'
|
927 |
} else {
|
928 |
$this->log('Could not save backup history because we have no backup array. Backup probably failed.');
|
929 |
$this->error('Could not save backup history because we have no backup array. Backup probably failed.');
|
@@ -931,10 +994,11 @@ class UpdraftPlus {
|
|
931 |
}
|
932 |
|
933 |
function get_backup_history() {
|
934 |
-
|
|
|
935 |
//by doing a raw DB query to get the most up-to-date data from this option we slightly narrow the window for the multiple-cron race condition
|
936 |
-
|
937 |
-
|
938 |
if(is_array($backup_history)) {
|
939 |
krsort($backup_history); //reverse sort so earliest backup is last on the array. Then we can array_pop.
|
940 |
} else {
|
@@ -1299,7 +1363,7 @@ class UpdraftPlus {
|
|
1299 |
|
1300 |
// Acts as a WordPress options filter
|
1301 |
function googledrive_clientid_checkchange($client_id) {
|
1302 |
-
if (UpdraftPlus_Options::get_updraft_option('updraft_googledrive_token') != '' && UpdraftPlus_Options::get_updraft_option('
|
1303 |
require_once(UPDRAFTPLUS_DIR.'/methods/googledrive.php');
|
1304 |
UpdraftPlus_BackupModule_googledrive::gdrive_auth_revoke(true);
|
1305 |
}
|
@@ -1358,6 +1422,28 @@ class UpdraftPlus {
|
|
1358 |
|
1359 |
if ('lastlog' == $_GET['subaction']) {
|
1360 |
echo htmlspecialchars(UpdraftPlus_Options::get_updraft_option('updraft_lastmessage', '(Nothing yet logged)'));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1361 |
} elseif ($_POST['subaction'] == 'credentials_test') {
|
1362 |
$method = (preg_match("/^[a-z0-9]+$/", $_POST['method'])) ? $_POST['method'] : "";
|
1363 |
|
@@ -1373,20 +1459,118 @@ class UpdraftPlus {
|
|
1373 |
}
|
1374 |
|
1375 |
function updraft_download_backup() {
|
1376 |
-
|
1377 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1378 |
$backup_history = $this->get_backup_history();
|
|
|
1379 |
$file = $backup_history[$timestamp][$type];
|
|
|
|
|
1380 |
$fullpath = $this->backups_dir_location().'/'.$file;
|
1381 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1382 |
//if the file doesn't exist and they're using one of the cloud options, fetch it down from the cloud.
|
1383 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1384 |
}
|
1385 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1386 |
$len = filesize($fullpath);
|
1387 |
|
1388 |
$filearr = explode('.',$file);
|
1389 |
-
// //we've only got zip and gz...for now
|
1390 |
$file_ext = array_pop($filearr);
|
1391 |
if($file_ext == 'zip') {
|
1392 |
header('Content-type: application/zip');
|
@@ -1422,15 +1606,17 @@ class UpdraftPlus {
|
|
1422 |
} else {
|
1423 |
readfile($fullpath);
|
1424 |
}
|
1425 |
-
|
1426 |
-
exit; //we exit immediately because otherwise admin-ajax appends an additional zero to the end
|
1427 |
} else {
|
1428 |
-
echo
|
1429 |
}
|
1430 |
}
|
1431 |
-
|
1432 |
-
function
|
1433 |
-
|
|
|
|
|
|
|
1434 |
|
1435 |
$method_include = UPDRAFTPLUS_DIR.'/methods/'.$service.'.php';
|
1436 |
if (file_exists($method_include)) require_once($method_include);
|
@@ -1440,6 +1626,7 @@ class UpdraftPlus {
|
|
1440 |
$remote_obj = new $objname;
|
1441 |
$remote_obj->download($file);
|
1442 |
} else {
|
|
|
1443 |
$this->error("Automatic backup restoration is not available with the method: $service.");
|
1444 |
}
|
1445 |
|
@@ -1465,11 +1652,15 @@ class UpdraftPlus {
|
|
1465 |
echo '<span style="font-weight:bold">Restoration Progress</span><div id="updraft-restore-progress">';
|
1466 |
|
1467 |
$updraft_dir = $this->backups_dir_location().'/';
|
|
|
|
|
|
|
1468 |
foreach($backup_history[$timestamp] as $type => $file) {
|
1469 |
-
|
|
|
1470 |
$fullpath = $updraft_dir.$file;
|
1471 |
if(!is_readable($fullpath) && $type != 'db') {
|
1472 |
-
$this->
|
1473 |
}
|
1474 |
# Types: uploads, themes, plugins, others, db
|
1475 |
if(is_readable($fullpath) && $type != 'db') {
|
@@ -1574,6 +1765,13 @@ class UpdraftPlus {
|
|
1574 |
return $memory_limit;
|
1575 |
}
|
1576 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1577 |
function memory_check($memory) {
|
1578 |
$memory_limit = $this->memory_check_current();
|
1579 |
return ($memory_limit >= $memory)?true:false;
|
@@ -1581,7 +1779,7 @@ class UpdraftPlus {
|
|
1581 |
|
1582 |
function execution_time_check($time) {
|
1583 |
$setting = ini_get('max_execution_time');
|
1584 |
-
return ( $setting==0
|
1585 |
}
|
1586 |
|
1587 |
function admin_init() {
|
@@ -1599,6 +1797,12 @@ class UpdraftPlus {
|
|
1599 |
if (UpdraftPlus_Options::user_can_manage() && UpdraftPlus_Options::get_updraft_option('updraft_service') == "dropbox" && UpdraftPlus_Options::get_updraft_option('updraft_dropboxtk_request_token','') == '') {
|
1600 |
add_action('admin_notices', array($this,'show_admin_warning_dropbox') );
|
1601 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
1602 |
}
|
1603 |
|
1604 |
function url_start($urls,$url) {
|
@@ -1631,7 +1835,7 @@ class UpdraftPlus {
|
|
1631 |
if (!defined('UPDRAFTPLUS_PREMIUM')) {
|
1632 |
return $this->url_start($urls,'updraftplus.com')."Need even more features and support? Check out UpdraftPlus Premium".$this->url_end($urls,'updraftplus.com');
|
1633 |
} else {
|
1634 |
-
return "Thanks for being an UpdraftPlus premium user. Keep visiting ".$this->url_start($urls,'
|
1635 |
}
|
1636 |
break;
|
1637 |
case 6:
|
@@ -1646,8 +1850,9 @@ class UpdraftPlus {
|
|
1646 |
}
|
1647 |
}
|
1648 |
|
1649 |
-
function settings_formcontents() {
|
1650 |
$updraft_dir = $this->backups_dir_location();
|
|
|
1651 |
?>
|
1652 |
<table class="form-table" style="width:850px;">
|
1653 |
<tr>
|
@@ -1772,18 +1977,50 @@ class UpdraftPlus {
|
|
1772 |
jQuery.get(ajaxurl, lastlog_sdata, function(response) {
|
1773 |
nexttimer = 1500;
|
1774 |
if (lastlog_lastmessage == response) { nexttimer = 4500; }
|
1775 |
-
|
1776 |
jQuery('#updraft_lastlogcontainer').html(response);
|
1777 |
lastlog_lastmessage = response;
|
1778 |
});
|
1779 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1780 |
jQuery(document).ready(function() {
|
1781 |
jQuery('#enableexpertmode').click(function() {
|
1782 |
jQuery('.expertmode').fadeIn();
|
1783 |
return false;
|
1784 |
});
|
1785 |
<?php if (!is_writable($updraft_dir)) echo "jQuery('.backupdirrow').show();\n"; ?>
|
1786 |
-
|
1787 |
jQuery('.updraftplusmethod').hide();
|
1788 |
<?php
|
1789 |
if ($active_service) echo "jQuery('.${active_service}').show();";
|
@@ -1858,6 +2095,37 @@ class UpdraftPlus {
|
|
1858 |
<?php
|
1859 |
}
|
1860 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1861 |
function settings_output() {
|
1862 |
|
1863 |
/*
|
@@ -1915,15 +2183,15 @@ class UpdraftPlus {
|
|
1915 |
}
|
1916 |
|
1917 |
if(isset($_POST['action']) && $_POST['action'] == 'updraft_backup') {
|
|
|
1918 |
echo '<div class="updated fade" style="max-width: 800px; font-size:140%; line-height: 140%; padding:14px; clear:left;"><strong>Schedule backup:</strong> ';
|
1919 |
if (wp_schedule_single_event(time()+5, 'updraft_backup_all') === false) {
|
1920 |
$this->log("A backup run failed to schedule");
|
1921 |
-
echo "Failed
|
1922 |
} else {
|
1923 |
-
echo "OK. Now load any page from your site to make sure the schedule can trigger
|
1924 |
$this->log("A backup run has been scheduled");
|
1925 |
}
|
1926 |
-
echo '</div>';
|
1927 |
}
|
1928 |
|
1929 |
// updraft_file_ids is not deleted
|
@@ -1954,11 +2222,11 @@ class UpdraftPlus {
|
|
1954 |
if($deleted_old_dirs) echo '<div style="color:blue">Old directories successfully deleted.</div>';
|
1955 |
|
1956 |
if(!$this->memory_check(96)) {?>
|
1957 |
-
<div style="color:orange">Your PHP memory limit is
|
1958 |
<?php
|
1959 |
}
|
1960 |
-
if(!$this->execution_time_check(
|
1961 |
-
<div style="color:orange">Your PHP max_execution_time is less than
|
1962 |
<?php
|
1963 |
}
|
1964 |
|
@@ -1980,6 +2248,12 @@ class UpdraftPlus {
|
|
1980 |
|
1981 |
<h2 style="clear:left;">Existing Schedule And Backups</h2>
|
1982 |
<table class="form-table" style="float:left; clear: both; width:545px;">
|
|
|
|
|
|
|
|
|
|
|
|
|
1983 |
<tr>
|
1984 |
<?php
|
1985 |
$updraft_dir = $this->backups_dir_location();
|
@@ -2008,30 +2282,11 @@ class UpdraftPlus {
|
|
2008 |
}
|
2009 |
}
|
2010 |
$current_time = get_date_from_gmt(gmdate('Y-m-d H:i:s'), 'D, F j, Y H:i T');
|
2011 |
-
$updraft_last_backup = UpdraftPlus_Options::get_updraft_option('updraft_last_backup');
|
2012 |
-
if($updraft_last_backup) {
|
2013 |
-
if ($updraft_last_backup['success']) {
|
2014 |
-
// Convert to GMT, then to blog time
|
2015 |
-
$last_backup = get_date_from_gmt(gmdate('Y-m-d H:i:s', $updraft_last_backup['backup_time']), 'D, F j, Y H:i T');
|
2016 |
-
} else {
|
2017 |
-
$last_backup = implode("<br>",$updraft_last_backup['errors']);
|
2018 |
-
}
|
2019 |
|
2020 |
-
|
2021 |
-
|
2022 |
-
|
2023 |
-
if (is_readable($potential_log_file)) $last_backup .= "<br><a href=\"?page=updraftplus&action=downloadlog&updraftplus_backup_nonce=".$updraft_last_backup['backup_nonce']."\">Download log file</a>";
|
2024 |
-
}
|
2025 |
-
} else {
|
2026 |
-
$last_backup = 'No backup has been completed.';
|
2027 |
-
$last_backup_color = 'blue';
|
2028 |
-
}
|
2029 |
|
2030 |
-
if(is_writable($updraft_dir)) {
|
2031 |
-
$backup_disabled = "";
|
2032 |
-
} else {
|
2033 |
-
$backup_disabled = 'disabled="disabled"';
|
2034 |
-
}
|
2035 |
?>
|
2036 |
|
2037 |
<th>Time now:</th>
|
@@ -2046,8 +2301,8 @@ class UpdraftPlus {
|
|
2046 |
<td style="color:blue"><?php echo $next_scheduled_backup_database?></td>
|
2047 |
</tr>
|
2048 |
<tr>
|
2049 |
-
<th>Last backup:</th>
|
2050 |
-
<td
|
2051 |
</tr>
|
2052 |
</table>
|
2053 |
<div style="float:left; width:200px; padding-top: 40px;">
|
@@ -2084,103 +2339,96 @@ class UpdraftPlus {
|
|
2084 |
<br style="clear:both" />
|
2085 |
<table class="form-table">
|
2086 |
<tr>
|
2087 |
-
<th>Last
|
2088 |
<td id="updraft_lastlogcontainer"><?php echo htmlspecialchars(UpdraftPlus_Options::get_updraft_option('updraft_lastmessage', '(Nothing yet logged)')); ?></td>
|
2089 |
</tr>
|
2090 |
<tr>
|
2091 |
<th>Download backups and logs:</th>
|
2092 |
-
<td><a href="#" title="Click to see available backups" onclick="jQuery('.download-backups').toggle();
|
2093 |
</tr>
|
2094 |
<tr>
|
2095 |
<td></td><td class="download-backups" style="display:none">
|
2096 |
-
<em>
|
2097 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2098 |
<?php
|
2099 |
-
|
2100 |
?>
|
2101 |
-
|
2102 |
-
<td><b><?php echo date('Y-m-d G:i',$key)?></b></td>
|
2103 |
-
<td>
|
2104 |
-
<?php if (isset($value['db'])) { ?>
|
2105 |
-
<form action="admin-ajax.php" method="post">
|
2106 |
-
<input type="hidden" name="action" value="updraft_download_backup" />
|
2107 |
-
<input type="hidden" name="type" value="db" />
|
2108 |
-
<input type="hidden" name="timestamp" value="<?php echo $key?>" />
|
2109 |
-
<input type="submit" value="Database" />
|
2110 |
-
</form>
|
2111 |
-
<?php } else { echo "(No database)"; } ?>
|
2112 |
-
</td>
|
2113 |
-
<td>
|
2114 |
-
<?php if (isset($value['plugins'])) { ?>
|
2115 |
-
<form action="admin-ajax.php" method="post">
|
2116 |
-
<input type="hidden" name="action" value="updraft_download_backup" />
|
2117 |
-
<input type="hidden" name="type" value="plugins" />
|
2118 |
-
<input type="hidden" name="timestamp" value="<?php echo $key?>" />
|
2119 |
-
<input type="submit" value="Plugins" />
|
2120 |
-
</form>
|
2121 |
-
<?php } else { echo "(No plugins)"; } ?>
|
2122 |
-
</td>
|
2123 |
-
<td>
|
2124 |
-
<?php if (isset($value['themes'])) { ?>
|
2125 |
-
<form action="admin-ajax.php" method="post">
|
2126 |
-
<input type="hidden" name="action" value="updraft_download_backup" />
|
2127 |
-
<input type="hidden" name="type" value="themes" />
|
2128 |
-
<input type="hidden" name="timestamp" value="<?php echo $key?>" />
|
2129 |
-
<input type="submit" value="Themes" />
|
2130 |
-
</form>
|
2131 |
-
<?php } else { echo "(No themes)"; } ?>
|
2132 |
-
</td>
|
2133 |
-
<td>
|
2134 |
-
<?php if (isset($value['uploads'])) { ?>
|
2135 |
-
<form action="admin-ajax.php" method="post">
|
2136 |
-
<input type="hidden" name="action" value="updraft_download_backup" />
|
2137 |
-
<input type="hidden" name="type" value="uploads" />
|
2138 |
-
<input type="hidden" name="timestamp" value="<?php echo $key?>" />
|
2139 |
-
<input type="submit" value="Uploads" />
|
2140 |
-
</form>
|
2141 |
-
<?php } else { echo "(No uploads)"; } ?>
|
2142 |
-
</td>
|
2143 |
-
<td>
|
2144 |
-
<?php if (isset($value['others'])) { ?>
|
2145 |
-
<form action="admin-ajax.php" method="post">
|
2146 |
-
<input type="hidden" name="action" value="updraft_download_backup" />
|
2147 |
-
<input type="hidden" name="type" value="others" />
|
2148 |
-
<input type="hidden" name="timestamp" value="<?php echo $key?>" />
|
2149 |
-
<input type="submit" value="Others" />
|
2150 |
-
</form>
|
2151 |
-
<?php } else { echo "(No others)"; } ?>
|
2152 |
-
</td>
|
2153 |
-
<td>
|
2154 |
-
<?php if (isset($value['nonce']) && preg_match("/^[0-9a-f]{12}$/",$value['nonce']) && is_readable($updraft_dir.'/log.'.$value['nonce'].'.txt')) { ?>
|
2155 |
-
<form action="options-general.php" method="get">
|
2156 |
-
<input type="hidden" name="action" value="downloadlog" />
|
2157 |
-
<input type="hidden" name="page" value="updraftplus" />
|
2158 |
-
<input type="hidden" name="updraftplus_backup_nonce" value="<?php echo $value['nonce']; ?>" />
|
2159 |
-
<input type="submit" value="Backup Log" />
|
2160 |
-
</form>
|
2161 |
-
<?php } else { echo "(No backup log)"; } ?>
|
2162 |
-
</td>
|
2163 |
-
</tr>
|
2164 |
-
<?php }?>
|
2165 |
-
</table>
|
2166 |
</td>
|
2167 |
</tr>
|
2168 |
</table>
|
2169 |
<?php
|
2170 |
-
if (
|
2171 |
?>
|
2172 |
-
<h2>UpdraftPlus
|
2173 |
<table>
|
2174 |
<tr>
|
2175 |
<td>
|
2176 |
-
<p style="max-width:800px;">Do you need WordPress Multisite support? Please check out <a href="http://updraftplus.com">UpdraftPlus Premium</a
|
2177 |
</td>
|
2178 |
</tr>
|
2179 |
</table>
|
2180 |
<?php } ?>
|
2181 |
<h2>Configure Backup Contents And Schedule</h2>
|
2182 |
<?php UpdraftPlus_Options::options_form_begin(); ?>
|
2183 |
-
<?php $this->settings_formcontents(); ?>
|
2184 |
</form>
|
2185 |
<div style="padding-top: 40px; display:none;" class="expertmode">
|
2186 |
<hr>
|
@@ -2219,7 +2467,7 @@ class UpdraftPlus {
|
|
2219 |
jQuery('.updraftplusmethod').hide();
|
2220 |
var active_class = jQuery(this).val();
|
2221 |
jQuery('.'+active_class).show();
|
2222 |
-
})
|
2223 |
})
|
2224 |
jQuery(window).load(function() {
|
2225 |
//this is for hiding the restore progress at the top after it is done
|
@@ -2233,10 +2481,101 @@ class UpdraftPlus {
|
|
2233 |
<?php
|
2234 |
}
|
2235 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2236 |
function show_admin_warning($message, $class = "updated") {
|
2237 |
echo '<div id="updraftmessage" class="'.$class.' fade">'."<p>$message</p></div>";
|
2238 |
}
|
2239 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2240 |
function show_admin_warning_unreadablelog() {
|
2241 |
$this->show_admin_warning('<strong>UpdraftPlus notice:</strong> The log file could not be read.');
|
2242 |
}
|
4 |
Plugin URI: http://updraftplus.com
|
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.4.27
|
8 |
Donate link: http://david.dw-perspective.org.uk/donate
|
9 |
License: GPLv3 or later
|
10 |
Author URI: http://wordshell.net
|
11 |
+
*/
|
12 |
|
13 |
/*
|
14 |
+
TODO - some are out of date/done, needs pruning
|
15 |
+
//When a manual backup is run, use a timer to update the 'Download backups and logs' section, just like 'Last finished backup run'. Beware of over-writing anything that's in there from a resumable downloader.
|
16 |
+
//Change DB encryption to not require whole gzip in memory (twice)
|
17 |
//Add SFTP, Box.Net, SugarSync and Microsoft Skydrive support??
|
18 |
//The restorer has a hard-coded wp-content - fix
|
|
|
|
|
19 |
//?? On 'backup now', open up a Lightbox, count down 5 seconds, then start examining the log file (if it can be found)
|
20 |
//Should make clear in dashboard what is a non-fatal error (i.e. can be retried) - leads to unnecessary bug reports
|
21 |
// 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.
|
23 |
// Warn the user if their zip-file creation is slooowww...
|
24 |
// Create a "Want Support?" button/console, that leads them through what is needed, and performs some basic tests...
|
25 |
// Resuming partial FTP uploads
|
26 |
+
// Make disk space check more intelligent (currently hard-coded at 35Mb)
|
27 |
+
// Specific folders on DropBox
|
28 |
// 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
|
29 |
// Multiple jobs
|
30 |
+
// Multisite - a separate 'blogs' zip
|
31 |
+
// Allow connecting to remote storage, scanning + populating backup history from it
|
32 |
// Change FTP to use SSL by default
|
33 |
+
// GoogleDrive in-dashboard download resumption loads the whole archive into memory - should instead either chunk or directly stream fo the file handle
|
|
|
34 |
// Multisite add-on should allow restoring of each blog individually
|
35 |
// When looking for files to delete, is the current encryption setting used? Should not be.
|
36 |
// Create single zip, containing even WordPress itself
|
37 |
// When a new backup starts, AJAX-update the 'Last backup' display in the admin page.
|
38 |
// Remove the recurrence of admin notices when settings are saved due to _wp_referer
|
|
|
39 |
|
40 |
Encrypt filesystem, if memory allows (and have option for abort if not); split up into multiple zips when needed
|
41 |
// Does not delete old custom directories upon a restore?
|
237 |
$logline .= (method_exists('ZipArchive', 'addFile')) ? "Y" : "N";
|
238 |
}
|
239 |
$this->log($logline);
|
240 |
+
$disk_free_space = @disk_free_space($updraft_dir);
|
241 |
+
$this->log("Free space on disk containing Updraft's temporary directory: ".round($disk_free_space/1048576,1)." Mb");
|
242 |
}
|
243 |
|
244 |
# Logs the given line, adding (relative) time stamp and newline
|
245 |
function log($line) {
|
246 |
if ($this->logfile_handle) fwrite($this->logfile_handle, sprintf("%08.03f", round(microtime(true)-$this->opened_log_time, 3))." ".$line."\n");
|
247 |
+
if ('download' == $this->jobdata_get('job_type')) {
|
248 |
+
// Download messages are keyed on the job (since they could be running several), and transient
|
249 |
+
// The values of the POST array were checked before
|
250 |
+
set_transient('ud_dlmess_'.$_POST['timestamp'].'_'.$_POST['type'], $line." (".date('M d H:i:s').")", 3600);
|
251 |
+
} else {
|
252 |
+
UpdraftPlus_Options::update_updraft_option("updraft_lastmessage", $line." (".date('M d H:i:s').")");
|
253 |
+
}
|
254 |
}
|
255 |
|
256 |
// This function is used by cloud methods to provide standardised logging, but more importantly to help us detect that meaningful activity took place during a resumption run, so that we can schedule further resumptions if it is worthwhile
|
267 |
|
268 |
if ($this->current_resumption >= 9 && $this->newresumption_scheduled == false && $percent > ( $this->current_resumption - 9)) {
|
269 |
$resume_interval = $this->jobdata_get('resume_interval');
|
270 |
+
if (!is_numeric($resume_interval) || $resume_interval<$this->minimum_resume_interval()) { $resume_interval = $this->minimum_resume_interval(); }
|
271 |
$schedule_for = time()+$resume_interval;
|
272 |
$this->newresumption_scheduled = $schedule_for;
|
273 |
$this->log("This is resumption ".$this->current_resumption.", but meaningful uploading is still taking place; so a new one will be scheduled");
|
275 |
}
|
276 |
}
|
277 |
|
278 |
+
function minimum_resume_interval() {
|
279 |
+
$inter = ini_get('max_execution_time');
|
280 |
+
if (!$inter || $inter>300) $inter = 300;
|
281 |
+
return $inter;
|
282 |
+
}
|
283 |
+
|
284 |
function backup_resume($resumption_no, $bnonce) {
|
285 |
|
286 |
@ignore_user_abort(true);
|
295 |
|
296 |
$btime = $this->backup_time;
|
297 |
|
298 |
+
$job_type = $this->jobdata_get('job_type');
|
299 |
+
|
300 |
+
$updraft_dir = $this->backups_dir_location();
|
301 |
+
|
302 |
+
$this->log("Backup run: resumption=$resumption_no, nonce=$bnonce, begun at=$btime, job type: $job_type");
|
303 |
$this->current_resumption = $resumption_no;
|
304 |
|
305 |
// Schedule again, to run in 5 minutes again, in case we again fail
|
306 |
// The actual interval can be increased (for future resumptions) by other code, if it detects apparent overlapping
|
307 |
$resume_interval = $this->jobdata_get('resume_interval');
|
308 |
+
if (!is_numeric($resume_interval) || $resume_interval<$this->minimum_resume_interval()) $resume_interval = $this->minimum_resume_interval();
|
309 |
|
310 |
// A different argument than before is needed otherwise the event is ignored
|
311 |
$next_resumption = $resumption_no+1;
|
312 |
if ($next_resumption < 10) {
|
313 |
+
$this->log("Scheduling a resumption ($next_resumption) after $resume_interval seconds in case this run gets aborted");
|
314 |
$schedule_for = time()+$resume_interval;
|
315 |
wp_schedule_single_event($schedule_for, 'updraft_backup_resume', array($next_resumption, $bnonce));
|
316 |
$this->newresumption_scheduled = $schedule_for;
|
320 |
|
321 |
// This should be always called; if there were no files in this run, it returns us an empty array
|
322 |
$backup_array = $this->resumable_backup_of_files($resumption_no);
|
|
|
|
|
323 |
|
324 |
+
// This save, if there was something, is then immediately picked up again
|
325 |
+
if (is_array($backup_array)) {
|
326 |
+
$this->log("Saving backup status to database (elements: ".count($backup_array).")");
|
327 |
+
$this->save_backup_history($backup_array);
|
328 |
}
|
329 |
|
330 |
+
// Switch of variable name is purely vestigial
|
331 |
+
$our_files = $backup_array;
|
332 |
if (!is_array($our_files)) $our_files = array();
|
333 |
|
334 |
$undone_files = array();
|
348 |
} else {
|
349 |
$this->log("Database dump: Creation was completed already");
|
350 |
}
|
351 |
+
|
352 |
$db_backup = $this->backup_db($backup_database);
|
353 |
+
|
354 |
+
if(is_array($our_files) && is_string($db_backup)) {
|
355 |
+
$our_files['db'] = $db_backup;
|
356 |
+
}
|
357 |
+
|
358 |
if ($backup_database != 'encrypted') $this->jobdata_set("backup_database", 'finished');
|
359 |
} else {
|
360 |
$this->log("Unrecognised data when trying to ascertain if the database was backed up ($backup_database)");
|
368 |
// Potentially encrypt the database if it is not already
|
369 |
if (isset($our_files['db']) && !preg_match("/\.crypt$/", $our_files['db'])) {
|
370 |
$our_files['db'] = $this->encrypt_file($our_files['db']);
|
371 |
+
// No need to save backup history now, as it will happen in a few lines time
|
372 |
if (preg_match("/\.crypt$/", $our_files['db'])) $this->jobdata_set("backup_database", 'encrypted');
|
373 |
}
|
374 |
|
375 |
+
if (isset($our_files['db']) && file_exists($updraft_dir.'/'.$our_files['db'])) {
|
376 |
+
$our_files['db-size'] = filesize($updraft_dir.'/'.$our_files['db']);
|
377 |
+
$this->save_backup_history($our_files);
|
378 |
+
}
|
379 |
+
|
380 |
foreach ($our_files as $key => $file) {
|
381 |
|
382 |
// Only continue if the stored info was about a dump
|
425 |
$this->boot_backup(false,true);
|
426 |
}
|
427 |
|
428 |
+
// This works with any amount of settings, but we provide also a jobdata_set for efficiency as normally there's only one setting
|
429 |
+
function jobdata_set_multi() {
|
430 |
+
if (!is_array($this->jobdata)) $this->jobdata = array();
|
431 |
+
|
432 |
+
$args = func_num_args();
|
433 |
+
|
434 |
+
for ($i=1; $i<=$args/2; $i++) {
|
435 |
+
$key = func_get_arg($i*2-2);
|
436 |
+
$value = func_get_arg($i*2-1);
|
437 |
$this->jobdata[$key] = $value;
|
|
|
|
|
438 |
}
|
439 |
+
if ($this->nonce) set_transient("updraft_jobdata_".$this->nonce, $this->jobdata, UPDRAFT_TRANSTIME);
|
440 |
+
}
|
441 |
+
|
442 |
+
function jobdata_set($key, $value) {
|
443 |
+
if (is_array($this->jobdata)) {
|
444 |
+
$this->jobdata[$key] = $value;
|
445 |
+
} else {
|
446 |
+
$this->jobdata = array($key => $value);
|
447 |
+
}
|
448 |
+
set_transient("updraft_jobdata_".$this->nonce, $this->jobdata, 14400);
|
449 |
}
|
450 |
|
451 |
+
|
452 |
function jobdata_get($key) {
|
453 |
if (!is_array($this->jobdata)) {
|
454 |
$this->jobdata = get_transient("updraft_jobdata_".$this->nonce);
|
498 |
|
499 |
# If the files and database schedules are the same, and if this the file one, then we rope in database too.
|
500 |
# On the other hand, if the schedules were the same and this was the database run, then there is nothing to do.
|
501 |
+
if (UpdraftPlus_Options::get_updraft_option('updraft_interval') == UpdraftPlus_Options::get_updraft_option('updraft_interval_database') || UpdraftPlus_Options::get_updraft_option('updraft_interval_database', 'xyz') == 'xyz' ) {
|
502 |
$backup_database = ($backup_files == true) ? true : false;
|
503 |
}
|
504 |
|
510 |
return;
|
511 |
}
|
512 |
|
513 |
+
$resume_interval = $this->minimum_resume_interval();
|
514 |
+
$max_execution_time = ini_get('max_execution_time');
|
515 |
+
if ($max_execution_time >0 && $max_execution_time<300 && $resume_interval< $max_execution_time + 30) $resume_interval = $max_execution_time + 30;
|
516 |
+
|
517 |
+
$initial_jobdata = array(
|
518 |
+
'resume_interval', $resume_interval,
|
519 |
+
'job_type', 'backup',
|
520 |
+
'backup_time', $this->backup_time,
|
521 |
+
'service', UpdraftPlus_Options::get_updraft_option('updraft_service')
|
522 |
+
);
|
523 |
|
524 |
+
// Save what *should* be done, to make it resumable from this point on
|
525 |
+
if ($backup_database) array_push($initial_jobdata, 'backup_database', 'begun');
|
526 |
+
if ($backup_files) array_push($initial_jobdata, 'backup_files', 'begun');
|
527 |
|
528 |
+
// Use of jobdata_set_multi saves around 200ms
|
529 |
+
call_user_func_array(array($this, 'jobdata_set_multi'), $initial_jobdata);
|
530 |
|
531 |
// Everthing is now set up; now go
|
532 |
$this->backup_resume(0, $this->nonce);
|
754 |
unset($backup_to_examine['db']);
|
755 |
}
|
756 |
}
|
757 |
+
|
758 |
if (isset($backup_to_examine['plugins']) || isset($backup_to_examine['themes']) || isset($backup_to_examine['uploads']) || isset($backup_to_examine['others'])) {
|
759 |
$file_backups_found++;
|
760 |
$this->log("$backup_datestamp: this set includes files; fileset count is now $file_backups_found");
|
773 |
unset($backup_to_examine['others']);
|
774 |
}
|
775 |
}
|
776 |
+
|
777 |
// Delete backup set completely if empty, o/w just remove DB
|
778 |
+
// We search on the four keys which represent data, allowing other keys to be used to track other things
|
779 |
+
if (!isset($backup_to_examine['plugins']) && !isset($backup_to_examine['themes']) && !isset($backup_to_examine['others']) && !isset($backup_to_examine['uploads']) && !isset($backup_to_examine['db']) ) {
|
780 |
$this->log("$backup_datestamp: this backup set is now empty; will remove from history");
|
781 |
unset($backup_history[$backup_datestamp]);
|
782 |
if (isset($backup_to_examine['nonce'])) {
|
813 |
// Reschedule - remove presently scheduled event
|
814 |
wp_clear_scheduled_hook('updraft_backup_resume', array($this->current_resumption + 1, $this->nonce));
|
815 |
// Add new event
|
816 |
+
if ($how_far_ahead < $this->minimum_resume_interval()) $how_far_ahead=$this->minimum_resume_interval();
|
817 |
$schedule_for = time() + $how_far_ahead;
|
818 |
wp_schedule_single_event($schedule_for, 'updraft_backup_resume', array($this->current_resumption + 1, $this->nonce));
|
819 |
$this->newresumption_scheduled = $schedule_for;
|
821 |
|
822 |
function increase_resume_and_reschedule($howmuch = 120) {
|
823 |
$resume_interval = $this->jobdata_get('resume_interval');
|
824 |
+
if (!is_numeric($resume_interval) || $resume_interval<$this->minimum_resume_interval()) { $resume_interval = $this->minimum_resume_interval(); }
|
825 |
if ($this->newresumption_scheduled != false) $this->reschedule($resume_interval+$howmuch);
|
826 |
$this->jobdata_set('resume_interval', $resume_interval+$howmuch);
|
827 |
$this->log("To decrease the likelihood of overlaps, increasing resumption interval to: ".($resume_interval+$howmuch));
|
906 |
if (UpdraftPlus_Options::get_updraft_option("updraft_include_$youwhat", true)) {
|
907 |
if ($transient_status == 'finished') {
|
908 |
$backup_array[$youwhat] = $backup_file_basename.'-'.$youwhat.'.zip';
|
909 |
+
if (file_exists($updraft_dir.'/'.$backup_file_basename.'-'.$youwhat.'.zip')) $backup_array[$youwhat.'-size'] = filesize($updraft_dir.'/'.$backup_file_basename.'-'.$youwhat.'.zip');
|
910 |
} else {
|
911 |
$created = $this->create_zip($whichdir, $youwhat, $updraft_dir, $backup_file_basename);
|
912 |
+
if ($created) {
|
913 |
+
$backup_array[$youwhat] = $created;
|
914 |
+
$backup_array[$youwhat.'-size'] = filesize($updraft_dir.'/'.$created);
|
915 |
+
}
|
916 |
}
|
917 |
} else {
|
918 |
$this->log("No backup of $youwhat: excluded by user's options");
|
924 |
|
925 |
if ($transient_status == 'finished') {
|
926 |
$backup_array['others'] = $backup_file_basename.'-others.zip';
|
927 |
+
if (file_exists($updraft_dir.'/'.$backup_file_basename.'-others.zip')) $backup_array['others-size'] = filesize($updraft_dir.'/'.$backup_file_basename.'-others.zip');
|
928 |
} else {
|
929 |
$this->log("Beginning backup of other directories found in the content directory");
|
930 |
|
964 |
|
965 |
if (count($other_dirlist)>0) {
|
966 |
$created = $this->create_zip($other_dirlist, 'others', $updraft_dir, $backup_file_basename);
|
967 |
+
if ($created) {
|
968 |
+
$backup_array['others'] = $created;
|
969 |
+
$backup_array['others-size'] = filesize($updraft_dir.'/'.$created);
|
970 |
+
}
|
971 |
} else {
|
972 |
$this->log("No backup of other directories: there was nothing found to back up");
|
973 |
}
|
984 |
$backup_history = UpdraftPlus_Options::get_updraft_option('updraft_backup_history');
|
985 |
$backup_history = (is_array($backup_history)) ? $backup_history : array();
|
986 |
$backup_array['nonce'] = $this->nonce;
|
987 |
+
$backup_array['service'] = $this->jobdata_get('service');
|
988 |
$backup_history[$this->backup_time] = $backup_array;
|
989 |
+
UpdraftPlus_Options::update_updraft_option('updraft_backup_history', $backup_history);
|
990 |
} else {
|
991 |
$this->log('Could not save backup history because we have no backup array. Backup probably failed.');
|
992 |
$this->error('Could not save backup history because we have no backup array. Backup probably failed.');
|
994 |
}
|
995 |
|
996 |
function get_backup_history() {
|
997 |
+
$backup_history = UpdraftPlus_Options::get_updraft_option('updraft_backup_history');
|
998 |
+
// In fact, it looks like the line below actually *introduces* a race condition
|
999 |
//by doing a raw DB query to get the most up-to-date data from this option we slightly narrow the window for the multiple-cron race condition
|
1000 |
+
// global $wpdb;
|
1001 |
+
// $backup_history = @unserialize($wpdb->get_var($wpdb->prepare("SELECT option_value from $wpdb->options WHERE option_name='updraft_backup_history'")));
|
1002 |
if(is_array($backup_history)) {
|
1003 |
krsort($backup_history); //reverse sort so earliest backup is last on the array. Then we can array_pop.
|
1004 |
} else {
|
1363 |
|
1364 |
// Acts as a WordPress options filter
|
1365 |
function googledrive_clientid_checkchange($client_id) {
|
1366 |
+
if (UpdraftPlus_Options::get_updraft_option('updraft_googledrive_token') != '' && UpdraftPlus_Options::get_updraft_option('updraft_googledrive_clientid') != $client_id) {
|
1367 |
require_once(UPDRAFTPLUS_DIR.'/methods/googledrive.php');
|
1368 |
UpdraftPlus_BackupModule_googledrive::gdrive_auth_revoke(true);
|
1369 |
}
|
1422 |
|
1423 |
if ('lastlog' == $_GET['subaction']) {
|
1424 |
echo htmlspecialchars(UpdraftPlus_Options::get_updraft_option('updraft_lastmessage', '(Nothing yet logged)'));
|
1425 |
+
} elseif ('lastbackup' == $_GET['subaction']) {
|
1426 |
+
echo $this->last_backup_html();
|
1427 |
+
} elseif ('historystatus' == $_GET['subaction']) {
|
1428 |
+
echo $this->existing_backup_table();
|
1429 |
+
} elseif ('downloadstatus' == $_GET['subaction'] && isset($_GET['timestamp']) && isset($_GET['type'])) {
|
1430 |
+
|
1431 |
+
echo get_transient('ud_dlmess_'.$_GET['timestamp'].'_'.$_GET['type']).'<br>';
|
1432 |
+
|
1433 |
+
if ($file = get_transient('ud_dlfile_'.$_GET['timestamp'].'_'.$_GET['type'])) {
|
1434 |
+
if ('failed' == $file) {
|
1435 |
+
echo "Download failed";
|
1436 |
+
} elseif (preg_match('/^downloaded:(.*)$/', $file, $matches) && file_exists($matches[1])) {
|
1437 |
+
$size = round(filesize($matches[1])/1024, 1);
|
1438 |
+
echo "File ready: $size Kb: You should: <button type=\"button\" onclick=\"updraftplus_downloadstage2('".$_GET['timestamp']."', '".$_GET['type']."')\">Download to your computer</button> and then, if you wish, <button id=\"uddownloaddelete_".$_GET['timestamp']."_".$_GET['type']."\" type=\"button\" onclick=\"updraftplus_deletefromserver('".$_GET['timestamp']."', '".$_GET['type']."')\">Delete from your web server</button>";
|
1439 |
+
} elseif (preg_match('/^downloading:(.*)$/', $file, $matches) && file_exists($matches[1])) {
|
1440 |
+
$size = round(filesize($matches[1])/1024, 1);
|
1441 |
+
echo "File downloading: ".basename($matches[1]).": $size Kb";
|
1442 |
+
} else {
|
1443 |
+
echo "No local copy present.";
|
1444 |
+
}
|
1445 |
+
}
|
1446 |
+
|
1447 |
} elseif ($_POST['subaction'] == 'credentials_test') {
|
1448 |
$method = (preg_match("/^[a-z0-9]+$/", $_POST['method'])) ? $_POST['method'] : "";
|
1449 |
|
1459 |
}
|
1460 |
|
1461 |
function updraft_download_backup() {
|
1462 |
+
|
1463 |
+
if (!isset($_REQUEST['_wpnonce']) || !wp_verify_nonce($_REQUEST['_wpnonce'], 'updraftplus_download')) die;
|
1464 |
+
|
1465 |
+
if (!isset($_REQUEST['timestamp']) || !is_numeric($_REQUEST['timestamp']) || !isset($_REQUEST['type']) || ('plugins' != $_REQUEST['type'] && 'themes' != $_REQUEST['type'] && 'uploads' != $_REQUEST['type'] && 'others' != $_REQUEST['type'] && 'db' != $_REQUEST['type'])) exit;
|
1466 |
+
|
1467 |
+
// Get the information on what is wanted
|
1468 |
+
$type = $_REQUEST['type'];
|
1469 |
+
$timestamp = $_REQUEST['timestamp'];
|
1470 |
+
|
1471 |
+
// You need a nonce before you can set job data. And we certainly don't yet have one.
|
1472 |
+
$this->backup_time_nonce();
|
1473 |
+
|
1474 |
+
$debug_mode = UpdraftPlus_Options::get_updraft_option('updraft_debug_mode');
|
1475 |
+
|
1476 |
+
// Set the job type before logging, as there can be different logging destinations
|
1477 |
+
$this->jobdata_set('job_type', 'download');
|
1478 |
+
|
1479 |
+
// Retrieve the information from our backup history
|
1480 |
$backup_history = $this->get_backup_history();
|
1481 |
+
// Base name
|
1482 |
$file = $backup_history[$timestamp][$type];
|
1483 |
+
|
1484 |
+
// Where it should end up being downloaded to
|
1485 |
$fullpath = $this->backups_dir_location().'/'.$file;
|
1486 |
+
|
1487 |
+
if (isset($_GET['stage']) && '2' == $_GET['stage']) {
|
1488 |
+
$this->spool_file($timestamp, $type, $fullpath);
|
1489 |
+
die;
|
1490 |
+
}
|
1491 |
+
|
1492 |
+
if (isset($_POST['stage']) && 'delete' == $_POST['stage']) {
|
1493 |
+
@unlink($fullpath);
|
1494 |
+
echo 'deleted';
|
1495 |
+
$this->log('The file has been deleted');
|
1496 |
+
die;
|
1497 |
+
}
|
1498 |
+
|
1499 |
+
// TODO: FIXME: Failed downloads may leave log files forever (though they are small)
|
1500 |
+
// Not that log() assumes that the data is in _POST, not _GET
|
1501 |
+
if ($debug_mode) $this->logfile_open($this->nonce);
|
1502 |
+
|
1503 |
+
$this->log("Requested to obtain file: timestamp=$timestamp, type=$type");
|
1504 |
+
|
1505 |
+
// The AJAX responder that updates on progress wants to see this
|
1506 |
+
set_transient('ud_dlfile_'.$timestamp.'_'.$type, 'downloading:'.$fullpath, 3600);
|
1507 |
+
|
1508 |
+
$service = (isset($backup_history[$timestamp]['service'])) ? $backup_history[$timestamp]['service'] : false;
|
1509 |
+
$this->jobdata_set('service', $service);
|
1510 |
+
|
1511 |
+
// Fetch it from the cloud, if we have not already got it
|
1512 |
+
|
1513 |
+
$needs_downloading = false;
|
1514 |
+
$known_size = isset($backup_history[$timestamp][$type.'-size']) ? $backup_history[$timestamp][$type.'-size'] : false;
|
1515 |
+
|
1516 |
+
if(!file_exists($fullpath)) {
|
1517 |
//if the file doesn't exist and they're using one of the cloud options, fetch it down from the cloud.
|
1518 |
+
$needs_downloading = true;
|
1519 |
+
$this->log('File does not yet exist locally - needs downloading');
|
1520 |
+
} elseif ($known_size>0 && filesize($fullpath) < $known_size) {
|
1521 |
+
$this->log('The file was found locally but did not match the size in the backup history - will resume downloading');
|
1522 |
+
$needs_downloading = true;
|
1523 |
+
} elseif ($known_size>0) {
|
1524 |
+
$this->log('The file was found locally and matched the recorded size from the backup history ('.round($known_size/1024,1).' Kb)');
|
1525 |
+
} else {
|
1526 |
+
$this->log('No file size was found recorded in the backup history. We will assume the local one is complete.');
|
1527 |
+
}
|
1528 |
+
|
1529 |
+
if ($needs_downloading) {
|
1530 |
+
// Close browser connection so that it can resume AJAX polling
|
1531 |
+
header('Connection: close');
|
1532 |
+
header('Content-Length: 0');
|
1533 |
+
header('Content-Encoding: none');
|
1534 |
+
session_write_close();
|
1535 |
+
echo "\r\n\r\n";
|
1536 |
+
$this->download_file($file, $service, true);
|
1537 |
+
if (is_readable($fullpath)) {
|
1538 |
+
$this->log('Remote fetch was successful (file size: '.round(filesize($fullpath)/1024,1).' Kb)');
|
1539 |
+
} else {
|
1540 |
+
$this->log('Remote fetch failed');
|
1541 |
+
}
|
1542 |
}
|
1543 |
+
|
1544 |
+
// Now, spool the thing to the browser
|
1545 |
+
if(is_file($fullpath) && is_readable($fullpath)) {
|
1546 |
+
|
1547 |
+
// That message is then picked up by the AJAX listener
|
1548 |
+
set_transient('ud_dlfile_'.$timestamp.'_'.$type, 'downloaded:'.$fullpath, 3600);
|
1549 |
+
|
1550 |
+
} else {
|
1551 |
+
|
1552 |
+
set_transient('ud_dlfile_'.$timestamp.'_'.$type, 'failed', 3600);
|
1553 |
+
|
1554 |
+
echo 'Remote fetch failed. File '.$fullpath.' did not exist or was unreadable. If you delete local backups then remote retrieval may have failed.';
|
1555 |
+
}
|
1556 |
+
|
1557 |
+
@fclose($this->logfile_handle);
|
1558 |
+
if (!$debug_mode) @unlink($this->logfile_name);
|
1559 |
+
|
1560 |
+
exit;
|
1561 |
+
|
1562 |
+
}
|
1563 |
+
|
1564 |
+
function spool_file($timestamp, $type, $fullpath) {
|
1565 |
+
|
1566 |
+
if (file_exists($fullpath)) {
|
1567 |
+
|
1568 |
+
$file = basename($fullpath);
|
1569 |
+
|
1570 |
$len = filesize($fullpath);
|
1571 |
|
1572 |
$filearr = explode('.',$file);
|
1573 |
+
// //we've only got zip and gz...for now
|
1574 |
$file_ext = array_pop($filearr);
|
1575 |
if($file_ext == 'zip') {
|
1576 |
header('Content-type: application/zip');
|
1606 |
} else {
|
1607 |
readfile($fullpath);
|
1608 |
}
|
1609 |
+
// $this->delete_local($file);
|
|
|
1610 |
} else {
|
1611 |
+
echo "File not found";
|
1612 |
}
|
1613 |
}
|
1614 |
+
|
1615 |
+
function download_file($file, $service=false, $detach_from_browser) {
|
1616 |
+
|
1617 |
+
if (!$service) $service = UpdraftPlus_Options::get_updraft_option('updraft_service');
|
1618 |
+
|
1619 |
+
$this->log("Requested file from remote service: service=$service, file=$file");
|
1620 |
|
1621 |
$method_include = UPDRAFTPLUS_DIR.'/methods/'.$service.'.php';
|
1622 |
if (file_exists($method_include)) require_once($method_include);
|
1626 |
$remote_obj = new $objname;
|
1627 |
$remote_obj->download($file);
|
1628 |
} else {
|
1629 |
+
$this->log("Automatic backup restoration is not available with the method: $service.");
|
1630 |
$this->error("Automatic backup restoration is not available with the method: $service.");
|
1631 |
}
|
1632 |
|
1652 |
echo '<span style="font-weight:bold">Restoration Progress</span><div id="updraft-restore-progress">';
|
1653 |
|
1654 |
$updraft_dir = $this->backups_dir_location().'/';
|
1655 |
+
|
1656 |
+
$service = (isset($backup_history[$timestamp]['service'])) ? $backup_history[$timestamp]['service'] : false;
|
1657 |
+
|
1658 |
foreach($backup_history[$timestamp] as $type => $file) {
|
1659 |
+
// All restorable entities must be given explicitly, as we can store other arbitrary data in the history array
|
1660 |
+
if ('themes' != $type && 'plugins' != $type && 'uploads' != $type && 'others' != $type && 'db' != $type) continue;
|
1661 |
$fullpath = $updraft_dir.$file;
|
1662 |
if(!is_readable($fullpath) && $type != 'db') {
|
1663 |
+
$this->download_file($file, $service);
|
1664 |
}
|
1665 |
# Types: uploads, themes, plugins, others, db
|
1666 |
if(is_readable($fullpath) && $type != 'db') {
|
1765 |
return $memory_limit;
|
1766 |
}
|
1767 |
|
1768 |
+
function disk_space_check($space) {
|
1769 |
+
$updraft_dir = $this->backups_dir_location();
|
1770 |
+
$disk_free_space = @disk_free_space($updraft_dir);
|
1771 |
+
if ($disk_free_space == false) return -1;
|
1772 |
+
return ($disk_free_space > $space) ? true : false;
|
1773 |
+
}
|
1774 |
+
|
1775 |
function memory_check($memory) {
|
1776 |
$memory_limit = $this->memory_check_current();
|
1777 |
return ($memory_limit >= $memory)?true:false;
|
1779 |
|
1780 |
function execution_time_check($time) {
|
1781 |
$setting = ini_get('max_execution_time');
|
1782 |
+
return ( $setting==0 || $setting >= $time) ? true : false;
|
1783 |
}
|
1784 |
|
1785 |
function admin_init() {
|
1797 |
if (UpdraftPlus_Options::user_can_manage() && UpdraftPlus_Options::get_updraft_option('updraft_service') == "dropbox" && UpdraftPlus_Options::get_updraft_option('updraft_dropboxtk_request_token','') == '') {
|
1798 |
add_action('admin_notices', array($this,'show_admin_warning_dropbox') );
|
1799 |
}
|
1800 |
+
|
1801 |
+
if (UpdraftPlus_Options::user_can_manage() && $this->disk_space_check(1024*1024*35) === false) add_action('admin_notices', array($this, 'show_admin_warning_diskspace'));
|
1802 |
+
|
1803 |
+
global $wp_version, $pagenow;
|
1804 |
+
if ($pagenow == 'options-general.php' && version_compare($wp_version, '3.2', '<')) add_action('admin_notices', array($this, 'show_admin_warning_wordpressversion'));
|
1805 |
+
|
1806 |
}
|
1807 |
|
1808 |
function url_start($urls,$url) {
|
1835 |
if (!defined('UPDRAFTPLUS_PREMIUM')) {
|
1836 |
return $this->url_start($urls,'updraftplus.com')."Need even more features and support? Check out UpdraftPlus Premium".$this->url_end($urls,'updraftplus.com');
|
1837 |
} else {
|
1838 |
+
return "Thanks for being an UpdraftPlus premium user. Keep visiting ".$this->url_start($urls,'updraftplus.com')."updraftplus.com".$this->url_end($urls,'updraftplus.com')." to see what's going on.";
|
1839 |
}
|
1840 |
break;
|
1841 |
case 6:
|
1850 |
}
|
1851 |
}
|
1852 |
|
1853 |
+
function settings_formcontents($last_backup_html) {
|
1854 |
$updraft_dir = $this->backups_dir_location();
|
1855 |
+
|
1856 |
?>
|
1857 |
<table class="form-table" style="width:850px;">
|
1858 |
<tr>
|
1977 |
jQuery.get(ajaxurl, lastlog_sdata, function(response) {
|
1978 |
nexttimer = 1500;
|
1979 |
if (lastlog_lastmessage == response) { nexttimer = 4500; }
|
1980 |
+
setTimeout(function(){updraft_showlastlog()}, nexttimer);
|
1981 |
jQuery('#updraft_lastlogcontainer').html(response);
|
1982 |
lastlog_lastmessage = response;
|
1983 |
});
|
1984 |
}
|
1985 |
+
var lastbackup_sdata = {
|
1986 |
+
action: 'updraft_ajax',
|
1987 |
+
subaction: 'lastbackup',
|
1988 |
+
nonce: '<?php echo wp_create_nonce('updraftplus-credentialtest-nonce'); ?>'
|
1989 |
+
};
|
1990 |
+
var lastbackup_laststatus = '<?php echo $last_backup_html?>'
|
1991 |
+
function updraft_showlastbackup(){
|
1992 |
+
jQuery.get(ajaxurl, lastbackup_sdata, function(response) {
|
1993 |
+
if (lastbackup_laststatus == response) {
|
1994 |
+
setTimeout(function(){updraft_showlastbackup()}, 7000);
|
1995 |
+
} else {
|
1996 |
+
jQuery('#updraft_last_backup').html(response);
|
1997 |
+
}
|
1998 |
+
lastbackup_laststatus = response;
|
1999 |
+
});
|
2000 |
+
}
|
2001 |
+
var updraft_historytimer = 0;
|
2002 |
+
function updraft_historytimertoggle() {
|
2003 |
+
if (updraft_historytimer) {
|
2004 |
+
clearTimeout(updraft_historytimer);
|
2005 |
+
updraft_historytimer = 0;
|
2006 |
+
} else {
|
2007 |
+
updraft_updatehistory();
|
2008 |
+
updraft_historytimer = setInterval(function(){updraft_updatehistory()}, 30000);
|
2009 |
+
}
|
2010 |
+
}
|
2011 |
+
function updraft_updatehistory() {
|
2012 |
+
jQuery.get(ajaxurl, { action: 'updraft_ajax', subaction: 'historystatus', nonce: '<?php echo wp_create_nonce('updraftplus-credentialtest-nonce'); ?>' }, function(response) {
|
2013 |
+
jQuery('#updraft_existing_backups').html(response);
|
2014 |
+
});
|
2015 |
+
}
|
2016 |
+
|
2017 |
jQuery(document).ready(function() {
|
2018 |
jQuery('#enableexpertmode').click(function() {
|
2019 |
jQuery('.expertmode').fadeIn();
|
2020 |
return false;
|
2021 |
});
|
2022 |
<?php if (!is_writable($updraft_dir)) echo "jQuery('.backupdirrow').show();\n"; ?>
|
2023 |
+
setTimeout(function(){updraft_showlastlog();}, 1200);
|
2024 |
jQuery('.updraftplusmethod').hide();
|
2025 |
<?php
|
2026 |
if ($active_service) echo "jQuery('.${active_service}').show();";
|
2095 |
<?php
|
2096 |
}
|
2097 |
|
2098 |
+
function last_backup_html() {
|
2099 |
+
|
2100 |
+
$updraft_last_backup = UpdraftPlus_Options::get_updraft_option('updraft_last_backup');
|
2101 |
+
|
2102 |
+
$updraft_dir = $this->backups_dir_location();
|
2103 |
+
|
2104 |
+
if($updraft_last_backup) {
|
2105 |
+
|
2106 |
+
if ($updraft_last_backup['success']) {
|
2107 |
+
// Convert to GMT, then to blog time
|
2108 |
+
$last_backup_text = get_date_from_gmt(gmdate('Y-m-d H:i:s', $updraft_last_backup['backup_time']), 'D, F j, Y H:i T');
|
2109 |
+
} else {
|
2110 |
+
$last_backup_text = implode("<br>",$updraft_last_backup['errors']);
|
2111 |
+
}
|
2112 |
+
|
2113 |
+
if (!empty($updraft_last_backup['backup_nonce'])) {
|
2114 |
+
$potential_log_file = $updraft_dir."/log.".$updraft_last_backup['backup_nonce'].".txt";
|
2115 |
+
if (is_readable($potential_log_file)) $last_backup_text .= "<br><a href=\"?page=updraftplus&action=downloadlog&updraftplus_backup_nonce=".$updraft_last_backup['backup_nonce']."\">Download log file</a>";
|
2116 |
+
}
|
2117 |
+
|
2118 |
+
$last_backup_color = ($updraft_last_backup['success']) ? 'green' : 'red';
|
2119 |
+
|
2120 |
+
} else {
|
2121 |
+
$last_backup_text = 'No backup has been completed.';
|
2122 |
+
$last_backup_color = 'blue';
|
2123 |
+
}
|
2124 |
+
|
2125 |
+
return "<span style=\"color:${last_backup_color}\">${last_backup_text}</span>";
|
2126 |
+
|
2127 |
+
}
|
2128 |
+
|
2129 |
function settings_output() {
|
2130 |
|
2131 |
/*
|
2183 |
}
|
2184 |
|
2185 |
if(isset($_POST['action']) && $_POST['action'] == 'updraft_backup') {
|
2186 |
+
// For unknown reasons, the <script> runs twice if put inside the <div>
|
2187 |
echo '<div class="updated fade" style="max-width: 800px; font-size:140%; line-height: 140%; padding:14px; clear:left;"><strong>Schedule backup:</strong> ';
|
2188 |
if (wp_schedule_single_event(time()+5, 'updraft_backup_all') === false) {
|
2189 |
$this->log("A backup run failed to schedule");
|
2190 |
+
echo "Failed.</div>";
|
2191 |
} else {
|
2192 |
+
echo "OK. Now load any page from your site to make sure the schedule can trigger.</div><script>setTimeout(function(){updraft_showlastbackup();}, 7000);</script>";
|
2193 |
$this->log("A backup run has been scheduled");
|
2194 |
}
|
|
|
2195 |
}
|
2196 |
|
2197 |
// updraft_file_ids is not deleted
|
2222 |
if($deleted_old_dirs) echo '<div style="color:blue">Old directories successfully deleted.</div>';
|
2223 |
|
2224 |
if(!$this->memory_check(96)) {?>
|
2225 |
+
<div style="color:orange">Your PHP memory limit is quite low. UpdraftPlus attempted to raise it but was unsuccessful. This plugin may not work properly with a memory limit of less than 96 Mb (though on the other hand, it has been used successfully with a 32Mb limit - your mileage may vary, but don't blame us!). Current limit is: <?php echo $this->memory_check_current(); ?> Mb</div>
|
2226 |
<?php
|
2227 |
}
|
2228 |
+
if(!$this->execution_time_check(60)) {?>
|
2229 |
+
<div style="color:orange">Your PHP max_execution_time is less than 60 seconds. This possibly means you're running in safe_mode. Either disable safe_mode or modify your php.ini to set max_execution_time to a higher number. If you do not, then longer will be needed to complete a backup. Present limit is: <?php echo ini_get('max_execution_time'); ?> seconds.</div>
|
2230 |
<?php
|
2231 |
}
|
2232 |
|
2248 |
|
2249 |
<h2 style="clear:left;">Existing Schedule And Backups</h2>
|
2250 |
<table class="form-table" style="float:left; clear: both; width:545px;">
|
2251 |
+
<noscript>
|
2252 |
+
<tr>
|
2253 |
+
<th>JavaScript warning:</th>
|
2254 |
+
<td style="color:red">This admin interface uses JavaScript heavily. You either need to activate it within your browser, or to use a JavaScript-capable browser.</td>
|
2255 |
+
</tr>
|
2256 |
+
</noscript>
|
2257 |
<tr>
|
2258 |
<?php
|
2259 |
$updraft_dir = $this->backups_dir_location();
|
2282 |
}
|
2283 |
}
|
2284 |
$current_time = get_date_from_gmt(gmdate('Y-m-d H:i:s'), 'D, F j, Y H:i T');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2285 |
|
2286 |
+
$backup_disabled = (is_writable($updraft_dir)) ? '' : 'disabled="disabled"';
|
2287 |
+
|
2288 |
+
$last_backup_html = $this->last_backup_html();
|
|
|
|
|
|
|
|
|
|
|
|
|
2289 |
|
|
|
|
|
|
|
|
|
|
|
2290 |
?>
|
2291 |
|
2292 |
<th>Time now:</th>
|
2301 |
<td style="color:blue"><?php echo $next_scheduled_backup_database?></td>
|
2302 |
</tr>
|
2303 |
<tr>
|
2304 |
+
<th>Last finished backup run:</th>
|
2305 |
+
<td id="updraft_last_backup"><?php echo $last_backup_html ?></td>
|
2306 |
</tr>
|
2307 |
</table>
|
2308 |
<div style="float:left; width:200px; padding-top: 40px;">
|
2339 |
<br style="clear:both" />
|
2340 |
<table class="form-table">
|
2341 |
<tr>
|
2342 |
+
<th>Last log message:</th>
|
2343 |
<td id="updraft_lastlogcontainer"><?php echo htmlspecialchars(UpdraftPlus_Options::get_updraft_option('updraft_lastmessage', '(Nothing yet logged)')); ?></td>
|
2344 |
</tr>
|
2345 |
<tr>
|
2346 |
<th>Download backups and logs:</th>
|
2347 |
+
<td><a href="#" title="Click to see available backups" onclick="jQuery('.download-backups').toggle(); updraft_historytimertoggle();"><?php echo count($backup_history)?> available</a></td>
|
2348 |
</tr>
|
2349 |
<tr>
|
2350 |
<td></td><td class="download-backups" style="display:none">
|
2351 |
+
<p><em><strong>Note</strong> - Pressing a button will make UpdraftPlus try to bring a backup file back from the remote storage (if any - e.g. Amazon S3, Dropbox, Google Drive, FTP) to your webserver, before then allowing you to download it to your computer. If the fetch from the remote storage stops progressing (wait 30 seconds to make sure), then click again to resume from where it left off. Remember that you can always visit the cloud storage website vendor's website directly.</em></p>
|
2352 |
+
<div id="ud_downloadstatus"></div>
|
2353 |
+
<script>
|
2354 |
+
var lastlog_lastmessage = "";
|
2355 |
+
function updraftplus_deletefromserver(timestamp, type) {
|
2356 |
+
var pdata = {
|
2357 |
+
action: 'updraft_download_backup',
|
2358 |
+
stage: 'delete',
|
2359 |
+
timestamp: timestamp,
|
2360 |
+
type: type,
|
2361 |
+
_wpnonce: '<?php echo wp_create_nonce("updraftplus_download"); ?>'
|
2362 |
+
};
|
2363 |
+
jQuery.post(ajaxurl, pdata, function(response) {
|
2364 |
+
if (response == 'deleted') {
|
2365 |
+
|
2366 |
+
} else {
|
2367 |
+
alert('We requested to delete the file, but could not understand the server\'s response '+response);
|
2368 |
+
}
|
2369 |
+
});
|
2370 |
+
}
|
2371 |
+
function updraftplus_downloadstage2(timestamp, type) {
|
2372 |
+
location.href=ajaxurl+'?_wpnonce=<?php echo wp_create_nonce("updraftplus_download"); ?>×tamp='+timestamp+'&type='+type+'&stage=2&action=updraft_download_backup';
|
2373 |
+
}
|
2374 |
+
function updraft_downloader(nonce, what) {
|
2375 |
+
// Create somewhere for the status to be found
|
2376 |
+
var stid = 'uddlstatus_'+nonce+'_'+what;
|
2377 |
+
if (!jQuery('#'+stid).length) {
|
2378 |
+
jQuery('#ud_downloadstatus').append('<div style="clear:left; border: 1px dashed; padding: 8px; margin-top: 4px; max-width:840px;" id="'+stid+'"><button onclick="jQuery(\'#'+stid+'\').fadeOut().remove();" type="button" style="float:right;">X</button><strong>Download '+what+' ('+nonce+')</strong>: <span id="'+stid+'_st">Begun looking for this entity</span></div>');
|
2379 |
+
setTimeout(function(){updraft_downloader_status(nonce, what)}, 200);
|
2380 |
+
}
|
2381 |
+
// Reset, in case this is a re-try
|
2382 |
+
jQuery('#'+stid+'_st').html('Begun looking for this entity');
|
2383 |
+
// Now send the actual request to kick it all off
|
2384 |
+
jQuery.post(ajaxurl, jQuery('#uddownloadform_'+what+'_'+nonce).serialize());
|
2385 |
+
// We don't want the form to submit as that replaces the document
|
2386 |
+
return false;
|
2387 |
+
}
|
2388 |
+
var dlstatus_sdata = {
|
2389 |
+
action: 'updraft_ajax',
|
2390 |
+
subaction: 'downloadstatus',
|
2391 |
+
nonce: '<?php echo wp_create_nonce('updraftplus-credentialtest-nonce'); ?>'
|
2392 |
+
};
|
2393 |
+
dlstatus_lastlog = '';
|
2394 |
+
function updraft_downloader_status(nonce, what) {
|
2395 |
+
var stid = 'uddlstatus_'+nonce+'_'+what;
|
2396 |
+
if (jQuery('#'+stid).length) {
|
2397 |
+
dlstatus_sdata.timestamp = nonce;
|
2398 |
+
dlstatus_sdata.type = what;
|
2399 |
+
jQuery.get(ajaxurl, dlstatus_sdata, function(response) {
|
2400 |
+
nexttimer = 1250;
|
2401 |
+
if (dlstatus_lastlog == response) { nexttimer = 3000; }
|
2402 |
+
setTimeout(function(){updraft_downloader_status(nonce, what)}, nexttimer);
|
2403 |
+
jQuery('#'+stid+'_st').html(response);
|
2404 |
+
dlstatus_lastlog = response;
|
2405 |
+
});
|
2406 |
+
}
|
2407 |
+
}
|
2408 |
+
</script>
|
2409 |
+
<div id="updraft_existing_backups">
|
2410 |
<?php
|
2411 |
+
print $this->existing_backup_table($backup_history);
|
2412 |
?>
|
2413 |
+
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2414 |
</td>
|
2415 |
</tr>
|
2416 |
</table>
|
2417 |
<?php
|
2418 |
+
if (is_multisite() && !file_exists(UPDRAFTPLUS_DIR.'/addons/multisite.php')) {
|
2419 |
?>
|
2420 |
+
<h2>UpdraftPlus Multisite</h2>
|
2421 |
<table>
|
2422 |
<tr>
|
2423 |
<td>
|
2424 |
+
<p style="max-width:800px;">Do you need WordPress Multisite support? Please check out <a href="http://updraftplus.com">UpdraftPlus Premium</a>.</p>
|
2425 |
</td>
|
2426 |
</tr>
|
2427 |
</table>
|
2428 |
<?php } ?>
|
2429 |
<h2>Configure Backup Contents And Schedule</h2>
|
2430 |
<?php UpdraftPlus_Options::options_form_begin(); ?>
|
2431 |
+
<?php $this->settings_formcontents($last_backup_html); ?>
|
2432 |
</form>
|
2433 |
<div style="padding-top: 40px; display:none;" class="expertmode">
|
2434 |
<hr>
|
2467 |
jQuery('.updraftplusmethod').hide();
|
2468 |
var active_class = jQuery(this).val();
|
2469 |
jQuery('.'+active_class).show();
|
2470 |
+
});
|
2471 |
})
|
2472 |
jQuery(window).load(function() {
|
2473 |
//this is for hiding the restore progress at the top after it is done
|
2481 |
<?php
|
2482 |
}
|
2483 |
|
2484 |
+
function existing_backup_table($backup_history = false) {
|
2485 |
+
|
2486 |
+
// Fetch it if it was not passed
|
2487 |
+
if ($backup_history === false) $backup_history = UpdraftPlus_Options::get_updraft_option('updraft_backup_history');
|
2488 |
+
if (!is_array($backup_history)) $backup_history=array();
|
2489 |
+
|
2490 |
+
$updraft_dir = $this->backups_dir_location();
|
2491 |
+
|
2492 |
+
echo '<table>';
|
2493 |
+
foreach($backup_history as $key=>$value) {
|
2494 |
+
?>
|
2495 |
+
<tr>
|
2496 |
+
<td><b><?php echo date('Y-m-d G:i',$key)?></b></td>
|
2497 |
+
<td>
|
2498 |
+
<?php if (isset($value['db'])) { ?>
|
2499 |
+
<form id="uddownloadform_db_<?php echo $key;?>" action="admin-ajax.php" onsubmit="return updraft_downloader(<?php echo $key;?>, 'db')" method="post">
|
2500 |
+
<?php wp_nonce_field('updraftplus_download'); ?>
|
2501 |
+
<input type="hidden" name="action" value="updraft_download_backup" />
|
2502 |
+
<input type="hidden" name="type" value="db" />
|
2503 |
+
<input type="hidden" name="timestamp" value="<?php echo $key?>" />
|
2504 |
+
<input type="submit" value="Database" />
|
2505 |
+
</form>
|
2506 |
+
<?php } else { echo "(No database)"; } ?>
|
2507 |
+
</td>
|
2508 |
+
<td>
|
2509 |
+
<?php if (isset($value['plugins'])) { ?>
|
2510 |
+
<form id="uddownloadform_plugins_<?php echo $key;?>" action="admin-ajax.php" onsubmit="return updraft_downloader(<?php echo $key;?>, 'plugins')" method="post">
|
2511 |
+
<?php wp_nonce_field('updraftplus_download'); ?>
|
2512 |
+
<input type="hidden" name="action" value="updraft_download_backup" />
|
2513 |
+
<input type="hidden" name="type" value="plugins" />
|
2514 |
+
<input type="hidden" name="timestamp" value="<?php echo $key?>" />
|
2515 |
+
<input type="submit" value="Plugins" />
|
2516 |
+
</form>
|
2517 |
+
<?php } else { echo "(No plugins)"; } ?>
|
2518 |
+
</td>
|
2519 |
+
<td>
|
2520 |
+
<?php if (isset($value['themes'])) { ?>
|
2521 |
+
<form id="uddownloadform_themes_<?php echo $key;?>" action="admin-ajax.php" onsubmit="return updraft_downloader(<?php echo $key;?>, 'themes')" method="post">
|
2522 |
+
<?php wp_nonce_field('updraftplus_download'); ?>
|
2523 |
+
<input type="hidden" name="action" value="updraft_download_backup" />
|
2524 |
+
<input type="hidden" name="type" value="themes" />
|
2525 |
+
<input type="hidden" name="timestamp" value="<?php echo $key?>" />
|
2526 |
+
<input type="submit" value="Themes" />
|
2527 |
+
</form>
|
2528 |
+
<?php } else { echo "(No themes)"; } ?>
|
2529 |
+
</td>
|
2530 |
+
<td>
|
2531 |
+
<?php if (isset($value['uploads'])) { ?>
|
2532 |
+
<form id="uddownloadform_uploads_<?php echo $key;?>" action="admin-ajax.php" onsubmit="return updraft_downloader(<?php echo $key;?>, 'uploads')" method="post">
|
2533 |
+
<?php wp_nonce_field('updraftplus_download'); ?>
|
2534 |
+
<input type="hidden" name="action" value="updraft_download_backup" />
|
2535 |
+
<input type="hidden" name="type" value="uploads" />
|
2536 |
+
<input type="hidden" name="timestamp" value="<?php echo $key?>" />
|
2537 |
+
<input type="submit" value="Uploads" />
|
2538 |
+
</form>
|
2539 |
+
<?php } else { echo "(No uploads)"; } ?>
|
2540 |
+
</td>
|
2541 |
+
<td>
|
2542 |
+
<?php if (isset($value['others'])) { ?>
|
2543 |
+
<form id="uddownloadform_others_<?php echo $key;?>" action="admin-ajax.php" onsubmit="return updraft_downloader(<?php echo $key;?>, 'others')" method="post">
|
2544 |
+
<?php wp_nonce_field('updraftplus_download'); ?>
|
2545 |
+
<input type="hidden" name="action" value="updraft_download_backup" />
|
2546 |
+
<input type="hidden" name="type" value="others" />
|
2547 |
+
<input type="hidden" name="timestamp" value="<?php echo $key?>" />
|
2548 |
+
<input type="submit" value="Others" />
|
2549 |
+
</form>
|
2550 |
+
<?php } else { echo "(No others)"; } ?>
|
2551 |
+
</td>
|
2552 |
+
<td>
|
2553 |
+
<?php if (isset($value['nonce']) && preg_match("/^[0-9a-f]{12}$/",$value['nonce']) && is_readable($updraft_dir.'/log.'.$value['nonce'].'.txt')) { ?>
|
2554 |
+
<form action="options-general.php" method="get">
|
2555 |
+
<input type="hidden" name="action" value="downloadlog" />
|
2556 |
+
<input type="hidden" name="page" value="updraftplus" />
|
2557 |
+
<input type="hidden" name="updraftplus_backup_nonce" value="<?php echo $value['nonce']; ?>" />
|
2558 |
+
<input type="submit" value="Backup Log" />
|
2559 |
+
</form>
|
2560 |
+
<?php } else { echo "(No backup log)"; } ?>
|
2561 |
+
</td>
|
2562 |
+
</tr>
|
2563 |
+
<?php }
|
2564 |
+
echo '</table>';
|
2565 |
+
}
|
2566 |
+
|
2567 |
function show_admin_warning($message, $class = "updated") {
|
2568 |
echo '<div id="updraftmessage" class="'.$class.' fade">'."<p>$message</p></div>";
|
2569 |
}
|
2570 |
|
2571 |
+
function show_admin_warning_diskspace() {
|
2572 |
+
$this->show_admin_warning('<strong>Warning:</strong> You have less than 35Mb of free disk space on the disk which UpdraftPlus is configured to use to create backups. UpdraftPlus could well run out of space. Contact your the operator of your server (e.g. your web hosting company) to resolve this issue.');
|
2573 |
+
}
|
2574 |
+
|
2575 |
+
function show_admin_warning_wordpressversion() {
|
2576 |
+
$this->show_admin_warning('<strong>Warning:</strong> UpdraftPlus does not officially support versions of WordPress before 3.2. It may work for you, but if it does not, then please be aware that no support is available until you upgrade WordPress.');
|
2577 |
+
}
|
2578 |
+
|
2579 |
function show_admin_warning_unreadablelog() {
|
2580 |
$this->show_admin_warning('<strong>UpdraftPlus notice:</strong> The log file could not be read.');
|
2581 |
}
|