PluginProbe
Database Backup for WordPress / 2.2
Database Backup for WordPress v2.2
trunk 1.3 1.4 2.0 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.2 2.2.1 2.2.2 2.2.3 2.2.4 2.3.0 2.3.1 2.3.3 2.4 2.5 All 28 releases
wp-db-backup / wp-db-backup.php

wp-db-backup.php in Database Backup for WordPress 2.2, at wp-db-backup.php

1,389 lines 51.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: WordPress Database Backup
4 Plugin URI: http://www.ilfilosofo.com/blog/wp-db-backup
5 Description: On-demand backup of your WordPress database. Navigate to <a href="edit.php?page=wp-db-backup">Manage &rarr; Backup</a> to get started.
6 Author: Austin Matzko
7 Author URI: http://www.ilfilosofo.com/
8 Version: 2.2
9
10 Development continued from that done by Skippy (http://www.skippy.net/)
11
12 Originally modified from Mark Ghosh's One Click Backup, which
13 in turn was derived from phpMyAdmin.
14
15 Many thanks to Owen (http://asymptomatic.net/wp/) for his patch
16 http://dev.wp-plugins.org/ticket/219
17
18 Copyright 2008 Austin Matzko (email : if.website at gmail.com)
19
20 This program is free software; you can redistribute it and/or modify
21 it under the terms of the GNU General Public License as published by
22 the Free Software Foundation; either version 2 of the License, or
23 (at your option) any later version.
24
25 This program is distributed in the hope that it will be useful,
26 but WITHOUT ANY WARRANTY; without even the implied warranty of
27 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 GNU General Public License for more details.
29
30 You should have received a copy of the GNU General Public License
31 along with this program; if not, write to the Free Software
32 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
33 */
34
35 /**
36 * Change WP_BACKUP_DIR if you want to
37 * use a different backup location
38 */
39
40 $rand = substr( md5( md5( DB_PASSWORD ) ), -5 );
41 global $wpdbb_content_dir, $wpdbb_content_url, $wpdbb_plugin_dir;
42 $wpdbb_content_dir = ( defined('WP_CONTENT_DIR') ) ? WP_CONTENT_DIR : ABSPATH . 'wp-content';
43 $wpdbb_content_url = ( defined('WP_CONTENT_URL') ) ? WP_CONTENT_URL : get_option('siteurl') . '/wp-content';
44 $wpdbb_plugin_dir = ( defined('WP_PLUGIN_DIR') ) ? WP_PLUGIN_DIR : $wpdbb_content_dir . '/plugins';
45
46 if ( ! defined('WP_BACKUP_DIR') ) {
47 define('WP_BACKUP_DIR', $wpdbb_content_dir . '/backup-' . $rand . '/');
48 }
49
50 if ( ! defined('WP_BACKUP_URL') ) {
51 define('WP_BACKUP_URL', $wpdbb_content_url . '/backup-' . $rand . '/');
52 }
53
54 if ( ! defined('ROWS_PER_SEGMENT') ) {
55 define('ROWS_PER_SEGMENT', 100);
56 }
57
58 /**
59 * Set MOD_EVASIVE_OVERRIDE to true
60 * and increase MOD_EVASIVE_DELAY
61 * if the backup stops prematurely.
62 */
63 // define('MOD_EVASIVE_OVERRIDE', false);
64 if ( ! defined('MOD_EVASIVE_DELAY') ) {
65 define('MOD_EVASIVE_DELAY', '500');
66 }
67
68 class wpdbBackup {
69
70 var $backup_complete = false;
71 var $backup_file = '';
72 var $backup_filename;
73 var $core_table_names;
74 var $errors = array();
75 var $basename;
76 var $page_url;
77 var $referer_check_key;
78 var $version = '2.1.5-alpha';
79
80 function gzip() {
81 return function_exists('gzopen');
82 }
83
84 function module_check() {
85 $mod_evasive = false;
86 if ( true === MOD_EVASIVE_OVERRIDE ) return true;
87 if ( false === MOD_EVASIVE_OVERRIDE ) return false;
88 if ( function_exists('apache_get_modules') )
89 foreach( (array) apache_get_modules() as $mod )
90 if ( false !== strpos($mod,'mod_evasive') || false !== strpos($mod,'mod_dosevasive') )
91 return true;
92 return false;
93 }
94
95 function wpdbBackup() {
96 global $table_prefix, $wpdb;
97 add_action('wp_ajax_save_backup_time', array(&$this, 'save_backup_time'));
98 add_action('init', array(&$this, 'init_textdomain'));
99 add_action('wp_db_backup_cron', array(&$this, 'cron_backup'));
100 add_action('wp_cron_daily', array(&$this, 'wp_cron_daily'));
101 add_filter('cron_schedules', array(&$this, 'add_sched_options'));
102 add_filter('wp_db_b_schedule_choices', array(&$this, 'schedule_choices'));
103
104 $table_prefix = ( isset( $table_prefix ) ) ? $table_prefix : $wpdb->prefix;
105 $datum = date("Ymd_B");
106 $this->backup_filename = DB_NAME . "_$table_prefix$datum.sql";
107 if ($this->gzip()) $this->backup_filename .= '.gz';
108
109 $this->core_table_names = array(
110 $wpdb->categories,
111 $wpdb->comments,
112 $wpdb->link2cat,
113 $wpdb->linkcategories,
114 $wpdb->links,
115 $wpdb->options,
116 $wpdb->post2cat,
117 $wpdb->postmeta,
118 $wpdb->posts,
119 $wpdb->terms,
120 $wpdb->term_taxonomy,
121 $wpdb->term_relationships,
122 $wpdb->users,
123 $wpdb->usermeta,
124 );
125
126 $this->backup_dir = trailingslashit(apply_filters('wp_db_b_backup_dir', WP_BACKUP_DIR));
127 $this->basename = 'wp-db-backup';
128
129 $this->referer_check_key = $this->basename . '-download_' . DB_NAME;
130 $query_args = array( 'page' => $this->basename );
131 if ( function_exists('wp_create_nonce') )
132 $query_args = array_merge( $query_args, array('_wpnonce' => wp_create_nonce($this->referer_check_key)) );
133 $this->page_url = add_query_arg( $query_args, get_option('siteurl') . '/wp-admin/edit.php');
134 if (isset($_POST['do_backup'])) {
135 $this->wp_secure('fatal');
136 check_admin_referer($this->referer_check_key);
137 $this->can_user_backup('main');
138 // save exclude prefs
139
140 $exc_revisions = (array) $_POST['exclude-revisions'];
141 $exc_spam = (array) $_POST['exclude-spam'];
142 update_option('wp_db_backup_excs', array('revisions' => $exc_revisions, 'spam' => $exc_spam));
143 switch($_POST['do_backup']) {
144 case 'backup':
145 add_action('init', array(&$this, 'perform_backup'));
146 break;
147 case 'fragments':
148 add_action('admin_menu', array(&$this, 'fragment_menu'));
149 break;
150 }
151 } elseif (isset($_GET['fragment'] )) {
152 $this->can_user_backup('frame');
153 add_action('init', array(&$this, 'init'));
154 } elseif (isset($_GET['backup'] )) {
155 $this->can_user_backup();
156 add_action('init', array(&$this, 'init'));
157 } else {
158 add_action('admin_menu', array(&$this, 'admin_menu'));
159 }
160 }
161
162 function init() {
163 $this->can_user_backup();
164 if (isset($_GET['backup'])) {
165 $via = isset($_GET['via']) ? $_GET['via'] : 'http';
166
167 $this->backup_file = $_GET['backup'];
168 $this->validate_file($this->backup_file);
169
170 switch($via) {
171 case 'smtp':
172 case 'email':
173 $success = $this->deliver_backup($this->backup_file, 'smtp', $_GET['recipient'], 'frame');
174 $this->error_display( 'frame' );
175 if ( $success ) {
176 echo '
177 <!-- ' . $via . ' -->
178 <script type="text/javascript"><!--\\
179 ';
180 echo '
181 alert("' . __('Backup Complete!','wp-db-backup') . '");
182 window.onbeforeunload = null;
183 </script>
184 ';
185 }
186 break;
187 default:
188 $this->deliver_backup($this->backup_file, $via);
189 $this->error_display( 'frame' );
190 }
191 die();
192 }
193 if (isset($_GET['fragment'] )) {
194 list($table, $segment, $filename) = explode(':', $_GET['fragment']);
195 $this->validate_file($filename);
196 $this->backup_fragment($table, $segment, $filename);
197 }
198
199 die();
200 }
201
202 function init_textdomain() {
203 load_plugin_textdomain('wp-db-backup', str_replace(ABSPATH, '', dirname(__FILE__)), dirname(plugin_basename(__FILE__)));
204 }
205
206 function build_backup_script() {
207 global $table_prefix, $wpdb;
208
209 echo "<div class='wrap'>";
210 echo '<fieldset class="options"><legend>' . __('Progress','wp-db-backup') . '</legend>
211 <p><strong>' .
212 __('DO NOT DO THE FOLLOWING AS IT WILL CAUSE YOUR BACKUP TO FAIL:','wp-db-backup').
213 '</strong></p>
214 <ol>
215 <li>'.__('Close this browser','wp-db-backup').'</li>
216 <li>'.__('Reload this page','wp-db-backup').'</li>
217 <li>'.__('Click the Stop or Back buttons in your browser','wp-db-backup').'</li>
218 </ol>
219 <p><strong>' . __('Progress:','wp-db-backup') . '</strong></p>
220 <div id="meterbox" style="height:11px;width:80%;padding:3px;border:1px solid #659fff;"><div id="meter" style="height:11px;background-color:#659fff;width:0%;text-align:center;font-size:6pt;">&nbsp;</div></div>
221 <div id="progress_message"></div>
222 <div id="errors"></div>
223 </fieldset>
224 <iframe id="backuploader" src="about:blank" style="visibility:hidden;border:none;height:1em;width:1px;"></iframe>
225 <script type="text/javascript">
226 //<![CDATA[
227 window.onbeforeunload = function() {
228 return "' . __('Navigating away from this page will cause your backup to fail.', 'wp-db-backup') . '";
229 }
230 function setMeter(pct) {
231 var meter = document.getElementById("meter");
232 meter.style.width = pct + "%";
233 meter.innerHTML = Math.floor(pct) + "%";
234 }
235 function setProgress(str) {
236 var progress = document.getElementById("progress_message");
237 progress.innerHTML = str;
238 }
239 function addError(str) {
240 var errors = document.getElementById("errors");
241 errors.innerHTML = errors.innerHTML + str + "<br />";
242 }
243
244 function backup(table, segment) {
245 var fram = document.getElementById("backuploader");
246 fram.src = "' . $this->page_url . '&fragment=" + table + ":" + segment + ":' . $this->backup_filename . ':";
247 }
248
249 var curStep = 0;
250
251 function nextStep() {
252 backupStep(curStep);
253 curStep++;
254 }
255
256 function finishBackup() {
257 var fram = document.getElementById("backuploader");
258 setMeter(100);
259 ';
260
261 $download_uri = add_query_arg('backup', $this->backup_filename, $this->page_url);
262 switch($_POST['deliver']) {
263 case 'http':
264 echo '
265 setProgress("' . sprintf(__("Backup complete, preparing <a href=\\\"%s\\\">backup</a> for download...",'wp-db-backup'), $download_uri) . '");
266 window.onbeforeunload = null;
267 fram.src = "' . $download_uri . '";
268 ';
269 break;
270 case 'smtp':
271 echo '
272 setProgress("' . sprintf(__("Backup complete, sending <a href=\\\"%s\\\">backup</a> via email...",'wp-db-backup'), $download_uri) . '");
273 window.onbeforeunload = null;
274 fram.src = "' . $download_uri . '&via=email&recipient=' . $_POST['backup_recipient'] . '";
275 ';
276 break;
277 default:
278 echo '
279 setProgress("' . sprintf(__("Backup complete, download <a href=\\\"%s\\\">here</a>.",'wp-db-backup'), $download_uri) . '");
280 window.onbeforeunload = null;
281 ';
282 }
283
284 echo '
285 }
286
287 function backupStep(step) {
288 switch(step) {
289 case 0: backup("", 0); break;
290 ';
291
292 $also_backup = array();
293 if (isset($_POST['other_tables'])) {
294 $also_backup = $_POST['other_tables'];
295 } else {
296 $also_backup = array();
297 }
298 $core_tables = $_POST['core_tables'];
299 $tables = array_merge($core_tables, $also_backup);
300 $step_count = 1;
301 foreach ($tables as $table) {
302 $rec_count = $wpdb->get_var("SELECT count(*) FROM {$table}");
303 $rec_segments = ceil($rec_count / ROWS_PER_SEGMENT);
304 $table_count = 0;
305 if ( $this->module_check() ) {
306 $delay = "setTimeout('";
307 $delay_time = "', " . (int) MOD_EVASIVE_DELAY . ")";
308 }
309 else { $delay = $delay_time = ''; }
310 do {
311 echo "case {$step_count}: {$delay}backup(\"{$table}\", {$table_count}){$delay_time}; break;\n";
312 $step_count++;
313 $table_count++;
314 } while($table_count < $rec_segments);
315 echo "case {$step_count}: {$delay}backup(\"{$table}\", -1){$delay_time}; break;\n";
316 $step_count++;
317 }
318 echo "case {$step_count}: finishBackup(); break;";
319
320 echo '
321 }
322 if(step != 0) setMeter(100 * step / ' . $step_count . ');
323 }
324
325 nextStep();
326 // ]]>
327 </script>
328 </div>
329 ';
330 $this->backup_menu();
331 }
332
333 function backup_fragment($table, $segment, $filename) {
334 global $table_prefix, $wpdb;
335
336 echo "$table:$segment:$filename";
337
338 if($table == '') {
339 $msg = __('Creating backup file...','wp-db-backup');
340 } else {
341 if($segment == -1) {
342 $msg = sprintf(__('Finished backing up table \\"%s\\".','wp-db-backup'), $table);
343 } else {
344 $msg = sprintf(__('Backing up table \\"%s\\"...','wp-db-backup'), $table);
345 }
346 }
347
348 if (is_writable($this->backup_dir)) {
349 $this->fp = $this->open($this->backup_dir . $filename, 'a');
350 if(!$this->fp) {
351 $this->error(__('Could not open the backup file for writing!','wp-db-backup'));
352 $this->error(array('loc' => 'frame', 'kind' => 'fatal', 'msg' => __('The backup file could not be saved. Please check the permissions for writing to your backup directory and try again.','wp-db-backup')));
353 }
354 else {
355 if($table == '') {
356 //Begin new backup of MySql
357 $this->stow("# " . __('WordPress MySQL database backup','wp-db-backup') . "\n");
358 $this->stow("#\n");
359 $this->stow("# " . sprintf(__('Generated: %s','wp-db-backup'),date("l j. F Y H:i T")) . "\n");
360 $this->stow("# " . sprintf(__('Hostname: %s','wp-db-backup'),DB_HOST) . "\n");
361 $this->stow("# " . sprintf(__('Database: %s','wp-db-backup'),$this->backquote(DB_NAME)) . "\n");
362 $this->stow("# --------------------------------------------------------\n");
363 } else {
364 if($segment == 0) {
365 // Increase script execution time-limit to 15 min for every table.
366 if ( !ini_get('safe_mode')) @set_time_limit(15*60);
367 // Create the SQL statements
368 $this->stow("# --------------------------------------------------------\n");
369 $this->stow("# " . sprintf(__('Table: %s','wp-db-backup'),$this->backquote($table)) . "\n");
370 $this->stow("# --------------------------------------------------------\n");
371 }
372 $this->backup_table($table, $segment);
373 }
374 }
375 } else {
376 $this->error(array('kind' => 'fatal', 'loc' => 'frame', 'msg' => __('The backup directory is not writeable! Please check the permissions for writing to your backup directory and try again.','wp-db-backup')));
377 }
378
379 if($this->fp) $this->close($this->fp);
380
381 $this->error_display('frame');
382
383 echo '<script type="text/javascript"><!--//
384 var msg = "' . $msg . '";
385 window.parent.setProgress(msg);
386 window.parent.nextStep();
387 //--></script>
388 ';
389 die();
390 }
391
392 function perform_backup() {
393 // are we backing up any other tables?
394 $also_backup = array();
395 if (isset($_POST['other_tables']))
396 $also_backup = $_POST['other_tables'];
397 $core_tables = $_POST['core_tables'];
398 $this->backup_file = $this->db_backup($core_tables, $also_backup);
399 if (FALSE !== $this->backup_file) {
400 if ('smtp' == $_POST['deliver']) {
401 $this->deliver_backup($this->backup_file, $_POST['deliver'], $_POST['backup_recipient'], 'main');
402 wp_redirect($this->page_url);
403 } elseif ('http' == $_POST['deliver']) {
404 $download_uri = add_query_arg('backup',$this->backup_file,$this->page_url);
405 wp_redirect($download_uri);
406 exit;
407 }
408 // we do this to say we're done.
409 $this->backup_complete = true;
410 }
411 }
412
413 function admin_header() {
414 ?>
415 <script type="text/javascript">
416 //<![CDATA[
417 if ( 'undefined' != typeof addLoadEvent ) {
418 addLoadEvent(function() {
419 var t = {'extra-tables-list':{name: 'other_tables[]'}, 'include-tables-list':{name: 'wp_cron_backup_tables[]'}};
420
421 for ( var k in t ) {
422 t[k].s = null;
423 var d = document.getElementById(k);
424 if ( ! d )
425 continue;
426 var ul = d.getElementsByTagName('ul').item(0);
427 if ( ul ) {
428 var lis = ul.getElementsByTagName('li');
429 if ( 3 > lis.length )
430 return;
431 var text = document.createElement('p');
432 text.className = 'instructions';
433 text.innerHTML = '<?php _e('Click and hold down <code>[SHIFT]</code> to toggle multiple checkboxes', 'wp-db-backup'); ?>';
434 ul.parentNode.insertBefore(text, ul);
435 }
436 t[k].p = d.getElementsByTagName("input");
437 for(var i=0; i < t[k].p.length; i++)
438 if(t[k].name == t[k].p[i].getAttribute('name')) {
439 t[k].p[i].id = k + '-table-' + i;
440 t[k].p[i].onkeyup = t[k].p[i].onclick = function(e) {
441 e = e ? e : event;
442 if ( 16 == e.keyCode )
443 return;
444 var match = /([\w-]*)-table-(\d*)/.exec(this.id);
445 var listname = match[1];
446 var that = match[2];
447 if ( null === t[listname].s )
448 t[listname].s = that;
449 else if ( e.shiftKey ) {
450 var start = Math.min(that, t[listname].s) + 1;
451 var end = Math.max(that, t[listname].s);
452 for( var j=start; j < end; j++)
453 t[listname].p[j].checked = t[listname].p[j].checked ? false : true;
454 t[listname].s = null;
455 }
456 }
457 }
458 }
459
460 <?php if ( function_exists('wp_schedule_event') ) : // needs to be at least WP 2.1 for ajax ?>
461 if ( 'undefined' == typeof XMLHttpRequest )
462 var xml = new ActiveXObject( navigator.userAgent.indexOf('MSIE 5') >= 0 ? 'Microsoft.XMLHTTP' : 'Msxml2.XMLHTTP' );
463 else
464 var xml = new XMLHttpRequest();
465
466 var initTimeChange = function() {
467 var timeWrap = document.getElementById('backup-time-wrap');
468 var backupTime = document.getElementById('next-backup-time');
469 if ( !! timeWrap && !! backupTime ) {
470 var span = document.createElement('span');
471 span.className = 'submit';
472 span.id = 'change-wrap';
473 span.innerHTML = '<input type="submit" id="change-backup-time" name="change-backup-time" value="<?php _e('Change','wp-db-backup'); ?>" />';
474 timeWrap.appendChild(span);
475 backupTime.ondblclick = function(e) { span.parentNode.removeChild(span); clickTime(e, backupTime); };
476 span.onclick = function(e) { span.parentNode.removeChild(span); clickTime(e, backupTime); };
477 }
478 }
479
480 var clickTime = function(e, backupTime) {
481 var tText = backupTime.innerHTML;
482 backupTime.innerHTML = '<input type="text" value="' + tText + '" name="backup-time-text" id="backup-time-text" /> <span class="submit"><input type="submit" name="save-backup-time" id="save-backup-time" value="<?php _e('Save', 'wp-db-backup'); ?>" /></span>';
483 backupTime.ondblclick = null;
484 var mainText = document.getElementById('backup-time-text');
485 mainText.focus();
486 var saveTButton = document.getElementById('save-backup-time');
487 if ( !! saveTButton )
488 saveTButton.onclick = function(e) { saveTime(backupTime, mainText); return false; };
489 if ( !! mainText )
490 mainText.onkeydown = function(e) {
491 e = e || window.event;
492 if ( 13 == e.keyCode ) {
493 saveTime(backupTime, mainText);
494 return false;
495 }
496 }
497 }
498
499 var saveTime = function(backupTime, mainText) {
500 var tVal = mainText.value;
501
502 xml.open('POST', 'admin-ajax.php', true);
503 xml.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
504 if ( xml.overrideMimeType )
505 xml.setRequestHeader('Connection', 'close');
506 xml.send('action=save_backup_time&_wpnonce=<?php echo wp_create_nonce($this->referer_check_key); ?>&backup-time='+tVal);
507 xml.onreadystatechange = function() {
508 if ( 4 == xml.readyState && '0' != xml.responseText ) {
509 backupTime.innerHTML = xml.responseText;
510 initTimeChange();
511 }
512 }
513 }
514
515 initTimeChange();
516 <?php endif; // wp_schedule_event exists ?>
517 });
518 }
519 //]]>
520 </script>
521 <style type="text/css">
522 .wp-db-backup-updated {
523 margin-top: 1em;
524 }
525
526 fieldset.options {
527 border: 1px solid;
528 margin-top: 1em;
529 padding: 1em;
530 }
531 fieldset.options div.tables-list {
532 float: left;
533 padding: 1em;
534 }
535
536 fieldset.options input {
537 }
538
539 fieldset.options legend {
540 font-size: larger;
541 font-weight: bold;
542 margin-bottom: .5em;
543 padding: 1em;
544 }
545
546 fieldset.options .instructions {
547 font-size: smaller;
548 }
549
550 fieldset.options ul {
551 list-style-type: none;
552 }
553 fieldset.options li {
554 text-align: left;
555 }
556
557 fieldset.options .submit {
558 border-top: none;
559 }
560 </style>
561 <?php
562 }
563
564 function admin_load() {
565 add_action('admin_head', array(&$this, 'admin_header'));
566 }
567
568 function admin_menu() {
569 $page_hook = add_management_page(__('Backup','wp-db-backup'), __('Backup','wp-db-backup'), 'import', $this->basename, array(&$this, 'backup_menu'));
570 add_action('load-' . $page_hook, array(&$this, 'admin_load'));
571 }
572
573 function fragment_menu() {
574 $page_hook = add_management_page(__('Backup','wp-db-backup'), __('Backup','wp-db-backup'), 'import', $this->basename, array(&$this, 'build_backup_script'));
575 add_action('load-' . $page_hook, array(&$this, 'admin_load'));
576 }
577
578 function save_backup_time() {
579 if ( $this->can_user_backup() ) {
580 // try to get a time from the input string
581 $time = strtotime(strval($_POST['backup-time']));
582 if ( ! empty( $time ) && time() < $time ) {
583 wp_clear_scheduled_hook( 'wp_db_backup_cron' ); // unschedule previous
584 $scheds = (array) wp_get_schedules();
585 $name = get_option('wp_cron_backup_schedule');
586 if ( 0 != $time ) {
587 wp_schedule_event($time, $name, 'wp_db_backup_cron');
588 echo gmdate(get_option('date_format') . ' ' . get_option('time_format'), $time + (get_option('gmt_offset') * 3600));
589 exit;
590 }
591 }
592 } else {
593 die(0);
594 }
595 }
596
597 /**
598 * Better addslashes for SQL queries.
599 * Taken from phpMyAdmin.
600 */
601 function sql_addslashes($a_string = '', $is_like = FALSE) {
602 if ($is_like) $a_string = str_replace('\\', '\\\\\\\\', $a_string);
603 else $a_string = str_replace('\\', '\\\\', $a_string);
604 return str_replace('\'', '\\\'', $a_string);
605 }
606
607 /**
608 * Add backquotes to tables and db-names in
609 * SQL queries. Taken from phpMyAdmin.
610 */
611 function backquote($a_name) {
612 if (!empty($a_name) && $a_name != '*') {
613 if (is_array($a_name)) {
614 $result = array();
615 reset($a_name);
616 while(list($key, $val) = each($a_name))
617 $result[$key] = '`' . $val . '`';
618 return $result;
619 } else {
620 return '`' . $a_name . '`';
621 }
622 } else {
623 return $a_name;
624 }
625 }
626
627 function open($filename = '', $mode = 'w') {
628 if ('' == $filename) return false;
629 if ($this->gzip())
630 $fp = @gzopen($filename, $mode);
631 else
632 $fp = @fopen($filename, $mode);
633 return $fp;
634 }
635
636 function close($fp) {
637 if ($this->gzip()) gzclose($fp);
638 else fclose($fp);
639 }
640
641 /**
642 * Write to the backup file
643 * @param string $query_line the line to write
644 * @return null
645 */
646 function stow($query_line) {
647 if ($this->gzip()) {
648 if(! @gzwrite($this->fp, $query_line))
649 $this->error(__('There was an error writing a line to the backup script:','wp-db-backup') . ' ' . $query_line . ' ' . $php_errormsg);
650 } else {
651 if(FALSE === @fwrite($this->fp, $query_line))
652 $this->error(__('There was an error writing a line to the backup script:','wp-db-backup') . ' ' . $query_line . ' ' . $php_errormsg);
653 }
654 }
655
656 /**
657 * Logs any error messages
658 * @param array $args
659 * @return bool
660 */
661 function error($args = array()) {
662 if ( is_string( $args ) )
663 $args = array('msg' => $args);
664 $args = array_merge( array('loc' => 'main', 'kind' => 'warn', 'msg' => ''), $args);
665 $this->errors[$args['kind']][] = $args['msg'];
666 if ( 'fatal' == $args['kind'] || 'frame' == $args['loc'])
667 $this->error_display($args['loc']);
668 return true;
669 }
670
671 /**
672 * Displays error messages
673 * @param array $errs
674 * @param string $loc
675 * @return string
676 */
677 function error_display($loc = 'main', $echo = true) {
678 $errs = $this->errors;
679 unset( $this->errors );
680 if ( ! count($errs) ) return;
681 $msg = '';
682 $err_list = array_slice(array_merge( (array) $errs['fatal'], (array) $errs['warn']), 0, 10);
683 if ( 10 == count( $err_list ) )
684 $err_list[9] = __('Subsequent errors have been omitted from this log.','wp-db-backup');
685 $wrap = ( 'frame' == $loc ) ? "<script type=\"text/javascript\">\n var msgList = ''; \n %1\$s \n if ( msgList ) alert(msgList); \n </script>" : '%1$s';
686 $line = ( 'frame' == $loc ) ?
687 "try{ window.parent.addError('%1\$s'); } catch(e) { msgList += ' %1\$s';}\n" :
688 "%1\$s<br />\n";
689 foreach( (array) $err_list as $err )
690 $msg .= sprintf($line,str_replace(array("\n","\r"), '', addslashes($err)));
691 $msg = sprintf($wrap,$msg);
692 if ( count($errs['fatal'] ) ) {
693 if ( function_exists('wp_die') && 'frame' != $loc ) wp_die(stripslashes($msg));
694 else die($msg);
695 }
696 else {
697 if ( $echo ) echo $msg;
698 else return $msg;
699 }
700 }
701
702 /**
703 * Taken partially from phpMyAdmin and partially from
704 * Alain Wolf, Zurich - Switzerland
705 * Website: http://restkultur.ch/personal/wolf/scripts/db_backup/
706
707 * Modified by Scott Merrill (http://www.skippy.net/)
708 * to use the WordPress $wpdb object
709 * @param string $table
710 * @param string $segment
711 * @return void
712 */
713 function backup_table($table, $segment = 'none') {
714 global $wpdb;
715
716 $table_structure = $wpdb->get_results("DESCRIBE $table");
717 if (! $table_structure) {
718 $this->error(__('Error getting table details','wp-db-backup') . ": $table");
719 return FALSE;
720 }
721
722 if(($segment == 'none') || ($segment == 0)) {
723 // Add SQL statement to drop existing table
724 $this->stow("\n\n");
725 $this->stow("#\n");
726 $this->stow("# " . sprintf(__('Delete any existing table %s','wp-db-backup'),$this->backquote($table)) . "\n");
727 $this->stow("#\n");
728 $this->stow("\n");
729 $this->stow("DROP TABLE IF EXISTS " . $this->backquote($table) . ";\n");
730
731 // Table structure
732 // Comment in SQL-file
733 $this->stow("\n\n");
734 $this->stow("#\n");
735 $this->stow("# " . sprintf(__('Table structure of table %s','wp-db-backup'),$this->backquote($table)) . "\n");
736 $this->stow("#\n");
737 $this->stow("\n");
738
739 $create_table = $wpdb->get_results("SHOW CREATE TABLE $table", ARRAY_N);
740 if (FALSE === $create_table) {
741 $err_msg = sprintf(__('Error with SHOW CREATE TABLE for %s.','wp-db-backup'), $table);
742 $this->error($err_msg);
743 $this->stow("#\n# $err_msg\n#\n");
744 }
745 $this->stow($create_table[0][1] . ' ;');
746
747 if (FALSE === $table_structure) {
748 $err_msg = sprintf(__('Error getting table structure of %s','wp-db-backup'), $table);
749 $this->error($err_msg);
750 $this->stow("#\n# $err_msg\n#\n");
751 }
752
753 // Comment in SQL-file
754 $this->stow("\n\n");
755 $this->stow("#\n");
756 $this->stow('# ' . sprintf(__('Data contents of table %s','wp-db-backup'),$this->backquote($table)) . "\n");
757 $this->stow("#\n");
758 }
759
760 if(($segment == 'none') || ($segment >= 0)) {
761 $defs = array();
762 $ints = array();
763 foreach ($table_structure as $struct) {
764 if ( (0 === strpos($struct->Type, 'tinyint')) ||
765 (0 === strpos(strtolower($struct->Type), 'smallint')) ||
766 (0 === strpos(strtolower($struct->Type), 'mediumint')) ||
767 (0 === strpos(strtolower($struct->Type), 'int')) ||
768 (0 === strpos(strtolower($struct->Type), 'bigint')) ) {
769 $defs[strtolower($struct->Field)] = ( null === $struct->Default ) ? 'NULL' : $struct->Default;
770 $ints[strtolower($struct->Field)] = "1";
771 }
772 }
773
774
775 // Batch by $row_inc
776
777 if($segment == 'none') {
778 $row_start = 0;
779 $row_inc = ROWS_PER_SEGMENT;
780 } else {
781 $row_start = $segment * ROWS_PER_SEGMENT;
782 $row_inc = ROWS_PER_SEGMENT;
783 }
784
785 do {
786 // don't include extra stuff, if so requested
787 $excs = (array) get_option('wp_db_backup_excs');
788 $where = '';
789 if ( is_array($excs['spam'] ) && in_array($table, $excs['spam']) ) {
790 $where = ' WHERE comment_approved != "spam"';
791 } elseif ( is_array($excs['revisions'] ) && in_array($table, $excs['revisions']) ) {
792 $where = ' WHERE post_type != "revision"';
793 }
794
795 if ( !ini_get('safe_mode')) @set_time_limit(15*60);
796 $table_data = $wpdb->get_results("SELECT * FROM $table $where LIMIT {$row_start}, {$row_inc}", ARRAY_A);
797
798 $entries = 'INSERT INTO ' . $this->backquote($table) . ' VALUES (';
799 // \x08\\x09, not required
800 $search = array("\x00", "\x0a", "\x0d", "\x1a");
801 $replace = array('\0', '\n', '\r', '\Z');
802 if($table_data) {
803 foreach ($table_data as $row) {
804 $values = array();
805 foreach ($row as $key => $value) {
806 if ($ints[strtolower($key)]) {
807 // make sure there are no blank spots in the insert syntax,
808 // yet try to avoid quotation marks around integers
809 $value = ( null === $value || '' === $value) ? $defs[strtolower($key)] : $value;
810 $values[] = ( '' === $value ) ? "''" : $value;
811 } else {
812 $values[] = "'" . str_replace($search, $replace, $this->sql_addslashes($value)) . "'";
813 }
814 }
815 $this->stow(" \n" . $entries . implode(', ', $values) . ') ;');
816 }
817 $row_start += $row_inc;
818 }
819 } while((count($table_data) > 0) and ($segment=='none'));
820 }
821
822 if(($segment == 'none') || ($segment < 0)) {
823 // Create footer/closing comment in SQL-file
824 $this->stow("\n");
825 $this->stow("#\n");
826 $this->stow("# " . sprintf(__('End of data contents of table %s','wp-db-backup'),$this->backquote($table)) . "\n");
827 $this->stow("# --------------------------------------------------------\n");
828 $this->stow("\n");
829 }
830 } // end backup_table()
831
832 function db_backup($core_tables, $other_tables) {
833 global $table_prefix, $wpdb;
834
835 if (is_writable($this->backup_dir)) {
836 $this->fp = $this->open($this->backup_dir . $this->backup_filename);
837 if(!$this->fp) {
838 $this->error(__('Could not open the backup file for writing!','wp-db-backup'));
839 return false;
840 }
841 } else {
842 $this->error(__('The backup directory is not writeable!','wp-db-backup'));
843 return false;
844 }
845
846 //Begin new backup of MySql
847 $this->stow("# " . __('WordPress MySQL database backup','wp-db-backup') . "\n");
848 $this->stow("#\n");
849 $this->stow("# " . sprintf(__('Generated: %s','wp-db-backup'),date("l j. F Y H:i T")) . "\n");
850 $this->stow("# " . sprintf(__('Hostname: %s','wp-db-backup'),DB_HOST) . "\n");
851 $this->stow("# " . sprintf(__('Database: %s','wp-db-backup'),$this->backquote(DB_NAME)) . "\n");
852 $this->stow("# --------------------------------------------------------\n");
853
854 if ( (is_array($other_tables)) && (count($other_tables) > 0) )
855 $tables = array_merge($core_tables, $other_tables);
856 else
857 $tables = $core_tables;
858
859 foreach ($tables as $table) {
860 // Increase script execution time-limit to 15 min for every table.
861 if ( !ini_get('safe_mode')) @set_time_limit(15*60);
862 // Create the SQL statements
863 $this->stow("# --------------------------------------------------------\n");
864 $this->stow("# " . sprintf(__('Table: %s','wp-db-backup'),$this->backquote($table)) . "\n");
865 $this->stow("# --------------------------------------------------------\n");
866 $this->backup_table($table);
867 }
868
869 $this->close($this->fp);
870
871 if (count($this->errors)) {
872 return false;
873 } else {
874 return $this->backup_filename;
875 }
876
877 } //wp_db_backup
878
879 /**
880 * Sends the backed-up file via email
881 * @param string $to
882 * @param string $subject
883 * @param string $message
884 * @return bool
885 */
886 function send_mail( $to, $subject, $message, $diskfile) {
887 global $phpmailer;
888
889 $filename = basename($diskfile);
890
891 extract( apply_filters( 'wp_mail', compact( 'to', 'subject', 'message' ) ) );
892
893 if ( !is_object( $phpmailer ) || ( strtolower(get_class( $phpmailer )) != 'phpmailer' ) ) {
894 if ( file_exists( ABSPATH . WPINC . '/class-phpmailer.php' ) )
895 require_once ABSPATH . WPINC . '/class-phpmailer.php';
896 if ( file_exists( ABSPATH . WPINC . '/class-smtp.php' ) )
897 require_once ABSPATH . WPINC . '/class-smtp.php';
898 if ( class_exists( 'PHPMailer') )
899 $phpmailer = new PHPMailer();
900 }
901
902 // try to use phpmailer directly (WP 2.2+)
903 if ( is_object( $phpmailer ) && ( strtolower(get_class( $phpmailer )) == 'phpmailer' ) ) {
904
905 // Get the site domain and get rid of www.
906 $sitename = strtolower( $_SERVER['SERVER_NAME'] );
907 if ( substr( $sitename, 0, 4 ) == 'www.' ) {
908 $sitename = substr( $sitename, 4 );
909 }
910 $from_email = 'wordpress@' . $sitename;
911 $from_name = 'WordPress';
912
913 // Empty out the values that may be set
914 $phpmailer->ClearAddresses();
915 $phpmailer->ClearAllRecipients();
916 $phpmailer->ClearAttachments();
917 $phpmailer->ClearBCCs();
918 $phpmailer->ClearCCs();
919 $phpmailer->ClearCustomHeaders();
920 $phpmailer->ClearReplyTos();
921
922 $phpmailer->AddAddress( $to );
923 $phpmailer->AddAttachment($diskfile, $filename);
924 $phpmailer->Body = $message;
925 $phpmailer->CharSet = apply_filters( 'wp_mail_charset', get_bloginfo('charset') );
926 $phpmailer->From = apply_filters( 'wp_mail_from', $from_email );
927 $phpmailer->FromName = apply_filters( 'wp_mail_from_name', $from_name );
928 $phpmailer->IsMail();
929 $phpmailer->Subject = $subject;
930
931 $result = @$phpmailer->Send();
932
933 // old-style: build the headers directly
934 } else {
935 $randomish = md5(time());
936 $boundary = "==WPBACKUP-$randomish";
937 $fp = fopen($diskfile,"rb");
938 $file = fread($fp,filesize($diskfile));
939 $this->close($fp);
940
941 $data = chunk_split(base64_encode($file));
942
943 $headers .= "MIME-Version: 1.0\n";
944 $headers = 'From: wordpress@' . preg_replace('#^www\.#', '', strtolower($_SERVER['SERVER_NAME'])) . "\n";
945 $headers .= "Content-Type: multipart/mixed; boundary=\"$boundary\"\n";
946
947 // Add a multipart boundary above the plain message
948 $message = "This is a multi-part message in MIME format.\n\n" .
949 "--{$boundary}\n" .
950 "Content-Type: text/plain; charset=\"" . get_bloginfo('charset') . "\"\n" .
951 "Content-Transfer-Encoding: 7bit\n\n" .
952 $message . "\n\n";
953
954 // Add file attachment to the message
955 $message .= "--{$boundary}\n" .
956 "Content-Type: application/octet-stream;\n" .
957 " name=\"{$filename}\"\n" .
958 "Content-Disposition: attachment;\n" .
959 " filename=\"{$filename}\"\n" .
960 "Content-Transfer-Encoding: base64\n\n" .
961 $data . "\n\n" .
962 "--{$boundary}--\n";
963
964 $result = @wp_mail($to, $subject, $message, $headers);
965 }
966 return false;
967 return $result;
968
969 }
970
971 function deliver_backup($filename = '', $delivery = 'http', $recipient = '', $location = 'main') {
972 if ('' == $filename) { return false; }
973
974 $diskfile = $this->backup_dir . $filename;
975 if ('http' == $delivery) {
976 if (! file_exists($diskfile))
977 $this->error(array('kind' => 'fatal', 'msg' => sprintf(__('File not found:%s','wp-db-backup'), "&nbsp;<strong>$filename</strong><br />") . '<br /><a href="' . $this->page_url . '">' . __('Return to Backup','wp-db-backup') . '</a>'));
978 header('Content-Description: File Transfer');
979 header('Content-Type: application/octet-stream');
980 header('Content-Length: ' . filesize($diskfile));
981 header("Content-Disposition: attachment; filename=$filename");
982 $success = readfile($diskfile);
983 unlink($diskfile);
984 } elseif ('smtp' == $delivery) {
985 if (! file_exists($diskfile)) {
986 $msg = sprintf(__('File %s does not exist!','wp-db-backup'), $diskfile);
987 $this->error($msg);
988 return false;
989 }
990 if (! is_email($recipient)) {
991 $recipient = get_option('admin_email');
992 }
993 $message = sprintf(__("Attached to this email is\n %1s\n Size:%2s kilobytes\n",'wp-db-backup'), $filename, round(filesize($diskfile)/1024));
994 $success = $this->send_mail($recipient, get_bloginfo('name') . ' ' . __('Database Backup','wp-db-backup'), $message, $diskfile);
995
996 if ( false == $success ) {
997 $msg = __('The following errors were reported:','wp-db-backup') . "\n ";
998 if ( function_exists('error_get_last') ) {
999 $err = error_get_last();
1000 $msg .= $err['message'];
1001 } else {
1002 $msg .= __('ERROR: The mail application has failed to deliver the backup.','wp-db-backup');
1003 }
1004 $this->error(array('kind' => 'fatal', 'loc' => $location, 'msg' => $msg));
1005 } else {
1006 unlink($diskfile);
1007 }
1008 }
1009 return $success;
1010 }
1011
1012 function backup_menu() {
1013 global $table_prefix, $wpdb;
1014 $feedback = '';
1015 $WHOOPS = FALSE;
1016
1017 // did we just do a backup? If so, let's report the status
1018 if ( $this->backup_complete ) {
1019 $feedback = '<div class="updated wp-db-backup-updated"><p>' . __('Backup Successful','wp-db-backup') . '!';
1020 $file = $this->backup_file;
1021 switch($_POST['deliver']) {
1022 case 'http':
1023 $feedback .= '<br />' . sprintf(__('Your backup file: <a href="%1s">%2s</a> should begin downloading shortly.','wp-db-backup'), WP_BACKUP_URL . "{$this->backup_file}", $this->backup_file);
1024 break;
1025 case 'smtp':
1026 if (! is_email($_POST['backup_recipient'])) {
1027 $feedback .= get_option('admin_email');
1028 } else {
1029 $feedback .= $_POST['backup_recipient'];
1030 }
1031 $feedback = '<br />' . sprintf(__('Your backup has been emailed to %s','wp-db-backup'), $feedback);
1032 break;
1033 case 'none':
1034 $feedback .= '<br />' . __('Your backup file has been saved on the server. If you would like to download it now, right click and select "Save As"','wp-db-backup');
1035 $feedback .= ':<br /> <a href="' . WP_BACKUP_URL . "$file\">$file</a> : " . sprintf(__('%s bytes','wp-db-backup'), filesize($this->backup_dir . $file));
1036 }
1037 $feedback .= '</p></div>';
1038 }
1039
1040 // security check
1041 $this->wp_secure();
1042
1043 if (count($this->errors)) {
1044 $feedback .= '<div class="updated wp-db-backup-updated error"><p><strong>' . __('The following errors were reported:','wp-db-backup') . '</strong></p>';
1045 $feedback .= '<p>' . $this->error_display( 'main', false ) . '</p>';
1046 $feedback .= "</p></div>";
1047 }
1048
1049 // did we just save options for wp-cron?
1050 if ( (function_exists('wp_schedule_event') || function_exists('wp_cron_init'))
1051 && isset($_POST['wp_cron_backup_options']) ) :
1052 do_action('wp_db_b_update_cron_options');
1053 if ( function_exists('wp_schedule_event') ) {
1054 wp_clear_scheduled_hook( 'wp_db_backup_cron' ); // unschedule previous
1055 $scheds = (array) wp_get_schedules();
1056 $name = strval($_POST['wp_cron_schedule']);
1057 $interval = ( isset($scheds[$name]['interval']) ) ?
1058 (int) $scheds[$name]['interval'] : 0;
1059 update_option('wp_cron_backup_schedule', $name, FALSE);
1060 if ( 0 !== $interval ) {
1061 wp_schedule_event(time() + $interval, $name, 'wp_db_backup_cron');
1062 }
1063 }
1064 else {
1065 update_option('wp_cron_backup_schedule', intval($_POST['cron_schedule']), FALSE);
1066 }
1067 update_option('wp_cron_backup_tables', $_POST['wp_cron_backup_tables']);
1068 if (is_email($_POST['cron_backup_recipient'])) {
1069 update_option('wp_cron_backup_recipient', $_POST['cron_backup_recipient'], FALSE);
1070 }
1071 $feedback .= '<div class="updated wp-db-backup-updated"><p>' . __('Scheduled Backup Options Saved!','wp-db-backup') . '</p></div>';
1072 endif;
1073
1074 $other_tables = array();
1075 $also_backup = array();
1076
1077 // Get complete db table list
1078 $all_tables = $wpdb->get_results("SHOW TABLES", ARRAY_N);
1079 $all_tables = array_map(create_function('$a', 'return $a[0];'), $all_tables);
1080 // Get list of WP tables that actually exist in this DB (for 1.6 compat!)
1081 $wp_backup_default_tables = array_intersect($all_tables, $this->core_table_names);
1082 // Get list of non-WP tables
1083 $other_tables = array_diff($all_tables, $wp_backup_default_tables);
1084
1085 if ('' != $feedback)
1086 echo $feedback;
1087
1088 if ( ! $this->wp_secure() )
1089 return;
1090
1091 // Give the new dirs the same perms as wp-content.
1092 // $stat = stat( ABSPATH . 'wp-content' );
1093 // $dir_perms = $stat['mode'] & 0000777; // Get the permission bits.
1094 $dir_perms = '0777';
1095
1096 // the file doesn't exist and can't create it
1097 if ( ! file_exists($this->backup_dir) && ! @mkdir($this->backup_dir) ) {
1098 ?><div class="updated wp-db-backup-updated error"><p><?php _e('WARNING: Your backup directory does <strong>NOT</strong> exist, and we cannot create it.','wp-db-backup'); ?></p>
1099 <p><?php printf(__('Using your FTP client, try to create the backup directory yourself: %s', 'wp-db-backup'), '<code>' . $this->backup_dir . '</code>'); ?></p></div><?php
1100 $WHOOPS = TRUE;
1101 // not writable due to write permissions
1102 } elseif ( !is_writable($this->backup_dir) && ! @chmod($this->backup_dir, $dir_perms) ) {
1103 ?><div class="updated wp-db-backup-updated error"><p><?php _e('WARNING: Your backup directory is <strong>NOT</strong> writable! We cannot create the backup files.','wp-db-backup'); ?></p>
1104 <p><?php printf(__('Using your FTP client, try to set the backup directory&rsquo;s write permission to %1$s or %2$s: %3$s', 'wp-db-backup'), '<code>777</code>', '<code>a+w</code>', '<code>' . $this->backup_dir . '</code>'); ?>
1105 </p></div><?php
1106 $WHOOPS = TRUE;
1107 } else {
1108 $this->fp = $this->open($this->backup_dir . 'test' );
1109 if( $this->fp ) {
1110 $this->close($this->fp);
1111 @unlink($this->backup_dir . 'test' );
1112 // the directory is not writable probably due to safe mode
1113 } else {
1114 ?><div class="updated wp-db-backup-updated error"><p><?php _e('WARNING: Your backup directory is <strong>NOT</strong> writable! We cannot create the backup files.','wp-db-backup'); ?></p><?php
1115 if( ini_get('safe_mode') ){
1116 ?><p><?php _e('This problem seems to be caused by your server&rsquo;s <code>safe_mode</code> file ownership restrictions, which limit what files web applications like WordPress can create.', 'wp-db-backup'); ?></p><?php
1117 }
1118 ?><?php printf(__('You can try to correct this problem by using your FTP client to delete and then re-create the backup directory: %s', 'wp-db-backup'), '<code>' . $this->backup_dir . '</code>');
1119 ?></div><?php
1120 $WHOOPS = TRUE;
1121 }
1122 }
1123
1124
1125
1126 if ( !file_exists($this->backup_dir . 'index.php') )
1127 @ touch($this->backup_dir . 'index.php');
1128 ?><div class='wrap'>
1129 <h2><?php _e('Backup','wp-db-backup') ?></h2>
1130 <form method="post" action="">
1131 <?php if ( function_exists('wp_nonce_field') ) wp_nonce_field($this->referer_check_key); ?>
1132 <fieldset class="options"><legend><?php _e('Tables','wp-db-backup') ?></legend>
1133 <div class="tables-list core-tables alternate">
1134 <h4><?php _e('These core WordPress tables will always be backed up:','wp-db-backup') ?></h4><ul><?php
1135 $excs = (array) get_option('wp_db_backup_excs');
1136 foreach ($wp_backup_default_tables as $table) {
1137 if ( $table == $wpdb->comments ) {
1138 $checked = ( is_array($excs['spam'] ) && in_array($table, $excs['spam']) ) ? ' checked=\'checked\'' : '';
1139 echo "<li><input type='hidden' name='core_tables[]' value='$table' /><code>$table</code> <span class='instructions'> <input type='checkbox' name='exclude-spam[]' value='$table' $checked /> " . __('Exclude spam comments', 'wp-db-backup') . '</span></li>';
1140 } elseif ( function_exists('wp_get_post_revisions') && $table == $wpdb->posts ) {
1141 $checked = ( is_array($excs['revisions'] ) && in_array($table, $excs['revisions']) ) ? ' checked=\'checked\'' : '';
1142 echo "<li><input type='hidden' name='core_tables[]' value='$table' /><code>$table</code> <span class='instructions'> <input type='checkbox' name='exclude-revisions[]' value='$table' $checked /> " . __('Exclude post revisions', 'wp-db-backup') . '</span></li>';
1143 } else {
1144 echo "<li><input type='hidden' name='core_tables[]' value='$table' /><code>$table</code></li>";
1145 }
1146 }
1147 ?></ul>
1148 </div>
1149 <div class="tables-list extra-tables" id="extra-tables-list">
1150 <?php
1151 if (count($other_tables) > 0) {
1152 ?>
1153 <h4><?php _e('You may choose to include any of the following tables:','wp-db-backup'); ?></h4>
1154 <ul>
1155 <?php
1156 foreach ($other_tables as $table) {
1157 ?>
1158 <li><label><input type="checkbox" name="other_tables[]" value="<?php echo $table; ?>" /> <code><?php echo $table; ?></code></label>
1159 <?php
1160 }
1161 ?></ul><?php
1162 }
1163 ?></div>
1164 </fieldset>
1165
1166 <fieldset class="options">
1167 <legend><?php _e('Backup Options','wp-db-backup'); ?></legend>
1168 <p><?php _e('What to do with the backup file:','wp-db-backup'); ?></p>
1169 <ul>
1170 <li><label for="do_save">
1171 <input type="radio" id="do_save" name="deliver" value="none" style="border:none;" />
1172 <?php _e('Save to server','wp-db-backup');
1173 echo " (<code>" . $this->backup_dir . "</code>)"; ?>
1174 </label></li>
1175 <li><label for="do_download">
1176 <input type="radio" checked="checked" id="do_download" name="deliver" value="http" style="border:none;" />
1177 <?php _e('Download to your computer','wp-db-backup'); ?>
1178 </label></li>
1179 <li><label for="do_email">
1180 <input type="radio" name="deliver" id="do_email" value="smtp" style="border:none;" />
1181 <?php _e('Email backup to:','wp-db-backup'); ?>
1182 <input type="text" name="backup_recipient" size="20" value="<?php echo get_option('admin_email'); ?>" />
1183 </label></li>
1184 </ul>
1185 <?php if ( ! $WHOOPS ) : ?>
1186 <input type="hidden" name="do_backup" id="do_backup" value="backup" />
1187 <p class="submit">
1188 <input type="submit" name="submit" onclick="document.getElementById('do_backup').value='fragments';" value="<?php _e('Backup now!','wp-db-backup'); ?>" />
1189 </p>
1190 <?php else : ?>
1191 <div class="updated wp-db-backup-updated error"><p><?php _e('WARNING: Your backup directory is <strong>NOT</strong> writable!','wp-db-backup'); ?></p></div>
1192 <?php endif; // ! whoops ?>
1193 </fieldset>
1194 <?php do_action('wp_db_b_backup_opts'); ?>
1195 </form>
1196
1197 <?php
1198 // this stuff only displays if some sort of wp-cron is available
1199 $cron = ( function_exists('wp_schedule_event') ) ? true : false; // wp-cron in WP 2.1+
1200 $cron_old = ( function_exists('wp_cron_init') && ! $cron ) ? true : false; // wp-cron plugin by Skippy
1201 if ( $cron_old || $cron ) :
1202 echo '<fieldset class="options"><legend>' . __('Scheduled Backup','wp-db-backup') . '</legend>';
1203 $datetime = get_option('date_format') . ' ' . get_option('time_format');
1204 if ( $cron ) :
1205 $next_cron = wp_next_scheduled('wp_db_backup_cron');
1206 if ( ! empty( $next_cron ) ) :
1207 ?>
1208 <p id="backup-time-wrap">
1209 <?php printf(__('Next Backup: %s','wp-db-backup'), '<span id="next-backup-time">' . gmdate($datetime, $next_cron + (get_option('gmt_offset') * 3600)) . '</span>'); ?>
1210 </p>
1211 <?php
1212 endif;
1213 elseif ( $cron_old ) :
1214 ?><p><?php printf(__('Last WP-Cron Daily Execution: %s','wp-db-backup'), gmdate($datetime, get_option('wp_cron_daily_lastrun') + (get_option('gmt_offset') * 3600))); ?><br /><?php
1215 printf(__('Next WP-Cron Daily Execution: %s','wp-db-backup'), gmdate($datetime, (get_option('wp_cron_daily_lastrun') + (get_option('gmt_offset') * 3600) + 86400))); ?></p><?php
1216 endif;
1217 ?><form method="post" action="">
1218 <?php if ( function_exists('wp_nonce_field') ) wp_nonce_field($this->referer_check_key); ?>
1219 <div class="tables-list">
1220 <h4><?php _e('Schedule: ','wp-db-backup'); ?></h4>
1221 <?php
1222 if ( $cron_old ) :
1223 $wp_cron_backup_schedule = get_option('wp_cron_backup_schedule');
1224 $schedule = array(0 => __('None','wp-db-backup'), 1 => __('Daily','wp-db-backup'));
1225 foreach ($schedule as $value => $name) {
1226 echo ' <input type="radio" style="border:none;" name="cron_schedule"';
1227 if ($wp_cron_backup_schedule == $value) {
1228 echo ' checked="checked" ';
1229 }
1230 echo 'value="' . $value . '" /> ' . $name;
1231 }
1232 elseif ( $cron ) :
1233 echo apply_filters('wp_db_b_schedule_choices', wp_get_schedules() );
1234 endif;
1235 $cron_recipient = get_option('wp_cron_backup_recipient');
1236 if (! is_email($cron_recipient)) {
1237 $cron_recipient = get_option('admin_email');
1238 }
1239 $cron_recipient_input = '<p><label for="cron_backup_recipient">' . __('Email backup to:','wp-db-backup') . ' <input type="text" name="cron_backup_recipient" id="cron_backup_recipient" size="20" value="' . $cron_recipient . '" /></label></p>';
1240 echo apply_filters('wp_db_b_cron_recipient_input', $cron_recipient_input);
1241 echo '</div><div class="tables-list alternate" id="include-tables-list">';
1242 $cron_tables = get_option('wp_cron_backup_tables');
1243 if (! is_array($cron_tables)) {
1244 $cron_tables = array();
1245 }
1246 if (count($other_tables) > 0) {
1247 echo '<h4>' . __('Tables to include in the scheduled backup:','wp-db-backup') . '</h4><ul>';
1248 foreach ($other_tables as $table) {
1249 echo '<li><input type="checkbox" ';
1250 if (in_array($table, $cron_tables)) {
1251 echo 'checked="checked" ';
1252 }
1253 echo "name='wp_cron_backup_tables[]' value='{$table}' /> <code>{$table}</code></li>";
1254 }
1255 echo '</ul>';
1256 }
1257 echo '<input type="hidden" name="wp_cron_backup_options" value="SET" /><p class="submit"><input type="submit" name="submit" value="' . __('Schedule backup','wp-db-backup') . '" /></p></div></form>';
1258 echo '</fieldset>';
1259 endif; // end of wp_cron (legacy) section
1260
1261 echo '</div>';
1262
1263 } // end wp_backup_menu()
1264
1265 function get_sched() {
1266 $options = array_keys( (array) wp_get_schedules() );
1267 $freq = get_option('wp_cron_backup_schedule');
1268 $freq = ( in_array( $freq , $options ) ) ? $freq : 'never';
1269 return $freq;
1270 }
1271
1272 function schedule_choices($schedule) { // create the cron menu based on the schedule
1273 $wp_cron_backup_schedule = $this->get_sched();
1274 $next_cron = wp_next_scheduled('wp_db_backup_cron');
1275 $wp_cron_backup_schedule = ( empty( $next_cron ) ) ? 'never' : $wp_cron_backup_schedule;
1276 $sort = array();
1277 foreach ( (array) $schedule as $key => $value ) $sort[$key] = $value['interval'];
1278 asort( $sort );
1279 $schedule_sorted = array();
1280 foreach ( (array) $sort as $key => $value ) $schedule_sorted[$key] = $schedule[$key];
1281 $menu = '<ul>';
1282 $schedule = array_merge( array( 'never' => array( 'interval' => 0, 'display' => __('Never','wp-db-backup') ) ),
1283 (array) $schedule_sorted );
1284 foreach ( $schedule as $name => $settings) {
1285 $interval = (int) $settings['interval'];
1286 if ( 0 == $interval && ! 'never' == $name ) continue;
1287 $display = ( ! '' == $settings['display'] ) ? $settings['display'] : sprintf(__('%s seconds','wp-db-backup'),$interval);
1288 $menu .= "<li><input type='radio' name='wp_cron_schedule' style='border:none;' ";
1289 if ($wp_cron_backup_schedule == $name) {
1290 $menu .= " checked='checked' ";
1291 }
1292 $menu .= "value='$name' /> $display</li>";
1293 }
1294 $menu .= '</ul>';
1295 return $menu;
1296 } // end schedule_choices()
1297
1298 function wp_cron_daily() { // for legacy cron plugin
1299 $schedule = intval(get_option('wp_cron_backup_schedule'));
1300 // If scheduled backup is disabled
1301 if (0 == $schedule)
1302 return;
1303 else return $this->cron_backup();
1304 }
1305
1306 function cron_backup() {
1307 global $table_prefix, $wpdb;
1308 $all_tables = $wpdb->get_results("SHOW TABLES", ARRAY_N);
1309 $all_tables = array_map(create_function('$a', 'return $a[0];'), $all_tables);
1310 $core_tables = array_intersect($all_tables, $this->core_table_names);
1311 $other_tables = get_option('wp_cron_backup_tables');
1312 $recipient = get_option('wp_cron_backup_recipient');
1313 $backup_file = $this->db_backup($core_tables, $other_tables);
1314 if (FALSE !== $backup_file)
1315 return $this->deliver_backup($backup_file, 'smtp', $recipient, 'main');
1316 else return false;
1317 }
1318
1319 function add_sched_options($sched) {
1320 $sched['weekly'] = array('interval' => 604800, 'display' => __('Once Weekly','wp-db-backup'));
1321 return $sched;
1322 }
1323
1324 /**
1325 * Checks that WordPress has sufficient security measures
1326 * @param string $kind
1327 * @return bool
1328 */
1329 function wp_secure($kind = 'warn', $loc = 'main') {
1330 global $wp_version;
1331 if ( function_exists('wp_verify_nonce') ) return true;
1332 else {
1333 $this->error(array('kind' => $kind, 'loc' => $loc, 'msg' => sprintf(__('Your WordPress version, %1s, lacks important security features without which it is unsafe to use the WP-DB-Backup plugin. Hence, this plugin is automatically disabled. Please consider <a href="%2s">upgrading WordPress</a> to a more recent version.','wp-db-backup'),$wp_version,'http://wordpress.org/download/')));
1334 return false;
1335 }
1336 }
1337
1338 /**
1339 * Checks that the user has sufficient permission to backup
1340 * @param string $loc
1341 * @return bool
1342 */
1343 function can_user_backup($loc = 'main') {
1344 $can = false;
1345 // make sure WPMU users are site admins, not ordinary admins
1346 if ( function_exists('is_site_admin') && ! is_site_admin() )
1347 return false;
1348 if ( ( $this->wp_secure('fatal', $loc) ) && current_user_can('import') )
1349 $can = $this->verify_nonce($_REQUEST['_wpnonce'], $this->referer_check_key, $loc);
1350 if ( false == $can )
1351 $this->error(array('loc' => $loc, 'kind' => 'fatal', 'msg' => __('You are not allowed to perform backups.','wp-db-backup')));
1352 return $can;
1353 }
1354
1355 /**
1356 * Verify that the nonce is legitimate
1357 * @param string $rec the nonce received
1358 * @param string $nonce what the nonce should be
1359 * @param string $loc the location of the check
1360 * @return bool
1361 */
1362 function verify_nonce($rec = '', $nonce = 'X', $loc = 'main') {
1363 if ( wp_verify_nonce($rec, $nonce) )
1364 return true;
1365 else
1366 $this->error(array('loc' => $loc, 'kind' => 'fatal', 'msg' => sprintf(__('There appears to be an unauthorized attempt from this site to access your database located at %1s. The attempt has been halted.','wp-db-backup'),get_option('home'))));
1367 }
1368
1369 /**
1370 * Check whether a file to be downloaded is
1371 * surreptitiously trying to download a non-backup file
1372 * @param string $file
1373 * @return null
1374 */
1375 function validate_file($file) {
1376 if ( (false !== strpos($file, '..')) || (false !== strpos($file, './')) || (':' == substr($file, 1, 1)) )
1377 $this->error(array('kind' => 'fatal', 'loc' => 'frame', 'msg' => __("Cheatin' uh ?",'wp-db-backup')));
1378 }
1379
1380 }
1381
1382 function wpdbBackup_init() {
1383 global $mywpdbbackup;
1384 $mywpdbbackup = new wpdbBackup();
1385 }
1386
1387 add_action('plugins_loaded', 'wpdbBackup_init');
1388 ?>
1389