PluginProbe
UpdraftPlus: WP Backup & Migration Plugin / 1.9.32
UpdraftPlus: WP Backup & Migration Plugin v1.9.32
1.26.7 1.26.6 1.26.5 1.26.4 1.26.3 1.9.19 1.9.25 1.9.26 1.9.30 1.9.31 1.9.32 1.9.4 1.9.40 1.9.41 1.9.42 1.9.43 1.9.44 1.9.45 1.9.46 1.9.5 1.9.50 1.9.51 1.9.60 1.9.62 1.9.63 All 371 releases
updraftplus / admin.php

admin.php in UpdraftPlus: WP Backup & Migration Plugin 1.9.32, at admin.php

4,185 lines 205.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined ('ABSPATH')) die('No direct access allowed');
4
5 // Admin-area code lives here. This gets called in admin_menu, earlier than admin_init
6
7 global $updraftplus_admin;
8 if (!is_a($updraftplus_admin, 'UpdraftPlus_Admin')) $updraftplus_admin = new UpdraftPlus_Admin();
9
10 class UpdraftPlus_Admin {
11
12 public $logged = array();
13
14 public function __construct() {
15 $this->admin_init();
16 }
17
18 private function admin_init() {
19
20 add_action('core_upgrade_preamble', array($this, 'core_upgrade_preamble'));
21 add_action('admin_action_upgrade-plugin', array($this, 'admin_action_upgrade_pluginortheme'));
22 add_action('admin_action_upgrade-theme', array($this, 'admin_action_upgrade_pluginortheme'));
23
24 add_action('admin_head', array($this,'admin_head'));
25 add_filter((is_multisite() ? 'network_admin_' : '').'plugin_action_links', array($this, 'plugin_action_links'), 10, 2);
26 add_action('wp_ajax_updraft_download_backup', array($this, 'updraft_download_backup'));
27 add_action('wp_ajax_updraft_ajax', array($this, 'updraft_ajax_handler'));
28 add_action('wp_ajax_plupload_action', array($this,'plupload_action'));
29 add_action('wp_ajax_plupload_action2', array($this,'plupload_action2'));
30
31 global $updraftplus, $wp_version, $pagenow;
32 add_filter('updraftplus_dirlist_others', array($updraftplus, 'backup_others_dirlist'));
33 add_filter('updraftplus_dirlist_uploads', array($updraftplus, 'backup_uploads_dirlist'));
34
35 // First, the checks that are on all (admin) pages:
36
37 $service = UpdraftPlus_Options::get_updraft_option('updraft_service');
38
39 if (UpdraftPlus_Options::user_can_manage()) {
40 if ('googledrive' === $service || (is_array($service) && in_array('googledrive', $service))) {
41 $opts = UpdraftPlus_Options::get_updraft_option('updraft_googledrive');
42 if (empty($opts)) {
43 $clientid = UpdraftPlus_Options::get_updraft_option('updraft_googledrive_clientid', '');
44 $token = UpdraftPlus_Options::get_updraft_option('updraft_googledrive_token', '');
45 } else {
46 $clientid = $opts['clientid'];
47 $token = (empty($opts['token'])) ? '' : $opts['token'];
48 }
49 if (!empty($clientid) && empty($token)) add_action('all_admin_notices', array($this,'show_admin_warning_googledrive'));
50 }
51 if ('dropbox' === $service || (is_array($service) && in_array('dropbox', $service))) {
52 $opts = UpdraftPlus_Options::get_updraft_option('updraft_dropbox');
53 if (empty($opts['tk_request_token'])) {
54 add_action('all_admin_notices', array($this,'show_admin_warning_dropbox') );
55 }
56 }
57 if ('bitcasa' === $service || (is_array($service) && in_array('bitcasa', $service))) {
58 $opts = UpdraftPlus_Options::get_updraft_option('updraft_bitcasa');
59 if (!empty($opts['clientid']) && !empty($opts['secret']) && empty($opts['token'])) add_action('all_admin_notices', array($this,'show_admin_warning_bitcasa') );
60 }
61 if ('copycom' === $service || (is_array($service) && in_array('copycom', $service))) {
62 $opts = UpdraftPlus_Options::get_updraft_option('updraft_copycom');
63 if (!empty($opts['clientid']) && !empty($opts['secret']) && empty($opts['token'])) add_action('all_admin_notices', array($this,'show_admin_warning_copycom') );
64 }
65 if ($this->disk_space_check(1048576*35) === false) add_action('all_admin_notices', array($this, 'show_admin_warning_diskspace'));
66 }
67
68 // Next, the actions that only come on the UpdraftPlus page
69 if ($pagenow != UpdraftPlus_Options::admin_page() || empty($_REQUEST['page']) || 'updraftplus' != $_REQUEST['page']) return;
70
71 if (UpdraftPlus_Options::user_can_manage() && defined('DISABLE_WP_CRON') && DISABLE_WP_CRON == true) {
72 add_action('all_admin_notices', array($this, 'show_admin_warning_disabledcron'));
73 }
74
75 if (UpdraftPlus_Options::get_updraft_option('updraft_debug_mode')) {
76 @ini_set('display_errors',1);
77 @error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);
78 add_action('all_admin_notices', array($this, 'show_admin_debug_warning'));
79 }
80
81 if (null === UpdraftPlus_Options::get_updraft_option('updraft_interval')) {
82 add_action('all_admin_notices', array($this, 'show_admin_nosettings_warning'));
83 }
84
85 # Avoid false positives, by attempting to raise the limit (as happens when we actually do a backup)
86 @set_time_limit(900);
87 $max_execution_time = (int)@ini_get('max_execution_time');
88 if ($max_execution_time>0 && $max_execution_time<20) {
89 add_action('all_admin_notices', array($this, 'show_admin_warning_execution_time'));
90 }
91
92 // LiteSpeed has a generic problem with terminating cron jobs
93 if (isset($_SERVER['SERVER_SOFTWARE']) && strpos($_SERVER['SERVER_SOFTWARE'], 'LiteSpeed') !== false) {
94 if (!is_file(ABSPATH.'.htaccess') || !preg_match('/noabort/i', file_get_contents(ABSPATH.'.htaccess'))) {
95 add_action('all_admin_notices', array($this, 'show_admin_warning_litespeed'));
96 }
97 }
98
99 if (version_compare($wp_version, '3.2', '<')) add_action('all_admin_notices', array($this, 'show_admin_warning_wordpressversion'));
100
101 add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_scripts'));
102
103 }
104
105 public function admin_enqueue_scripts() {
106
107 wp_enqueue_style('jquery-ui', UPDRAFTPLUS_URL.'/includes/jquery-ui-1.8.22.custom.css');
108
109 global $wp_version;
110 if (version_compare($wp_version, '3.3', '<')) {
111 # Require a newer jQuery (3.2.1 has 1.6.1, so we go for something not too much newer). We use .on() in a way that is incompatible with < 1.7
112 wp_deregister_script('jquery');
113 wp_register_script('jquery', 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js', false, '1.7.2', false);
114 wp_enqueue_script('jquery');
115 # No plupload until 3.3
116 # Put in footer, to make sure that jQuery loads first
117 wp_enqueue_script('updraftplus-admin-ui', UPDRAFTPLUS_URL.'/includes/updraft-admin-ui.js', array('jquery', 'jquery-ui-dialog'), '37', true);
118 } else {
119 wp_enqueue_script('updraftplus-admin-ui', UPDRAFTPLUS_URL.'/includes/updraft-admin-ui.js', array('jquery', 'jquery-ui-dialog', 'plupload-all'), '37');
120 }
121
122 wp_localize_script( 'updraftplus-admin-ui', 'updraftlion', array(
123 'sendonlyonwarnings' => __('Send a report only when there are warnings/errors', 'updraftplus'),
124 'wholebackup' => __('When the Email storage method is enabled, also send the entire backup', 'updraftplus'),
125 'emailsizelimits' => esc_attr(sprintf(__('Be aware that mail servers tend to have size limits; typically around %s Mb; backups larger than any limits will likely not arrive.','updraftplus'), '10-20')),
126 'rescanning' => __('Rescanning (looking for backups that you have uploaded manually into the internal backup store)...','updraftplus'),
127 'rescanningremote' => __('Rescanning remote and local storage for backup sets...','updraftplus'),
128 'enteremailhere' => esc_attr(__('To send to more than one address, separate each address with a comma.', 'updraftplus')),
129 'excludedeverything' => __('If you exclude both the database and the files, then you have excluded everything!', 'updraftplus'),
130 'restoreproceeding' => __('The restore operation has begun. Do not press stop or close your browser until it reports itself as having finished.', 'updraftplus'),
131 'unexpectedresponse' => __('Unexpected response:','updraftplus'),
132 'servererrorcode' => __('The web server returned an error code (try again, or check your web server logs)', 'updraftplus'),
133 'newuserpass' => __("The new user's RackSpace console password is (this will not be shown again):", 'updraftplus'),
134 'trying' => __('Trying...', 'updraftplus'),
135 'calculating' => __('calculating...','updraftplus'),
136 'begunlooking' => __('Begun looking for this entity','updraftplus'),
137 'stilldownloading' => __('Some files are still downloading or being processed - please wait.', 'updraftplus'),
138 'processing' => __('Processing files - please wait...', 'updraftplus'),
139 'emptyresponse' => __('Error: the server sent an empty response.', 'updraftplus'),
140 'warnings' => __('Warnings:','updraftplus'),
141 'errors' => __('Errors:','updraftplus'),
142 'jsonnotunderstood' => __('Error: the server sent us a response (JSON) which we did not understand.', 'updraftplus'),
143 'error' => __('Error:','updraftplus'),
144 'fileready' => __('File ready.','updraftplus'),
145 'youshould' => __('You should:','updraftplus'),
146 'deletefromserver' => __('Delete from your web server','updraftplus'),
147 'downloadtocomputer' => __('Download to your computer','updraftplus'),
148 'andthen' => __('and then, if you wish,', 'updraftplus'),
149 'notunderstood' => __('Download error: the server sent us a response which we did not understand.', 'updraftplus'),
150 'requeststart' => __('Requesting start of backup...', 'updraftplus'),
151 'phpinfo' => __('PHP information', 'updraftplus'),
152 'delete_old_dirs' => __('Delete Old Directories', 'updraftplus'),
153 'raw' => __('Raw backup history', 'updraftplus'),
154 'notarchive' => __('This file does not appear to be an UpdraftPlus backup archive (such files are .zip or .gz files which have a name like: backup_(time)_(site name)_(code)_(type).(zip|gz)).', 'updraftplus').' '.__('However, UpdraftPlus archives are standard zip/SQL files - so if you are sure that your file has the right format, then you can rename it to match that pattern.','updraftplus'),
155 'notarchive2' => '<p>'.__('This file does not appear to be an UpdraftPlus backup archive (such files are .zip or .gz files which have a name like: backup_(time)_(site name)_(code)_(type).(zip|gz)).', 'updraftplus').'</p> '.apply_filters('updraftplus_if_foreign_then_premium_message', '<p><a href="http://updraftplus.com/shop/updraftplus-premium/">'.__('If this is a backup created by a different backup plugin, then UpdraftPlus Premium may be able to help you.', 'updraftplus').'</a></p>'),
156 'makesure' => __('(make sure that you were trying to upload a zip file previously created by UpdraftPlus)','updraftplus'),
157 'uploaderror' => __('Upload error:','updraftplus'),
158 'notdba' => __('This file does not appear to be an UpdraftPlus encrypted database archive (such files are .gz.crypt files which have a name like: backup_(time)_(site name)_(code)_db.crypt.gz).','updraftplus'),
159 'uploaderr' => __('Upload error', 'updraftplus'),
160 'followlink' => __('Follow this link to attempt decryption and download the database file to your computer.','updraftplus'),
161 'thiskey' => __('This decryption key will be attempted:','updraftplus'),
162 'unknownresp' => __('Unknown server response:','updraftplus'),
163 'ukrespstatus' => __('Unknown server response status:','updraftplus'),
164 'uploaded' => __('The file was uploaded.','updraftplus'),
165 'backupnow' => __('Backup Now', 'updraftplus'),
166 'cancel' => __('Cancel', 'updraftplus'),
167 'deletebutton' => __('Delete', 'updraftplus'),
168 'createbutton' => __('Create', 'updraftplus'),
169 'close' => __('Close', 'updraftplus'),
170 'restore' => __('Restore', 'updraftplus'),
171 'download' => __('Download log file', 'updraftplus')
172 ) );
173 }
174
175 public function core_upgrade_preamble() {
176 if (!class_exists('UpdraftPlus_Addon_Autobackup')) {
177 if (defined('UPDRAFTPLUS_NOADS_B')) return;
178 # TODO: Remove legacy/wrong use of transient any time from 1 Jun 2014
179 if (true == get_transient('updraftplus_dismissedautobackup')) return;
180 $dismissed_until = UpdraftPlus_Options::get_updraft_option('updraftplus_dismissedautobackup', 0);
181 if ($dismissed_until > time()) return;
182 }
183 ?>
184 <div id="updraft-autobackup" class="updated" style="padding: 6px; margin:8px 0px;">
185 <?php if (!class_exists('UpdraftPlus_Addon_Autobackup')) { ?>
186 <div style="float:right;"><a href="#" onclick="jQuery('#updraft-autobackup').slideUp(); jQuery.post(ajaxurl, {action: 'updraft_ajax', subaction: 'dismissautobackup', nonce: '<?php echo wp_create_nonce('updraftplus-credentialtest-nonce');?>' });"><?php echo sprintf(__('Dismiss (for %s weeks)', 'updraftplus'), 12); ?></a></div> <?php } ?>
187 <h3 style="margin-top: 0px;"><?php _e('Be safe with an automatic backup','updraftplus');?></h3>
188 <?php echo apply_filters('updraftplus_autobackup_blurb', __('UpdraftPlus Premium can <strong>automatically</strong> take a backup of your plugins or themes and database before you update.', 'updraftplus').' <a href="http://updraftplus.com/shop/autobackup/">'.__('Be safe every time, without needing to remember - follow this link to learn more.' ,'updraftplus').'</a>'); ?>
189 </div>
190 <script>
191 jQuery(document).ready(function() {
192 jQuery('#updraft-autobackup').appendTo('.wrap p:first');
193 });
194 </script>
195 <?php
196 }
197
198 public function admin_head() {
199
200 global $pagenow;
201 if ($pagenow != UpdraftPlus_Options::admin_page() || !isset($_REQUEST['page']) || 'updraftplus' != $_REQUEST['page']) return;
202
203 $chunk_size = min(wp_max_upload_size()-1024, 1024*1024*2);
204
205 # The multiple_queues argument is ignored in plupload 2.x (WP3.9+) - http://make.wordpress.org/core/2014/04/11/plupload-2-x-in-wordpress-3-9/
206 # max_file_size is also in filters as of plupload 2.x, but in its default position is still supported for backwards-compatibility. Likewise, our use of filters.extensions below is supported by a backwards-compatibility option (the current way is filters.mime-types.extensions
207
208 $plupload_init = array(
209 'runtimes' => 'html5,flash,silverlight,html4',
210 'browse_button' => 'plupload-browse-button',
211 'container' => 'plupload-upload-ui',
212 'drop_element' => 'drag-drop-area',
213 'file_data_name' => 'async-upload',
214 'multiple_queues' => true,
215 'max_file_size' => '100Gb',
216 'chunk_size' => $chunk_size.'b',
217 'url' => admin_url('admin-ajax.php'),
218 'filters' => array(array('title' => __('Allowed Files'), 'extensions' => 'zip,tar,gz,bz2,crypt,sql,txt')),
219 'multipart' => true,
220 'multi_selection' => true,
221 'urlstream_upload' => true,
222 // additional post data to send to our ajax hook
223 'multipart_params' => array(
224 '_ajax_nonce' => wp_create_nonce('updraft-uploader'),
225 'action' => 'plupload_action'
226 )
227 );
228 // 'flash_swf_url' => includes_url('js/plupload/plupload.flash.swf'),
229 // 'silverlight_xap_url' => includes_url('js/plupload/plupload.silverlight.xap'),
230
231 # WP 3.9 updated to plupload 2.0 - https://core.trac.wordpress.org/ticket/25663
232 if (is_file(ABSPATH.WPINC.'/js/plupload/Moxie.swf')) {
233 $plupload_init['flash_swf_url'] = includes_url('js/plupload/Moxie.swf');
234 } else {
235 $plupload_init['flash_swf_url'] = includes_url('js/plupload/plupload.flash.swf');
236 }
237
238 if (is_file(ABSPATH.WPINC.'/js/plupload/Moxie.xap')) {
239 $plupload_init['silverlight_xap_url'] = includes_url('js/plupload/Moxie.xap');
240 } else {
241 $plupload_init['silverlight_xap_url'] = includes_url('js/plupload/plupload.silverlight.swf');
242 }
243
244 ?><script type="text/javascript">
245 var updraft_plupload_config=<?php echo json_encode($plupload_init); ?>;
246 var updraft_credentialtest_nonce='<?php echo wp_create_nonce('updraftplus-credentialtest-nonce');?>';
247 var updraft_download_nonce='<?php echo wp_create_nonce('updraftplus_download');?>';
248 var updraft_siteurl = '<?php echo esc_js(site_url());?>';
249 var updraft_accept_archivename = <?php echo apply_filters('updraftplus_accept_archivename_js', "[]");?>;
250 <?php
251 $plupload_init['browse_button'] = 'plupload-browse-button2';
252 $plupload_init['container'] = 'plupload-upload-ui2';
253 $plupload_init['drop_element'] = 'drag-drop-area2';
254 $plupload_init['multipart_params']['action'] = 'plupload_action2';
255 $plupload_init['filters'] = array(array('title' => __('Allowed Files'), 'extensions' => 'crypt'));
256 ?>
257 var updraft_plupload_config2=<?php echo json_encode($plupload_init); ?>;
258 var updraft_downloader_nonce = '<?php wp_create_nonce("updraftplus_download"); ?>'
259 <?php
260 $overdue = $this->howmany_overdue_crons();
261 if ($overdue >= 4) { ?>
262 jQuery(document).ready(function(){
263 setTimeout(function(){updraft_check_overduecrons();}, 11000);
264 function updraft_check_overduecrons() {
265 jQuery.get(ajaxurl, { action: 'updraft_ajax', subaction: 'checkoverduecrons', nonce: updraft_credentialtest_nonce }, function(data, response) {
266 if ('success' == response) {
267 try {
268 resp = jQuery.parseJSON(data);
269 if (resp.m) {
270 jQuery('#updraft-insert-admin-warning').html(resp.m);
271 }
272 } catch(err) {
273 console.log(data);
274 }
275 }
276 });
277 }
278 });
279 <?php } ?>
280 </script>
281 <style type="text/css">
282 .updraft-bigbutton {
283 padding: 2px 0px;
284 margin-right: 14px !important;
285 font-size:22px !important;
286 min-height: 32px;
287 min-width: 180px;
288 }
289 .updraft_debugrow th {
290 text-align: right;
291 font-weight: bold;
292 padding-right: 8px;
293 min-width: 140px;
294 }
295 .updraft_debugrow td {
296 min-width: 300px;
297 }
298 .updraftplus-morefiles-row-delete {
299 cursor: pointer;
300 color: red;
301 font-size: 100%;
302 font-weight: bold;
303 border: 0px;
304 border-radius: 3px;
305 padding: 2px;
306 margin: 0 6px;
307 }
308 .updraftplus-morefiles-row-delete:hover {
309 cursor: pointer;
310 color: white;
311 background: red;
312 }
313
314 #updraft-wrap .form-table th {
315 width: 230px;
316 }
317 .updraftplus-remove a {
318 color: red;
319 }
320 .updraftplus-remove:hover {
321 background-color: red;
322 }
323 .updraftplus-remove a:hover {
324 color: #fff;
325 }
326 .drag-drop #drag-drop-area2 {
327 border: 4px dashed #ddd;
328 height: 200px;
329 }
330 #drag-drop-area2 .drag-drop-inside {
331 margin: 36px auto 0;
332 width: 350px;
333 }
334 #filelist, #filelist2 {
335 width: 100%;
336 }
337 #filelist .file, #filelist2 .file, #ud_downloadstatus .file, #ud_downloadstatus2 .file {
338 padding: 5px;
339 background: #ececec;
340 border: solid 1px #ccc;
341 margin: 4px 0;
342 }
343 #filelist .fileprogress, #filelist2 .fileprogress, #ud_downloadstatus .dlfileprogress, #ud_downloadstatus2 .dlfileprogress {
344 width: 0%;
345 background: #f6a828;
346 height: 5px;
347 }
348 #ud_downloadstatus .raw, #ud_downloadstatus2 .raw {
349 margin-top: 8px;
350 clear:left;
351 }
352 #ud_downloadstatus .file, #ud_downloadstatus2 .file {
353 margin-top: 8px;
354 }
355
356 </style>
357 <?php
358
359 }
360
361 private function disk_space_check($space) {
362 global $updraftplus;
363 $updraft_dir = $updraftplus->backups_dir_location();
364 $disk_free_space = @disk_free_space($updraft_dir);
365 if ($disk_free_space == false) return -1;
366 return ($disk_free_space > $space) ? true : false;
367 }
368
369 # Adds the settings link under the plugin on the plugin screen.
370 public function plugin_action_links($links, $file) {
371 if (is_array($links) && $file == 'updraftplus/updraftplus.php'){
372 $settings_link = '<a href="'.UpdraftPlus_Options::admin_page_url().'?page=updraftplus">'.__("Settings", "updraftplus").'</a>';
373 array_unshift($links, $settings_link);
374 // $settings_link = '<a href="http://david.dw-perspective.org.uk/donate">'.__("Donate","UpdraftPlus").'</a>';
375 // array_unshift($links, $settings_link);
376 $settings_link = '<a href="http://updraftplus.com">'.__("Add-Ons / Pro Support","updraftplus").'</a>';
377 array_unshift($links, $settings_link);
378 }
379 return $links;
380 }
381
382 public function admin_action_upgrade_pluginortheme() {
383
384 if (isset($_GET['action']) && ($_GET['action'] == 'upgrade-plugin' || $_GET['action'] == 'upgrade-theme') && !class_exists('UpdraftPlus_Addon_Autobackup') && !defined('UPDRAFTPLUS_NOADS_B')) {
385
386 # TODO: Remove legacy/erroneous use of transient any time after 1 Jun 2014
387 $dismissed = get_transient('updraftplus_dismissedautobackup');
388 if (true == $dismissed) return;
389 $dismissed_until = UpdraftPlus_Options::get_updraft_option('updraftplus_dismissedautobackup', 0);
390 if ($dismissed_until > time()) return;
391
392 if ( 'upgrade-plugin' == $_GET['action'] ) {
393 $title = __('Update Plugin');
394 $parent_file = 'plugins.php';
395 $submenu_file = 'plugins.php';
396 } else {
397 $title = __('Update Theme');
398 $parent_file = 'themes.php';
399 $submenu_file = 'themes.php';
400 }
401
402 require_once(ABSPATH.'wp-admin/admin-header.php');
403
404 ?>
405 <div id="updraft-autobackup" class="updated" style="float:left; padding: 6px; margin:8px 0px;">
406 <div style="float:right;"><a href="#" onclick="jQuery('#updraft-autobackup').slideUp(); jQuery.post(ajaxurl, {action: 'updraft_ajax', subaction: 'dismissautobackup', nonce: '<?php echo wp_create_nonce('updraftplus-credentialtest-nonce');?>' });"><?php echo sprintf(__('Dismiss (for %s weeks)', 'updraftplus'), 10); ?></a></div>
407 <h3 style="margin-top: 0px;"><?php _e('Be safe with an automatic backup','updraftplus');?></h3>
408 <p><?php echo __('UpdraftPlus Premium can <strong>automatically</strong> take a backup of your plugins or themes and database before you update.', 'updraftplus').' <a href="http://updraftplus.com/shop/autobackup/">'.__('Be safe every time, without needing to remember - follow this link to learn more.' ,'updraftplus').'</a>'; ?></p>
409 </div>
410 <?php
411 }
412 }
413
414 public function show_admin_warning($message, $class = "updated") {
415 echo '<div class="updraftmessage '.$class.'">'."<p>$message</p></div>";
416 }
417
418 public function show_admin_nosettings_warning() {
419 $this->show_admin_warning('<strong>'.__('Welcome to UpdraftPlus!', 'updraftplus').'</strong> '.__('To make a backup, just press the Backup Now button.', 'updraftplus').' <a href="#" id="updraft-navtab-settings2">'.__('To change any of the default settings of what is backed up, to configure scheduled backups, to send your backups to remote storage (recommended), and more, go to the settings tab.', 'updraftplus').'</a>');
420 }
421
422 public function show_admin_warning_execution_time() {
423 $this->show_admin_warning('<strong>'.__('Warning','updraftplus').':</strong> '.sprintf(__('The amount of time allowed for WordPress plugins to run is very low (%s seconds) - you should increase it to avoid backup failures due to time-outs (consult your web hosting company for more help - it is the max_execution_time PHP setting; the recommended value is %s seconds or more)', 'updraftplus'), (int)@ini_get('max_execution_time'), 90));
424 }
425
426 public function show_admin_warning_disabledcron() {
427 $this->show_admin_warning('<strong>'.__('Warning','updraftplus').':</strong> '.__('The scheduler is disabled in your WordPress install, via the DISABLE_WP_CRON setting. No backups can run (even &quot;Backup Now&quot;) unless either you have set up a facility to call the scheduler manually, or until it is enabled.','updraftplus').' <a href="http://updraftplus.com/faqs/my-scheduled-backups-and-pressing-backup-now-does-nothing-however-pressing-debug-backup-does-produce-a-backup/#disablewpcron">'.__('Go here for more information.','updraftplus').'</a>', 'updated updraftplus-disable-wp-cron-warning');
428 }
429
430 public function show_admin_warning_diskspace() {
431 $this->show_admin_warning('<strong>'.__('Warning','updraftplus').':</strong> '.sprintf(__('You have less than %s 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.','updraftplus'),'35 Mb'));
432 }
433
434 public function show_admin_warning_wordpressversion() {
435 $this->show_admin_warning('<strong>'.__('Warning','updraftplus').':</strong> '.sprintf(__('UpdraftPlus does not officially support versions of WordPress before %s. It may work for you, but if it does not, then please be aware that no support is available until you upgrade WordPress.', 'updraftplus'), '3.2'));
436 }
437
438 public function show_admin_warning_litespeed() {
439 $this->show_admin_warning('<strong>'.__('Warning','updraftplus').':</strong> '.sprintf(__('Your website is hosted using the %s web server.','updraftplus'),'LiteSpeed').' <a href="http://updraftplus.com/faqs/i-am-having-trouble-backing-up-and-my-web-hosting-company-uses-the-litespeed-webserver/">'.__('Please consult this FAQ if you have problems backing up.', 'updraftplus').'</a>');
440 }
441
442 public function show_admin_debug_warning() {
443 $this->show_admin_warning('<strong>'.__('Notice','updraftplus').':</strong> '.__('UpdraftPlus\'s debug mode is on. You may see debugging notices on this page not just from UpdraftPlus, but from any other plugin installed. Please try to make sure that the notice you are seeing is from UpdraftPlus before you raise a support request.', 'updraftplus').'</a>');
444 }
445
446 public function show_admin_warning_overdue_crons($howmany) {
447 $ret = '<div class="updraftmessage updated"><p>';
448 $ret .= '<strong>'.__('Warning','updraftplus').':</strong> '.sprintf(__('WordPress has a number (%d) of scheduled tasks which are overdue. Unless this is a development site, this probably means that the scheduler in your WordPress install is not working.', 'updraftplus'), $howmany).' <a href="http://updraftplus.com/faqs/scheduler-wordpress-installation-working/">'.__('Read this page for a guide to possible causes and how to fix it.', 'updraftplus').'</a>';
449 $ret .= '</p></div>';
450 return $ret;
451 }
452
453 public function show_admin_warning_dropbox() {
454 $this->show_admin_warning('<strong>'.__('UpdraftPlus notice:','updraftplus').'</strong> <a href="'.UpdraftPlus_Options::admin_page_url().'?page=updraftplus&action=updraftmethod-dropbox-auth&updraftplus_dropboxauth=doit">'.sprintf(__('Click here to authenticate your %s account (you will not be able to back up to %s without it).','updraftplus'),'Dropbox','Dropbox').'</a>');
455 }
456
457 public function show_admin_warning_bitcasa() {
458 $this->show_admin_warning('<strong>'.__('UpdraftPlus notice:','updraftplus').'</strong> <a href="'.UpdraftPlus_Options::admin_page_url().'?page=updraftplus&action=updraftmethod-bitcasa-auth&updraftplus_bitcasaauth=doit">'.sprintf(__('Click here to authenticate your %s account (you will not be able to back up to %s without it).','updraftplus'),'Bitcasa','Bitcasa').'</a>');
459 }
460
461 public function show_admin_warning_copycom() {
462 $this->show_admin_warning('<strong>'.__('UpdraftPlus notice:','updraftplus').'</strong> <a href="'.UpdraftPlus_Options::admin_page_url().'?page=updraftplus&action=updraftmethod-copycom-auth&updraftplus_copycomauth=doit">'.sprintf(__('Click here to authenticate your %s account (you will not be able to back up to %s without it).','updraftplus'),'Copy.Com','Copy').'</a>');
463 }
464
465 public function show_admin_warning_googledrive() {
466 $this->show_admin_warning('<strong>'.__('UpdraftPlus notice:','updraftplus').'</strong> <a href="'.UpdraftPlus_Options::admin_page_url().'?page=updraftplus&action=updraftmethod-googledrive-auth&updraftplus_googleauth=doit">'.sprintf(__('Click here to authenticate your %s account (you will not be able to back up to %s without it).','updraftplus'),'Google Drive','Google Drive').'</a>');
467 }
468
469 // This options filter removes ABSPATH off the front of updraft_dir, if it is given absolutely and contained within it
470 public function prune_updraft_dir_prefix($updraft_dir) {
471 if ('/' == substr($updraft_dir, 0, 1) || "\\" == substr($updraft_dir, 0, 1) || preg_match('/^[a-zA-Z]:/', $updraft_dir)) {
472 $wcd = trailingslashit(WP_CONTENT_DIR);
473 if (strpos($updraft_dir, $wcd) === 0) {
474 $updraft_dir = substr($updraft_dir, strlen($wcd));
475 }
476 # Legacy
477 // if (strpos($updraft_dir, ABSPATH) === 0) {
478 // $updraft_dir = substr($updraft_dir, strlen(ABSPATH));
479 // }
480 }
481 return $updraft_dir;
482 }
483
484 public function updraft_download_backup() {
485
486 @set_time_limit(900);
487
488 global $updraftplus;
489
490 if (!isset($_REQUEST['_wpnonce']) || !wp_verify_nonce($_REQUEST['_wpnonce'], 'updraftplus_download')) die;
491 if (!isset($_REQUEST['timestamp']) || !is_numeric($_REQUEST['timestamp']) || !isset($_REQUEST['type'])) exit;
492
493 $findex = (isset($_REQUEST['findex'])) ? $_REQUEST['findex'] : 0;
494 if (empty($findex)) $findex=0;
495
496 $backupable_entities = $updraftplus->get_backupable_file_entities(true);
497 $type_match = false;
498 foreach ($backupable_entities as $type => $info) {
499 if ($_REQUEST['type'] == $type) $type_match = true;
500 }
501
502 if (!$type_match && 'db' != substr($_REQUEST['type'], 0, 2)) exit;
503
504 // Get the information on what is wanted
505 $type = $_REQUEST['type'];
506 $timestamp = $_REQUEST['timestamp'];
507
508 // You need a nonce before you can set job data. And we certainly don't yet have one.
509 $updraftplus->backup_time_nonce($timestamp);
510
511 $debug_mode = UpdraftPlus_Options::get_updraft_option('updraft_debug_mode');
512
513 // Set the job type before logging, as there can be different logging destinations
514 $updraftplus->jobdata_set('job_type', 'download');
515 $updraftplus->jobdata_set('job_time_ms', $updraftplus->job_time_ms);
516
517 // Retrieve the information from our backup history
518 $backup_history = $updraftplus->get_backup_history();
519 // Base name
520 $file = $backup_history[$timestamp][$type];
521
522 // Deal with multi-archive sets
523 if (is_array($file)) $file=$file[$findex];
524
525 // Where it should end up being downloaded to
526 $fullpath = $updraftplus->backups_dir_location().'/'.$file;
527
528 if (isset($_GET['stage']) && '2' == $_GET['stage']) {
529 $updraftplus->spool_file($type, $fullpath);
530 die;
531 }
532
533 if (isset($_POST['stage']) && 'delete' == $_POST['stage']) {
534 @unlink($fullpath);
535 echo 'deleted';
536 $updraftplus->log('The file has been deleted');
537 die;
538 }
539
540 // TODO: FIXME: Failed downloads may leave log files forever (though they are small)
541 // Note that log() assumes that the data is in _POST, not _GET
542 if ($debug_mode) $updraftplus->logfile_open($updraftplus->nonce);
543
544 set_error_handler(array($updraftplus, 'php_error'), E_ALL & ~E_STRICT);
545
546 $updraftplus->log("Requested to obtain file: timestamp=$timestamp, type=$type, index=$findex");
547
548 $itext = (empty($findex)) ? '' : $findex;
549 $known_size = isset($backup_history[$timestamp][$type.$itext.'-size']) ? $backup_history[$timestamp][$type.$itext.'-size'] : 0;
550
551 $services = (isset($backup_history[$timestamp]['service'])) ? $backup_history[$timestamp]['service'] : false;
552 if (is_string($services)) $services = array($services);
553
554 $updraftplus->jobdata_set('service', $services);
555
556 // Fetch it from the cloud, if we have not already got it
557
558 $needs_downloading = false;
559
560 if(!file_exists($fullpath)) {
561 //if the file doesn't exist and they're using one of the cloud options, fetch it down from the cloud.
562 $needs_downloading = true;
563 $updraftplus->log('File does not yet exist locally - needs downloading');
564 } elseif ($known_size>0 && filesize($fullpath) < $known_size) {
565 $updraftplus->log("The file was found locally (".filesize($fullpath).") but did not match the size in the backup history ($known_size) - will resume downloading");
566 $needs_downloading = true;
567 } elseif ($known_size>0) {
568 $updraftplus->log('The file was found locally and matched the recorded size from the backup history ('.round($known_size/1024,1).' Kb)');
569 } else {
570 $updraftplus->log('No file size was found recorded in the backup history. We will assume the local one is complete.');
571 $known_size = filesize($fullpath);
572 }
573
574 // The AJAX responder that updates on progress wants to see this
575 $updraftplus->jobdata_set('dlfile_'.$timestamp.'_'.$type.'_'.$findex, "downloading:$known_size:$fullpath");
576
577 if ($needs_downloading) {
578 $this->close_browser_connection();
579 $is_downloaded = false;
580 add_action('http_request_args', array($updraftplus, 'modify_http_options'));
581 foreach ($services as $service) {
582 if ($is_downloaded) continue;
583 $download = $this->download_file($file, $service);
584 if (is_readable($fullpath) && $download !== false) {
585 clearstatcache();
586 $updraftplus->log('Remote fetch was successful (file size: '.round(filesize($fullpath)/1024,1).' Kb)');
587 $is_downloaded = true;
588 } else {
589 clearstatcache();
590 if (0 === @filesize($fullpath)) @unlink($fullpath);
591 $updraftplus->log('Remote fetch failed');
592 }
593 }
594 remove_action('http_request_args', array($updraftplus, 'modify_http_options'));
595 }
596
597 // Now, spool the thing to the browser
598 if(is_file($fullpath) && is_readable($fullpath)) {
599
600 // That message is then picked up by the AJAX listener
601 $updraftplus->jobdata_set('dlfile_'.$timestamp.'_'.$type.'_'.$findex, 'downloaded:'.filesize($fullpath).":$fullpath");
602
603 } else {
604 $updraftplus->jobdata_set('dlfile_'.$timestamp.'_'.$type.'_'.$findex, 'failed');
605 $updraftplus->jobdata_set('dlerrors_'.$timestamp.'_'.$type.'_'.$findex, $updraftplus->errors);
606 $updraftplus->log('Remote fetch failed. File '.$fullpath.' did not exist or was unreadable. If you delete local backups then remote retrieval may have failed.');
607 }
608
609 restore_error_handler();
610
611 @fclose($updraftplus->logfile_handle);
612 if (!$debug_mode) @unlink($updraftplus->logfile_name);
613
614 exit;
615
616 }
617
618 private function close_browser_connection($txt = '') {
619 // Close browser connection so that it can resume AJAX polling
620 header('Content-Length: '.((!empty($txt)) ? 4+strlen($txt) : '0'));
621 header('Connection: close');
622 header('Content-Encoding: none');
623 if (session_id()) session_write_close();
624 echo "\r\n\r\n";
625 echo $txt;
626 }
627
628 # Pass only a single service, as a string, into this function
629 private function download_file($file, $service) {
630
631 global $updraftplus;
632
633 @set_time_limit(900);
634
635 $updraftplus->log("Requested file from remote service: $service: $file");
636
637 $method_include = UPDRAFTPLUS_DIR.'/methods/'.$service.'.php';
638 if (file_exists($method_include)) require_once($method_include);
639
640 $objname = "UpdraftPlus_BackupModule_${service}";
641 if (method_exists($objname, "download")) {
642 $remote_obj = new $objname;
643 return $remote_obj->download($file);
644 } else {
645 $updraftplus->log("Automatic backup restoration is not available with the method: $service.");
646 $updraftplus->log("$file: ".sprintf(__("The backup archive for this file could not be found. The remote storage method in use (%s) does not allow us to retrieve files. To perform any restoration using UpdraftPlus, you will need to obtain a copy of this file and place it inside UpdraftPlus's working folder", 'updraftplus'), $service)." (".$this->prune_updraft_dir_prefix($updraftplus->backups_dir_location()).")", 'error');
647 return false;
648 }
649
650 }
651
652 // Called via AJAX
653 public function updraft_ajax_handler() {
654
655 global $updraftplus;
656
657 // Test the nonce
658 $nonce = (empty($_REQUEST['nonce'])) ? "" : $_REQUEST['nonce'];
659 if (!wp_verify_nonce($nonce, 'updraftplus-credentialtest-nonce') || empty($_REQUEST['subaction'])) die('Security check');
660 if (isset($_REQUEST['subaction']) && 'lastlog' == $_REQUEST['subaction']) {
661 echo htmlspecialchars(UpdraftPlus_Options::get_updraft_option('updraft_lastmessage', '('.__('Nothing yet logged', 'updraftplus').')'));
662 } elseif (isset($_GET['subaction']) && 'activejobs_list' == $_GET['subaction']) {
663 $download_status = array();
664 if (!empty($_GET['downloaders'])) {
665 foreach(explode(':', $_GET['downloaders']) as $downloader) {
666 # prefix, timestamp, entity, index
667 if (preg_match('/^([^,]+),(\d+),([-a-z]+|db[0-9]+),(\d+)$/', $downloader, $matches)) {
668 $updraftplus->nonce = $matches[2];
669 $status = $this->download_status($matches[2], $matches[3], $matches[4]);
670 if (is_array($status)) {
671 $status['base'] = $matches[1];
672 $status['timestamp'] = $matches[2];
673 $status['what'] = $matches[3];
674 $status['findex'] = (empty($matches[4])) ? '0' : $matches[4];
675 $download_status[] = $status;
676 }
677 }
678 }
679 }
680 if (!empty($_GET['oneshot'])) {
681 $job_id = get_site_option('updraft_oneshotnonce', false);
682 $active_jobs = (false === $job_id) ? '' : $this->print_active_job($job_id, true);
683 } else {
684 $active_jobs = $this->print_active_jobs();
685 }
686 echo json_encode(array(
687 'l' => htmlspecialchars(UpdraftPlus_Options::get_updraft_option('updraft_lastmessage', '('.__('Nothing yet logged', 'updraftplus').')')),
688 'j' => $active_jobs,
689 'ds' => $download_status
690 ));
691 } elseif (isset($_REQUEST['subaction']) && 'callwpaction' == $_REQUEST['subaction'] && !empty($_REQUEST['wpaction'])) {
692 ob_start();
693
694 $res = '<em>Request received: </em>';
695
696 if (preg_match('/^([^:]+)+:(.*)$/', stripslashes($_REQUEST['wpaction']), $matches)) {
697 $action = $matches[1];
698 if (null === ($args = json_decode($matches[2], true))) {
699 $res .= "The parameters (should be JSON) could not be decoded";
700 $action = false;
701 } else {
702 $res .= "Will despatch action: ".htmlspecialchars($action).", parameters: ".htmlspecialchars(implode(',', $args));
703 }
704 } else {
705 $action = $_REQUEST['wpaction'];
706 $res .= "Will despatch action: ".htmlspecialchars($action).", no parameters";
707 }
708
709 echo json_encode(array('r' => $res));
710 $ret = ob_get_clean();
711 ob_end_clean();
712 $this->close_browser_connection($ret);
713 if (!empty($action)) {
714 if (!empty($args)) {
715 do_action_ref_array($action, $args);
716 } else {
717 do_action($action);
718 }
719 }
720 die;
721 } elseif (isset($_REQUEST['subaction']) && 'httpget' == $_REQUEST['subaction']) {
722 if (empty($_REQUEST['uri'])) {
723 echo json_encode(array('r' => ''));
724 die;
725 }
726 $uri = $_REQUEST['uri'];
727 if (!empty($_REQUEST['curl'])) {
728 if (!function_exists('curl_exec')) {
729 echo json_encode(array('e' => 'No Curl installed'));
730 die;
731 }
732 $ch = curl_init();
733 curl_setopt($ch, CURLOPT_URL, $uri);
734 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
735 curl_setopt($ch, CURLOPT_FAILONERROR, true);
736 curl_setopt($ch, CURLOPT_HEADER, true);
737 curl_setopt($ch, CURLOPT_VERBOSE, true);
738 curl_setopt($ch, CURLOPT_STDERR, $output=fopen('php://temp', "w+"));
739 $response = curl_exec($ch);
740 $error = curl_error($ch);
741 $getinfo = curl_getinfo($ch);
742 curl_close($ch);
743 $resp = array();
744 if (false === $response) {
745 $resp['e'] = htmlspecialchars($error);
746 # json_encode(array('e' => htmlspecialchars($error)));
747 }
748 $resp['r'] = (empty($response)) ? '' : htmlspecialchars(substr($response, 0, 2048));
749 rewind($output);
750 $verb = stream_get_contents($output);
751 if (!empty($verb)) $resp['r'] = htmlspecialchars($verb)."\n\n".$resp['r'];
752 echo json_encode($resp);
753 // echo json_encode(array('r' => htmlspecialchars(substr($response, 0, 2048))));
754 } else {
755 $response = wp_remote_get($uri, array('timeout' => 10));
756 if (is_wp_error($response)) {
757 echo json_encode(array('e' => htmlspecialchars($response->get_error_message())));
758 die;
759 }
760 echo json_encode(array('r' => $response['response']['code'].': '.htmlspecialchars(substr($response['body'], 0, 2048))));
761 }
762 die;
763 } elseif (isset($_REQUEST['subaction']) && 'dismissautobackup' == $_REQUEST['subaction']) {
764 UpdraftPlus_Options::update_updraft_option('updraftplus_dismissedautobackup', time() + 84*86400);
765 } elseif (isset($_REQUEST['subaction']) && 'dismissexpiry' == $_REQUEST['subaction']) {
766 UpdraftPlus_Options::update_updraft_option('updraftplus_dismissedexpiry', time() + 14*86400);
767 } elseif (isset($_REQUEST['subaction']) && 'poplog' == $_REQUEST['subaction']){
768 # New code to handle AJAX request for log file
769
770 #Set the backup nonce to either passed value or the latest backup
771 if (empty($_REQUEST['backup_nonce'])){
772 list ($mod_time, $log_file, $nonce) = $updraftplus->last_modified_log();
773 } else {
774 $nonce = $_REQUEST['backup_nonce'];
775 }
776
777 if (!preg_match('/^[0-9a-f]+$/', $nonce)) die('Security check');
778
779 $log_content = '';
780
781 if (!empty($nonce)) {
782 $updraft_dir = $updraftplus->backups_dir_location();
783
784 # Open the log file and read into log content
785 $potential_log_file = $updraft_dir."/log.".$nonce.".txt";
786
787 if (is_readable($potential_log_file)){
788 $log_content = file_get_contents($potential_log_file);
789 } else {
790 $log_content .= __('The log file could not be read.','updraftplus');
791 }
792
793 } else {
794 $log_content .= __('The log file could not be read.','updraftplus');
795 }
796
797
798 echo json_encode(array(
799 'html' => $log_content,
800 'nonce' => $nonce
801 ));
802
803 } elseif (isset($_GET['subaction']) && 'restore_alldownloaded' == $_GET['subaction'] && isset($_GET['restoreopts']) && isset($_GET['timestamp'])) {
804
805 $backups = $updraftplus->get_backup_history();
806 $updraft_dir = $updraftplus->backups_dir_location();
807
808 $timestamp = (int)$_GET['timestamp'];
809 if (!isset($backups[$timestamp])) {
810 echo json_encode(array('m' => '', 'w' => '', 'e' => __('No such backup set exists', 'updraftplus')));
811 die;
812 }
813
814 $mess = array();
815 parse_str($_GET['restoreopts'], $res);
816
817 if (isset($res['updraft_restore'])) {
818
819 set_error_handler(array($this, 'get_php_errors'), E_ALL & ~E_STRICT);
820
821 $elements = array_flip($res['updraft_restore']);
822
823 $warn = array(); $err = array();
824
825 @set_time_limit(900);
826 $max_execution_time = (int)@ini_get('max_execution_time');
827
828 if ($max_execution_time>0 && $max_execution_time<61) {
829 $warn[] = sprintf(__('The PHP setup on this webserver allows only %s seconds for PHP to run, and does not allow this limit to be raised. If you have a lot of data to import, and if the restore operation times out, then you will need to ask your web hosting company for ways to raise this limit (or attempt the restoration piece-by-piece).', 'updraftplus'), $max_execution_time);
830 }
831
832 if (isset($backups[$timestamp]['native']) && false == $backups[$timestamp]['native']) {
833 $warn[] = __('This backup set was not known by UpdraftPlus to be created by the current WordPress installation, but was found in remote storage.', 'updraftplus').' '.__('You should make sure that this really is a backup set intended for use on this website, before you restore (rather than a backup set of an unrelated website that was using the same storage location).', 'updraftplus');
834 }
835
836 if (isset($elements['db'])) {
837 // Analyse the header of the database file + display results
838 list ($mess2, $warn2, $err2) = $this->analyse_db_file($timestamp, $res);
839 $mess = array_merge($mess, $mess2);
840 $warn = array_merge($warn, $warn2);
841 $err = array_merge($err, $err2);
842 foreach ($backups[$timestamp] as $bid => $bval) {
843 if ('db' != $bid && 'db' == substr($bid, 0, 2) && '-size' != substr($bid, -5, 5)) {
844 $warn[] = __('Only the WordPress database can be restored; you will need to deal with the external database manually.', 'updraftplus');
845 break;
846 }
847 }
848 }
849
850 $backupable_entities = $updraftplus->get_backupable_file_entities(true, true);
851 $backupable_plus_db = $backupable_entities;
852 $backupable_plus_db['db'] = array('path' => 'path-unused', 'description' => __('Database', 'updraftplus'));
853
854 if (!empty($backups[$timestamp]['meta_foreign'])) {
855 $foreign_known = apply_filters('updraftplus_accept_archivename', array());
856 if (!is_array($foreign_known) || empty($foreign_known[$backups[$timestamp]['meta_foreign']])) {
857 $err[] = sprintf(__('Backup created by unknown source (%s) - cannot be restored.', 'updraftplus'), $backups[$timestamp]['meta_foreign']);
858 } else {
859 # For some reason, on PHP 5.5 passing by reference in a single array stopped working with apply_filters_ref_array (though not with do_action_ref_array).
860 $backupable_plus_db = apply_filters_ref_array("updraftplus_importforeign_backupable_plus_db", array($backupable_plus_db, array($foreign_known[$backups[$timestamp]['meta_foreign']], &$mess, &$warn, &$err)));
861 }
862 }
863
864 foreach ($backupable_plus_db as $type => $info) {
865 if (!isset($elements[$type])) continue;
866 $whatwegot = $backups[$timestamp][$type];
867 if (is_string($whatwegot)) $whatwegot = array($whatwegot);
868 $expected_index = 0;
869 $missing = '';
870 ksort($whatwegot);
871 $outof = false;
872 foreach ($whatwegot as $index => $file) {
873 if (preg_match('/\d+of(\d+)\.zip/', $file, $omatch)) { $outof = max($matches[1], 1); }
874 if ($index != $expected_index) {
875 $missing .= ($missing == '') ? (1+$expected_index) : ",".(1+$expected_index);
876 }
877 if (!file_exists($updraft_dir.'/'.$file)) {
878 $err[] = sprintf(__('File not found (you need to upload it): %s', 'updraftplus'), $updraft_dir.'/'.$file);
879 } elseif (filesize($updraft_dir.'/'.$file) == 0) {
880 $err[] = sprintf(__('File was found, but is zero-sized (you need to re-upload it): %s', 'updraftplus'), $file);
881 } else {
882 $itext = (0 == $index) ? '' : $index;
883 if (!empty($backups[$timestamp][$type.$itext.'-size']) && $backups[$timestamp][$type.$itext.'-size'] != filesize($updraft_dir.'/'.$file)) {
884 if (empty($warn['doublecompressfixed'])) {
885 $warn[] = sprintf(__('File (%s) was found, but has a different size (%s) from what was expected (%s) - it may be corrupt.', 'updraftplus'), $file, filesize($updraft_dir.'/'.$file), $backups[$timestamp][$type.$itext.'-size']);
886 }
887 }
888 do_action_ref_array("updraftplus_checkzip_$type", array($updraft_dir.'/'.$file, &$mess, &$warn, &$err));
889 }
890 $expected_index++;
891 }
892 do_action_ref_array("updraftplus_checkzip_end_$type", array(&$mess, &$warn, &$err));
893 # Detect missing archives where they are missing from the end of the set
894 if ($outof>0 && $expected_index < $outof) {
895 for ($j = $expected_index; $j<$outof; $j++) {
896 $missing .= ($missing == '') ? (1+$j) : ",".(1+$j);
897 }
898 }
899 if ('' != $missing) {
900 $warn[] = sprintf(__("This multi-archive backup set appears to have the following archives missing: %s", 'updraftplus'), $missing.' ('.$info['description'].')');
901 }
902 }
903
904 if (0 == count($err) && 0 == count($warn)) {
905 $mess_first = __('The backup archive files have been successfully processed. Now press Restore again to proceed.', 'updraftplus');
906 } elseif (0 == count($err)) {
907 $mess_first = __('The backup archive files have been processed, but with some warnings. If all is well, then now press Restore again to proceed. Otherwise, cancel and correct any problems first.', 'updraftplus');
908 } else {
909 $mess_first = __('The backup archive files have been processed, but with some errors. You will need to cancel and correct any problems before retrying.', 'updraftplus');
910 }
911
912 if (count($this->logged) >0) {
913 foreach ($this->logged as $lwarn) $warn[] = $lwarn;
914 }
915 restore_error_handler();
916
917 echo json_encode(array('m' => '<p>'.$mess_first.'</p>'.implode('<br>', $mess), 'w' => implode('<br>', $warn), 'e' => implode('<br>', $err)));
918 }
919
920 } elseif (isset($_POST['backup_timestamp']) && 'deleteset' == $_REQUEST['subaction']) {
921 $backups = $updraftplus->get_backup_history();
922 $timestamp = $_POST['backup_timestamp'];
923 if (!isset($backups[$timestamp])) {
924 echo json_encode(array('result' => 'error', 'message' => __('Backup set not found', 'updraftplus')));
925 die;
926 }
927
928 // You need a nonce before you can set job data. And we certainly don't yet have one.
929 $updraftplus->backup_time_nonce();
930 // Set the job type before logging, as there can be different logging destinations
931 $updraftplus->jobdata_set('job_type', 'delete');
932 $updraftplus->jobdata_set('job_time_ms', $updraftplus->job_time_ms);
933
934 if (UpdraftPlus_Options::get_updraft_option('updraft_debug_mode')) {
935 $updraftplus->logfile_open($updraftplus->nonce);
936 set_error_handler(array($updraftplus, 'php_error'), E_ALL & ~E_STRICT);
937 }
938
939 $updraft_dir = $updraftplus->backups_dir_location();
940 $backupable_entities = $updraftplus->get_backupable_file_entities(true, true);
941
942 $nonce = isset($backups[$timestamp]['nonce']) ? $backups[$timestamp]['nonce'] : '';
943
944 $delete_from_service = array();
945
946 if (isset($_POST['delete_remote']) && 1==$_POST['delete_remote']) {
947 // Locate backup set
948 if (isset($backups[$timestamp]['service'])) {
949 $services = is_string($backups[$timestamp]['service']) ? array($backups[$timestamp]['service']) : $backups[$timestamp]['service'];
950 if (is_array($services)) {
951 foreach ($services as $service) {
952 if ($service != 'none') $delete_from_service[] = $service;
953 }
954 }
955 }
956 }
957
958 $files_to_delete = array();
959 foreach ($backupable_entities as $key => $ent) {
960 if (isset($backups[$timestamp][$key])) {
961 $files_to_delete[$key] = $backups[$timestamp][$key];
962 }
963 }
964 // Delete DB
965 if (isset($backups[$timestamp]['db'])) $files_to_delete['db'] = $backups[$timestamp]['db'];
966
967 // Also delete the log
968 if ($nonce && !UpdraftPlus_Options::get_updraft_option('updraft_debug_mode')) {
969 $files_to_delete['log'] = "log.$nonce.txt";
970 }
971
972 unset($backups[$timestamp]);
973 UpdraftPlus_Options::update_updraft_option('updraft_backup_history', $backups);
974
975 $message = '';
976
977 $local_deleted = 0;
978 $remote_deleted = 0;
979 add_action('http_request_args', array($updraftplus, 'modify_http_options'));
980 foreach ($files_to_delete as $key => $files) {
981 # Local deletion
982 if (is_string($files)) $files=array($files);
983 foreach ($files as $file) {
984 if (is_file($updraft_dir.'/'.$file)) {
985 if (@unlink($updraft_dir.'/'.$file)) $local_deleted++;
986 }
987 }
988 if ('log' != $key && count($delete_from_service) > 0) {
989 foreach ($delete_from_service as $service) {
990 if ('email' == $service) continue;
991 if (file_exists(UPDRAFTPLUS_DIR."/methods/$service.php")) require_once(UPDRAFTPLUS_DIR."/methods/$service.php");
992 $objname = "UpdraftPlus_BackupModule_".$service;
993 $deleted = -1;
994 if (class_exists($objname)) {
995 # TODO: Re-use the object (i.e. prevent repeated connection setup/teardown)
996 $remote_obj = new $objname;
997 $deleted = $remote_obj->delete($files);
998 }
999 if ($deleted === -1) {
1000 //echo __('Did not know how to delete from this cloud service.', 'updraftplus');
1001 } elseif ($deleted !== false) {
1002 $remote_deleted = $remote_deleted + count($files);
1003 } else {
1004 // Do nothing
1005 }
1006 }
1007 }
1008 }
1009 remove_action('http_request_args', array($updraftplus, 'modify_http_options'));
1010 $message .= __('The backup set has been removed.', 'updraftplus')."\n";
1011 $message .= sprintf(__('Local archives deleted: %d', 'updraftplus'),$local_deleted)."\n";
1012 $message .= sprintf(__('Remote archives deleted: %d', 'updraftplus'),$remote_deleted)."\n";
1013
1014 $updraftplus->log("Local archives deleted: ".$local_deleted);
1015 $updraftplus->log("Remote archives deleted: ".$remote_deleted);
1016
1017 print json_encode(array('result' => 'success', 'message' => $message));
1018
1019 if (UpdraftPlus_Options::get_updraft_option('updraft_debug_mode')) {
1020 restore_error_handler();
1021 }
1022
1023
1024 } elseif ('rawbackuphistory' == $_REQUEST['subaction']) {
1025
1026 echo '<h3 id="ud-debuginfo-rawbackups">'.__('Known backups (raw)', 'updraftplus').'</h3><pre>';
1027 var_dump($updraftplus->get_backup_history());
1028 echo '</pre>';
1029
1030 echo '<h3 id="ud-debuginfo-files">Files</h3><pre>';
1031 $updraft_dir = $updraftplus->backups_dir_location();
1032 $raw_output = array();
1033 $d = dir($updraft_dir);
1034 while (false !== ($entry = $d->read())) {
1035 $fp = $updraft_dir.'/'.$entry;
1036 $mtime = filemtime($fp);
1037 if (is_dir($fp)) {
1038 $size = ' d';
1039 } elseif (is_link($fp)) {
1040 $size = ' l';
1041 } elseif (is_file($fp)) {
1042 $size = sprintf("%8.1f", round(filesize($fp)/1024, 1)).' '.gmdate('r', $mtime);
1043 } else {
1044 $size = ' ?';
1045 }
1046 if (preg_match('/^log\.(.*)\.txt$/', $entry, $lmatch)) $entry = '<a target="_top" href="?action=downloadlog&page=updraftplus&updraftplus_backup_nonce='.htmlspecialchars($lmatch[1]).'">'.$entry.'</a>';
1047 $raw_output[$mtime] = empty($raw_output[$mtime]) ? sprintf("%s %s\n", $size, $entry) : $raw_output[$mtime].sprintf("%s %s\n", $size, $entry);
1048 }
1049 @$d->close();
1050 krsort($raw_output, SORT_NUMERIC);
1051 foreach ($raw_output as $line) echo $line;
1052 echo '</pre>';
1053
1054 echo '<h3 id="ud-debuginfo-options">'.__('Options (raw)', 'updraftplus').'</h3>';
1055 $opts = $this->get_settings_keys();
1056 asort($opts);
1057 // <tr><th>'.__('Key','updraftplus').'</th><th>'.__('Value','updraftplus').'</th></tr>
1058 echo '<table><thead></thead><tbody>';
1059 foreach ($opts as $opt) {
1060 echo '<tr><td>'.htmlspecialchars($opt).'</td><td>'.htmlspecialchars(print_r(UpdraftPlus_Options::get_updraft_option($opt), true)).'</td>';
1061 }
1062 echo '</tbody></table>';
1063
1064 } elseif ('countbackups' == $_REQUEST['subaction']) {
1065 $backup_history = UpdraftPlus_Options::get_updraft_option('updraft_backup_history');
1066 $backup_history = (is_array($backup_history))?$backup_history:array();
1067 #echo sprintf(__('%d set(s) available', 'updraftplus'), count($backup_history));
1068 echo __('Existing Backups', 'updraftplus').' ('.count($backup_history).')';
1069 } elseif ('ping' == $_REQUEST['subaction']) {
1070 // The purpose of this is to detect brokenness caused by extra line feeds in plugins/themes - before it breaks other AJAX operations and leads to support requests
1071 echo 'pong';
1072 } elseif ('checkoverduecrons' == $_REQUEST['subaction']) {
1073 $how_many_overdue = $this->howmany_overdue_crons();
1074 if ($how_many_overdue >= 4) echo json_encode(array('m' => $this->show_admin_warning_overdue_crons($how_many_overdue)));
1075 } elseif ('delete_old_dirs' == $_REQUEST['subaction']) {
1076 $this->delete_old_dirs_go(false);
1077 } elseif ('phpinfo' == $_REQUEST['subaction']) {
1078 phpinfo(INFO_ALL ^ (INFO_CREDITS | INFO_LICENSE));
1079
1080 echo '<h3 id="ud-debuginfo-constants">'.__('Constants', 'updraftplus').'</h3>';
1081 $opts = @get_defined_constants();
1082 ksort($opts);
1083 // <tr><th>'.__('Key','updraftplus').'</th><th>'.__('Value','updraftplus').'</th></tr>
1084 echo '<table><thead></thead><tbody>';
1085 foreach ($opts as $key => $opt) {
1086 echo '<tr><td>'.htmlspecialchars($key).'</td><td>'.htmlspecialchars(print_r($opt, true)).'</td>';
1087 }
1088 echo '</tbody></table>';
1089
1090 } elseif ('doaction' == $_REQUEST['subaction'] && !empty($_REQUEST['subsubaction']) && 'updraft_' == substr($_REQUEST['subsubaction'], 0, 8)) {
1091 do_action($_REQUEST['subsubaction']);
1092 } elseif ('backupnow' == $_REQUEST['subaction']) {
1093
1094 $backupnow_nocloud = (empty($_REQUEST['backupnow_nocloud'])) ? false : true;
1095 $event = (!empty($_REQUEST['backupnow_nofiles'])) ? 'updraft_backupnow_backup_database' : ((!empty($_REQUEST['backupnow_nodb'])) ? 'updraft_backupnow_backup' : 'updraft_backupnow_backup_all');
1096
1097 $msg = '<strong>'.__('Start backup','updraftplus').':</strong> '.htmlspecialchars(__('OK. You should soon see activity in the "Last log message" field below.','updraftplus'));
1098 $this->close_browser_connection($msg);
1099
1100 do_action($event, apply_filters('updraft_backupnow_options', array('nocloud' => $backupnow_nocloud)));
1101
1102 # Old-style: schedule an event in 5 seconds time. This has the advantage of testing out the scheduler, and alerting the user if it doesn't work... but has the disadvantage of not working in that case.
1103 # I don't think the </div>s should be here - in case this is ever re-activated
1104 // if (wp_schedule_single_event(time()+5, $event, array($backupnow_nocloud)) === false) {
1105 // $updraftplus->log("A backup run failed to schedule");
1106 // echo __("Failed.", 'updraftplus')."</div>";
1107 // } else {
1108 // echo htmlspecialchars(__('OK. You should soon see activity in the "Last log message" field below.','updraftplus'))." <a href=\"http://updraftplus.com/faqs/my-scheduled-backups-and-pressing-backup-now-does-nothing-however-pressing-debug-backup-does-produce-a-backup/\"><br>".__('Nothing happening? Follow this link for help.','updraftplus')."</a></div>";
1109 // $updraftplus->log("A backup run has been scheduled");
1110 // }
1111
1112 } elseif (isset($_GET['subaction']) && 'lastbackup' == $_GET['subaction']) {
1113 echo $this->last_backup_html();
1114 } elseif (isset($_GET['subaction']) && 'activejobs_delete' == $_GET['subaction'] && isset($_GET['jobid'])) {
1115
1116 $cron = get_option('cron');
1117 $found_it = 0;
1118 foreach ($cron as $time => $job) {
1119 if (isset($job['updraft_backup_resume'])) {
1120 foreach ($job['updraft_backup_resume'] as $hook => $info) {
1121 if (isset($info['args'][1]) && $info['args'][1] == $_GET['jobid']) {
1122 $args = $cron[$time]['updraft_backup_resume'][$hook]['args'];
1123 wp_unschedule_event($time, 'updraft_backup_resume', $args);
1124 if (!$found_it) echo json_encode(array('ok' => 'Y', 'm' => __('Job deleted', 'updraftplus')));
1125 $found_it = 1;
1126 }
1127 }
1128 }
1129 }
1130
1131 if (!$found_it) echo json_encode(array('ok' => 'N', 'm' => __('Could not find that job - perhaps it has already finished?', 'updraftplus')));
1132
1133 } elseif (isset($_GET['subaction']) && 'diskspaceused' == $_GET['subaction'] && isset($_GET['entity'])) {
1134 if ('updraft' == $_GET['entity']) {
1135 echo $this->recursive_directory_size($updraftplus->backups_dir_location());
1136 } else {
1137 $backupable_entities = $updraftplus->get_backupable_file_entities(true, false);
1138 if (!empty($backupable_entities[$_GET['entity']])) {
1139 # Might be an array
1140 $basedir = $backupable_entities[$_GET['entity']];
1141 $dirs = apply_filters('updraftplus_dirlist_'.$_GET['entity'], $basedir);
1142 echo $this->recursive_directory_size($dirs, $updraftplus->get_exclude($_GET['entity']), $basedir);
1143 } else {
1144 _e('Error', 'updraftplus');
1145 }
1146 }
1147 } elseif (isset($_GET['subaction']) && 'historystatus' == $_GET['subaction']) {
1148 $remotescan = (isset($_GET['remotescan']) && $_GET['remotescan'] == 1);
1149 $rescan = ($remotescan || (isset($_GET['rescan']) && $_GET['rescan'] == 1));
1150 if ($rescan) $messages = $this->rebuild_backup_history($remotescan);
1151
1152 $backup_history = UpdraftPlus_Options::get_updraft_option('updraft_backup_history');
1153 $backup_history = (is_array($backup_history)) ? $backup_history : array();
1154 $output = $this->existing_backup_table($backup_history);
1155
1156 if (is_array($messages) && !empty($messages)) {
1157 $noutput = '<div style="margin-left: 100px; margin-top: 10px;"><ul style="list-style: disc inside;">';
1158 foreach ($messages as $msg) {
1159 $noutput .= '<li>'.(($msg['desc']) ? $msg['desc'].': ' : '').'<em>'.$msg['message'].'</em></li>';
1160 }
1161 $noutput .= '</ul></div>';
1162 $output = $noutput.$output;
1163 }
1164
1165 // echo @json_encode(array('n' => sprintf(__('%d set(s) available', 'updraftplus'), count($backup_history)), 't' => $output));
1166 echo @json_encode(array('n' => sprintf(__('Existing Backups', 'updraftplus').' (%d)', count($backup_history)), 't' => $output));
1167 } elseif (isset($_GET['subaction']) && 'downloadstatus' == $_GET['subaction'] && isset($_GET['timestamp']) && isset($_GET['type'])) {
1168
1169 $findex = (isset($_GET['findex'])) ? $_GET['findex'] : '0';
1170 if (empty($findex)) $findex = '0';
1171 $updraftplus->nonce = $_GET['timestamp'];
1172
1173 echo json_encode($this->download_status($_GET['timestamp'], $_GET['type'], $findex));
1174
1175 } elseif (isset($_POST['subaction']) && $_POST['subaction'] == 'credentials_test') {
1176 $method = (preg_match("/^[a-z0-9]+$/", $_POST['method'])) ? $_POST['method'] : "";
1177
1178 require_once(UPDRAFTPLUS_DIR."/methods/$method.php");
1179 $objname = "UpdraftPlus_BackupModule_$method";
1180
1181 $this->logged = array();
1182 # TODO: Add action for WP HTTP SSL stuff
1183 set_error_handler(array($this, 'get_php_errors'), E_ALL & ~E_STRICT);
1184 if (method_exists($objname, "credentials_test")) {
1185 $obj = new $objname;
1186 $obj->credentials_test();
1187 }
1188 if (count($this->logged) >0) {
1189 echo "\n\n".__('Messages:', 'updraftplus')."\n";
1190 foreach ($this->logged as $err) {
1191 echo "* $err\n";
1192 }
1193 }
1194 restore_error_handler();
1195 }
1196 die;
1197
1198 }
1199
1200 public function howmany_overdue_crons() {
1201 $how_many_overdue = 0;
1202 if (function_exists('_get_cron_array') || (is_file(ABSPATH.WPINC.'/cron.php') && include_once(ABSPATH.WPINC.'/cron.php') && function_exists('_get_cron_array'))) {
1203 $crons = _get_cron_array();
1204 if (is_array($crons)) {
1205 $timenow = time();
1206 foreach ($crons as $jt => $job) {
1207 if ($jt < $timenow) {
1208 $how_many_overdue++;
1209 }
1210 }
1211 }
1212 }
1213 return $how_many_overdue;
1214 }
1215
1216 public function get_php_errors($errno, $errstr, $errfile, $errline) {
1217 global $updraftplus;
1218 if (0 == error_reporting()) return true;
1219 $logline = $updraftplus->php_error_to_logline($errno, $errstr, $errfile, $errline);
1220 $this->logged[] = $logline;
1221 # Don't pass it up the chain (since it's going to be output to the user always)
1222 return true;
1223 }
1224
1225 private function download_status($timestamp, $type, $findex) {
1226
1227 global $updraftplus;
1228
1229 $response = array( 'm' => $updraftplus->jobdata_get('dlmessage_'.$timestamp.'_'.$type.'_'.$findex).'<br>' );
1230
1231 if ($file = $updraftplus->jobdata_get('dlfile_'.$timestamp.'_'.$type.'_'.$findex)) {
1232 if ('failed' == $file) {
1233 $response['e'] = __('Download failed','updraftplus').'<br>';
1234 $errs = $updraftplus->jobdata_get('dlerrors_'.$timestamp.'_'.$type.'_'.$findex);
1235 if (is_array($errs) && !empty($errs)) {
1236 $response['e'] .= '<ul style="list-style: disc inside;">';
1237 foreach ($errs as $err) {
1238 if (is_array($err)) {
1239 $response['e'] .= '<li>'.htmlspecialchars($err['message']).'</li>';
1240 } else {
1241 $response['e'] .= '<li>'.htmlspecialchars($err).'</li>';
1242 }
1243 }
1244 $response['e'] .= '</ul>';
1245 }
1246 } elseif (preg_match('/^downloaded:(\d+):(.*)$/', $file, $matches) && file_exists($matches[2])) {
1247 $response['p'] = 100;
1248 $response['f'] = $matches[2];
1249 $response['s'] = (int)$matches[1];
1250 $response['t'] = (int)$matches[1];
1251 $response['m'] = __('File ready.', 'updraftplus');
1252 } elseif (preg_match('/^downloading:(\d+):(.*)$/', $file, $matches) && file_exists($matches[2])) {
1253 // Convert to bytes
1254 $response['f'] = $matches[2];
1255 $total_size = (int)max($matches[1], 1);
1256 $cur_size = filesize($matches[2]);
1257 $response['s'] = $cur_size;
1258 $response['t'] = $total_size;
1259 $response['m'] .= __("Download in progress", 'updraftplus').' ('.round($cur_size/1024).' / '.round(($total_size/1024)).' Kb)';
1260 $response['p'] = round(100*$cur_size/$total_size);
1261 } else {
1262 $response['m'] .= __('No local copy present.', 'updraftplus');
1263 $response['p'] = 0;
1264 $response['s'] = 0;
1265 $response['t'] = 1;
1266 }
1267 }
1268 return $response;
1269 }
1270
1271 private function analyse_db_file($timestamp, $res) {
1272
1273 $mess = array(); $warn = array(); $err = array();
1274
1275 global $updraftplus, $wp_version;
1276 include(ABSPATH.WPINC.'/version.php');
1277
1278 # This attempts to raise the maximum packet size. This can't be done within the session, only globally. Therefore, it has to be done before the session starts; in our case, during the pre-analysis.
1279 $updraftplus->get_max_packet_size();
1280
1281 $backup = $updraftplus->get_backup_history($timestamp);
1282 if (!isset($backup['nonce']) || !isset($backup['db'])) return array($mess, $warn, $err);
1283
1284 $updraft_dir = $updraftplus->backups_dir_location();
1285
1286 $db_file = (is_string($backup['db'])) ? $updraft_dir.'/'.$backup['db'] : $updraft_dir.'/'.$backup['db'][0];
1287
1288 if (!is_readable($db_file)) return array($mess, $warn, $err);
1289
1290 // Encrypted - decrypt it
1291 if ($updraftplus->is_db_encrypted($db_file)) {
1292
1293 $encryption = UpdraftPlus_Options::get_updraft_option('updraft_encryptionphrase');
1294
1295 if (!$encryption) {
1296 if (class_exists('UpdraftPlus_Addon_MoreDatabase')) {
1297 $err[] = sprintf(__('Error: %s', 'updraftplus'), __('Decryption failed. The database file is encrypted, but you have no encryption key entered.', 'updraftplus'));
1298 } else {
1299 $err[] = sprintf(__('Error: %s', 'updraftplus'), __('Decryption failed. The database file is encrypted.', 'updraftplus'));
1300 }
1301 return array($mess, $warn, $err);
1302 }
1303
1304 $ciphertext = $updraftplus->decrypt($db_file, $encryption);
1305
1306 if ($ciphertext) {
1307 $new_db_file = $updraft_dir.'/'.basename($db_file, '.crypt');
1308 if (!file_put_contents($new_db_file, $ciphertext)) {
1309 $err[] = __('Failed to write out the decrypted database to the filesystem.','updraftplus');
1310 return array($mess, $warn, $err);
1311 }
1312 $db_file = $new_db_file;
1313 } else {
1314 $err[] = __('Decryption failed. The most likely cause is that you used the wrong key.','updraftplus');
1315 return array($mess, $warn, $err);
1316 }
1317 }
1318
1319 # Even the empty schema when gzipped comes to 1565 bytes; a blank WP 3.6 install at 5158. But we go low, in case someone wants to share single tables.
1320 if (filesize($db_file) < 1000) {
1321 $err[] = sprintf(__('The database is too small to be a valid WordPress database (size: %s Kb).','updraftplus'), round(filesize($db_file)/1024, 1));
1322 return array($mess, $warn, $err);
1323 }
1324
1325 $is_plain = ('.gz' == substr($db_file, -3, 3)) ? false : true;
1326
1327 $dbhandle = ($is_plain) ? fopen($db_file, 'r') : $this->gzopen_for_read($db_file, $warn, $err);
1328 if (!is_resource($dbhandle)) {
1329 $err[] = __('Failed to open database file.','updraftplus');
1330 return array($mess, $warn, $err);
1331 }
1332
1333 # Analyse the file, print the results.
1334
1335 $line = 0;
1336 $old_siteurl = '';
1337 $old_home = '';
1338 $old_table_prefix = '';
1339 $old_siteinfo = array();
1340 $gathering_siteinfo = true;
1341 $old_wp_version = '';
1342 $old_php_version = '';
1343
1344 $tables_found = array();
1345
1346 // TODO: If the backup is the right size/checksum, then we could restore the $line <= 100 in the 'while' condition and not bother scanning the whole thing? Or better: sort the core tables to be first so that this usually terminates early
1347
1348 $wanted_tables = array('terms', 'term_taxonomy', 'term_relationships', 'commentmeta', 'comments', 'links', 'options', 'postmeta', 'posts', 'users', 'usermeta');
1349
1350 $migration_warning = false;
1351
1352 # Don't set too high - we want a timely response returned to the browser
1353 @set_time_limit(90);
1354
1355 while ((($is_plain && !feof($dbhandle)) || (!$is_plain && !gzeof($dbhandle))) && ($line<100 || count($wanted_tables)>0)) {
1356 $line++;
1357 // Up to 1Mb
1358 $buffer = ($is_plain) ? rtrim(fgets($dbhandle, 1048576)) : rtrim(gzgets($dbhandle, 1048576));
1359 // Comments are what we are interested in
1360 if (substr($buffer, 0, 1) == '#') {
1361 if ('' == $old_siteurl && preg_match('/^\# Backup of: (http(.*))$/', $buffer, $matches)) {
1362 $old_siteurl = untrailingslashit($matches[1]);
1363 $mess[] = __('Backup of:', 'updraftplus').' '.htmlspecialchars($old_siteurl).((!empty($old_wp_version)) ? ' '.sprintf(__('(version: %s)', 'updraftplus'), $old_wp_version) : '');
1364 // Check for should-be migration
1365 if (!$migration_warning && $old_siteurl != untrailingslashit(site_url())) {
1366 $migration_warning = true;
1367 $powarn = apply_filters('updraftplus_dbscan_urlchange', sprintf(__('Warning: %s', 'updraftplus'), '<a href="http://updraftplus.com/shop/migrator/">'.__('This backup set is from a different site - this is not a restoration, but a migration. You need the Migrator add-on in order to make this work.', 'updraftplus').'</a>'), $old_siteurl, $res);
1368 if (!empty($powarn)) $warn[] = $powarn;
1369 }
1370 } elseif ('' == $old_home && preg_match('/^\# Home URL: (http(.*))$/', $buffer, $matches)) {
1371 $old_home = untrailingslashit($matches[1]);
1372 // Check for should-be migration
1373 if (!$migration_warning && $old_home != home_url()) {
1374 $migration_warning = true;
1375 $powarn = apply_filters('updraftplus_dbscan_urlchange', sprintf(__('Warning: %s', 'updraftplus'), '<a href="http://updraftplus.com/shop/migrator/">'.__('This backup set is from a different site - this is not a restoration, but a migration. You need the Migrator add-on in order to make this work.', 'updraftplus').'</a>'), $old_home, $res);
1376 if (!empty($powarn)) $warn[] = $powarn;
1377 }
1378 } elseif ('' == $old_wp_version && preg_match('/^\# WordPress Version: ([0-9]+(\.[0-9]+)+)(-[-a-z0-9]+,)?(.*)$/', $buffer, $matches)) {
1379 $old_wp_version = $matches[1];
1380 if (!empty($matches[3])) $old_wp_version .= substr($matches[3], 0, strlen($matches[3])-1);
1381 if (version_compare($old_wp_version, $wp_version, '>')) {
1382 //$mess[] = sprintf(__('%s version: %s', 'updraftplus'), 'WordPress', $old_wp_version);
1383 $warn[] = sprintf(__('You are importing from a newer version of WordPress (%s) into an older one (%s). There are no guarantees that WordPress can handle this.', 'updraftplus'), $old_wp_version, $wp_version);
1384 }
1385 if (preg_match('/running on PHP ([0-9]+\.[0-9]+)(\s|\.)/', $matches[4], $nmatches) && preg_match('/^([0-9]+\.[0-9]+)(\s|\.)/', PHP_VERSION, $cmatches)) {
1386 $old_php_version = $nmatches[1];
1387 $current_php_version = $cmatches[1];
1388 if (version_compare($old_php_version, $current_php_version, '>')) {
1389 //$mess[] = sprintf(__('%s version: %s', 'updraftplus'), 'WordPress', $old_wp_version);
1390 $warn[] = sprintf(__('The site in this backup was running on a webserver with version %s of %s. ', 'updraftplus'), $old_php_version, 'PHP').' '.sprintf(__('This is significantly newer than the server which you are now restoring onto (version %s).', 'updraftplus'), PHP_VERSION).' '.sprintf(__('You should only proceed if you cannot update the current server and are confident (or willing to risk) that your plugins/themes/etc. are compatible with the older %s version.', 'updraftplus'), 'PHP').' '.sprintf(__('Any support requests to do with %s should be raised with your web hosting company.', 'updraftplus'), 'PHP');
1391 }
1392 }
1393 } elseif ('' == $old_table_prefix && (preg_match('/^\# Table prefix: (\S+)$/', $buffer, $matches) || preg_match('/^-- Table prefix: (\S+)$/i', $buffer, $matches))) {
1394 $old_table_prefix = $matches[1];
1395 // echo '<strong>'.__('Old table prefix:', 'updraftplus').'</strong> '.htmlspecialchars($old_table_prefix).'<br>';
1396 } elseif ($gathering_siteinfo && preg_match('/^\# Site info: (\S+)$/', $buffer, $matches)) {
1397 if ('end' == $matches[1]) {
1398 $gathering_siteinfo = false;
1399 // Sanity checks
1400 if (isset($old_siteinfo['multisite']) && !$old_siteinfo['multisite'] && is_multisite()) {
1401 // Just need to check that you're crazy
1402 if (!defined('UPDRAFTPLUS_EXPERIMENTAL_IMPORTINTOMULTISITE') || UPDRAFTPLUS_EXPERIMENTAL_IMPORTINTOMULTISITE != true) {
1403 $err[] = sprintf(__('Error: %s', 'updraftplus'), __('You are running on WordPress multisite - but your backup is not of a multisite site.', 'updraftplus'));
1404 return array($mess, $warn, $err);
1405 }
1406 // Got the needed code?
1407 if (!class_exists('UpdraftPlusAddOn_MultiSite') || !class_exists('UpdraftPlus_Addons_Migrator')) {
1408 $err[] = sprintf(__('Error: %s', 'updraftplus'), __('To import an ordinary WordPress site into a multisite installation requires both the multisite and migrator add-ons.', 'updraftplus'));
1409 return array($mess, $warn, $err);
1410 }
1411 } elseif (isset($old_siteinfo['multisite']) && $old_siteinfo['multisite'] && !is_multisite()) {
1412 $warn[] = __('Warning:', 'updraftplus').' '.__('Your backup is of a WordPress multisite install; but this site is not. Only the first site of the network will be accessible.', 'updraftplus').' <a href="http://codex.wordpress.org/Create_A_Network">'.__('If you want to restore a multisite backup, you should first set up your WordPress installation as a multisite.', 'updraftplus').'</a>';
1413 }
1414 } elseif (preg_match('/^([^=]+)=(.*)$/', $matches[1], $kvmatches)) {
1415 $key = $kvmatches[1];
1416 $val = $kvmatches[2];
1417 if ('multisite' == $key && $val) {
1418 $mess[] = '<strong>'.__('Site information:','updraftplus').'</strong>'.' is a WordPress Network';
1419 }
1420 $old_siteinfo[$key]=$val;
1421 }
1422 }
1423
1424 } elseif (preg_match('/^\s*create table \`?([^\`\(]*)\`?\s*\(/i', $buffer, $matches)) {
1425 $table = $matches[1];
1426 $tables_found[] = $table;
1427 if ($old_table_prefix) {
1428 // Remove prefix
1429 $table = $updraftplus->str_replace_once($old_table_prefix, '', $table);
1430 if (in_array($table, $wanted_tables)) {
1431 $wanted_tables = array_diff($wanted_tables, array($table));
1432 }
1433 }
1434 }
1435 }
1436
1437 if ($is_plain) {
1438 @fclose($dbhandle);
1439 } else {
1440 @gzclose($dbhandle);
1441 }
1442
1443 /* $blog_tables = "CREATE TABLE $wpdb->terms (
1444 CREATE TABLE $wpdb->term_taxonomy (
1445 CREATE TABLE $wpdb->term_relationships (
1446 CREATE TABLE $wpdb->commentmeta (
1447 CREATE TABLE $wpdb->comments (
1448 CREATE TABLE $wpdb->links (
1449 CREATE TABLE $wpdb->options (
1450 CREATE TABLE $wpdb->postmeta (
1451 CREATE TABLE $wpdb->posts (
1452 $users_single_table = "CREATE TABLE $wpdb->users (
1453 $users_multi_table = "CREATE TABLE $wpdb->users (
1454 $usermeta_table = "CREATE TABLE $wpdb->usermeta (
1455 $ms_global_tables = "CREATE TABLE $wpdb->blogs (
1456 CREATE TABLE $wpdb->blog_versions (
1457 CREATE TABLE $wpdb->registration_log (
1458 CREATE TABLE $wpdb->site (
1459 CREATE TABLE $wpdb->sitemeta (
1460 CREATE TABLE $wpdb->signups (
1461 */
1462
1463 $missing_tables = array();
1464 if ($old_table_prefix) {
1465 foreach ($wanted_tables as $table) {
1466 if (!in_array($old_table_prefix.$table, $tables_found)) {
1467 $missing_tables[] = $table;
1468 }
1469 }
1470 if (count($missing_tables)>0) {
1471 $warn[] = sprintf(__('This database backup is missing core WordPress tables: %s', 'updraftplus'), implode(', ', $missing_tables));
1472 }
1473 } else {
1474 if (empty($backup['meta_foreign'])) {
1475 $warn[] = __('UpdraftPlus was unable to find the table prefix when scanning the database backup.', 'updraftplus');
1476 }
1477 }
1478
1479 return array($mess, $warn, $err);
1480
1481 }
1482
1483 private function gzopen_for_read($file, &$warn, &$err) {
1484 if (!function_exists('gzopen') || !function_exists('gzread')) {
1485 $missing = '';
1486 if (!function_exists('gzopen')) $missing .= 'gzopen';
1487 if (!function_exists('gzread')) $missing .= ($missing) ? ', gzread' : 'gzread';
1488 $err[] = sprintf(__("Your web server's PHP installation has these functions disabled: %s.", 'updraftplus'), implode(', ', $missing)).' '.sprintf(__('Your hosting company must enable these functions before %s can work.', 'updraftplus'), __('restoration', 'updraftplus'));
1489 return false;
1490 }
1491 if (false === ($dbhandle = gzopen($file, 'r'))) return false;
1492 if (false === ($bytes = gzread($dbhandle, 3))) return false;
1493 # Double-gzipped?
1494 if ('H4sI' != base64_encode($bytes)) {
1495 if (0 === gzseek($dbhandle, 0)) {
1496 return $dbhandle;
1497 } else {
1498 @gzclose($dbhandle);
1499 return gzopen($file, 'r');
1500 }
1501 }
1502 # Yes, it's double-gzipped
1503
1504 $what_to_return = false;
1505 $mess = __('The database file appears to have been compressed twice - probably the website you downloaded it from had a mis-configured webserver.', 'updraftplus');
1506 $messkey = 'doublecompress';
1507 $err_msg = '';
1508
1509 if (false === ($fnew = fopen($file.".tmp", 'w')) || !is_resource($fnew)) {
1510
1511 @gzclose($dbhandle);
1512 $err_msg = __('The attempt to undo the double-compression failed.', 'updraftplus');
1513
1514 } else {
1515
1516 @fwrite($fnew, $bytes);
1517 $emptimes = 0;
1518 while (!gzeof($dbhandle)) {
1519 $bytes = @gzread($dbhandle, 131072);
1520 if (empty($bytes)) {
1521 global $updraftplus;
1522 $emptimes++;
1523 $updraftplus->log("Got empty gzread ($emptimes times)");
1524 if ($emptimes>2) break;
1525 } else {
1526 @fwrite($fnew, $bytes);
1527 }
1528 }
1529
1530 gzclose($dbhandle);
1531 fclose($fnew);
1532 # On some systems (all Windows?) you can't rename a gz file whilst it's gzopened
1533 if (!rename($file.".tmp", $file)) {
1534 $err_msg = __('The attempt to undo the double-compression failed.', 'updraftplus');
1535 } else {
1536 $mess .= ' '.__('The attempt to undo the double-compression succeeded.', 'updraftplus');
1537 $messkey = 'doublecompressfixed';
1538 $what_to_return = gzopen($file, 'r');
1539 }
1540
1541 }
1542
1543 $warn[$messkey] = $mess;
1544 if (!empty($err_msg)) $err[] = $err_msg;
1545 return $what_to_return;
1546 }
1547
1548 public function upload_dir($uploads) {
1549 global $updraftplus;
1550 $updraft_dir = $updraftplus->backups_dir_location();
1551 if (is_writable($updraft_dir)) $uploads['path'] = $updraft_dir;
1552 return $uploads;
1553 }
1554
1555 // We do actually want to over-write
1556 public function unique_filename_callback($dir, $name, $ext) {
1557 return $name.$ext;
1558 }
1559
1560 public function sanitize_file_name($filename) {
1561 // WordPress 3.4.2 on multisite (at least) adds in an unwanted underscore
1562 return preg_replace('/-db(.*)\.gz_\.crypt$/', '-db$1.gz.crypt', $filename);
1563 }
1564
1565 public function plupload_action() {
1566 // check ajax nonce
1567
1568 global $updraftplus;
1569 @set_time_limit(900);
1570
1571 if (!UpdraftPlus_Options::user_can_manage()) exit;
1572 check_ajax_referer('updraft-uploader');
1573
1574 $updraft_dir = $updraftplus->backups_dir_location();
1575 if (!@$updraftplus->really_is_writable($updraft_dir)) {
1576 echo json_encode(array('e' => sprintf(__("Backup directory (%s) is not writable, or does not exist.", 'updraftplus'), $updraft_dir).' '.__('You will find more information about this in the Settings section.', 'updraftplus')));
1577 exit;
1578 }
1579
1580 add_filter('upload_dir', array($this, 'upload_dir'));
1581 add_filter('sanitize_file_name', array($this, 'sanitize_file_name'));
1582 // handle file upload
1583
1584 $farray = array('test_form' => true, 'action' => 'plupload_action');
1585
1586 $farray['test_type'] = false;
1587 $farray['ext'] = 'x-gzip';
1588 $farray['type'] = 'application/octet-stream';
1589
1590 if (!isset($_POST['chunks'])) {
1591 $farray['unique_filename_callback'] = array($this, 'unique_filename_callback');
1592 }
1593
1594 $status = wp_handle_upload(
1595 $_FILES['async-upload'],
1596 $farray
1597 );
1598 remove_filter('upload_dir', array($this, 'upload_dir'));
1599 remove_filter('sanitize_file_name', array($this, 'sanitize_file_name'));
1600
1601 if (isset($status['error'])) {
1602 echo json_encode(array('e' => $status['error']));
1603 exit;
1604 }
1605
1606 // If this was the chunk, then we should instead be concatenating onto the final file
1607 if (isset($_POST['chunks']) && isset($_POST['chunk']) && preg_match('/^[0-9]+$/',$_POST['chunk'])) {
1608 $final_file = basename($_POST['name']);
1609 if (!rename($status['file'], $updraft_dir.'/'.$final_file.'.'.$_POST['chunk'].'.zip.tmp')) {
1610 @unlink($status['file']);
1611 echo json_encode(array('e' => sprintf(__('Error: %s', 'updraftplus'), __('This file could not be uploaded', 'updraftplus'))));
1612 exit;
1613 }
1614 $status['file'] = $updraft_dir.'/'.$final_file.'.'.$_POST['chunk'].'.zip.tmp';
1615
1616 // Final chunk? If so, then stich it all back together
1617 if ($_POST['chunk'] == $_POST['chunks']-1) {
1618 if ($wh = fopen($updraft_dir.'/'.$final_file, 'wb')) {
1619 for ($i=0 ; $i<$_POST['chunks']; $i++) {
1620 $rf = $updraft_dir.'/'.$final_file.'.'.$i.'.zip.tmp';
1621 if ($rh = fopen($rf, 'rb')) {
1622 while ($line = fread($rh, 32768)) fwrite($wh, $line);
1623 fclose($rh);
1624 @unlink($rf);
1625 }
1626 }
1627 fclose($wh);
1628 $status['file'] = $updraft_dir.'/'.$final_file;
1629 if ('.tar' == substr($final_file, -4, 4)) {
1630 if (file_exists($status['file'].'.gz')) unlink($status['file'].'.gz');
1631 if (file_exists($status['file'].'.bz2')) unlink($status['file'].'.bz2');
1632 } elseif ('.tar.gz' == substr($final_file, -7, 7)) {
1633 if (file_exists(substr($status['file'], 0, strlen($status['file'])-3))) unlink(substr($status['file'], 0, strlen($status['file'])-3));
1634 if (file_exists(substr($status['file'], 0, strlen($status['file'])-3).'.bz2')) unlink(substr($status['file'], 0, strlen($status['file'])-3).'.bz2');
1635 } elseif ('.tar.bz2' == substr($final_file, -8, 8)) {
1636 if (file_exists(substr($status['file'], 0, strlen($status['file'])-4))) unlink(substr($status['file'], 0, strlen($status['file'])-4));
1637 if (file_exists(substr($status['file'], 0, strlen($status['file'])-4).'.gz')) unlink(substr($status['file'], 0, strlen($status['file'])-3).'.gz');
1638 }
1639 }
1640 }
1641
1642 }
1643
1644 $response = array();
1645 if (!isset($_POST['chunks']) || (isset($_POST['chunk']) && $_POST['chunk'] == $_POST['chunks']-1)) {
1646 $file = basename($status['file']);
1647 # TODO: Make compatible with incremental naming scheme
1648 if (!preg_match('/^log\.[a-f0-9]{12}\.txt/i', $file) && !preg_match('/^backup_([\-0-9]{15})_.*_([0-9a-f]{12})-([\-a-z]+)([0-9]+(of[0-9]+)?)?\.(zip|gz|gz\.crypt)$/i', $file, $matches)) {
1649 $accept = apply_filters('updraftplus_accept_archivename', array());
1650 if (is_array($accept)) {
1651 foreach ($accept as $acc) {
1652 if (preg_match('/'.$acc['pattern'].'/i', $file)) $accepted = $acc['desc'];
1653 }
1654 }
1655 if (!empty($accepted)) {
1656 $response['dm'] = sprintf(__('This backup was created by %s, and can be imported.', 'updraftplus'), $accepted);
1657 } else {
1658 @unlink($status['file']);
1659 echo json_encode(array('e' => sprintf(__('Error: %s', 'updraftplus'),__('Bad filename format - this does not look like a file created by UpdraftPlus','updraftplus'))));
1660 exit;
1661 }
1662 } else {
1663 $backupable_entities = $updraftplus->get_backupable_file_entities(true);
1664 $type = $matches[3];
1665 if ('db' != $type && !isset($backupable_entities[$type]) && !preg_match('/^log\.[a-f0-9]{12}\.txt/', $file)) {
1666 @unlink($status['file']);
1667 echo json_encode(array('e' => sprintf(__('Error: %s', 'updraftplus'),sprintf(__('This looks like a file created by UpdraftPlus, but this install does not know about this type of object: %s. Perhaps you need to install an add-on?','updraftplus'), htmlspecialchars($type)))));
1668 exit;
1669 }
1670 }
1671 }
1672
1673 // send the uploaded file url in response
1674 $response['m'] = $status['url'];
1675 echo json_encode($response);
1676 exit;
1677 }
1678
1679 # Database decrypter
1680 public function plupload_action2() {
1681
1682 @set_time_limit(900);
1683 global $updraftplus;
1684
1685 if (!UpdraftPlus_Options::user_can_manage()) exit;
1686 check_ajax_referer('updraft-uploader');
1687
1688 $updraft_dir = $updraftplus->backups_dir_location();
1689 if (!is_writable($updraft_dir)) exit;
1690
1691 add_filter('upload_dir', array($this, 'upload_dir'));
1692 add_filter('sanitize_file_name', array($this, 'sanitize_file_name'));
1693 // handle file upload
1694
1695 $farray = array( 'test_form' => true, 'action' => 'plupload_action2' );
1696
1697 $farray['test_type'] = false;
1698 $farray['ext'] = 'crypt';
1699 $farray['type'] = 'application/octet-stream';
1700
1701 if (isset($_POST['chunks'])) {
1702 // $farray['ext'] = 'zip';
1703 // $farray['type'] = 'application/zip';
1704 } else {
1705 $farray['unique_filename_callback'] = array($this, 'unique_filename_callback');
1706 }
1707
1708 $status = wp_handle_upload(
1709 $_FILES['async-upload'],
1710 $farray
1711 );
1712 remove_filter('upload_dir', array($this, 'upload_dir'));
1713 remove_filter('sanitize_file_name', array($this, 'sanitize_file_name'));
1714
1715 if (isset($status['error'])) {
1716 echo 'ERROR:'.$status['error'];
1717 exit;
1718 }
1719
1720 // If this was the chunk, then we should instead be concatenating onto the final file
1721 if (isset($_POST['chunks']) && isset($_POST['chunk']) && preg_match('/^[0-9]+$/',$_POST['chunk'])) {
1722 $final_file = basename($_POST['name']);
1723 rename($status['file'], $updraft_dir.'/'.$final_file.'.'.$_POST['chunk'].'.zip.tmp');
1724 $status['file'] = $updraft_dir.'/'.$final_file.'.'.$_POST['chunk'].'.zip.tmp';
1725
1726 // Final chunk? If so, then stich it all back together
1727 if ($_POST['chunk'] == $_POST['chunks']-1) {
1728 if ($wh = fopen($updraft_dir.'/'.$final_file, 'wb')) {
1729 for ($i=0 ; $i<$_POST['chunks']; $i++) {
1730 $rf = $updraft_dir.'/'.$final_file.'.'.$i.'.zip.tmp';
1731 if ($rh = fopen($rf, 'rb')) {
1732 while ($line = fread($rh, 32768)) fwrite($wh, $line);
1733 fclose($rh);
1734 @unlink($rf);
1735 }
1736 }
1737 fclose($wh);
1738 $status['file'] = $updraft_dir.'/'.$final_file;
1739 }
1740 }
1741
1742 }
1743
1744 if (!isset($_POST['chunks']) || (isset($_POST['chunk']) && $_POST['chunk'] == $_POST['chunks']-1)) {
1745 $file = basename($status['file']);
1746 if (!preg_match('/^backup_([\-0-9]{15})_.*_([0-9a-f]{12})-db([0-9]+)?\.(gz\.crypt)$/i', $file)) {
1747
1748 @unlink($status['file']);
1749 echo 'ERROR:'.__('Bad filename format - this does not look like an encrypted database file created by UpdraftPlus','updraftplus');
1750
1751 exit;
1752 }
1753 }
1754
1755 // send the uploaded file url in response
1756 // echo 'OK:'.$status['url'];
1757 echo 'OK:'.$file;
1758 exit;
1759 }
1760
1761
1762 public function settings_output() {
1763
1764 global $updraftplus;
1765
1766 /*
1767 we use request here because the initial restore is triggered by a POSTed form. we then may need to obtain credentials
1768 for the WP_Filesystem. to do this WP outputs a form, but we don't pass our parameters via that. So the values are
1769 passed back in as GET parameters.
1770 */
1771 if(isset($_REQUEST['action']) && $_REQUEST['action'] == 'updraft_restore' && isset($_REQUEST['backup_timestamp'])) {
1772 $backup_success = $this->restore_backup($_REQUEST['backup_timestamp']);
1773 if(empty($updraftplus->errors) && $backup_success === true) {
1774 // If we restored the database, then that will have out-of-date information which may confuse the user - so automatically re-scan for them.
1775 $this->rebuild_backup_history();
1776 echo '<p><strong>';
1777 $updraftplus->log_e('Restore successful!');
1778 echo '</strong></p>';
1779 $updraftplus->log("Restore successful");
1780 echo '<strong>'.__('Actions','updraftplus').':</strong> <a href="'.UpdraftPlus_Options::admin_page_url().'?page=updraftplus&updraft_restore_success=true">'.__('Return to UpdraftPlus Configuration','updraftplus').'</a>';
1781 return;
1782 } elseif (is_wp_error($backup_success)) {
1783 echo '<p>';
1784 $updraftplus->log_e('Restore failed...');
1785 echo '</p>';
1786 $updraftplus->log_wp_error($backup_success);
1787 $updraftplus->log("Restore failed");
1788 $updraftplus->list_errors();
1789 echo '<strong>'.__('Actions','updraftplus').':</strong> <a href="'.UpdraftPlus_Options::admin_page_url().'?page=updraftplus">'.__('Return to UpdraftPlus Configuration','updraftplus').'</a>';
1790 return;
1791 } elseif (false === $backup_success) {
1792 # This means, "not yet - but stay on the page because we may be able to do it later, e.g. if the user types in the requested information"
1793 return;
1794 }
1795 }
1796
1797 if(isset($_REQUEST['action']) && 'updraft_delete_old_dirs' == $_REQUEST['action']) {
1798 $nonce = (empty($_REQUEST['_wpnonce'])) ? "" : $_REQUEST['_wpnonce'];
1799 if (!wp_verify_nonce($nonce, 'updraftplus-credentialtest-nonce')) die('Security check');
1800 $this->delete_old_dirs_go();
1801 return;
1802 }
1803
1804 if(!empty($_REQUEST['action']) && 'updraftplus_broadcastaction' == $_REQUEST['action'] && !empty($_REQUEST['subaction'])) {
1805 $nonce = (empty($_REQUEST['nonce'])) ? "" : $_REQUEST['nonce'];
1806 if (!wp_verify_nonce($nonce, 'updraftplus-credentialtest-nonce')) die('Security check');
1807 do_action($_REQUEST['subaction']);
1808 return;
1809 }
1810
1811 if(isset($_GET['error'])) $this->show_admin_warning(htmlspecialchars($_GET['error']), 'error');
1812 if(isset($_GET['message'])) $this->show_admin_warning(htmlspecialchars($_GET['message']));
1813
1814 if(isset($_GET['action']) && $_GET['action'] == 'updraft_create_backup_dir' && isset($_GET['nonce']) && wp_verify_nonce($_GET['nonce'], 'create_backup_dir')) {
1815 $created = $this->create_backup_dir();
1816 if(is_wp_error($created)) {
1817 echo '<p>'.__('Backup directory could not be created', 'updraftplus').'...<br/>';
1818 echo '<ul style="list-style: disc inside;">';
1819 foreach ($created->get_error_messages() as $key => $msg) {
1820 echo '<li>'.htmlspecialchars($msg).'</li>';
1821 }
1822 echo '</ul></p>';
1823 } elseif ($created !== false) {
1824 echo '<p>'.__('Backup directory successfully created.', 'updraftplus').'</p><br/>';
1825 }
1826 echo '<b>'.__('Actions','updraftplus').':</b> <a href="'.UpdraftPlus_Options::admin_page_url().'?page=updraftplus">'.__('Return to UpdraftPlus Configuration', 'updraftplus').'</a>';
1827 return;
1828 }
1829
1830 do_action('updraftplus_settings_page_init');
1831
1832 echo '<div id="updraft_backup_started" class="updated fade" style="display:none; max-width: 800px; font-size:140%; line-height: 140%; padding:14px; clear:left;"></div>';
1833
1834 if(isset($_POST['action']) && 'updraft_backup_debug_all' == $_POST['action']) {
1835 $updraftplus->boot_backup(true,true);
1836 } elseif (isset($_POST['action']) && 'updraft_backup_debug_db' == $_POST['action']) {
1837 $updraftplus->boot_backup(false, true, false, true);
1838 } elseif (isset($_POST['action']) && 'updraft_wipesettings' == $_POST['action']) {
1839 $settings = $this->get_settings_keys();
1840 foreach ($settings as $s) UpdraftPlus_Options::delete_updraft_option($s);
1841
1842 # These aren't in get_settings_keys() because they are always in the options table, regardless of context
1843 global $wpdb;
1844 $wpdb->query("DELETE FROM $wpdb->options WHERE ( option_name LIKE 'updraftplus_unlocked_%' OR option_name LIKE 'updraftplus_locked_%' OR option_name LIKE 'updraftplus_last_lock_time_%' OR option_name LIKE 'updraftplus_semaphore_%')");
1845
1846 $site_options = array('updraft_oneshotnonce');
1847 foreach ($site_options as $s) delete_site_option($s);
1848
1849 $this->show_admin_warning(__("Your settings have been wiped.", 'updraftplus'));
1850 }
1851 ?>
1852
1853 <div class="wrap" id="updraft-wrap">
1854 <h1><?php echo $updraftplus->plugin_title; ?></h1>
1855
1856 <a href="http://updraftplus.com">UpdraftPlus.Com</a> | <a href="https://updraftplus.com/news/"><?php _e('News','updraftplus');?></a> | <a href="https://twitter.com/updraftplus"><?php _e('Twitter', 'updraftplus');?></a> | <?php if (!defined('UPDRAFTPLUS_NOADS_B')) { ?><a href="http://updraftplus.com/shop/updraftplus-premium/"><?php _e("Premium",'updraftplus');?></a>
1857 | <?php } ?><a href="http://updraftplus.com/support/"><?php _e("Support",'updraftplus');?></a> | <a href="http://david.dw-perspective.org.uk"><?php _e("Lead developer's homepage",'updraftplus');?></a> | <?php if (1==0 && !defined('UPDRAFTPLUS_NOADS_B')) { ?><a href="http://wordshell.net">WordShell - WordPress command line</a> | <a href="http://david.dw-perspective.org.uk/donate"><?php _e('Donate', 'updraftplus');?></a> | <?php } ?><a href="http://updraftplus.com/support/frequently-asked-questions/">FAQs</a> | <a href="https://www.simbahosting.co.uk/s3/shop/"><?php _e('More plugins', 'updraftplus');?></a> - <?php _e('Version','updraftplus');?>: <?php echo $updraftplus->version; ?>
1858 <br>
1859
1860 <div id="updraft-hidethis">
1861 <p><strong><?php _e('Warning:', 'updraftplus'); ?> <?php _e("If you can still read these words after the page finishes loading, then there is a JavaScript or jQuery problem in the site.", 'updraftplus'); ?> <a href="http://updraftplus.com/do-you-have-a-javascript-or-jquery-error/"><?php _e('Go here for more information.', 'updraftplus'); ?></a></strong></p>
1862 </div>
1863
1864 <?php
1865 if(isset($_GET['updraft_restore_success'])) {
1866 echo "<div class=\"updated fade\" style=\"padding:8px;\"><strong>".__('Your backup has been restored.','updraftplus').'</strong> '.__('If your restore included files, then your old (themes, uploads, plugins, whatever) directories have been retained with "-old" appended to their name. Remove them when you are satisfied that the backup worked properly.')."</div>";
1867 }
1868
1869 $ws_advert = $updraftplus->wordshell_random_advert(1);
1870 if ($ws_advert) { echo '<div class="updated fade" style="max-width: 800px; font-size:140%; line-height: 140%; padding:14px; clear:left;">'.$ws_advert.'</div>'; }
1871
1872 if(!$updraftplus->memory_check(64)) {?>
1873 <div class="updated" style="padding:8px;"><?php _e("Your PHP memory limit (set by your web hosting company) is very low. UpdraftPlus attempted to raise it but was unsuccessful. This plugin may struggle with a memory limit of less than 64 Mb - especially if you have very large files uploaded (though on the other hand, many sites will be successful with a 32Mb limit - your experience may vary).",'updraftplus');?> <?php _e('Current limit is:','updraftplus');?> <?php echo $updraftplus->memory_check_current(); ?> Mb</div>
1874 <?php
1875 }
1876
1877 if($this->scan_old_dirs(true)) $this->print_delete_old_dirs_form();
1878
1879 if(!empty($updraftplus->errors)) {
1880 echo '<div class="error fade" style="padding:8px;">';
1881 $updraftplus->list_errors();
1882 echo '</div>';
1883 }
1884
1885 $backup_history = UpdraftPlus_Options::get_updraft_option('updraft_backup_history');
1886 if (empty($backup_history)) {
1887 $this->rebuild_backup_history();
1888 $backup_history = UpdraftPlus_Options::get_updraft_option('updraft_backup_history');
1889 }
1890 $backup_history = (is_array($backup_history))?$backup_history:array();
1891 ?>
1892
1893 <h2 class="nav-tab-wrapper" style="margin: 14px 0px;">
1894 <a class="nav-tab nav-tab-active" href="#updraft-navtab-status-content" id="updraft-navtab-status"><?php _e('Current Status', 'updraftplus');?></a>
1895 <a class="nav-tab" href="#updraft-navtab-backups-contents" id="updraft-navtab-backups"><?php echo __('Existing Backups', 'updraftplus').' ('.count($backup_history).')';?></a>
1896 <a class="nav-tab" id="updraft-navtab-settings" href="#updraft-navtab-settings-content"><?php _e('Settings', 'updraftplus');?></a>
1897 <a class="nav-tab" id="updraft-navtab-expert" href="#updraft-navtab-expert-content"><?php _e('Debugging / Expert Tools', 'updraftplus');?></a>
1898 </h2>
1899
1900 <?php
1901 $updraft_dir = $updraftplus->backups_dir_location();
1902 $backup_disabled = ($updraftplus->really_is_writable($updraft_dir)) ? '' : 'disabled="disabled"';
1903 ?>
1904
1905 <div id="updraft-poplog" >
1906 <div id="updraft-poplog-content"></div>
1907 </div>
1908
1909 <div id="updraft-navtab-status-content">
1910
1911 <div id="updraft-insert-admin-warning"></div>
1912
1913 <table class="form-table" style="float:left; clear: both;">
1914 <noscript>
1915 <tr>
1916 <th><?php _e('JavaScript warning','updraftplus');?>:</th>
1917 <td style="color:red"><?php _e('This admin interface uses JavaScript heavily. You either need to activate it within your browser, or to use a JavaScript-capable browser.','updraftplus');?></td>
1918 </tr>
1919 </noscript>
1920
1921 <tr>
1922 <th><?php _e('Actions', 'updraftplus');?>:</th>
1923 <td>
1924
1925 <button type="button" <?php echo $backup_disabled ?> class="button-primary updraft-bigbutton" <?php if ($backup_disabled) echo 'title="'.esc_attr(__('This button is disabled because your backup directory is not writable (see the settings).', 'updraftplus')).'" ';?> onclick="jQuery('#backupnow_label').val(''); jQuery('#updraft-backupnow-modal').dialog('open');"><?php _e('Backup Now', 'updraftplus');?></button>
1926
1927 <button type="button" class="button-primary updraft-bigbutton" onclick="updraft_openrestorepanel();">
1928 <?php _e('Restore','updraftplus');?>
1929 </button>
1930
1931 <button type="button" class="button-primary updraft-bigbutton" onclick="jQuery('#updraft-migrate-modal').dialog('open');"><?php _e('Clone/Migrate','updraftplus');?></button>
1932
1933 </td>
1934 </tr>
1935
1936 <?php
1937 // UNIX timestamp
1938 $next_scheduled_backup = wp_next_scheduled('updraft_backup');
1939 if ($next_scheduled_backup) {
1940 // Convert to GMT
1941 $next_scheduled_backup_gmt = gmdate('Y-m-d H:i:s', $next_scheduled_backup);
1942 // Convert to blog time zone
1943 $next_scheduled_backup = get_date_from_gmt($next_scheduled_backup_gmt, 'D, F j, Y H:i');
1944 } else {
1945 $next_scheduled_backup = __('Nothing currently scheduled','updraftplus');
1946 }
1947
1948 $next_scheduled_backup_database = wp_next_scheduled('updraft_backup_database');
1949 if (UpdraftPlus_Options::get_updraft_option('updraft_interval_database',UpdraftPlus_Options::get_updraft_option('updraft_interval')) == UpdraftPlus_Options::get_updraft_option('updraft_interval')) {
1950 $next_scheduled_backup_database = ('Nothing currently scheduled' == $next_scheduled_backup) ? $next_scheduled_backup : __("At the same time as the files backup", 'updraftplus');
1951 } else {
1952 if ($next_scheduled_backup_database) {
1953 // Convert to GMT
1954 $next_scheduled_backup_database_gmt = gmdate('Y-m-d H:i:s', $next_scheduled_backup_database);
1955 // Convert to blog time zone
1956 $next_scheduled_backup_database = get_date_from_gmt($next_scheduled_backup_database_gmt, 'D, F j, Y H:i');
1957 } else {
1958 $next_scheduled_backup_database = __('Nothing currently scheduled', 'updraftplus');
1959 }
1960 }
1961 $current_time = get_date_from_gmt(gmdate('Y-m-d H:i:s'), 'D, F j, Y H:i');
1962
1963 $last_backup_html = $this->last_backup_html();
1964
1965 ?>
1966
1967 <script>var lastbackup_laststatus = '<?php echo esc_js($last_backup_html);?>';</script>
1968
1969 <tr>
1970 <th><span title="<?php _e('All the times shown in this section are using WordPress\'s configured time zone, which you can set in Settings -> General', 'updraftplus'); ?>"><?php _e('Next scheduled backups', 'updraftplus');?>:</span></th>
1971 <td>
1972 <table style="border: 0px; padding: 0px; margin: 0 10px 0 0;">
1973 <tr>
1974 <td style="width: 124px; vertical-align:top; margin: 0px; padding: 0px;"><?php _e('Files','updraftplus'); ?>:</td><td style="color:blue; margin: 0px; padding: 0px;"><?php echo $next_scheduled_backup?></td>
1975 </tr><tr>
1976 <td style="width: 124px; vertical-align:top; margin: 0px; padding: 0px;"><?php _e('Database','updraftplus');?>: </td><td style="color:blue; margin: 0px; padding: 0px;"><?php echo $next_scheduled_backup_database?></td>
1977 </tr><tr>
1978 <td style="width: 124px; vertical-align:top; margin: 0px; padding: 0px;"><?php _e('Time now','updraftplus');?>: </td><td style="color:blue; margin: 0px; padding: 0px;"><?php echo $current_time?></td>
1979 </table>
1980 </td>
1981 </tr>
1982 <tr>
1983 <th><?php _e('Last backup job run:','updraftplus');?></th>
1984 <td id="updraft_last_backup"><?php echo $last_backup_html ?></td>
1985 </tr>
1986 </table>
1987
1988 <br style="clear:both" />
1989 <table class="form-table">
1990
1991 <?php $active_jobs = $this->print_active_jobs();?>
1992 <tr id="updraft_activejobsrow" style="<?php if (!$active_jobs) echo 'display:none;'; ?>">
1993 <th><?php _e('Backups in progress:', 'updraftplus');?></th>
1994 <td id="updraft_activejobs"><?php echo $active_jobs;?></td>
1995 </tr>
1996
1997 <tr id="updraft_lastlogmessagerow">
1998 <th><?php _e('Last log message','updraftplus');?>:</th>
1999 <td>
2000 <span id="updraft_lastlogcontainer"><?php echo htmlspecialchars(UpdraftPlus_Options::get_updraft_option('updraft_lastmessage', __('(Nothing yet logged)','updraftplus'))); ?></span><br>
2001 <a href="?page=updraftplus&action=downloadlatestmodlog&wpnonce=<?php echo wp_create_nonce('updraftplus_download') ?>" class="updraft-log-link" onclick="event.preventDefault(); updraft_popuplog('');"><?php _e('Download most recently modified log file','updraftplus');?></a>
2002 </td>
2003 </tr>
2004
2005 <!--<tr>
2006 <th><?php echo htmlspecialchars(__('Backups, logs & restoring','updraftplus')); ?>:</th>
2007 <td><a id="updraft_showbackups" href="#" title="<?php _e('Press to see available backups','updraftplus');?>" onclick="updraft_openrestorepanel(0); return false;"><?php echo sprintf(__('%d set(s) available', 'updraftplus'), count($backup_history)); ?></a></td>
2008 </tr>-->
2009
2010 <?php
2011 # Currently disabled - not sure who we want to show this to
2012 if (1==0 && !defined('UPDRAFTPLUS_NOADS_B')) {
2013 $feed = $updraftplus->get_updraftplus_rssfeed();
2014 if (is_a($feed, 'SimplePie')) {
2015 echo '<tr><th style="vertical-align:top;">'.__('Latest UpdraftPlus.com news:', 'updraftplus').'</th><td style="vertical-align:top;">';
2016 echo '<ul style="list-style: disc inside;">';
2017 foreach ($feed->get_items(0, 5) as $item) {
2018 echo '<li>';
2019 echo '<a href="'.esc_attr($item->get_permalink()).'">';
2020 echo htmlspecialchars($item->get_title());
2021 # D, F j, Y H:i
2022 echo "</a> (".htmlspecialchars($item->get_date('j F Y')).")";
2023 echo '</li>';
2024 }
2025 echo '</ul></td></tr>';
2026 }
2027 }
2028 ?>
2029 </table>
2030
2031 <div id="updraft-migrate-modal" title="<?php _e('Migrate Site', 'updraftplus'); ?>">
2032
2033 <?php
2034 if (class_exists('UpdraftPlus_Addons_Migrator')) {
2035 echo '<p>'.str_replace('"', "&quot;", __('Migration of data from another site happens through the "Restore" button. A "migration" is ultimately the same as a restoration - but using backup archives that you import from another site. UpdraftPlus modifies the restoration operation appropriately, to fit the backup data to the new site.', 'updraftplus')).' '.sprintf(__('<a href="%s">Read this article to see step-by-step how it\'s done.</a>', 'updraftplus'),'http://updraftplus.com/faqs/how-do-i-migrate-to-a-new-site-location/');
2036 } else {
2037 echo '<p>'.__('Do you want to migrate or clone/duplicate a site?', 'updraftplus').'</p><p>'.__('Then, try out our "Migrator" add-on. After using it once, you\'ll have saved the purchase price compared to the time needed to copy a site by hand.', 'updraftplus').'</p><p><a href="http://updraftplus.com/shop/migrator/">'.__('Get it here.', 'updraftplus').'</a>';
2038 }
2039 ?>
2040 </p>
2041 </div>
2042
2043 <div id="updraft-iframe-modal">
2044 <div id="updraft-iframe-modal-innards">
2045 </div>
2046 </div>
2047
2048 <div id="updraft-backupnow-modal" title="UpdraftPlus - <?php _e('Perform a one-time backup','updraftplus'); ?>">
2049 <p><?php _e("To proceed, press 'Backup Now'. Then, watch the 'Last Log Message' field for activity.", 'updraftplus');?></p>
2050
2051 <p>
2052 <input type="checkbox" id="backupnow_nodb"> <label for="backupnow_nodb"><?php _e("Don't include the database in the backup", 'updraftplus'); ?></label><br>
2053 <input type="checkbox" id="backupnow_nofiles"> <label for="backupnow_nofiles"><?php _e("Don't include any files in the backup", 'updraftplus'); ?></label><br>
2054 <input type="checkbox" id="backupnow_nocloud"> <label for="backupnow_nocloud"><?php _e("Don't send this backup to remote storage", 'updraftplus'); ?></label>
2055 </p>
2056
2057 <?php do_action('updraft_backupnow_modal_afteroptions'); ?>
2058
2059 <p><?php _e('Does nothing happen when you attempt backups?','updraftplus');?> <a href="http://updraftplus.com/faqs/my-scheduled-backups-and-pressing-backup-now-does-nothing-however-pressing-debug-backup-does-produce-a-backup/"><?php _e('Go here for help.', 'updraftplus');?></a></p>
2060 </div>
2061
2062 <?php
2063 if (is_multisite() && !file_exists(UPDRAFTPLUS_DIR.'/addons/multisite.php')) {
2064 ?>
2065 <h2>UpdraftPlus <?php _e('Multisite','updraftplus');?></h2>
2066 <table>
2067 <tr>
2068 <td>
2069 <p style="max-width:800px;"><?php echo __('Do you need WordPress Multisite support?','updraftplus').' <a href="http://updraftplus.com/">'. __('Please check out UpdraftPlus Premium, or the stand-alone Multisite add-on.','updraftplus');?></a>.</p>
2070 </td>
2071 </tr>
2072 </table>
2073 <?php } ?>
2074
2075 </div>
2076
2077 <div id="updraft-navtab-backups-content" style="display:none;">
2078 <?php $this->settings_downloadingandrestoring($backup_history); ?>
2079 </div>
2080
2081 <div id="updraft-navtab-settings-content" style="display:none;">
2082 <h2 style="margin-top: 6px;"><?php _e('Configure Backup Contents And Schedule','updraftplus');?></h2>
2083 <?php UpdraftPlus_Options::options_form_begin(); ?>
2084 <?php $this->settings_formcontents($last_backup_html); ?>
2085 </form>
2086 </div>
2087
2088 <div id="updraft-navtab-expert-content" style="display:none;">
2089 <?php $this->settings_expertsettings($backup_disabled); ?>
2090 </div>
2091
2092 <?php
2093 }
2094
2095 private function settings_downloadingandrestoring($backup_history = array()) {
2096 global $updraftplus;
2097 //<td class="download-backups" style="display:none; border: 2px dashed #aaa;">
2098 ?>
2099 <div class="download-backups form-table">
2100 <h2><?php echo __('Existing Backups: Downloading And Restoring', 'updraftplus'); ?></h2>
2101 <p style="display:none; background-color:pink; padding:8px; margin:4px;border: 1px dotted;" id="ud-whitespace-warning">
2102 <?php echo '<strong>'.__('Warning','updraftplus').':</strong> '.__('Your WordPress installation has a problem with outputting extra whitespace. This can corrupt backups that you download from here.','updraftplus').' <a href="http://updraftplus.com/problems-with-extra-white-space/">'.__('Please consult this FAQ for help on what to do about it.', 'updraftplus').'</a>';?>
2103 </p>
2104 <p>
2105 <ul style="list-style: disc inside; max-width: 1000px;">
2106 <li><strong><?php _e('Downloading','updraftplus');?>:</strong> <?php _e("Pressing a button for Database/Plugins/Themes/Uploads/Others will make UpdraftPlus try to bring the backup file back from the remote storage (if any - e.g. Amazon S3, Dropbox, Google Drive, FTP) to your webserver. Then you will be allowed to download it to your computer. If the fetch from the remote storage stops progressing (wait 30 seconds to make sure), then press again to resume. Remember that you can also visit the cloud storage vendor's website directly.",'updraftplus');?></li>
2107 <li>
2108 <strong><?php _e('Restoring:','updraftplus');?></strong> <?php _e('Press the Restore button next to the chosen backup set.', 'updraftplus');?>
2109 </li>
2110 <li>
2111 <strong><?php _e('More tasks:','updraftplus');?></strong>
2112 <a href="#" onclick="jQuery('#updraft-plupload-modal').slideToggle(); return false;"><?php _e('Upload backup files','updraftplus');?></a>
2113 | <a href="#" onclick="updraft_updatehistory(1, 0); return false;" title="<?php echo __('Press here to look inside your UpdraftPlus directory (in your web hosting space) for any new backup sets that you have uploaded.', 'updraftplus').' '.__('The location of this directory is set in the expert settings, in the Settings tab.','updraftplus'); ?>"><?php _e('Rescan local folder for new backup sets','updraftplus');?></a>
2114 | <a href="#" onclick="updraft_updatehistory(1, 1); return false;" title="<?php _e('Press here to look inside any remote storage methods for any existing backup sets.','updraftplus'); ?>"><?php _e('Rescan remote storage','updraftplus');?></a>
2115 </li>
2116 <?php
2117 if (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Opera') || false !== strpos($_SERVER['HTTP_USER_AGENT'], 'OPR/')) { ?>
2118 <li><strong><?php _e('Opera web browser','updraftplus');?>:</strong> <?php _e('If you are using this, then turn Turbo/Road mode off.','updraftplus');?></li>
2119 <?php } ?>
2120 <?php
2121 $service = UpdraftPlus_Options::get_updraft_option('updraft_service');
2122 if ($service === 'googledrive' || (is_array($service) && in_array('googledrive', $service))) {
2123 ?><li><strong><?php _e('Google Drive','updraftplus');?>:</strong> <?php _e('Google changed their permissions setup recently (April 2013). To download or restore from Google Drive, you <strong>must</strong> first re-authenticate (using the link in the Google Drive configuration section).','updraftplus');?></li>
2124 <?php } ?>
2125
2126 <li title="<?php _e('This is a count of the contents of your Updraft directory','updraftplus');?>"><strong><?php _e('Web-server disk space in use by UpdraftPlus','updraftplus');?>:</strong> <span id="updraft_diskspaceused"><em><?php _e('calculating...', 'updraftplus'); ?></em></span> <a href="#" onclick="updraftplus_diskspace(); return false;"><?php _e('refresh','updraftplus');?></a></li></ul>
2127 </p>
2128
2129 <div id="updraft-plupload-modal" title="<?php _e('UpdraftPlus - Upload backup files','updraftplus'); ?>" style="width: 75%; margin: 16px; display:none; margin-left: 100px;">
2130 <p style="max-width: 610px;"><em><?php _e("Upload files into UpdraftPlus. Use this to import backups made on a different WordPress installation." ,'updraftplus');?> <?php echo htmlspecialchars(__('Or, you can place them manually into your UpdraftPlus directory (usually wp-content/updraft), e.g. via FTP, and then use the "rescan" link above.', 'updraftplus'));?></em></p>
2131 <?php
2132 global $wp_version;
2133 if (version_compare($wp_version, '3.3', '<')) {
2134 echo '<em>'.sprintf(__('This feature requires %s version %s or later', 'updraftplus'), 'WordPress', '3.3').'</em>';
2135 } else {
2136 ?>
2137 <div id="plupload-upload-ui" style="width: 70%;">
2138 <div id="drag-drop-area">
2139 <div class="drag-drop-inside">
2140 <p class="drag-drop-info"><?php _e('Drop backup files here', 'updraftplus'); ?></p>
2141 <p><?php _ex('or', 'Uploader: Drop backup files here - or - Select Files'); ?></p>
2142 <p class="drag-drop-buttons"><input id="plupload-browse-button" type="button" value="<?php esc_attr_e('Select Files'); ?>" class="button" /></p>
2143 </div>
2144 </div>
2145 <div id="filelist">
2146 </div>
2147 </div>
2148 <?php
2149 }
2150 ?>
2151
2152 </div>
2153
2154 <div id="ud_downloadstatus"></div>
2155 <div id="updraft_existing_backups" style="margin-bottom:12px;">
2156 <?php
2157 print $this->existing_backup_table($backup_history);
2158 ?>
2159 </div>
2160 </div>
2161
2162 <div id="updraft-message-modal" title="UpdraftPlus">
2163 <div id="updraft-message-modal-innards" style="padding: 4px;">
2164 </div>
2165 </div>
2166
2167 <div id="updraft-delete-modal" title="<?php _e('Delete backup set', 'updraftplus');?>">
2168 <form id="updraft_delete_form" method="post">
2169 <p style="margin-top:3px; padding-top:0">
2170 <?php _e('Are you sure that you wish to remove this backup set from UpdraftPlus?', 'updraftplus'); ?>
2171 </p>
2172 <fieldset>
2173 <input type="hidden" name="nonce" value="<?php echo wp_create_nonce('updraftplus-credentialtest-nonce');?>">
2174 <input type="hidden" name="action" value="updraft_ajax">
2175 <input type="hidden" name="subaction" value="deleteset">
2176 <input type="hidden" name="backup_timestamp" value="0" id="updraft_delete_timestamp">
2177 <input type="hidden" name="backup_nonce" value="0" id="updraft_delete_nonce">
2178 <div id="updraft-delete-remote-section"><input checked="checked" type="checkbox" name="delete_remote" id="updraft_delete_remote" value="1"> <label for="updraft_delete_remote"><?php _e('Also delete from remote storage', 'updraftplus');?></label><br>
2179 <p id="updraft-delete-waitwarning" style="display:none;"><em><?php _e('Deleting... please allow time for the communications with the remote storage to complete.', 'updraftplus');?></em></p>
2180 </div>
2181 </fieldset>
2182 </form>
2183 </div>
2184
2185 <div id="updraft-restore-modal" title="UpdraftPlus - <?php _e('Restore backup','updraftplus');?>">
2186 <p><strong><?php _e('Restore backup from','updraftplus');?>:</strong> <span class="updraft_restore_date"></span></p>
2187
2188 <div id="updraft-restore-modal-stage2">
2189
2190 <p><strong><?php _e('Retrieving (if necessary) and preparing backup files...', 'updraftplus');?></strong></p>
2191 <div id="ud_downloadstatus2"></div>
2192
2193 <div id="updraft-restore-modal-stage2a"></div>
2194
2195 </div>
2196
2197 <div id="updraft-restore-modal-stage1">
2198 <p><?php _e("Restoring will replace this site's themes, plugins, uploads, database and/or other content directories (according to what is contained in the backup set, and your selection).",'updraftplus');?> <?php _e('Choose the components to restore','updraftplus');?>:</p>
2199 <form id="updraft_restore_form" method="post">
2200 <fieldset>
2201 <input type="hidden" name="action" value="updraft_restore">
2202 <input type="hidden" name="backup_timestamp" value="0" id="updraft_restore_timestamp">
2203 <input type="hidden" name="meta_foreign" value="0" id="updraft_restore_meta_foreign">
2204 <?php
2205
2206 # The 'off' check is for badly configured setups - http://wordpress.org/support/topic/plugin-wp-super-cache-warning-php-safe-mode-enabled-but-safe-mode-is-off
2207 if($updraftplus->detect_safe_mode()) {
2208 echo "<p><em>".__('Your web server has PHP\'s so-called safe_mode active.','updraftplus').' '.__('This makes time-outs much more likely. You are recommended to turn safe_mode off, or to restore only one entity at a time, <a href="http://updraftplus.com/faqs/i-want-to-restore-but-have-either-cannot-or-have-failed-to-do-so-from-the-wp-admin-console/">or to restore manually</a>.', 'updraftplus')."</em></p><br/>";
2209 }
2210
2211 $backupable_entities = $updraftplus->get_backupable_file_entities(true, true);
2212 foreach ($backupable_entities as $type => $info) {
2213 if (!isset($info['restorable']) || $info['restorable'] == true) {
2214 echo '<div><input id="updraft_restore_'.$type.'" type="checkbox" name="updraft_restore[]" value="'.$type.'"> <label id="updraft_restore_label_'.$type.'" for="updraft_restore_'.$type.'">'.$info['description'].'</label><br>';
2215
2216 do_action("updraftplus_restore_form_$type");
2217
2218 echo '</div>';
2219 } else {
2220 $sdescrip = isset($info['shortdescription']) ? $info['shortdescription'] : $info['description'];
2221 echo "<div style=\"margin: 8px 0;\"><em>".htmlspecialchars(sprintf(__('The following entity cannot be restored automatically: "%s".', 'updraftplus'), $sdescrip))." ".__('You will need to restore it manually.', 'updraftplus')."</em><br>".'<input id="updraft_restore_'.$type.'" type="hidden" name="updraft_restore[]" value="'.$type.'">';
2222 echo '</div>';
2223 }
2224 }
2225 ?>
2226 <div><input id="updraft_restore_db" type="checkbox" name="updraft_restore[]" value="db"> <label for="updraft_restore_db"><?php _e('Database','updraftplus'); ?></label><br>
2227
2228 <div id="updraft_restorer_dboptions" style="display:none; padding:12px; margin: 8px 0 4px; border: dashed 1px;"><h4 style="margin: 0px 0px 6px; padding:0px;"><?php echo sprintf(__('%s restoration options:','updraftplus'),__('Database','updraftplus')); ?></h4>
2229
2230 <?php
2231
2232 do_action("updraftplus_restore_form_db");
2233
2234 if (!class_exists('UpdraftPlus_Addons_Migrator')) {
2235
2236 echo '<a href="http://updraftplus.com/faqs/tell-me-more-about-the-search-and-replace-site-location-in-the-database-option/">'.__('You can search and replace your database (for migrating a website to a new location/URL) with the Migrator add-on - follow this link for more information','updraftplus').'</a>';
2237
2238 }
2239
2240 ?>
2241
2242 </div>
2243
2244 </div>
2245 </fieldset>
2246 </form>
2247 <p><em><a href="http://updraftplus.com/faqs/what-should-i-understand-before-undertaking-a-restoration/" target="_new"><?php _e('Do read this helpful article of useful things to know before restoring.','updraftplus');?></a></em></p>
2248 </div>
2249
2250 </div>
2251
2252 <?php
2253 }
2254
2255 public function settings_debugrow($head, $content) {
2256 echo "<tr class=\"updraft_debugrow\"><th>$head</th><td>$content</td></tr>";
2257 }
2258
2259 private function settings_expertsettings($backup_disabled) {
2260 global $updraftplus, $wpdb;
2261 $backupable_entities = $updraftplus->get_backupable_file_entities(true, true);
2262 ?>
2263 <div class="expertmode">
2264 <p><em><?php _e('Unless you have a problem, you can completely ignore everything here.', 'updraftplus');?></em></p>
2265 <table>
2266 <?php
2267
2268 $this->settings_debugrow(__('Web server:','updraftplus'), htmlspecialchars($_SERVER["SERVER_SOFTWARE"]).' ('.htmlspecialchars(php_uname()).')');
2269
2270 $this->settings_debugrow('ABSPATH:', htmlspecialchars(ABSPATH));
2271 $this->settings_debugrow('WP_CONTENT_DIR:', htmlspecialchars(WP_CONTENT_DIR));
2272 $this->settings_debugrow('WP_PLUGIN_DIR:', htmlspecialchars(WP_PLUGIN_DIR));
2273 $this->settings_debugrow('Table prefix:', htmlspecialchars($updraftplus->get_table_prefix()));
2274 $peak_memory_usage = memory_get_peak_usage(true)/1024/1024;
2275 $memory_usage = memory_get_usage(true)/1024/1024;
2276 $this->settings_debugrow(__('Peak memory usage','updraftplus').':', $peak_memory_usage.' MB');
2277 $this->settings_debugrow(__('Current memory usage','updraftplus').':', $memory_usage.' MB');
2278 $this->settings_debugrow(__('Memory limit', 'updraftplus').':', htmlspecialchars(ini_get('memory_limit')));
2279 $this->settings_debugrow(sprintf(__('%s version:','updraftplus'), 'PHP'), htmlspecialchars(phpversion()).' - <a href="admin-ajax.php?page=updraftplus&action=updraft_ajax&subaction=phpinfo&nonce='.wp_create_nonce('updraftplus-credentialtest-nonce').'" id="updraftplus-phpinfo">'.__('show PHP information (phpinfo)', 'updraftplus').'</a>');
2280 $this->settings_debugrow(sprintf(__('%s version:','updraftplus'), 'MySQL'), htmlspecialchars($wpdb->db_version()));
2281 if (function_exists('curl_version') && function_exists('curl_exec')) {
2282 $cv = curl_version();
2283 $cvs = $cv['version'].' / SSL: '.$cv['ssl_version'].' / libz: '.$cv['libz_version'];
2284 } else {
2285 $cvs = '-';
2286 }
2287 $this->settings_debugrow(sprintf(__('%s version:','updraftplus'), 'Curl'), htmlspecialchars($cvs));
2288 if (version_compare(phpversion(), '5.2.0', '>=') && extension_loaded('zip')) {
2289 $ziparchive_exists = __('Yes', 'updraftplus');
2290 } else {
2291 # First do class_exists, because method_exists still sometimes segfaults due to a rare PHP bug
2292 $ziparchive_exists = (class_exists('ZipArchive') && method_exists('ZipArchive', 'addFile')) ? __('Yes', 'updraftplus') : __('No', 'updraftplus');
2293 }
2294 $this->settings_debugrow('ZipArchive::addFile:', $ziparchive_exists);
2295 $binzip = $updraftplus->find_working_bin_zip(false, false);
2296 $this->settings_debugrow(__('zip executable found:', 'updraftplus'), ((is_string($binzip)) ? __('Yes').': '.$binzip : __('No')));
2297 $hosting_bytes_free = $updraftplus->get_hosting_disk_quota_free();
2298 if (is_array($hosting_bytes_free)) {
2299 $perc = round(100*$hosting_bytes_free[1]/(max($hosting_bytes_free[2], 1)), 1);
2300 $this->settings_debugrow(__('Free disk space in account:', 'updraftplus'), sprintf(__('%s (%s used)', 'updraftplus'), round($hosting_bytes_free[3]/1048576, 1)." Mb", "$perc %"));
2301 }
2302
2303 $this->settings_debugrow(__('Plugins for debugging:', 'updraftplus'),'<a href="'.wp_nonce_url(self_admin_url('update.php?action=install-plugin&updraftplus_noautobackup=1&plugin=wp-crontrol'), 'install-plugin_wp-crontrol').'">WP Crontrol</a> | <a href="'.wp_nonce_url(self_admin_url('update.php?action=install-plugin&updraftplus_noautobackup=1&plugin=sql-executioner'), 'install-plugin_sql-executioner').'">SQL Executioner</a> | <a href="'.wp_nonce_url(self_admin_url('update.php?action=install-plugin&updraftplus_noautobackup=1&plugin=advanced-code-editor'), 'install-plugin_advanced-code-editor').'">Advanced Code Editor</a> '.(current_user_can('edit_plugins') ? '<a href="'.self_admin_url('plugin-editor.php?file=updraftplus/updraftplus.php').'">(edit UpdraftPlus)</a>' : '').' | <a href="'.wp_nonce_url(self_admin_url('update.php?action=install-plugin&updraftplus_noautobackup=1&plugin=wp-filemanager'), 'install-plugin_wp-filemanager').'">WP Filemanager</a>');
2304
2305 $this->settings_debugrow("HTTP Get: ", '<input id="updraftplus_httpget_uri" type="text" style="width: 300px; height: 22px;"> <a href="#" id="updraftplus_httpget_go">'.__('Fetch', 'updraftplus').'</a> <a href="#" id="updraftplus_httpget_gocurl">'.__('Fetch', 'updraftplus').' (Curl)</a><p id="updraftplus_httpget_results"></p>');
2306
2307 $this->settings_debugrow("Call WordPress action:", '<input id="updraftplus_callwpaction" type="text" style="width: 300px; height: 22px;"> <a href="#" id="updraftplus_callwpaction_go">'.__('Call', 'updraftplus').'</a><div id="updraftplus_callwpaction_results"></div>');
2308
2309 $this->settings_debugrow('', '<a href="admin-ajax.php?page=updraftplus&action=updraft_ajax&subaction=backuphistoryraw&nonce='.wp_create_nonce('updraftplus-credentialtest-nonce').'" id="updraftplus-rawbackuphistory">'.__('Show raw backup and file list', 'updraftplus').'</a>');
2310
2311 echo '</table>';
2312
2313 do_action('updraftplus_debugtools_dashboard');
2314
2315 echo '<h3>'.__('Total (uncompressed) on-disk data:','updraftplus').'</h3>';
2316 echo '<p style="clear: left; max-width: 600px;"><em>'.__('N.B. This count is based upon what was, or was not, excluded the last time you saved the options.', 'updraftplus').'</em></p><table>';
2317
2318 foreach ($backupable_entities as $key => $info) {
2319
2320 $sdescrip = preg_replace('/ \(.*\)$/', '', $info['description']);
2321 if (strlen($sdescrip) > 20 && isset($info['shortdescription'])) $sdescrip = $info['shortdescription'];
2322
2323 // echo '<div style="clear: left;float:left; width:150px;">'.ucfirst($sdescrip).':</strong></div><div style="float:left;"><span id="updraft_diskspaceused_'.$key.'"><em></em></span> <a href="#" onclick="updraftplus_diskspace_entity(\''.$key.'\'); return false;">'.__('count','updraftplus').'</a></div>';
2324 $this->settings_debugrow(ucfirst($sdescrip).':', '<span id="updraft_diskspaceused_'.$key.'"><em></em></span> <a href="#" onclick="updraftplus_diskspace_entity(\''.$key.'\'); return false;">'.__('count','updraftplus').'</a>');
2325 }
2326
2327 ?>
2328
2329 </table></p>
2330 <p style="clear: left; padding-top: 20px; max-width: 600px; margin:0;"><?php _e('The buttons below will immediately execute a backup run, independently of WordPress\'s scheduler. If these work whilst your scheduled backups do absolutely nothing (i.e. not even produce a log file), then it means that your scheduler is broken.','updraftplus');?> <a href="http://updraftplus.com/faqs/my-scheduled-backups-and-pressing-backup-now-does-nothing-however-pressing-debug-backup-does-produce-a-backup/"><?php _e('Go here for more information.', 'updraftplus'); ?></a></p>
2331
2332 <table border="0" style="border: none;">
2333 <tbody>
2334 <tr>
2335 <td>
2336 <form method="post" action="<?php echo add_query_arg(array('updraft_restore_success' => false, 'action' => false, 'page' => 'updraftplus')); ?>">
2337 <input type="hidden" name="action" value="updraft_backup_debug_all" />
2338 <p><input type="submit" class="button-primary" <?php echo $backup_disabled ?> value="<?php _e('Debug Full Backup','updraftplus');?>" onclick="return(confirm('<?php echo htmlspecialchars(__('This will cause an immediate backup. The page will stall loading until it finishes (ie, unscheduled).','updraftplus'));?>'))" /></p>
2339 </form>
2340 </td><td>
2341 <form method="post" action="<?php echo add_query_arg(array('updraft_restore_success' => false, 'action' => false, 'page' => 'updraftplus')); ?>">
2342 <input type="hidden" name="action" value="updraft_backup_debug_db" />
2343 <p><input type="submit" class="button-primary" <?php echo $backup_disabled ?> value="<?php _e('Debug Database Backup','updraftplus');?>" onclick="return(confirm('<?php echo htmlspecialchars(__('This will cause an immediate DB backup. The page will stall loading until it finishes (ie, unscheduled). The backup may well run out of time; really this button is only helpful for checking that the backup is able to get through the initial stages, or for small WordPress sites..','updraftplus'));?>'))" /></p>
2344 </form>
2345 </td>
2346 </tr>
2347 </tbody>
2348 </table>
2349 <h3><?php _e('Wipe Settings','updraftplus');?></h3>
2350 <p style="max-width: 600px;"><?php _e('This button will delete all UpdraftPlus settings (but not any of your existing backups from your cloud storage). You will then need to enter all your settings again. You can also do this before deactivating/deinstalling UpdraftPlus if you wish.','updraftplus');?></p>
2351 <form method="post" action="<?php echo add_query_arg(array('updraft_restore_success' => false, 'action' => false, 'page' => 'updraftplus')); ?>">
2352 <input type="hidden" name="action" value="updraft_wipesettings" />
2353 <p><input type="submit" class="button-primary" value="<?php _e('Wipe All Settings','updraftplus'); ?>" onclick="return(confirm('<?php echo htmlspecialchars(__('This will delete all your UpdraftPlus settings - are you sure you want to do this?'));?>'))" /></p>
2354 </form>
2355 </div>
2356 <?php
2357 }
2358
2359 private function print_delete_old_dirs_form($include_blurb = true) {
2360 ?>
2361 <?php if ($include_blurb) {
2362 ?>
2363 <div id="updraft_delete_old_dirs_pagediv" class="updated" style="padding:8px;"><p> <?php _e('Your WordPress install has old directories from its state before you restored/migrated (technical information: these are suffixed with -old). You should press this button to delete them as soon as you have verified that the restoration worked.','updraftplus');?></p><?php } ?>
2364 <form method="post" onsubmit="return updraft_delete_old_dirs();" action="<?php echo add_query_arg(array('updraft_restore_success' => false, 'action' => false, 'page' => 'updraftplus')); ?>">
2365 <?php wp_nonce_field('updraftplus-credentialtest-nonce'); ?>
2366 <input type="hidden" name="action" value="updraft_delete_old_dirs">
2367 <input type="submit" class="button-primary" value="<?php echo esc_attr(__('Delete Old Directories', 'updraftplus'));?>" />
2368 </form>
2369 <?php
2370 if ($include_blurb) echo '</div>';
2371 }
2372
2373
2374 private function print_active_jobs() {
2375 $cron = get_option('cron');
2376 if (!is_array($cron)) $cron = array();
2377 // $found_jobs = 0;
2378 $ret = '';
2379
2380 foreach ($cron as $time => $job) {
2381 if (isset($job['updraft_backup_resume'])) {
2382 foreach ($job['updraft_backup_resume'] as $hook => $info) {
2383 if (isset($info['args'][1])) {
2384 // $found_jobs++;
2385 $job_id = $info['args'][1];
2386 $ret .= $this->print_active_job($job_id, false, $time, $info['args'][0]);
2387 }
2388 }
2389 }
2390 }
2391
2392 // if (0 == $found_jobs) $ret .= '<p><em>'.__('(None)', 'updraftplus').'</em></p>';
2393 return $ret;
2394 }
2395
2396 private function print_active_job($job_id, $is_oneshot = false, $time = false, $next_resumption = false) {
2397
2398 $ret = '';
2399
2400 global $updraftplus;
2401
2402 $jobdata = $updraftplus->jobdata_getarray($job_id);
2403 if (false == apply_filters('updraftplus_print_active_job_continue', true, $is_oneshot, $next_resumption, $jobdata)) return '';
2404
2405 #if (!is_array($jobdata)) $jobdata = array();
2406 if (!isset($jobdata['backup_time'])) return '';
2407
2408 $backupable_entities = $updraftplus->get_backupable_file_entities(true, true);
2409
2410 $began_at = (isset($jobdata['backup_time'])) ? get_date_from_gmt(gmdate('Y-m-d H:i:s', (int)$jobdata['backup_time']), 'D, F j, Y H:i') : '?';
2411
2412 $jobstatus = empty($jobdata['jobstatus']) ? 'unknown' : $jobdata['jobstatus'];
2413 $stage = 0;
2414 switch ($jobstatus) {
2415 # Stage 0
2416 case 'begun':
2417 $curstage = __('Backup begun', 'updraftplus');
2418 break;
2419 # Stage 1
2420 case 'filescreating':
2421 $stage = 1;
2422 $curstage = __('Creating file backup zips', 'updraftplus');
2423 if (!empty($jobdata['filecreating_substatus']) && isset($backupable_entities[$jobdata['filecreating_substatus']['e']]['description'])) {
2424
2425 $sdescrip = preg_replace('/ \(.*\)$/', '', $backupable_entities[$jobdata['filecreating_substatus']['e']]['description']);
2426 if (strlen($sdescrip) > 20 && isset($jobdata['filecreating_substatus']['e']) && is_array($jobdata['filecreating_substatus']['e']) && isset($backupable_entities[$jobdata['filecreating_substatus']['e']]['shortdescription'])) $sdescrip = $backupable_entities[$jobdata['filecreating_substatus']['e']]['shortdescription'];
2427 $curstage .= ' ('.$sdescrip.')';
2428 if (isset($jobdata['filecreating_substatus']['i']) && isset($jobdata['filecreating_substatus']['t'])) {
2429 $stage = min(2, 1 + ($jobdata['filecreating_substatus']['i']/max($jobdata['filecreating_substatus']['t'],1)));
2430 }
2431 }
2432 break;
2433 case 'filescreated':
2434 $stage = 2;
2435 $curstage = __('Created file backup zips', 'updraftplus');
2436 break;
2437
2438 # Stage 4
2439 case 'clouduploading':
2440 $stage = 4;
2441 $curstage = __('Uploading files to remote storage', 'updraftplus');
2442 if (isset($jobdata['uploading_substatus']['t']) && isset($jobdata['uploading_substatus']['i'])) {
2443 $t = max((int)$jobdata['uploading_substatus']['t'], 1);
2444 $i = min($jobdata['uploading_substatus']['i']/$t, 1);
2445 $p = min($jobdata['uploading_substatus']['p'], 1);
2446 $pd = $i + $p/$t;
2447 $stage = 4 + $pd;
2448 $curstage .= ' '.sprintf(__('(%s%%, file %s of %s)', 'updraftplus'), floor(100*$pd), $jobdata['uploading_substatus']['i']+1, $t);
2449 }
2450 break;
2451 case 'pruning':
2452 $stage = 5;
2453 $curstage = __('Pruning old backup sets', 'updraftplus');
2454 break;
2455 case 'resumingforerrors':
2456 $stage = -1;
2457 $curstage = __('Waiting until scheduled time to retry because of errors', 'updraftplus');
2458 break;
2459 # Stage 6
2460 case 'finished':
2461 $stage = 6;
2462 $curstage = __('Backup finished', 'updraftplus');
2463 break;
2464 default:
2465
2466 # Database creation and encryption occupies the space from 2 to 4. Databases are created then encrypted, then the next databae is created/encrypted, etc.
2467 if ('dbcreated' == substr($jobstatus, 0, 9)) {
2468 $jobstatus = 'dbcreated';
2469 $whichdb = substr($jobstatus, 9);
2470 if (!is_numeric($whichdb)) $whichdb = 0;
2471 $howmanydbs = max((empty($jobdata['backup_database']) || !is_array($jobdata['backup_database'])) ? 1 : count($jobdata['backup_database']), 1);
2472 $perdbspace = 2/$howmanydbs;
2473
2474 $stage = min(4, 2 + ($whichdb+2)*$perdbspace);
2475
2476 $curstage = __('Created database backup', 'updraftplus');
2477
2478 } elseif ('dbcreating' == substr($jobstatus, 0, 10)) {
2479 $whichdb = substr($jobstatus, 10);
2480 if (!is_numeric($whichdb)) $whichdb = 0;
2481 $howmanydbs = (empty($jobdata['backup_database']) || !is_array($jobdata['backup_database'])) ? 1 : count($jobdata['backup_database']);
2482 $perdbspace = 2/$howmanydbs;
2483 $jobstatus = 'dbcreating';
2484
2485 $stage = min(4, 2 + $whichdb*$perdbspace);
2486
2487 $curstage = __('Creating database backup', 'updraftplus');
2488 if (!empty($jobdata['dbcreating_substatus']['t'])) {
2489 $curstage .= ' ('.sprintf(__('table: %s', 'updraftplus'), $jobdata['dbcreating_substatus']['t']).')';
2490 if (!empty($jobdata['dbcreating_substatus']['i']) && !empty($jobdata['dbcreating_substatus']['a'])) {
2491 $substage = max(0.001, ($jobdata['dbcreating_substatus']['i'] / max($jobdata['dbcreating_substatus']['a'],1)));
2492 $stage += $substage * $perdbspace * 0.5;
2493 }
2494 }
2495 } elseif ('dbencrypting' == substr($jobstatus, 0, 12)) {
2496 $whichdb = substr($jobstatus, 12);
2497 if (!is_numeric($whichdb)) $whichdb = 0;
2498 $howmanydbs = (empty($jobdata['backup_database']) || !is_array($jobdata['backup_database'])) ? 1 : count($jobdata['backup_database']);
2499 $perdbspace = 2/$howmanydbs;
2500 $stage = min(4, 2 + $whichdb*$perdbspace + $perdbspace*0.5);
2501 $jobstatus = 'dbencrypting';
2502 $curstage = __('Encrypting database', 'updraftplus');
2503 } elseif ('dbencrypted' == substr($jobstatus, 0, 11)) {
2504 $whichdb = substr($jobstatus, 11);
2505 if (!is_numeric($whichdb)) $whichdb = 0;
2506 $howmanydbs = (empty($jobdata['backup_database']) || !is_array($jobdata['backup_database'])) ? 1 : count($jobdata['backup_database']);
2507 $jobstatus = 'dbencrypted';
2508 $perdbspace = 2/$howmanydbs;
2509 $stage = min(4, 2 + $whichdb*$perdbspace + $perdbspace);
2510 $curstage = __('Encrypted database', 'updraftplus');
2511 } else {
2512 $curstage = __('Unknown', 'updraftplus');
2513 }
2514 }
2515
2516 $runs_started = (empty($jobdata['runs_started'])) ? array() : $jobdata['runs_started'];
2517 $time_passed = (empty($jobdata['run_times'])) ? array() : $jobdata['run_times'];
2518 $last_checkin_ago = -1;
2519 if (is_array($time_passed)) {
2520 foreach ($time_passed as $run => $passed) {
2521 if (isset($runs_started[$run])) {
2522 $time_ago = microtime(true) - ($runs_started[$run] + $time_passed[$run]);
2523 if ($time_ago < $last_checkin_ago || $last_checkin_ago == -1) $last_checkin_ago = $time_ago;
2524 }
2525 }
2526 }
2527
2528 $next_res_after = $time-time();
2529 $next_res_txt = ($is_oneshot) ? '' : ' - '.sprintf(__("next resumption: %d (after %ss)", 'updraftplus'), $next_resumption, $next_res_after). ' ';
2530 $last_activity_txt = ($last_checkin_ago >= 0) ? ' - '.sprintf(__('last activity: %ss ago', 'updraftplus'), floor($last_checkin_ago)).' ' : '';
2531
2532 if (($last_checkin_ago < 50 && $next_res_after>30) || $is_oneshot) {
2533 $show_inline_info = $last_activity_txt;
2534 $title_info = $next_res_txt;
2535 } else {
2536 $show_inline_info = $next_res_txt;
2537 $title_info = $last_activity_txt;
2538 }
2539
2540 $ret .= '<div style="min-width: 480px; margin-top: 4px; clear:left; float:left; padding: 8px; border: 1px solid;" id="updraft-jobid-'.$job_id.'"><span style="font-weight:bold;" title="'.esc_attr(sprintf(__('Job ID: %s', 'updraftplus'), $job_id)).$title_info.'">'.$began_at.'</span> ';
2541
2542 $ret .= $show_inline_info;
2543 $ret .= '- <a href="?page=updraftplus&action=downloadlog&updraftplus_backup_nonce='.$job_id.'" class="updraft-log-link" onclick="event.preventDefault(); updraft_popuplog(\''.$job_id.'\');">'.__('show log', 'updraftplus').'</a>';
2544
2545 if (!$is_oneshot) $ret .=' - <a title="'.esc_attr(__('Note: the progress bar below is based on stages, NOT time. Do not stop the backup simply because it seems to have remained in the same place for a while - that is normal.', 'updraftplus')).'" href="javascript:updraft_activejobs_delete(\''.$job_id.'\')">'.__('delete schedule', 'updraftplus').'</a>';
2546
2547 if (!empty($jobdata['warnings']) && is_array($jobdata['warnings'])) {
2548 $ret .= '<ul style="list-style: disc inside;">';
2549 foreach ($jobdata['warnings'] as $warning) {
2550 $ret .= '<li>'.sprintf(__('Warning: %s', 'updraftplus'), make_clickable(htmlspecialchars($warning))).'</li>';
2551 }
2552 $ret .= '</ul>';
2553 }
2554
2555 $ret .= '<div style="border-radius: 4px; margin-top: 8px; padding-top: 4px;border: 1px solid #aaa; width: 100%; height: 22px; position: relative; text-align: center; font-style: italic;">';
2556 $ret .= htmlspecialchars($curstage);
2557 $ret .= '<div style="z-index:-1; position: absolute; left: 0px; top: 0px; text-align: center; background-color: #f6a828; height: 100%; width:'.(($stage>0) ? (ceil((100/6)*$stage)) : '0').'%"></div>';
2558 $ret .= '</div></div>';
2559
2560 $ret .= '</div>';
2561
2562 return $ret;
2563
2564 }
2565
2566 private function delete_old_dirs_go($show_return = true) {
2567 echo ($show_return) ? '<h1>UpdraftPlus - '.__('Remove old directories', 'updraftplus').'</h1>' : '<h2>'.__('Remove old directories', 'updraftplus').'</h2>';
2568
2569 if($this->delete_old_dirs()) {
2570 echo '<p>'.__('Old directories successfully removed.','updraftplus').'</p><br/>';
2571 } else {
2572 echo '<p>',__('Old directory removal failed for some reason. You may want to do this manually.','updraftplus').'</p><br/>';
2573 }
2574 if ($show_return) echo '<b>'.__('Actions','updraftplus').':</b> <a href="'.UpdraftPlus_Options::admin_page_url().'?page=updraftplus">'.__('Return to UpdraftPlus Configuration','updraftplus').'</a>';
2575 }
2576
2577 //deletes the -old directories that are created when a backup is restored.
2578 private function delete_old_dirs() {
2579 global $wp_filesystem, $updraftplus;
2580 $credentials = request_filesystem_credentials(wp_nonce_url(UpdraftPlus_Options::admin_page_url()."?page=updraftplus&action=updraft_delete_old_dirs", 'updraftplus-credentialtest-nonce'));
2581 WP_Filesystem($credentials);
2582 if ($wp_filesystem->errors->get_error_code()) {
2583 foreach ($wp_filesystem->errors->get_error_messages() as $message)
2584 show_message($message);
2585 exit;
2586 }
2587 // From WP_CONTENT_DIR - which contains 'themes'
2588 $ret = $this->delete_old_dirs_dir($wp_filesystem->wp_content_dir());
2589
2590 $updraft_dir = $updraftplus->backups_dir_location();
2591 if ($updraft_dir) {
2592 $ret4 = ($updraft_dir) ? $this->delete_old_dirs_dir($updraft_dir, false) : true;
2593 } else {
2594 $ret4 = true;
2595 }
2596
2597 // $ret2 = $this->delete_old_dirs_dir($wp_filesystem->abspath());
2598 $plugs = untrailingslashit($wp_filesystem->wp_plugins_dir());
2599 if ($wp_filesystem->is_dir($plugs.'-old')) {
2600 print "<strong>".__('Delete','updraftplus').": </strong>plugins-old: ";
2601 if(!$wp_filesystem->delete($plugs.'-old', true)) {
2602 $ret3 = false;
2603 print "<strong>".__('Failed', 'updraftplus')."</strong><br>";
2604 } else {
2605 $ret3 = true;
2606 print "<strong>".__('OK', 'updraftplus')."</strong><br>";
2607 }
2608 } else {
2609 $ret3 = true;
2610 }
2611
2612 return $ret && $ret3 && $ret4;
2613 }
2614
2615 private function delete_old_dirs_dir($dir, $wpfs = true) {
2616
2617 $dir = trailingslashit($dir);
2618
2619 global $wp_filesystem, $updraftplus;
2620
2621 if ($wpfs) {
2622 $list = $wp_filesystem->dirlist($dir);
2623 } else {
2624 $list = scandir($dir);
2625 }
2626 if (!is_array($list)) return false;
2627
2628 $ret = true;
2629 foreach ($list as $item) {
2630 $name = (is_array($item)) ? $item['name'] : $item;
2631 if ("-old" == substr($name, -4, 4)) {
2632 //recursively delete
2633 print "<strong>".__('Delete','updraftplus').": </strong>".htmlspecialchars($name).": ";
2634
2635 if ($wpfs) {
2636 if(!$wp_filesystem->delete($dir.$name, true)) {
2637 $ret = false;
2638 echo "<strong>".__('Failed', 'updraftplus')."</strong><br>";
2639 } else {
2640 echo "<strong>".__('OK', 'updraftplus')."</strong><br>";
2641 }
2642 } else {
2643 if ($updraftplus->remove_local_directory($dir.$name)) {
2644 echo "<strong>".__('OK', 'updraftplus')."</strong><br>";
2645 } else {
2646 $ret = false;
2647 echo "<strong>".__('Failed', 'updraftplus')."</strong><br>";
2648 }
2649 }
2650 }
2651 }
2652 return $ret;
2653 }
2654
2655 // The aim is to get a directory that is writable by the webserver, because that's the only way we can create zip files
2656 private function create_backup_dir() {
2657
2658 global $wp_filesystem, $updraftplus;
2659
2660 if (false === ($credentials = request_filesystem_credentials(UpdraftPlus_Options::admin_page().'?page=updraftplus&action=updraft_create_backup_dir&nonce='.wp_create_nonce('create_backup_dir')))) {
2661 return false;
2662 }
2663
2664 if ( ! WP_Filesystem($credentials) ) {
2665 // our credentials were no good, ask the user for them again
2666 request_filesystem_credentials(UpdraftPlus_Options::admin_page().'?page=updraftplus&action=updraft_create_backup_dir&nonce='.wp_create_nonce('create_backup_dir'), '', true);
2667 return false;
2668 }
2669
2670 $updraft_dir = $updraftplus->backups_dir_location();
2671
2672 $default_backup_dir = $wp_filesystem->find_folder(dirname($updraft_dir)).basename($updraft_dir);
2673
2674 $updraft_dir = ($updraft_dir) ? $wp_filesystem->find_folder(dirname($updraft_dir)).basename($updraft_dir) : $default_backup_dir;
2675
2676 if (!$wp_filesystem->is_dir($default_backup_dir) && !$wp_filesystem->mkdir($default_backup_dir, 0775)) {
2677 $wperr = new WP_Error;
2678 if ( $wp_filesystem->errors->get_error_code() ) {
2679 foreach ( $wp_filesystem->errors->get_error_messages() as $message ) {
2680 $wperr->add('mkdir_error', $message);
2681 }
2682 return $wperr;
2683 } else {
2684 return new WP_Error('mkdir_error', __('The request to the filesystem to create the directory failed.', 'updraftplus'));
2685 }
2686 }
2687
2688 if ($wp_filesystem->is_dir($default_backup_dir)) {
2689
2690 if ($updraftplus->really_is_writable($updraft_dir)) return true;
2691
2692 @$wp_filesystem->chmod($default_backup_dir, 0775);
2693 if ($updraftplus->really_is_writable($updraft_dir)) return true;
2694
2695 @$wp_filesystem->chmod($default_backup_dir, 0777);
2696
2697 if ($updraftplus->really_is_writable($updraft_dir)) {
2698 echo '<p>'.__('The folder was created, but we had to change its file permissions to 777 (world-writable) to be able to write to it. You should check with your hosting provider that this will not cause any problems', 'updraftplus').'</p>';
2699 return true;
2700 } else {
2701 @$wp_filesystem->chmod($default_backup_dir, 0775);
2702 $show_dir = (0 === strpos($default_backup_dir, ABSPATH)) ? substr($default_backup_dir, strlen(ABSPATH)) : $default_backup_dir;
2703 return new WP_Error('writable_error', __('The folder exists, but your webserver does not have permission to write to it.', 'updraftplus').' '.__('You will need to consult with your web hosting provider to find out how to set permissions for a WordPress plugin to write to the directory.', 'updraftplus').' ('.$show_dir.')');
2704 }
2705 }
2706
2707 return true;
2708 }
2709
2710 //scans the content dir to see if any -old dirs are present
2711 private function scan_old_dirs($print_as_comment = false) {
2712 global $updraftplus;
2713 $dirs = scandir(untrailingslashit(WP_CONTENT_DIR));
2714 if (!is_array($dirs)) $dirs = array();
2715 $dirs_u = @scandir($updraftplus->backups_dir_location());
2716 if (!is_array($dirs_u)) $dirs_u = array();
2717 foreach (array_merge($dirs, $dirs_u) as $dir) {
2718 if (preg_match('/-old$/', $dir)) {
2719 if ($print_as_comment) echo '<!--'.htmlspecialchars($dir).'-->';
2720 return true;
2721 }
2722 }
2723 # No need to scan ABSPATH - we don't backup there
2724 if (is_dir(untrailingslashit(WP_PLUGIN_DIR).'-old')) {
2725 if ($print_as_comment) echo '<!--'.htmlspecialchars(untrailingslashit(WP_PLUGIN_DIR).'-old').'-->';
2726 return true;
2727 }
2728 return false;
2729 }
2730
2731 public function storagemethod_row($method, $header, $contents) {
2732 ?>
2733 <tr class="updraftplusmethod <?php echo $method;?>">
2734 <th><?php echo $header;?></th>
2735 <td><?php echo $contents;?></td>
2736 </tr>
2737 <?php
2738 }
2739
2740 private function last_backup_html() {
2741
2742 global $updraftplus;
2743
2744 $updraft_last_backup = UpdraftPlus_Options::get_updraft_option('updraft_last_backup');
2745
2746 if($updraft_last_backup) {
2747
2748 // Convert to GMT, then to blog time
2749 $last_backup_text = "<span style=\"color:".(($updraft_last_backup['success']) ? 'green' : 'black').";\">".get_date_from_gmt(gmdate('Y-m-d H:i:s', (int)$updraft_last_backup['backup_time']), 'D, F j, Y H:i').'</span><br>';
2750
2751 if (is_array($updraft_last_backup['errors'])) {
2752 foreach ($updraft_last_backup['errors'] as $err) {
2753 $level = (is_array($err)) ? $err['level'] : 'error';
2754 $message = (is_array($err)) ? $err['message'] : $err;
2755
2756 $last_backup_text .= ('warning' == $level) ? "<span style=\"color:orange;\">" : "<span style=\"color:red;\">";
2757
2758 if ('warning' == $level) {
2759 $message = sprintf(__("Warning: %s", 'updraftplus'), make_clickable(htmlspecialchars($message)));
2760 } else {
2761 $message = htmlspecialchars($message);
2762 }
2763
2764 $last_backup_text .= $message;
2765
2766 $last_backup_text .= '</span><br>';
2767 }
2768 }
2769
2770 if (!empty($updraft_last_backup['backup_nonce'])) {
2771 $updraft_dir = $updraftplus->backups_dir_location();
2772
2773 $potential_log_file = $updraft_dir."/log.".$updraft_last_backup['backup_nonce'].".txt";
2774 if (is_readable($potential_log_file)) $last_backup_text .= "<a href=\"?page=updraftplus&action=downloadlog&updraftplus_backup_nonce=".$updraft_last_backup['backup_nonce']."\" class=\"updraft-log-link\" onclick=\"event.preventDefault(); updraft_popuplog('".$updraft_last_backup['backup_nonce']."');\">".__('Download log file','updraftplus')."</a>";
2775 }
2776
2777 } else {
2778 $last_backup_text = "<span style=\"color:blue;\">".__('No backup has been completed.','updraftplus')."</span>";
2779 }
2780
2781 return $last_backup_text;
2782
2783 }
2784
2785 public function get_intervals() {
2786 return apply_filters('updraftplus_backup_intervals', array(
2787 "manual" => _x("Manual", 'i.e. Non-automatic', 'updraftplus'),
2788 'every4hours' => sprintf(__("Every %s hours", 'updraftplus'), '4'),
2789 'every8hours' => sprintf(__("Every %s hours", 'updraftplus'), '8'),
2790 'twicedaily' => sprintf(__("Every %s hours", 'updraftplus'), '12'),
2791 'daily' => __("Daily", 'updraftplus'),
2792 'weekly' => __("Weekly", 'updraftplus'),
2793 'fortnightly' => __("Fortnightly", 'updraftplus'),
2794 'monthly' => __("Monthly", 'updraftplus')
2795 ));
2796 }
2797
2798 private function settings_formcontents($last_backup_html) {
2799
2800 global $updraftplus;
2801
2802 $updraft_dir = $updraftplus->backups_dir_location();
2803
2804 ?>
2805 <table class="form-table">
2806 <tr>
2807 <th><?php _e('File backup intervals','updraftplus'); ?>:</th>
2808 <td><select id="updraft_interval" name="updraft_interval" onchange="jQuery(document).trigger('updraftplus_interval_changed'); updraft_check_same_times();">
2809 <?php
2810 $intervals = $this->get_intervals();
2811 $selected_interval = UpdraftPlus_Options::get_updraft_option('updraft_interval','manual');
2812 foreach ($intervals as $cronsched => $descrip) {
2813 echo "<option value=\"$cronsched\" ";
2814 if ($cronsched == $selected_interval) echo 'selected="selected"';
2815 echo ">".htmlspecialchars($descrip)."</option>\n";
2816 }
2817 ?>
2818 </select> <span id="updraft_files_timings"><?php echo apply_filters('updraftplus_schedule_showfileopts', '<input type="hidden" name="updraftplus_starttime_files" value="">'); ?></span>
2819 <?php
2820 echo __('and retain this many backups', 'updraftplus').': ';
2821 $updraft_retain = (int)UpdraftPlus_Options::get_updraft_option('updraft_retain', 2);
2822 $updraft_retain = ($updraft_retain > 0) ? $updraft_retain : 1;
2823 ?> <input type="number" min="1" step="1" name="updraft_retain" value="<?php echo $updraft_retain ?>" style="width:48px;" />
2824 </td>
2825 </tr>
2826
2827 <!--
2828 <tr id="updraft_incremental_row">
2829 <th><?php _e('Incremental file backup intervals', 'updraftplus'); ?>:</th>
2830 <td>
2831 <?php do_action('updraftplus_incremental_cell', $selected_interval); ?>
2832 <a href="http://updraftplus.com/support/tell-me-more-about-incremental-backups/"><em><?php _e('Tell me more about incremental backups', 'updraftplus'); ?><em></a>
2833 </td>
2834 </tr>
2835 -->
2836 <?php apply_filters('updraftplus_after_file_intervals', false, $selected_interval); ?>
2837 <tr>
2838 <th><?php _e('Database backup intervals','updraftplus'); ?>:</th>
2839 <td><select id="updraft_interval_database" name="updraft_interval_database" onchange="updraft_check_same_times();">
2840 <?php
2841 foreach ($intervals as $cronsched => $descrip) {
2842 echo "<option value=\"$cronsched\" ";
2843 if ($cronsched == UpdraftPlus_Options::get_updraft_option('updraft_interval_database', UpdraftPlus_Options::get_updraft_option('updraft_interval'))) echo 'selected="selected"';
2844 echo ">$descrip</option>\n";
2845 }
2846 ?>
2847 </select> <span id="updraft_db_timings"><?php echo apply_filters('updraftplus_schedule_showdbopts', '<input type="hidden" name="updraftplus_starttime_db" value="">'); ?></span>
2848 <?php
2849 echo __('and retain this many backups', 'updraftplus').': ';
2850 $updraft_retain_db = (int)UpdraftPlus_Options::get_updraft_option('updraft_retain_db', $updraft_retain);
2851 $updraft_retain_db = ($updraft_retain_db > 0) ? $updraft_retain_db : 1;
2852 ?> <input type="number" min="1" step="1" name="updraft_retain_db" value="<?php echo $updraft_retain_db ?>" style="width:48px" />
2853 </td>
2854 </tr>
2855 <tr class="backup-interval-description">
2856 <td></td><td><div style="max-width:670px;"><p><?php echo htmlspecialchars(__('If you would like to automatically schedule backups, choose schedules from the dropdowns above.', 'updraftplus').' '.__('If the two schedules are the same, then the two backups will take place together.', 'updraftplus')); ?></p>
2857 <?php echo apply_filters('updraftplus_fixtime_ftinfo', '<p><strong>'.__('To fix the time at which a backup should take place,','updraftplus').' </strong> ('.__('e.g. if your server is busy at day and you want to run overnight','updraftplus').'), <a href="http://updraftplus.com/shop/updraftplus-premium/">'.htmlspecialchars(__('use UpdraftPlus Premium', 'updraftplus')).'</a></p>'); ?>
2858 </div></td>
2859 </tr>
2860 <tr>
2861 <th><?php _e('Include in files backup', 'updraftplus');?>:</th>
2862 <td>
2863
2864 <?php
2865 $backupable_entities = $updraftplus->get_backupable_file_entities(true, true);
2866 # The true (default value if non-existent) here has the effect of forcing a default of on.
2867 foreach ($backupable_entities as $key => $info) {
2868 $included = (UpdraftPlus_Options::get_updraft_option("updraft_include_$key", apply_filters("updraftplus_defaultoption_include_".$key, true))) ? 'checked="checked"' : "";
2869 if ('others' == $key || 'uploads' == $key) {
2870
2871 $include_exclude = UpdraftPlus_Options::get_updraft_option('updraft_include_'.$key.'_exclude', ('others' == $key) ? UPDRAFT_DEFAULT_OTHERS_EXCLUDE : UPDRAFT_DEFAULT_UPLOADS_EXCLUDE);
2872
2873 ?><input id="updraft_include_<?php echo $key; ?>" type="checkbox" name="updraft_include_<?php echo $key; ?>" value="1" <?php echo $included; ?> /> <label <?php if ('others' == $key) echo 'title="'.sprintf(__('Your wp-content directory server path: %s', 'updraftplus'), WP_CONTENT_DIR).'"';?> for="updraft_include_<?php echo $key ?>"><?php echo ('others' == $key) ? __('Any other directories found inside wp-content', 'updraftplus') : htmlspecialchars($info['description']);?></label><br><?php
2874
2875 $display = ($included) ? '' : 'style="display:none;"';
2876
2877 echo "<div id=\"updraft_include_".$key."_exclude\" $display>";
2878
2879 echo '<label for="updraft_include_'.$key.'_exclude">'.__('Exclude these:', 'updraftplus').'</label>';
2880
2881 echo '<input title="'.__('If entering multiple files/directories, then separate them with commas. For entities at the top level, you can use a * at the start or end of the entry as a wildcard.', 'updraftplus').'" type="text" id="updraft_include_'.$key.'_exclude" name="updraft_include_'.$key.'_exclude" size="54" value="'.htmlspecialchars($include_exclude).'" />';
2882
2883 echo '<br>';
2884
2885 echo '</div>';
2886
2887 } else {
2888 echo "<input id=\"updraft_include_$key\" type=\"checkbox\" name=\"updraft_include_$key\" value=\"1\" $included /><label for=\"updraft_include_$key\"".((isset($info['htmltitle'])) ? ' title="'.htmlspecialchars($info['htmltitle']).'"' : '')."> ".htmlspecialchars($info['description'])."</label><br>";
2889 do_action("updraftplus_config_option_include_$key");
2890 }
2891 }
2892 ?>
2893 <p><?php echo apply_filters('updraftplus_admin_directories_description', __('The above directories are everything, except for WordPress core itself which you can download afresh from WordPress.org.', 'updraftplus').' <a href="http://updraftplus.com/shop/">'.htmlspecialchars(__('See also the "More Files" add-on from our shop.', 'updraftplus'))); ?></a></p>
2894 <?php if (1==0 && !defined('UPDRAFTPLUS_NOADS_B')) echo '<p><a href="http://wordshell.net">('.__('Use WordShell for automatic backup, version control and patching', 'updraftplus').').</a></p>';?>
2895 </td>
2896 </tr>
2897
2898 </table>
2899
2900 <h2><?php _e('Database Options','updraftplus');?></h2>
2901
2902 <table class="form-table" style="width:900px;">
2903
2904 <tr>
2905 <th><?php _e('Database encryption phrase','updraftplus');?>:</th>
2906
2907 <td>
2908 <?php
2909 echo apply_filters('updraft_database_encryption_config', '<a href="http://updraftplus.com/shop/updraftplus-premium/">'.__("Don't want to be spied on? UpdraftPlus Premium can encrypt your database backup.", 'updraftplus').'</a> '.__('It can also backup external databases.', 'updraftplus'));
2910 ?>
2911 </td>
2912 </tr>
2913 <tr class="backup-crypt-description">
2914 <td></td>
2915
2916 <td>
2917
2918 <a href="#" onclick="jQuery('#updraftplus_db_decrypt').val(jQuery('#updraft_encryptionphrase').val()); jQuery('#updraft-manualdecrypt-modal').slideToggle(); return false;"><?php _e('You can manually decrypt an encrypted database here.','updraftplus');?></a>
2919
2920 <div id="updraft-manualdecrypt-modal" style="width: 85%; margin: 6px; display:none; margin-left: 100px;">
2921 <p><h3><?php _e("Manually decrypt a database backup file" ,'updraftplus');?></h3></p>
2922
2923 <?php
2924 global $wp_version;
2925 if (version_compare($wp_version, '3.3', '<')) {
2926 echo '<em>'.sprintf(__('This feature requires %s version %s or later', 'updraftplus'), 'WordPress', '3.3').'</em>';
2927 } else {
2928 ?>
2929
2930 <div id="plupload-upload-ui2" style="width: 80%;">
2931 <div id="drag-drop-area2">
2932 <div class="drag-drop-inside">
2933 <p class="drag-drop-info"><?php _e('Drop encrypted database files (db.gz.crypt files) here to upload them for decryption'); ?></p>
2934 <p><?php _ex('or', 'Uploader: Drop db.gz.crypt files here to upload them for decryption - or - Select Files'); ?></p>
2935 <p class="drag-drop-buttons"><input id="plupload-browse-button2" type="button" value="<?php esc_attr_e('Select Files'); ?>" class="button" /></p>
2936 <p style="margin-top: 18px;"><?php _e('First, enter the decryption key','updraftplus')?>: <input id="updraftplus_db_decrypt" type="text" size="12"></input></p>
2937 </div>
2938 </div>
2939 <div id="filelist2">
2940 </div>
2941 </div>
2942
2943 <?php } ?>
2944
2945 </div>
2946
2947
2948 </td>
2949 </tr>
2950
2951 <?php
2952 #'<a href="http://updraftplus.com/shop/updraftplus-premium/">'.__("This feature is part of UpdraftPlus Premium.", 'updraftplus').'</a>'
2953 $moredbs_config = apply_filters('updraft_database_moredbs_config', false);
2954 if (!empty($moredbs_config)) {
2955 ?>
2956
2957 <tr>
2958 <th><?php _e('Back up more databases', 'updraftplus');?>:</th>
2959
2960 <td><?php
2961
2962 echo $moredbs_config;
2963
2964 ?>
2965
2966 </td>
2967 </tr>
2968
2969 <?php } ?>
2970
2971 </table>
2972
2973 <h2><?php _e('Reporting','updraftplus');?></h2>
2974
2975 <table class="form-table" style="width:900px;">
2976
2977 <?php
2978 $report_rows = apply_filters('updraftplus_report_form', false);
2979 if (is_string($report_rows)) {
2980 echo $report_rows;
2981 } else {
2982 ?>
2983
2984 <tr>
2985 <th><?php _e('Email', 'updraftplus'); ?>:</th>
2986 <td>
2987 <?php
2988 $updraft_email = UpdraftPlus_Options::get_updraft_option('updraft_email');
2989 ?>
2990 <input type="checkbox" id="updraft_email" name="updraft_email" value="<?php esc_attr_e(get_bloginfo('admin_email')); ?>"<?php if (!empty($updraft_email)) echo ' checked="checked"';?> > <br><label for="updraft_email"><?php echo sprintf(__("Check this box to have a basic report sent to your site's admin address (%s).",'updraftplus'), htmlspecialchars(get_bloginfo('admin_email'))); ?></label>
2991 <?php
2992 if (!class_exists('UpdraftPlus_Addon_Reporting')) echo '<a href="http://updraftplus.com/shop/reporting/">'.__('For more reporting features, use the Reporting add-on.', 'updraftplus').'</a>';
2993 ?>
2994 </td>
2995 </tr>
2996
2997 <?php } ?>
2998
2999 </table>
3000
3001 <h2><?php _e('Copying Your Backup To Remote Storage','updraftplus');?></h2>
3002
3003 <?php
3004 $debug_mode = (UpdraftPlus_Options::get_updraft_option('updraft_debug_mode')) ? 'checked="checked"' : "";
3005 // Should be one of s3, dropbox, ftp, googledrive, email, or whatever else is added
3006 $active_service = UpdraftPlus_Options::get_updraft_option('updraft_service');
3007 ?>
3008
3009 <table class="form-table" style="width:900px;">
3010 <tr>
3011 <th><?php _e('Choose your remote storage','updraftplus');?>:</th>
3012 <td><?php
3013
3014 if (false === apply_filters('updraftplus_storage_printoptions', false, $active_service)) {
3015 if (is_array($active_service)) $active_service = $updraftplus->just_one($active_service);
3016 ?>
3017
3018 <select name="updraft_service" id="updraft-service">
3019 <option value="none" <?php
3020 if ('none' === $active_service) echo ' selected="selected"'; ?>><?php _e('None','updraftplus'); ?></option>
3021 <?php
3022 foreach ($updraftplus->backup_methods as $method => $description) {
3023 echo "<option value=\"$method\"";
3024 if ($active_service === $method || (is_array($active_service) && in_array($method, $active_service))) echo ' selected="selected"';
3025 echo '>'.$description;
3026 echo "</option>\n";
3027 }
3028 ?>
3029 </select>
3030
3031 <?php echo '<p><a href="http://updraftplus.com/shop/morestorage/">'.htmlspecialchars(__('You can send a backup to more than one destination with an add-on.','updraftplus')).'</a></p>'; ?>
3032
3033 </td>
3034 </tr>
3035
3036 <?php } ?>
3037
3038 <tr class="updraftplusmethod none" style="display:none;">
3039 <td></td>
3040 <td><em><?php echo htmlspecialchars(__('If you choose no remote storage, then the backups remain on the web-server. This is not recommended (unless you plan to manually copy them to your computer), as losing the web-server would mean losing both your website and the backups in one event.', 'updraftplus'));?></em></td>
3041 </tr>
3042
3043 <?php
3044 $method_objects = array();
3045 foreach ($updraftplus->backup_methods as $method => $description) {
3046 do_action('updraftplus_config_print_before_storage', $method);
3047 require_once(UPDRAFTPLUS_DIR.'/methods/'.$method.'.php');
3048 $call_method = 'UpdraftPlus_BackupModule_'.$method;
3049 $method_objects[$method] = new $call_method;
3050 $method_objects[$method]->config_print();
3051 do_action('updraftplus_config_print_after_storage', $method);
3052 }
3053 ?>
3054
3055 </table>
3056 <script type="text/javascript">
3057 /* <![CDATA[ */
3058
3059 jQuery(document).ready(function() {
3060 <?php
3061 $really_is_writable = $updraftplus->really_is_writable($updraft_dir);
3062 if (!$really_is_writable) echo "jQuery('.backupdirrow').show();\n";
3063 ?>
3064 <?php
3065 if (!empty($active_service)) {
3066 if (is_array($active_service)) {
3067 foreach ($active_service as $serv) {
3068 echo "jQuery('.${serv}').show();\n";
3069 }
3070 } else {
3071 echo "jQuery('.${active_service}').show();\n";
3072 }
3073 } else {
3074 echo "jQuery('.none').show();\n";
3075 }
3076 foreach ($updraftplus->backup_methods as $method => $description) {
3077 // already done: require_once(UPDRAFTPLUS_DIR.'/methods/'.$method.'.php');
3078 $call_method = "UpdraftPlus_BackupModule_$method";
3079 if (method_exists($call_method, 'config_print_javascript_onready')) {
3080 $method_objects[$method]->config_print_javascript_onready();
3081 }
3082 }
3083 ?>
3084 });
3085 /* ]]> */
3086 </script>
3087 <table class="form-table" style="width:900px;">
3088 <tr>
3089 <td colspan="2"><h2><?php _e('Advanced / Debugging Settings','updraftplus'); ?></h2></td>
3090 </tr>
3091
3092 <tr>
3093 <th><?php _e('Expert settings','updraftplus');?>:</th>
3094 <td><a id="enableexpertmode" href="#enableexpertmode"><?php _e('Show expert settings','updraftplus');?></a> - <?php _e("click this to show some further options; don't bother with this unless you have a problem or are curious.",'updraftplus');?> <?php do_action('updraftplus_expertsettingsdescription'); ?></td>
3095 </tr>
3096 <?php
3097 $delete_local = UpdraftPlus_Options::get_updraft_option('updraft_delete_local', 1);
3098 $split_every_mb = UpdraftPlus_Options::get_updraft_option('updraft_split_every', 500);
3099 if (!is_numeric($split_every_mb)) $split_every_mb = 500;
3100 if ($split_every_mb < UPDRAFTPLUS_SPLIT_MIN) $split_every_mb = UPDRAFTPLUS_SPLIT_MIN;
3101 ?>
3102
3103 <tr class="expertmode" style="display:none;">
3104 <th><?php _e('Debug mode','updraftplus');?>:</th>
3105 <td><input type="checkbox" id="updraft_debug_mode" name="updraft_debug_mode" value="1" <?php echo $debug_mode; ?> /> <br><label for="updraft_debug_mode"><?php _e('Check this to receive more information and emails on the backup process - useful if something is going wrong.','updraftplus');?> <?php _e('This will also cause debugging output from all plugins to be shown upon this screen - please do not be surprised to see these.', 'updraftplus');?></label></td>
3106 </tr>
3107
3108 <tr class="expertmode" style="display:none;">
3109 <th><?php _e('Split archives every:','updraftplus');?></th>
3110 <td><input type="text" name="updraft_split_every" id="updraft_split_every" value="<?php echo $split_every_mb ?>" size="5" /> Mb<br><?php echo sprintf(__('UpdraftPlus will split up backup archives when they exceed this file size. The default value is %s megabytes. Be careful to leave some margin if your web-server has a hard size limit (e.g. the 2 Gb / 2048 Mb limit on some 32-bit servers/file systems).','updraftplus'), 500); ?></td>
3111 </tr>
3112
3113 <tr class="deletelocal expertmode" style="display:none;">
3114 <th><?php _e('Delete local backup','updraftplus');?>:</th>
3115 <td><input type="checkbox" id="updraft_delete_local" name="updraft_delete_local" value="1" <?php if ($delete_local) echo 'checked="checked"'; ?>> <br><label for="updraft_delete_local"><?php _e('Check this to delete any superfluous backup files from your server after the backup run finishes (i.e. if you uncheck, then any files despatched remotely will also remain locally, and any files being kept locally will not be subject to the retention limits).','updraftplus');?></label></td>
3116 </tr>
3117
3118 <tr class="expertmode backupdirrow" style="display:none;">
3119 <th><?php _e('Backup directory','updraftplus');?>:</th>
3120 <td><input type="text" name="updraft_dir" id="updraft_dir" style="width:525px" value="<?php echo htmlspecialchars($this->prune_updraft_dir_prefix($updraft_dir)); ?>" /></td>
3121 </tr>
3122 <tr class="expertmode backupdirrow" style="display:none;">
3123 <td></td><td><?php
3124
3125 if($really_is_writable) {
3126 $dir_info = '<span style="color:green">'.__('Backup directory specified is writable, which is good.','updraftplus').'</span>';
3127 } else {
3128 $dir_info = '<span style="color:red">';
3129 if (!is_dir($updraft_dir)) {
3130 $dir_info .= __('Backup directory specified does <b>not</b> exist.','updraftplus');
3131 } else {
3132 $dir_info .= __('Backup directory specified exists, but is <b>not</b> writable.','updraftplus');
3133 }
3134 $dir_info .= ' <span style="font-size:110%;font-weight:bold"><a href="'.UpdraftPlus_Options::admin_page_url().'?page=updraftplus&action=updraft_create_backup_dir&nonce='.wp_create_nonce('create_backup_dir').'">'.__('Click here to attempt to create the directory and set the permissions','updraftplus').'</a></span>, '.__('or, to reset this option','updraftplus').' <a href="#" onclick="jQuery(\'#updraft_dir\').val(\'updraft\'); return false;">'.__('click here','updraftplus').'</a>. '.__('If that is unsuccessful check the permissions on your server or change it to another directory that is writable by your web server process.','updraftplus').'</span>';
3135 }
3136
3137 echo $dir_info.' '.__("This is where UpdraftPlus will write the zip files it creates initially. This directory must be writable by your web server. It is relative to your content directory (which by default is called wp-content).", 'updraftplus').' '.__("<b>Do not</b> place it inside your uploads or plugins directory, as that will cause recursion (backups of backups of backups of...).",'updraftplus');?></td>
3138 </tr>
3139
3140 <tr class="expertmode" style="display:none;">
3141 <th><?php _e('Use the server\'s SSL certificates','updraftplus');?>:</th>
3142 <td><input type="checkbox" id="updraft_ssl_useservercerts" name="updraft_ssl_useservercerts" value="1" <?php if (UpdraftPlus_Options::get_updraft_option('updraft_ssl_useservercerts')) echo 'checked="checked"'; ?>> <br><label for="updraft_ssl_useservercerts"><?php _e('By default UpdraftPlus uses its own store of SSL certificates to verify the identity of remote sites (i.e. to make sure it is talking to the real Dropbox, Amazon S3, etc., and not an attacker). We keep these up to date. However, if you get an SSL error, then choosing this option (which causes UpdraftPlus to use your web server\'s collection instead) may help.','updraftplus');?></label></td>
3143 </tr>
3144
3145 <tr class="expertmode" style="display:none;">
3146 <th><?php _e('Do not verify SSL certificates','updraftplus');?>:</th>
3147 <td><input type="checkbox" id="updraft_ssl_disableverify" name="updraft_ssl_disableverify" value="1" <?php if (UpdraftPlus_Options::get_updraft_option('updraft_ssl_disableverify')) echo 'checked="checked"'; ?>> <br><label for="updraft_ssl_disableverify"><?php _e('Choosing this option lowers your security by stopping UpdraftPlus from verifying the identity of encrypted sites that it connects to (e.g. Dropbox, Google Drive). It means that UpdraftPlus will be using SSL only for encryption of traffic, and not for authentication.','updraftplus');?> <?php _e('Note that not all cloud backup methods are necessarily using SSL authentication.', 'updraftplus');?></label></td>
3148 </tr>
3149
3150 <tr class="expertmode" style="display:none;">
3151 <th><?php _e('Disable SSL entirely where possible', 'updraftplus');?>:</th>
3152 <td><input type="checkbox" id="updraft_ssl_nossl" name="updraft_ssl_nossl" value="1" <?php if (UpdraftPlus_Options::get_updraft_option('updraft_ssl_nossl')) echo 'checked="checked"'; ?>> <br><label for="updraft_ssl_nossl"><?php _e('Choosing this option lowers your security by stopping UpdraftPlus from using SSL for authentication and encrypted transport at all, where possible. Note that some cloud storage providers do not allow this (e.g. Dropbox), so with those providers this setting will have no effect.','updraftplus');?> <a href="http://updraftplus.com/faqs/i-get-ssl-certificate-errors-when-backing-up-andor-restoring/"><?php _e('See this FAQ also.', 'updraftplus');?></a></label></td>
3153 </tr>
3154
3155 <?php do_action('updraftplus_configprint_expertoptions'); ?>
3156
3157 <tr>
3158 <td></td>
3159 <td>
3160 <?php
3161 $ws_ad = $updraftplus->wordshell_random_advert(1);
3162 if ($ws_ad) {
3163 ?>
3164 <p style="margin: 10px 0; padding: 10px; font-size: 140%; background-color: lightYellow; border-color: #E6DB55; border: 1px solid; border-radius: 4px;">
3165 <?php echo $ws_ad; ?>
3166 </p>
3167 <?php
3168 }
3169 ?>
3170 </td>
3171 </tr>
3172 <tr>
3173 <td></td>
3174 <td>
3175 <input type="hidden" name="action" value="update" />
3176 <input type="submit" class="button-primary" value="<?php _e('Save Changes','updraftplus');?>" />
3177 </td>
3178 </tr>
3179 </table>
3180 <?php
3181 }
3182
3183 public function show_double_warning($text, $extraclass = '', $echo = true) {
3184
3185 $ret = "<div class=\"error updraftplusmethod $extraclass\"><p>$text</p></div>";
3186 $ret .= "<p style=\"border:1px solid; padding: 6px;\">$text</p>";
3187
3188 if ($echo) echo $ret;
3189 return $ret;
3190
3191 }
3192
3193 public function optionfilter_split_every($value) {
3194 $value = absint($value);
3195 if (!$value >= UPDRAFTPLUS_SPLIT_MIN) $value = UPDRAFTPLUS_SPLIT_MIN;
3196 return $value;
3197 }
3198
3199 public function curl_check($service, $has_fallback = false, $extraclass = '', $echo = true) {
3200
3201 $ret = '';
3202
3203 // Check requirements
3204 if (!function_exists("curl_init") || !function_exists('curl_exec')) {
3205
3206 $ret .= $this->show_double_warning('<strong>'.__('Warning','updraftplus').':</strong> '.sprintf(__('Your web server\'s PHP installation does not included a <strong>required</strong> (for %s) module (%s). Please contact your web hosting provider\'s support and ask for them to enable it.', 'updraftplus'), $service, 'Curl').' '.sprintf(__("Your options are 1) Install/enable %s or 2) Change web hosting companies - %s is a standard PHP component, and required by all cloud backup plugins that we know of.",'updraftplus'), 'Curl', 'Curl'), $extraclass, false);
3207
3208 } else {
3209 $curl_version = curl_version();
3210 $curl_ssl_supported= ($curl_version['features'] & CURL_VERSION_SSL);
3211 if (!$curl_ssl_supported) {
3212 if ($has_fallback) {
3213 $ret .= '<p><strong>'.__('Warning','updraftplus').':</strong> '.sprintf(__("Your web server's PHP/Curl installation does not support https access. Communications with %s will be unencrypted. ask your web host to install Curl/SSL in order to gain the ability for encryption (via an add-on).",'updraftplus'),$service).'</p>';
3214 } else {
3215 $ret .= $this->show_double_warning('<p><strong>'.__('Warning','updraftplus').':</strong> '.sprintf(__("Your web server's PHP/Curl installation does not support https access. We cannot access %s without this support. Please contact your web hosting provider's support. %s <strong>requires</strong> Curl+https. Please do not file any support requests; there is no alternative.",'updraftplus'),$service).'</p>', $extraclass, false);
3216 }
3217 } else {
3218 $ret .= '<p><em>'.sprintf(__("Good news: Your site's communications with %s can be encrypted. If you see any errors to do with encryption, then look in the 'Expert Settings' for more help.", 'updraftplus'),$service).'</em></p>';
3219 }
3220 }
3221 if ($echo) {
3222 echo $ret;
3223 } else {
3224 return $ret;
3225 }
3226 }
3227
3228 # If $basedirs is passed as an array, then $directorieses must be too
3229 private function recursive_directory_size($directorieses, $exclude = array(), $basedirs = '') {
3230
3231 $size = 0;
3232
3233 if (is_string($directorieses)) {
3234 $basedirs = $directorieses;
3235 $directorieses = array($directorieses);
3236 }
3237
3238 if (is_string($basedirs)) $basedirs = array($basedirs);
3239
3240 foreach ($directorieses as $ind => $directories) {
3241 if (!is_array($directories)) $directories=array($directories);
3242
3243 $basedir = empty($basedirs[$ind]) ? $basedirs[0] : $basedirs[$ind];
3244
3245 foreach ($directories as $dir) {
3246 if (is_file($dir)) {
3247 $size += @filesize($dir);
3248 } else {
3249 $suffix = ('' != $basedir) ? ((0 === strpos($dir, $basedir.'/')) ? substr($dir, 1+strlen($basedir)) : '') : '';
3250 $size += $this->recursive_directory_size_raw($basedir, $exclude, $suffix);
3251 }
3252 }
3253
3254 }
3255
3256 // foreach ($basedirs as $ind => $basedir) {
3257 //
3258 // $directories = $directorieses[$ind];
3259 // if (!is_array($directories)) $directories=array($directories);
3260 //
3261 // foreach ($directories as $dir) {
3262 // error_log($dir);
3263 // if (is_file($dir)) {
3264 // $size += @filesize($dir);
3265 // } else {
3266 // $suffix = ('' != $basedir) ? ((0 === strpos($dir, $basedir.'/')) ? substr($dir, 1+strlen($basedir)) : '') : '';
3267 // $size += $this->recursive_directory_size_raw($basedir, $exclude, $suffix);
3268 // }
3269 // }
3270 //
3271 // }
3272
3273 if ($size > 1073741824) {
3274 return round($size / 1073741824, 1).' Gb';
3275 } elseif ($size > 1048576) {
3276 return round($size / 1048576, 1).' Mb';
3277 } elseif ($size > 1024) {
3278 return round($size / 1024, 1).' Kb';
3279 } else {
3280 return round($size, 1).' b';
3281 }
3282
3283 }
3284
3285 private function recursive_directory_size_raw($prefix_directory, &$exclude = array(), $suffix_directory = '') {
3286
3287 $directory = $prefix_directory.('' == $suffix_directory ? '' : '/'.$suffix_directory);
3288 $size = 0;
3289 if(substr($directory, -1) == '/') $directory = substr($directory,0,-1);
3290
3291 if(!file_exists($directory) || !is_dir($directory) || !is_readable($directory)) return -1;
3292 if (file_exists($directory.'/.donotbackup')) return 0;
3293
3294 if($handle = opendir($directory)) {
3295 while (($file = readdir($handle)) !== false) {
3296 if ($file != '.' && $file != '..') {
3297 $spath = ('' == $suffix_directory) ? $file : $suffix_directory.'/'.$file;
3298 if (false !== ($fkey = array_search($spath, $exclude))) {
3299 unset($exclude[$fkey]);
3300 continue;
3301 }
3302 $path = $directory.'/'.$file;
3303 if(is_file($path)) {
3304 $size += filesize($path);
3305 } elseif(is_dir($path)) {
3306 $handlesize = $this->recursive_directory_size_raw($prefix_directory, $exclude, $suffix_directory.('' == $suffix_directory ? '' : '/').$file);
3307 if($handlesize >= 0) { $size += $handlesize; }# else { return -1; }
3308 }
3309 }
3310 }
3311 closedir($handle);
3312 }
3313
3314 return $size;
3315
3316 }
3317
3318 private function existing_backup_table($backup_history = false) {
3319
3320 global $updraftplus;
3321 $ret = '';
3322
3323 // Fetch it if it was not passed
3324 if (false === $backup_history) $backup_history = UpdraftPlus_Options::get_updraft_option('updraft_backup_history');
3325 if (!is_array($backup_history)) $backup_history=array();
3326
3327 $updraft_dir = $updraftplus->backups_dir_location();
3328
3329 $backupable_entities = $updraftplus->get_backupable_file_entities(true, true);
3330
3331 $ret .= '<table>';
3332
3333 $accept = apply_filters('updraftplus_accept_archivename', array());
3334 if (!is_array($accept)) $accept = array();
3335
3336 krsort($backup_history);
3337
3338 $nonce_field = wp_nonce_field('updraftplus_download', '_wpnonce', true, false);
3339
3340 if (empty($backup_history)) {
3341 $ret .= "<p><em>".__('You have not yet made any backups.', 'updraftplus')."</em></p>";
3342 }
3343
3344 foreach ($backup_history as $key=>$backup) {
3345 # https://core.trac.wordpress.org/ticket/25331
3346 # $pretty_date = date_i18n('Y-m-d G:i',$key);
3347 // Convert to blog time zone
3348 $pretty_date = get_date_from_gmt(gmdate('Y-m-d H:i:s', (int)$key), 'Y-m-d G:i');
3349
3350 $esc_pretty_date = esc_attr($pretty_date);
3351 $entities = '';
3352 $sval = ((isset($backup['service']) && $backup['service'] != 'email' && $backup['service'] != 'none')) ? '1' : '0';
3353 $title = __('Delete this backup set', 'updraftplus');
3354 $non = $backup['nonce'];
3355 $rawbackup = "<h2>$esc_pretty_date ($key)</h2><pre><p>".esc_attr(print_r($backup, true));
3356 if (!empty($non)) {
3357 $jd = $updraftplus->jobdata_getarray($non);
3358 if (!empty($jd) && is_array($jd)) {
3359 $rawbackup .= '</p><p>'.esc_attr(print_r($jd, true));
3360 }
3361 }
3362 $rawbackup .= '</p></pre>';
3363
3364 $jobdata = $updraftplus->jobdata_getarray($non);
3365 $datespan = apply_filters('updraftplus_showbackup_date', '<strong>'.$pretty_date.'</strong>', $backup, $jobdata);
3366
3367 $ret .= <<<ENDHERE
3368 <tr id="updraft_existing_backups_row_$key">
3369 <td><div class="updraftplus-remove" style="width: 19px; height: 19px; padding-top:0px; font-size: 18px; text-align:center;font-weight:bold; border-radius: 7px;"><a style="text-decoration:none;" href="javascript:updraft_delete('$key', '$non', $sval);" title="$title">×</a></div></td><td class="updraft_existingbackup_date" data-rawbackup="$rawbackup">$datespan
3370 ENDHERE;
3371
3372 # TODO: This probably isn't showing the right thing when an incremental backup finishes
3373 if (is_array($jobdata) && !empty($jobdata['resume_interval']) && (empty($jobdata['jobstatus']) || 'finished' != $jobdata['jobstatus'])) {
3374 $ret .= apply_filters('updraftplus_msg_unfinishedbackup', "<br><span title=\"".esc_attr(__('If you are seeing more backups than you expect, then it is probably because the deletion of old backup sets does not happen until a fresh backup completes.', 'updraftplus'))."\">".__('(Not finished)', 'updraftplus').'</span>', $jobdata, $non);
3375 }
3376
3377 $ret .= "</td>\n";
3378
3379 if (empty($backup['meta_foreign']) || !empty($accept[$backup['meta_foreign']]['separatedb'])) {
3380 $ret .= "<td>";
3381 if (isset($backup['db'])) {
3382 $entities .= '/db=0/';
3383 $sdescrip = preg_replace('/ \(.*\)$/', '', __('Database','updraftplus'));
3384
3385 if (!empty($backup['meta_foreign']) && isset($accept[$backup['meta_foreign']])) {
3386 $desc_source = $accept[$backup['meta_foreign']]['desc'];
3387 } else {
3388 $desc_source = __('unknown source', 'updraftplus');
3389 }
3390
3391 $dbt = empty($backup['meta_foreign']) ? __('Database','updraftplus') : sprintf(__('Database (created by %s)', 'updraftplus'), $desc_source);
3392
3393 $ret .= <<<ENDHERE
3394 <form id="uddownloadform_db_${key}_0" action="admin-ajax.php" onsubmit="return updraft_downloader('uddlstatus_', $key, 'db', '#ud_downloadstatus', '0', '$esc_pretty_date', true)" method="post">
3395 $nonce_field
3396 <input type="hidden" name="action" value="updraft_download_backup" />
3397 <input type="hidden" name="type" value="db" />
3398 <input type="hidden" name="timestamp" value="$key" />
3399 <input type="submit" value="$dbt" />
3400 </form>
3401 ENDHERE;
3402 } else {
3403 $ret .= sprintf(_x('(No %s)','Message shown when no such object is available','updraftplus'), __('database', 'updraftplus'));
3404 }
3405 # External databases
3406 foreach ($backup as $bkey => $binfo) {
3407 if ('db' == $bkey || 'db' != substr($bkey, 0, 2) || '-size' == substr($bkey, -5, 5)) continue;
3408 $dbt = __('External database','updraftplus').' ('.substr($bkey, 2).')';
3409 $ret .= <<<ENDHERE
3410 <form id="uddownloadform_${bkey}_${key}_0" action="admin-ajax.php" onsubmit="return updraft_downloader('uddlstatus_', $key, '$bkey', '#ud_downloadstatus', '0', '$esc_pretty_date', true)" method="post">
3411 $nonce_field
3412 <input type="hidden" name="action" value="updraft_download_backup" />
3413 <input type="hidden" name="type" value="$bkey" />
3414 <input type="hidden" name="timestamp" value="$key" />
3415 <input type="submit" value="$dbt" />
3416 </form>
3417 ENDHERE;
3418 }
3419 $ret .="</td>";
3420 } else {
3421 # Foreign without separate db
3422 $entities = '/db=0/meta_foreign=1/';
3423 }
3424
3425 if (!empty($backup['meta_foreign']) && !empty($accept[$backup['meta_foreign']]) && !empty($accept[$backup['meta_foreign']]['separatedb'])) {
3426 $entities .= '/meta_foreign=2/';
3427 }
3428
3429 // Now go through each of the file entities
3430 foreach ($backupable_entities as $type => $info) {
3431 if (!empty($backup['meta_foreign']) && 'wpcore' != $type) continue;
3432 $colspan = 1;
3433 if (!empty($backup['meta_foreign'])) {
3434 $colspan = (1+count($backupable_entities));
3435 if (empty($accept[$backup['meta_foreign']]['separatedb'])) $colspan++;
3436 }
3437 $ret .= (1 == $colspan) ? '<td>' : '<td colspan="'.$colspan.'">';
3438 $ide = '';
3439 if ('wpcore' == $type) $wpcore_restore_descrip = $info['description'];
3440 if (empty($backup['meta_foreign'])) {
3441 $sdescrip = preg_replace('/ \(.*\)$/', '', $info['description']);
3442 if (strlen($sdescrip) > 20 && isset($info['shortdescription'])) $sdescrip = $info['shortdescription'];
3443 } else {
3444 $info['description'] = 'WordPress';
3445
3446 if (isset($accept[$backup['meta_foreign']])) {
3447 $desc_source = $accept[$backup['meta_foreign']]['desc'];
3448 $ide .= sprintf(__('Backup created by: %s.', 'updraftplus'), $accept[$backup['meta_foreign']]['desc']).' ';
3449 } else {
3450 $desc_source = __('unknown source', 'updraftplus');
3451 $ide .= __('Backup created by unknown source (%s) - cannot be restored.', 'updraftplus').' ';
3452 }
3453
3454
3455 $sdescrip = (empty($accept[$backup['meta_foreign']]['separatedb'])) ? sprintf(__('Files and database WordPress backup (created by %s)', 'updraftplus'), $desc_source) : sprintf(__('Files backup (created by %s)', 'updraftplus'), $desc_source);
3456 if ('wpcore' == $type) $wpcore_restore_descrip = $sdescrip;
3457 }
3458 if (isset($backup[$type])) {
3459 if (!is_array($backup[$type])) $backup[$type]=array($backup[$type]);
3460 $howmanyinset = count($backup[$type]);
3461 $expected_index = 0;
3462 $index_missing = false;
3463 $set_contents = '';
3464 $entities .= "/$type=";
3465 $whatfiles = $backup[$type];
3466 ksort($whatfiles);
3467 foreach ($whatfiles as $findex => $bfile) {
3468 $set_contents .= ($set_contents == '') ? $findex : ",$findex";
3469 if ($findex != $expected_index) $index_missing = true;
3470 $expected_index++;
3471 }
3472 $entities .= $set_contents.'/';
3473 if (!empty($backup['meta_foreign'])) {
3474 $entities .= '/plugins=0//themes=0//uploads=0//others=0/';
3475 }
3476 $first_printed = true;
3477 foreach ($whatfiles as $findex => $bfile) {
3478 $ide .= __('Press here to download', 'updraftplus').' '.strtolower($info['description']);
3479 $pdescrip = ($findex > 0) ? $sdescrip.' ('.($findex+1).')' : $sdescrip;
3480 if (!$first_printed) {
3481 $ret .= '<div style="display:none;">';
3482 }
3483 if (count($backup[$type]) >0) {
3484 $ide .= ' '.sprintf(__('(%d archive(s) in set).', 'updraftplus'), $howmanyinset);
3485 }
3486 if ($index_missing) {
3487 $ide .= ' '.__('You appear to be missing one or more archives from this multi-archive set.', 'updraftplus');
3488 }
3489 $ret .= <<<ENDHERE
3490 <form id="uddownloadform_${type}_${key}_${findex}" action="admin-ajax.php" onsubmit="return updraft_downloader('uddlstatus_', '$key', '$type', '#ud_downloadstatus', '$set_contents', '$esc_pretty_date', true)" method="post">
3491 $nonce_field
3492 <input type="hidden" name="action" value="updraft_download_backup" />
3493 <input type="hidden" name="type" value="$type" />
3494 <input type="hidden" name="timestamp" value="$key" />
3495 <input type="hidden" name="findex" value="$findex" />
3496 <input type="submit" title="$ide" value="$pdescrip" />
3497 </form>
3498 ENDHERE;
3499 if (!$first_printed) {
3500 $ret .= '</div>';
3501 } else {
3502 $first_printed = false;
3503 }
3504 }
3505 } else {
3506 $ret .= sprintf(_x('(No %s)','Message shown when no such object is available','updraftplus'), preg_replace('/\s\(.{12,}\)/', '', strtolower($sdescrip)));
3507 }
3508 $ret .= '</td>';
3509 };
3510 if (empty($backup['meta_foreign'])) {
3511 $ret .= '<td>';
3512 if (isset($backup['nonce']) && preg_match("/^[0-9a-f]{12}$/",$backup['nonce']) && is_readable($updraft_dir.'/log.'.$backup['nonce'].'.txt')) {
3513 $nval = $backup['nonce'];
3514 $lt = esc_attr(__('Backup Log','updraftplus'));
3515 $url = UpdraftPlus_Options::admin_page();
3516 $ret .= <<<ENDHERE
3517 <form action="$url" method="get">
3518 <input type="hidden" name="action" value="downloadlog" />
3519 <input type="hidden" name="page" value="updraftplus" />
3520 <input type="hidden" name="updraftplus_backup_nonce" value="$nval" />
3521 <input type="submit" value="$lt" class="updraft-log-link" onclick="event.preventDefault(); updraft_popuplog('$nval');" />
3522 </form>
3523 ENDHERE;
3524 } else {
3525 $ret .= "(No&nbsp;backup&nbsp;log)";
3526 }
3527 $ret .= "</td>";
3528 }
3529
3530 $ret .= <<<ENDHERE
3531 <td>
3532 <form method="post" action="">
3533 <input type="hidden" name="backup_timestamp" value="$key">
3534 <input type="hidden" name="action" value="updraft_restore" />
3535 ENDHERE;
3536 if ($entities) {
3537 $show_data = $pretty_date;
3538 if (isset($backup['native']) && false == $backup['native']) {
3539 $show_data .= ' '.__('(backup set imported from remote storage)', 'updraftplus');
3540 }
3541 # jQuery('#updraft_restore_label_wpcore').html('".esc_js($wpcore_restore_descrip)."');
3542 $ret .= '<button title="'.__('After pressing this button, you will be given the option to choose which components you wish to restore','updraftplus').'" type="button" class="button-primary" style="padding-top:2px;padding-bottom:2px;font-size:16px !important; min-height:26px;" onclick="'."updraft_restore_setoptions('$entities');
3543 jQuery('#updraft_restore_timestamp').val('$key'); jQuery('.updraft_restore_date').html('$show_data'); ";
3544 $ret .= "updraft_restore_stage = 1; jQuery('#updraft-restore-modal').dialog('open'); jQuery('#updraft-restore-modal-stage1').show();jQuery('#updraft-restore-modal-stage2').hide(); jQuery('#updraft-restore-modal-stage2a').html(''); updraft_activejobs_update(true);\">".__('Restore', 'updraftplus').'</button>';
3545 }
3546 $ret .= <<<ENDHERE
3547 </form>
3548 </td>
3549 </tr>
3550 ENDHERE;
3551 }
3552 $ret .= '</table>';
3553 return $ret;
3554 }
3555
3556 // This function examines inside the updraft directory to see if any new archives have been uploaded. If so, it adds them to the backup set. (Non-present items are also removed, only if the service is 'none').
3557 // If $remotescan is set, then remote storage is also scanned
3558 public function rebuild_backup_history($remotescan = false) {
3559
3560 # TODO: Make compatible with incremental naming scheme
3561
3562 global $updraftplus;
3563 $messages = array();
3564 $gmt_offset = get_option('gmt_offset');
3565
3566 # Array of nonces keyed by filename
3567 $known_files = array();
3568 # Array of backup times keyed by nonce
3569 $known_nonces = array();
3570 $changes = false;
3571
3572 $backupable_entities = $updraftplus->get_backupable_file_entities(true, false);
3573
3574 $backup_history = UpdraftPlus_Options::get_updraft_option('updraft_backup_history');
3575 if (!is_array($backup_history)) $backup_history = array();
3576 $updraft_dir = $updraftplus->backups_dir_location();
3577 if (!is_dir($updraft_dir)) return;
3578
3579 $accept = apply_filters('updraftplus_accept_archivename', array());
3580 if (!is_array($accept)) $accept = array();
3581 // Process what is known from the database backup history; this means populating $known_files and $known_nonces
3582 foreach ($backup_history as $btime => $bdata) {
3583 $found_file = false;
3584 foreach ($bdata as $key => $values) {
3585 if ('db' != $key && !isset($backupable_entities[$key])) continue;
3586 // Record which set this file is found in
3587 if (!is_array($values)) $values=array($values);
3588 foreach ($values as $val) {
3589 if (!is_string($val)) continue;
3590 if (preg_match('/^backup_([\-0-9]{15})_.*_([0-9a-f]{12})-[\-a-z]+([0-9]+(of[0-9]+)?)?+\.(zip|gz|gz\.crypt)$/i', $val, $matches)) {
3591 $nonce = $matches[2];
3592 if (isset($bdata['service']) && ($bdata['service'] === 'none' || (is_array($bdata['service']) && array('none') === $bdata['service'])) && !is_file($updraft_dir.'/'.$val)) {
3593 # File without remote storage is no longer present
3594 } else {
3595 $found_file = true;
3596 $known_files[$val] = $nonce;
3597 $known_nonces[$nonce] = (empty($known_nonces[$nonce]) || $known_nonces[$nonce]<100) ? $btime : min($btime, $known_nonces[$nonce]);
3598 }
3599 } else {
3600 $accepted = false;
3601 foreach ($accept as $fkey => $acc) {
3602 if (preg_match('/'.$acc['pattern'].'/i', $val)) $accepted = $fkey;
3603 }
3604 if (!empty($accepted) && (false != ($btime = apply_filters('updraftplus_foreign_gettime', false, $fkey, $val))) && $btime > 0) {
3605 $found_file = true;
3606 # Generate a nonce; this needs to be deterministic and based on the filename only
3607 $nonce = substr(md5($val), 0, 12);
3608 $known_files[$val] = $nonce;
3609 $known_nonces[$nonce] = (empty($known_nonces[$nonce]) || $known_nonces[$nonce]<100) ? $btime : min($btime, $known_nonces[$nonce]);
3610 }
3611 }
3612 }
3613 }
3614 if (!$found_file) {
3615 # File recorded as being without remote storage is no longer present - though it may in fact exist in remote storage, and this will be picked up later
3616 unset($backup_history[$btime]);
3617 $changes = true;
3618 }
3619 }
3620
3621 $remotefiles = array();
3622 $remotesizes = array();
3623 # Scan remote storage and get back lists of files and their sizes
3624 # TODO: Make compatible with incremental naming
3625 if ($remotescan) {
3626 add_action('http_request_args', array($updraftplus, 'modify_http_options'));
3627 foreach ($updraftplus->backup_methods as $method => $desc) {
3628 require_once(UPDRAFTPLUS_DIR.'/methods/'.$method.'.php');
3629 $objname = 'UpdraftPlus_BackupModule_'.$method;
3630 $obj = new $objname;
3631 if (!method_exists($obj, 'listfiles')) continue;
3632 $files = $obj->listfiles('backup_');
3633 if (is_array($files)) {
3634 foreach ($files as $entry) {
3635 $n = $entry['name'];
3636 if (!preg_match('/^backup_([\-0-9]{15})_.*_([0-9a-f]{12})-([\-a-z]+)([0-9]+(of[0-9]+)?)?\.(zip|gz|gz\.crypt)$/i', $n, $matches)) continue;
3637 if (isset($remotefiles[$n])) {
3638 $remotefiles[$n][] = $method;
3639 } else {
3640 $remotefiles[$n] = array($method);
3641 }
3642 if (!empty($entry['size'])) {
3643 if (empty($remotesizes[$n]) || $remotesizes[$n] < $entry['size']) $remotesizes[$n] = $entry['size'];
3644 }
3645 }
3646 } elseif (is_wp_error($files)) {
3647 foreach ($files->get_error_codes() as $code) {
3648 if ('no_settings' == $code || 'no_addon' == $code || 'insufficient_php' == $code) continue;
3649 $messages[] = array(
3650 'method' => $method,
3651 'desc' => $desc,
3652 'code' => $code,
3653 'message' => $files->get_error_message($code)
3654 );
3655 }
3656 }
3657 }
3658 remove_action('http_request_args', array($updraftplus, 'modify_http_options'));
3659 }
3660
3661 if (!$handle = opendir($updraft_dir)) return;
3662
3663 // See if there are any more files in the local directory than the ones already known about
3664 while (false !== ($entry = readdir($handle))) {
3665 $accepted_foreign = false;
3666 $potmessage = false;
3667 if ('.' == $entry || '..' == $entry) continue;
3668 # TODO: Make compatible with Incremental naming
3669 if (preg_match('/^backup_([\-0-9]{15})_.*_([0-9a-f]{12})-([\-a-z]+)([0-9]+(of[0-9]+)?)?\.(zip|gz|gz\.crypt)$/i', $entry, $matches)) {
3670
3671 // Interpret the time as one from the blog's local timezone, rather than as UTC
3672 # $matches[1] is YYYY-MM-DD-HHmm, to be interpreted as being the local timezone
3673 $btime2 = strtotime($matches[1]);
3674 $btime = (!empty($offset)) ? $btime2 - $gmt_offset*3600 : $btime2;
3675
3676 $nonce = $matches[2];
3677 $type = $matches[3];
3678 if ('db' == $type) {
3679 $type .= $matches[4];
3680 $index = 0;
3681 } else {
3682 $index = (empty($matches[4])) ? '0' : (max((int)$matches[4]-1,0));
3683 }
3684 $itext = ($index == 0) ? '' : $index;
3685 } elseif (false != ($accepted_foreign = apply_filters('updraftplus_accept_foreign', false, $entry)) && false !== ($btime = apply_filters('updraftplus_foreign_gettime', false, $accepted_foreign, $entry))) {
3686 $nonce = substr(md5($entry), 0, 12);
3687 $type = (preg_match('/\.sql(\.(bz2|gz))?$/i', $entry) || preg_match('/-database-([-0-9]+)\.zip$/i', $entry)) ? 'db' : 'wpcore';
3688 $index = '0';
3689 $itext = '';
3690 $potmessage = array(
3691 'code' => 'foundforeign_'.md5($entry),
3692 'desc' => $entry,
3693 'method' => '',
3694 'message' => sprintf(__('Backup created by: %s.', 'updraftplus'), $accept[$accepted_foreign]['desc'])
3695 );
3696 } elseif ('.zip' == strtolower(substr($entry, -4, 4)) || preg_match('/\.sql(\.(bz2|gz))?$/i', $entry)) {
3697 $potmessage = array(
3698 'code' => 'possibleforeign_'.md5($entry),
3699 'desc' => $entry,
3700 'method' => '',
3701 'message' => __('This file does not appear to be an UpdraftPlus backup archive (such files are .zip or .gz files which have a name like: backup_(time)_(site name)_(code)_(type).(zip|gz)).', 'updraftplus').' <a href="http://updraftplus.com/shop/updraftplus-premium/">'.__('If this is a backup created by a different backup plugin, then UpdraftPlus Premium may be able to help you.', 'updraftplus').'</a>'
3702 );
3703 $messages[$potmessage['code']] = $potmessage;
3704 continue;
3705 } else {
3706 continue;
3707 }
3708 // The time from the filename does not include seconds. Need to identify the seconds to get the right time
3709 if (isset($known_nonces[$nonce])) {
3710 $btime_exact = $known_nonces[$nonce];
3711 # TODO: If the btime we had was more than 60 seconds earlier, then this must be an increment - we then need to change the $backup_history array accordingly. We can pad the '60 second' test, as there's no option to run an increment more frequently than every 4 hours (though someone could run one manually from the CLI)
3712 if ($btime > 100 && $btime_exact - $btime > 60 && !empty($backup_history[$btime_exact])) {
3713 # TODO: This needs testing
3714 # The code below assumes that $backup_history[$btime] is presently empty
3715 # Re-key array, indicating the newly-found time to be the start of the backup set
3716 $backup_history[$btime] = $backup_history[$btime_exact];
3717 unset($backup_history[$btime_exact]);
3718 $btime_exact = $btime;
3719 }
3720 $btime = $btime_exact;
3721 }
3722 if ($btime <= 100) continue;
3723 $fs = @filesize($updraft_dir.'/'.$entry);
3724
3725 if (!isset($known_files[$entry])) {
3726 $changes = true;
3727 if (is_array($potmessage)) $messages[$potmessage['code']] = $potmessage;
3728 }
3729
3730 # TODO: Code below here has not been reviewed or adjusted for compatibility with incremental backups
3731 # Make sure we have the right list of services
3732 $current_services = (!empty($backup_history[$btime]) && !empty($backup_history[$btime]['service'])) ? $backup_history[$btime]['service'] : array();
3733 if (is_string($current_services)) $current_services = array($current_services);
3734 if (!is_array($current_services)) $current_services = array();
3735 if (!empty($remotefiles[$entry])) {
3736 if (0 == count(array_diff($current_services, $remotefiles[$entry]))) {
3737 $backup_history[$btime]['service'] = $remotefiles[$entry];
3738 $changes = true;
3739 }
3740 # Get the right size (our local copy may be too small)
3741 foreach ($remotefiles[$entry] as $rem) {
3742 if (!empty($rem['size']) && $rem['size'] > $fs) {
3743 $fs = $rem['size'];
3744 $changes = true;
3745 }
3746 }
3747 # Remove from $remotefiles, so that we can later see what was left over
3748 unset($remotefiles[$entry]);
3749 } else {
3750 # Not known remotely
3751 if (!empty($backup_history[$btime])) {
3752 if (empty($backup_history[$btime]['service']) || ('none' !== $backup_history[$btime]['service'] && '' !== $backup_history[$btime]['service'] && array('none') !== $backup_history[$btime]['service'])) {
3753 $backup_history[$btime]['service'] = 'none';
3754 $changes = true;
3755 }
3756 } else {
3757 $backup_history[$btime]['service'] = 'none';
3758 $changes = true;
3759 }
3760 }
3761
3762 $backup_history[$btime][$type][$index] = $entry;
3763 if ($fs > 0) $backup_history[$btime][$type.$itext.'-size'] = $fs;
3764 $backup_history[$btime]['nonce'] = $nonce;
3765 if (!empty($accepted_foreign)) $backup_history[$btime]['meta_foreign'] = $accepted_foreign;
3766 }
3767
3768 # Any found in remote storage that we did not previously know about?
3769 # Compare $remotefiles with $known_files / $known_nonces, and adjust $backup_history
3770 if (count($remotefiles) > 0) {
3771
3772 # $backup_history[$btime]['nonce'] = $nonce
3773 foreach ($remotefiles as $file => $services) {
3774 if (!preg_match('/^backup_([\-0-9]{15})_.*_([0-9a-f]{12})-([\-a-z]+)([0-9]+(of[0-9]+)?)?\.(zip|gz|gz\.crypt)$/i', $file, $matches)) continue;
3775 $nonce = $matches[2];
3776 $type = $matches[3];
3777 if ('db' == $type) {
3778 $index = 0;
3779 $type .= $matches[4];
3780 } else {
3781 $index = (empty($matches[4])) ? '0' : (max((int)$matches[4]-1,0));
3782 }
3783 $itext = ($index == 0) ? '' : $index;
3784 $btime2 = strtotime($matches[1]);
3785 $btime = (!empty($offset)) ? $btime2 - $gmt_offset*3600 : $btime2;
3786
3787 if (isset($known_nonces[$nonce])) $btime = $known_nonces[$nonce];
3788 if ($btime <= 100) continue;
3789 # Remember that at this point, we already know that the file is not known about locally
3790 if (isset($backup_history[$btime])) {
3791 if (!isset($backup_history[$btime]['service']) || ((is_array($backup_history[$btime]['service']) && $backup_history[$btime]['service'] !== $services) || is_string($backup_history[$btime]['service']) && (1 != count($services) || $services[0] !== $backup_history[$btime]['service']))) {
3792 $changes = true;
3793 $backup_history[$btime]['service'] = $services;
3794 $backup_history[$btime]['nonce'] = $nonce;
3795 }
3796 if (!isset($backup_history[$btime][$type][$index])) {
3797 $changes = true;
3798 $backup_history[$btime][$type][$index] = $file;
3799 $backup_history[$btime]['nonce'] = $nonce;
3800 if (!empty($remotesizes[$file])) $backup_history[$btime][$type.$itext.'-size'] = $remotesizes[$file];
3801 }
3802 } else {
3803 $changes = true;
3804 $backup_history[$btime]['service'] = $services;
3805 $backup_history[$btime][$type][$index] = $file;
3806 $backup_history[$btime]['nonce'] = $nonce;
3807 if (!empty($remotesizes[$file])) $backup_history[$btime][$type.$itext.'-size'] = $remotesizes[$file];
3808 $backup_history[$btime]['native'] = false;
3809 $messages['nonnative'] = array(
3810 'message' => __('One or more backups has been added from scanning remote storage; note that these backups will not be automatically deleted through the "retain" settings; if/when you wish to delete them then you must do so manually.', 'updraftplus'),
3811 'code' => 'nonnative',
3812 'desc' => '',
3813 'method' => ''
3814 );
3815 }
3816
3817 }
3818 }
3819
3820 if ($changes) UpdraftPlus_Options::update_updraft_option('updraft_backup_history', $backup_history);
3821
3822 return $messages;
3823
3824 }
3825
3826 // Return values: false = 'not yet' (not necessarily terminal); WP_Error = terminal failure; true = success
3827 private function restore_backup($timestamp) {
3828
3829 @set_time_limit(900);
3830
3831 global $wp_filesystem, $updraftplus;
3832 $backup_history = UpdraftPlus_Options::get_updraft_option('updraft_backup_history');
3833 if(!is_array($backup_history[$timestamp])) {
3834 echo '<p>'.__('This backup does not exist in the backup history - restoration aborted. Timestamp:','updraftplus')." $timestamp</p><br/>";
3835 return new WP_Error('does_not_exist', __('Backup does not exist in the backup history', 'updraftplus'));
3836 }
3837
3838 // request_filesystem_credentials passes on fields just via hidden name/value pairs.
3839 // Build array of parameters to be passed via this
3840 $extra_fields = array();
3841 if (isset($_POST['updraft_restore']) && is_array($_POST['updraft_restore'])) {
3842 foreach ($_POST['updraft_restore'] as $entity) {
3843 $_POST['updraft_restore_'.$entity] = 1;
3844 $extra_fields[] = 'updraft_restore_'.$entity;
3845 }
3846 }
3847 // Now make sure that updraft_restorer_ option fields get passed along to request_filesystem_credentials
3848 foreach ($_POST as $key => $value) {
3849 if (0 === strpos($key, 'updraft_restorer_')) $extra_fields[] = $key;
3850 }
3851
3852 $credentials = request_filesystem_credentials(UpdraftPlus_Options::admin_page()."?page=updraftplus&action=updraft_restore&backup_timestamp=$timestamp", '', false, false, $extra_fields);
3853 WP_Filesystem($credentials);
3854 if ( $wp_filesystem->errors->get_error_code() ) {
3855 echo '<p><em><a href="http://updraftplus.com/faqs/asked-ftp-details-upon-restorationmigration-updates/">'.__('Why am I seeing this?', 'updraftplus').'</a></em></p>';
3856 foreach ( $wp_filesystem->errors->get_error_messages() as $message ) show_message($message);
3857 exit;
3858 }
3859
3860 # Set up logging
3861 $updraftplus->backup_time_nonce();
3862 $updraftplus->jobdata_set('job_type', 'restore');
3863 $updraftplus->jobdata_set('job_time_ms', $updraftplus->job_time_ms);
3864 $updraftplus->logfile_open($updraftplus->nonce);
3865
3866 # Provide download link for the log file
3867
3868 #echo '<p><a target="_new" href="?action=downloadlog&page=updraftplus&updraftplus_backup_nonce='.htmlspecialchars($updraftplus->nonce).'">'.__('Follow this link to download the log file for this restoration.', 'updraftplus').'</a></p>';
3869
3870 # TODO: Automatic purging of old log files
3871 # TODO: Provide option to auto-email the log file
3872
3873 //if we make it this far then WP_Filesystem has been instantiated and is functional (tested with ftpext, what about suPHP and other situations where direct may work?)
3874 echo '<h1>'.__('UpdraftPlus Restoration: Progress', 'updraftplus').'</h1><div id="updraft-restore-progress">';
3875
3876 $this->show_admin_warning('<a target="_new" href="?action=downloadlog&page=updraftplus&updraftplus_backup_nonce='.htmlspecialchars($updraftplus->nonce).'">'.__('Follow this link to download the log file for this restoration (needed for any support requests).', 'updraftplus').'</a>');
3877
3878 $updraft_dir = trailingslashit($updraftplus->backups_dir_location());
3879 $foreign_known = apply_filters('updraftplus_accept_archivename', array());
3880
3881 $service = (isset($backup_history[$timestamp]['service'])) ? $backup_history[$timestamp]['service'] : false;
3882 if (!is_array($service)) $service = array($service);
3883
3884 // Now, need to turn any updraft_restore_<entity> fields (that came from a potential WP_Filesystem form) back into parts of the _POST array (which we want to use)
3885 if (empty($_POST['updraft_restore']) || (!is_array($_POST['updraft_restore']))) $_POST['updraft_restore'] = array();
3886
3887 $backup_set = $backup_history[$timestamp];
3888 $entities_to_restore = array();
3889 foreach ($_POST['updraft_restore'] as $entity) {
3890 if (empty($backup_set['meta_foreign'])) {
3891 $entities_to_restore[$entity] = $entity;
3892 } else {
3893 if ('db' == $entity && !empty($foreign_known[$backup_set['meta_foreign']]) && !empty($foreign_known[$backup_set['meta_foreign']]['separatedb'])) {
3894 $entities_to_restore[$entity] = 'db';
3895 } else {
3896 $entities_to_restore[$entity] = 'wpcore';
3897 }
3898 }
3899 }
3900
3901 foreach ($_POST as $key => $value) {
3902 if (0 === strpos($key, 'updraft_restore_')) {
3903 $nkey = substr($key, 16);
3904 if (!isset($entities_to_restore[$nkey])) {
3905 $_POST['updraft_restore'][] = $nkey;
3906 if (empty($backup_set['meta_foreign'])) {
3907 $entities_to_restore[$nkey] = $nkey;
3908 } else {
3909 if ('db' == $entity && !empty($foreign_known[$backup_set['meta_foreign']]['separatedb'])) {
3910 $entities_to_restore[$nkey] = 'db';
3911 } else {
3912 $entities_to_restore[$nkey] = 'wpcore';
3913 }
3914 }
3915 }
3916 }
3917 }
3918
3919 if (0 == count($_POST['updraft_restore'])) {
3920 echo '<p>'.__('ABORT: Could not find the information on which entities to restore.', 'updraftplus').'</p>';
3921 echo '<p>'.__('If making a request for support, please include this information:','updraftplus').' '.count($_POST).' : '.htmlspecialchars(serialize($_POST)).'</p>';
3922 return new WP_Error('missing_info', 'Backup information not found');
3923 }
3924
3925 $updraftplus->log("Restore job started. Entities to restore: ".implode(', ', array_flip($entities_to_restore)));
3926
3927 set_error_handler(array($updraftplus, 'php_error'), E_ALL & ~E_STRICT);
3928
3929 /*
3930 $_POST['updraft_restore'] is typically something like: array( 0=>'db', 1=>'plugins', 2=>'themes'), etc.
3931 i.e. array ( 'db', 'plugins', themes')
3932 */
3933
3934 $backupable_entities = $updraftplus->get_backupable_file_entities(true, true);
3935
3936 uksort($backup_set, array($this, 'sort_restoration_entities'));
3937
3938 // We use a single object for each entity, because we want to store information about the backup set
3939 require_once(UPDRAFTPLUS_DIR.'/restorer.php');
3940
3941 global $updraftplus_restorer;
3942 $updraftplus_restorer = new Updraft_Restorer(new Updraft_Restorer_Skin, $backup_set);
3943
3944 $second_loop = array();
3945
3946 echo "<h2>".__('Final checks', 'updraftplus').'</h2>';
3947
3948 if (empty($backup_set['meta_foreign'])) {
3949 $entities_to_download = $entities_to_restore;
3950 } else {
3951 if (!empty($foreign_known[$backup_set['meta_foreign']]['separatedb'])) {
3952 $entities_to_download = array();
3953 if (in_array('db', $entities_to_restore)) {
3954 $entities_to_download['db'] = 1;
3955 }
3956 if (count($entities_to_restore) > 1 || !in_array('db', $entities_to_restore)) {
3957 $entities_to_download['wpcore'] = 1;
3958 }
3959 } else {
3960 $entities_to_download = array('wpcore' => 1);
3961 }
3962 }
3963
3964 // First loop: make sure that files are present + readable; and populate array for second loop
3965 foreach ($backup_set as $type => $files) {
3966 // All restorable entities must be given explicitly, as we can store other arbitrary data in the history array
3967 if (!isset($backupable_entities[$type]) && 'db' != $type) continue;
3968 if (isset($backupable_entities[$type]['restorable']) && $backupable_entities[$type]['restorable'] == false) continue;
3969
3970 if (!isset($entities_to_download[$type])) continue;
3971 if ('wpcore' == $type && is_multisite() && 0 === $updraftplus_restorer->ud_backup_is_multisite) {
3972 echo "<p>$type: <strong>";
3973 echo __('Skipping restoration of WordPress core when importing a single site into a multisite installation. If you had anything necessary in your WordPress directory then you will need to re-add it manually from the zip file.', 'updraftplus');
3974 #TODO
3975 #$updraftplus->log_e('Skipping restoration of WordPress core when importing a single site into a multisite installation. If you had anything necessary in your WordPress directory then you will need to re-add it manually from the zip file.');
3976 echo "</strong></p>";
3977 continue;
3978 }
3979
3980 if (is_string($files)) $files=array($files);
3981
3982 foreach ($files as $ind => $file) {
3983 $fullpath = $updraft_dir.$file;
3984 echo sprintf(__("Looking for %s archive: file name: %s", 'updraftplus'), $type, htmlspecialchars($file))."<br>";
3985
3986 add_action('http_request_args', array($updraftplus, 'modify_http_options'));
3987 foreach ($service as $serv) {
3988 if(!is_readable($fullpath)) {
3989 $sd = (empty($updraftplus->backup_methods[$serv])) ? $serv : $updraftplus->backup_methods[$serv];
3990 echo __("File is not locally present - needs retrieving from remote storage",'updraftplus')." ($sd)";
3991 $this->download_file($file, $serv);
3992 echo ": ";
3993 if (!is_readable($fullpath)) {
3994 echo __("Error", 'updraftplus');
3995 } else {
3996 echo __("OK", 'updraftplus');
3997 }
3998 echo '<br>';
3999 }
4000 }
4001 remove_action('http_request_args', array($updraftplus, 'modify_http_options'));
4002
4003 $index = ($ind == 0) ? '' : $ind;
4004 // If a file size is stored in the backup data, then verify correctness of the local file
4005 if (isset($backup_history[$timestamp][$type.$index.'-size'])) {
4006 $fs = $backup_history[$timestamp][$type.$index.'-size'];
4007 echo __("Archive is expected to be size:",'updraftplus')." ".round($fs/1024, 1)." Kb: ";
4008 $as = @filesize($fullpath);
4009 if ($as == $fs) {
4010 echo __('OK','updraftplus').'<br>';
4011 } else {
4012 echo "<strong>".__('Error:','updraftplus')."</strong> ".__('file is size:', 'updraftplus')." ".round($as/1024)." ($fs, $as)<br>";
4013 }
4014 } else {
4015 echo __("The backup records do not contain information about the proper size of this file.",'updraftplus')."<br>";
4016 }
4017 if (!is_readable($fullpath)) {
4018 echo __('Could not find one of the files for restoration', 'updraftplus')." ($file)<br>";
4019 $updraftplus->log("$file: ".__('Could not find one of the files for restoration', 'updraftplus'), 'error');
4020 echo '</div>';
4021 restore_error_handler();
4022 return false;
4023 }
4024 }
4025
4026 if (empty($updraftplus_restorer->ud_foreign)) {
4027 $types = array($type);
4028 } else {
4029 if ('db' != $type || empty($foreign_known[$updraftplus_restorer->ud_foreign]['separatedb'])) {
4030 $types = array('wpcore');
4031 } else {
4032 $types = array('db');
4033 }
4034 }
4035
4036 foreach ($types as $check_type) {
4037 $info = (isset($backupable_entities[$check_type])) ? $backupable_entities[$check_type] : array();
4038 $val = $updraftplus_restorer->pre_restore_backup($files, $check_type, $info);
4039 if (is_wp_error($val)) {
4040 $updraftplus->log_wp_error($val);
4041 foreach ($val->get_error_messages() as $msg) {
4042 echo '<strong>'.__('Error:', 'updraftplus').'</strong> '.htmlspecialchars($msg).'<br>';
4043 }
4044 foreach ($val->get_error_codes() as $code) {
4045 if ('already_exists' == $code) $this->print_delete_old_dirs_form(false);
4046 }
4047 echo '</div>'; //close the updraft_restore_progress div even if we error
4048 restore_error_handler();
4049 return $val;
4050 } elseif (false === $val) {
4051 echo '</div>'; //close the updraft_restore_progress div even if we error
4052 restore_error_handler();
4053 return false;
4054 }
4055 }
4056
4057 foreach ($entities_to_restore as $entity => $via) {
4058 if ($via == $type) $second_loop[$entity] = $files;
4059 }
4060
4061 }
4062
4063 $updraftplus_restorer->delete = (UpdraftPlus_Options::get_updraft_option('updraft_delete_local')) ? true : false;
4064 if ('none' === $service || 'email' === $service || empty($service) || (is_array($service) && 1 == count($service) && (in_array('none', $service) || in_array('', $service) || in_array('email', $service))) || !empty($updraftplus_restorer->ud_foreign)) {
4065 if ($updraftplus_restorer->delete) $updraftplus->log_e('Will not delete any archives after unpacking them, because there was no cloud storage for this backup');
4066 $updraftplus_restorer->delete = false;
4067 }
4068
4069 if (!empty($updraftplus_restorer->ud_foreign)) $updraftplus->log("Foreign backup; created by: ".$updraftplus_restorer->ud_foreign);
4070
4071 // Second loop: now actually do the restoration
4072 uksort($second_loop, array($this, 'sort_restoration_entities'));
4073 foreach ($second_loop as $type => $files) {
4074 # Types: uploads, themes, plugins, others, db
4075 $info = (isset($backupable_entities[$type])) ? $backupable_entities[$type] : array();
4076
4077 echo ('db' == $type) ? "<h2>".__('Database','updraftplus')."</h2>" : "<h2>".$info['description']."</h2>";
4078 $updraftplus->log("Entity: ".$type);
4079
4080 if (is_string($files)) $files = array($files);
4081 foreach ($files as $fkey => $file) {
4082 $last_one = (1 == count($second_loop) && 1 == count($files));
4083 $val = $updraftplus_restorer->restore_backup($file, $type, $info, $last_one);
4084
4085 if(is_wp_error($val)) {
4086 $updraftplus->log_e($val);
4087 foreach ($val->get_error_messages() as $msg) {
4088 echo '<strong>'.__('Error message', 'updraftplus').':</strong> '.htmlspecialchars($msg).'<br>';
4089 }
4090 $codes = $val->get_error_codes();
4091 if (is_array($codes)) {
4092 foreach ($codes as $code) {
4093 $data = $val->get_error_data($code);
4094 if (!empty($data)) {
4095 $pdata = (is_string($data)) ? $data : serialize($data);
4096 echo '<strong>'.__('Error data:', 'updraftplus').'</strong> '.htmlspecialchars($pdata).'<br>';
4097 if (false !== strpos($pdata, 'PCLZIP_ERR_BAD_FORMAT (-10)')) {
4098 echo '<a href="http://updraftplus.com/faqs/error-message-pclzip_err_bad_format-10-invalid-archive-structure-mean/"><strong>'.__('Please consult this FAQ for help on what to do about it.', 'updraftplus').'</strong></a><br>';
4099 }
4100 }
4101 }
4102 }
4103 echo '</div>'; //close the updraft_restore_progress div even if we error
4104 restore_error_handler();
4105 return $val;
4106 } elseif (false === $val) {
4107 echo '</div>'; //close the updraft_restore_progress div even if we error
4108 restore_error_handler();
4109 return false;
4110 }
4111 unset($files[$fkey]);
4112 }
4113 unset($second_loop[$type]);
4114 }
4115
4116 foreach (array('template', 'stylesheet', 'template_root', 'stylesheet_root') as $opt) {
4117 add_filter('pre_option_'.$opt, array($this, 'option_filter_'.$opt));
4118 }
4119 if (!function_exists('validate_current_theme')) require_once(ABSPATH.WPINC.'/themes');
4120
4121 # Have seen a case where the current theme in the DB began with a capital, but not on disk - and this breaks migrating from Windows to a case-sensitive system
4122 $template = get_option('template');
4123 if (!empty($template) && $template != WP_DEFAULT_THEME && $template != strtolower($template)) {
4124
4125 $theme_root = get_theme_root($template);
4126 $theme_root2 = get_theme_root(strtolower($template));
4127
4128 if (!file_exists("$theme_root/$template/style.css") && file_exists("$theme_root/".strtolower($template)."/style.css")) {
4129 $updraftplus->log_e("Theme directory (%s) not found, but lower-case version exists; updating database option accordingly", $template);
4130 update_option('template', strtolower($template));
4131 }
4132
4133 }
4134
4135
4136 if (!validate_current_theme()) {
4137 global $updraftplus;
4138 echo '<strong>';
4139 $updraftplus->log_e("The current theme was not found; to prevent this stopping the site from loading, your theme has been reverted to the default theme");
4140 echo '</strong>';
4141 }
4142 #foreach (array('template', 'stylesheet', 'template_root', 'stylesheet_root') as $opt) {
4143 # remove_filter('pre_option_'.$opt, array($this, 'option_filter_'.$opt));
4144 #}
4145
4146 echo '</div>'; //close the updraft_restore_progress div
4147
4148 restore_error_handler();
4149 return true;
4150 }
4151
4152 public function option_filter_template($val) { global $updraftplus; return $updraftplus->option_filter_get('template'); }
4153
4154 public function option_filter_stylesheet($val) { global $updraftplus; return $updraftplus->option_filter_get('stylesheet'); }
4155
4156 public function option_filter_template_root($val) { global $updraftplus; return $updraftplus->option_filter_get('template_root'); }
4157
4158 public function option_filter_stylesheet_root($val) { global $updraftplus; return $updraftplus->option_filter_get('stylesheet_root'); }
4159
4160 function sort_restoration_entities($a, $b) {
4161 if ($a == $b) return 0;
4162 # Put the database first
4163 # Put wpcore after plugins/uploads/themes (needed for restores of foreign all-in-one formats)
4164 if ('db' == $a || 'wpcore' == $b) return -1;
4165 if ('db' == $b || 'wpcore' == $a) return 1;
4166 # After wpcore, next last is others
4167 if ('others' == $b) return -1;
4168 if ('others' == $a) return 1;
4169 return strcmp($a, $b);
4170 }
4171
4172 public function return_array($input) {
4173 if (!is_array($input)) $input = array();
4174 return $input;
4175 }
4176
4177 # TODO: Remove legacy storage setting keys from here
4178 private function get_settings_keys() {
4179 return array('updraft_autobackup_default', 'updraft_dropbox', 'updraft_googledrive', 'updraftplus_tmp_googledrive_access_token', 'updraftplus_dismissedautobackup', 'updraftplus_dismissedexpiry', 'updraft_interval', 'updraft_interval_increments', 'updraft_interval_database', 'updraft_retain', 'updraft_retain_db', 'updraft_encryptionphrase', 'updraft_service', 'updraft_dropbox_appkey', 'updraft_dropbox_secret', 'updraft_googledrive_clientid', 'updraft_googledrive_secret', 'updraft_googledrive_remotepath', 'updraft_ftp_login', 'updraft_ftp_pass', 'updraft_ftp_remote_path', 'updraft_server_address', 'updraft_dir', 'updraft_email', 'updraft_delete_local', 'updraft_debug_mode', 'updraft_include_plugins', 'updraft_include_themes', 'updraft_include_uploads', 'updraft_include_others', 'updraft_include_wpcore', 'updraft_include_wpcore_exclude', 'updraft_include_more', 'updraft_include_blogs', 'updraft_include_mu-plugins', 'updraft_include_others_exclude', 'updraft_include_uploads_exclude',
4180 'updraft_lastmessage', 'updraft_googledrive_token', 'updraft_dropboxtk_request_token', 'updraft_dropboxtk_access_token', 'updraft_dropbox_folder',
4181 'updraft_last_backup', 'updraft_starttime_files', 'updraft_starttime_db', 'updraft_startday_db', 'updraft_startday_files', 'updraft_sftp_settings', 'updraft_s3', 'updraft_s3generic', 'updraft_dreamhost', 'updraft_s3generic_login', 'updraft_s3generic_pass', 'updraft_s3generic_remote_path', 'updraft_s3generic_endpoint', 'updraft_webdav_settings', 'updraft_disable_ping', 'updraft_openstack', 'updraft_bitcasa', 'updraft_copycom', 'updraft_cloudfiles', 'updraft_cloudfiles_user', 'updraft_cloudfiles_apikey', 'updraft_cloudfiles_path', 'updraft_cloudfiles_authurl', 'updraft_ssl_useservercerts', 'updraft_ssl_disableverify', 'updraft_s3_login', 'updraft_s3_pass', 'updraft_s3_remote_path', 'updraft_dreamobjects_login', 'updraft_dreamobjects_pass', 'updraft_dreamobjects_remote_path', 'updraft_report_warningsonly', 'updraft_report_wholebackup', 'updraft_log_syslog', 'updraft_extradatabases');
4182 }
4183
4184 }
4185