PluginProbe
Database Backup for WordPress / 1.4
Database Backup for WordPress v1.4
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 1.4, at wp-db-backup.php

488 lines 17.3 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.skippy.net/plugins/
5 Description: On-demand backup of your WordPress database.
6 Author: Scott Merrill
7 Version: 1.4
8 Author URI: http://www.skippy.net/
9
10 Much of this was modified from Mark Ghosh's One Click Backup, which
11 in turn was derived from phpMyAdmin.
12
13 */
14
15 add_action('admin_menu', 'add_wp_backup_menu');
16 add_action('wp_cron_daily', 'wp_cron_db_backup');
17 global $wp_backup_dir, $wp_backup_error;
18 $wp_backup_error = '';
19 $wp_backup_dir = 'wp-content/backup/';
20
21 // this needs to live outside of any function so that the
22 // download can be sent to the browser
23 if (isset($_GET['backup'])) {
24 wp_deliver_backup ($_GET['backup'], 'http');
25 die();
26 }
27 if ( (isset($_POST['do_backup'])) && ('backup' == $_POST['do_backup']) ) {
28 // should we compress the output?
29 if ('gzip' == $_POST['gzip']) {
30 $gzip = TRUE;
31 } else {
32 $gzip = FALSE;
33 }
34 // are we backing up any other tables?
35 $also_backup = array();
36 if (isset($_POST['other_tables'])) {
37 $also_backup = $_POST['other_tables'];
38 }
39 $core_tables = $_POST['core_tables'];
40 $backup_file = wp_db_backup($gzip, $core_tables, $also_backup);
41 if (FALSE !== $backup_file) {
42 if ('smtp' == $_POST['deliver']) {
43 wp_deliver_backup ($backup_file, $_POST['deliver'], $_POST['backup_recipient']);
44 } elseif ('http' == $_POST['deliver']) {
45 header('Refresh: 3; ' . get_settings('siteurl') . "/wp-admin/edit.php?page=wp-db-backup.php&backup=$backup_file");
46 }
47 // we do this to say we're done.
48 $_POST['do_backup'] = 'DONE';
49 // and we do this to pass the filename, and avoid a global
50 $_POST['gzip'] = $backup_file;
51 }
52 }
53
54 ///////////////////////////////
55 function add_wp_backup_menu() {
56 add_management_page('Backup', 'Backup', 9, __FILE__, 'wp_backup_menu');
57 }
58
59 /////////////////////////////////////////////////////////
60 function sql_addslashes($a_string = '', $is_like = FALSE)
61 {
62 /*
63 Better addslashes for SQL queries.
64 Taken from phpMyAdmin.
65 */
66 if ($is_like) {
67 $a_string = str_replace('\\', '\\\\\\\\', $a_string);
68 } else {
69 $a_string = str_replace('\\', '\\\\', $a_string);
70 }
71 $a_string = str_replace('\'', '\\\'', $a_string);
72
73 return $a_string;
74 } // function sql_addslashes($a_string = '', $is_like = FALSE)
75
76 ///////////////////////////////////////////////////////////
77 function backquote($a_name)
78 {
79 /*
80 Add backqouotes to tables and db-names in
81 SQL queries. Taken from phpMyAdmin.
82 */
83 if (!empty($a_name) && $a_name != '*') {
84 if (is_array($a_name)) {
85 $result = array();
86 reset($a_name);
87 while(list($key, $val) = each($a_name)) {
88 $result[$key] = '`' . $val . '`';
89 }
90 return $result;
91 } else {
92 return '`' . $a_name . '`';
93 }
94 } else {
95 return $a_name;
96 }
97 } // function backquote($a_name, $do_it = TRUE)
98
99 /////////////////////////////
100 function backup_table($table) {
101 global $wp_backup_error, $wpdb;
102
103 /*
104 Taken partially from phpMyAdmin and partially from
105 Alain Wolf, Zurich - Switzerland
106 Website: http://restkultur.ch/personal/wolf/scripts/db_backup/
107
108 Modified by Scott Merril (http://www.skippy.net/)
109 to use the WordPress $wpdb object
110 */
111
112 $sql_statements = '';
113
114 //
115 // Add SQL statement to drop existing table
116 $sql_statements .= "\n";
117 $sql_statements .= "\n";
118 $sql_statements .= "#\n";
119 $sql_statements .= "# Delete any existing table " . backquote($table) . "\n";
120 $sql_statements .= "#\n";
121 $sql_statements .= "\n";
122 $sql_statements .= "DROP TABLE IF EXISTS " . backquote($table) . ";\n";
123
124 //
125 //Table structure
126 // Comment in SQL-file
127 $sql_statements .= "\n";
128 $sql_statements .= "\n";
129 $sql_statements .= "#\n";
130 $sql_statements .= "# Table structure of table " . backquote($table) . "\n";
131 $sql_statements .= "#\n";
132 $sql_statements .= "\n";
133
134 $create_table = $wpdb->get_results("SHOW CREATE TABLE $table", ARRAY_N);
135 if (FALSE === $create_table) {
136 $wp_backup_error .= "Error with SHOW CREATE TABLE for $table.\r\n";
137 return "#\n# Error with SHOW CREATE TABLE for $table!\n#\n";
138 }
139 $sql_statements .= $create_table[0][1] . ' ;';
140
141 $table_structure = $wpdb->get_results("DESCRIBE $table");
142 if (FALSE === $table_structure) {
143 $wp_backup_error .= "Error getting table structure of $table\r\n";
144 return "#\n# Error getting table structure of $table!\n#\n";
145 }
146
147 $table_data = $wpdb->get_results("SELECT * FROM $table", ARRAY_A);
148 if (FALSE === $table_data) {
149 $wp_backup_error .= "Error getting table contents from $table\r\n";
150 return "#\n# Error getting table contents fom $table!\n#\n";
151 }
152
153 //
154 // Comment in SQL-file
155 $sql_statements .= "\n";
156 $sql_statements .= "\n";
157 $sql_statements .= "#\n";
158 $sql_statements .= '# Data contents of table ' . backquote($table) . "\n";
159 $sql_statements .= "#\n";
160
161 $ints = array();
162 foreach ($table_structure as $struct) {
163 if ( (0 === strpos($struct->Type, 'tinyint')) ||
164 (0 === strpos(strtolower($struct->Type), 'smallint')) ||
165 (0 === strpos(strtolower($struct->Type), 'mediumint')) ||
166 (0 === strpos(strtolower($struct->Type), 'int')) ||
167 (0 === strpos(strtolower($struct->Type), 'bigint')) ||
168 (0 === strpos(strtolower($struct->Type), 'timestamp')) ) {
169 $ints[strtolower($struct->Field)] = "1";
170 }
171 }
172
173 $entries = 'INSERT INTO ' . backquote($table) . ' VALUES (';
174 // \x08\\x09, not required
175 $search = array("\x00", "\x0a", "\x0d", "\x1a");
176 $replace = array('\0', '\n', '\r', '\Z');
177 foreach ($table_data as $row) {
178 $values = array();
179 foreach ($row as $key => $value) {
180 if ($ints[strtolower($key)]) {
181 $values[] = $value;
182 } else {
183 $values[] = "'" . str_replace($search, $replace, sql_addslashes($value)) . "'";
184 }
185 }
186 $sql_statements .= " \n" . $entries . implode(', ', $values) . ') ;';
187 }
188 // Create footer/closing comment in SQL-file
189 $sql_statements .= "\n";
190 $sql_statements .= "#\n";
191 $sql_statements .= "# End of data contents of table " . backquote($table) . "\n";
192 $sql_statements .= "# --------------------------------------------------------\n";
193 $sql_statements .= "\n";
194
195 return $sql_statements;
196
197 } // end backup_table()
198
199 ////////////////////////////
200 function wp_db_backup($gzip = FALSE, $core_tables, $other_tables) {
201
202 global $wp_backup_dir, $wp_backup_error, $table_prefix, $wpdb;
203
204 $done = array();
205
206 $datum = date("Ymd_B");
207 $wp_backup_filename = DB_NAME . "_$table_prefix$datum.sql";
208 if ($gzip) {
209 $wp_backup_filename .= '.gz';
210 }
211
212 //Begin new backup of MySql
213 $sql = "# WordPress MySQL database backup\n";
214 $sql .= "#\n";
215 $sql .= "# Generated: " . date("l j. F Y H:i T") . "\n";
216 $sql .= "# Hostname: " . DB_HOST . "\n";
217 $sql .= "# Database: " . backquote(DB_NAME) . "\n";
218 $sql .= "# --------------------------------------------------------\n";
219
220 foreach ($core_tables as $table) {
221 if (in_array($table, $done)) { continue; }
222 // Increase script execution time-limit to 15 min for every table.
223 if ( !ini_get('safe_mode')) @set_time_limit(15*60);
224 //ini_set('memory_limit', '16M');
225 // Create the SQL statements
226 $tbl = "# --------------------------------------------------------\n";
227 $tbl .= "# Table: " . backquote($table) . "\n";
228 $tbl .= "# --------------------------------------------------------\n";
229 $tbl .= backup_table($table);
230 $sql .= $tbl;
231 $done[] = $table;
232 }
233
234 if (count($other_tables) > 0) {
235 foreach ($other_tables as $other_table) {
236 if (in_array($other_table, $done)) { continue; }
237 // Increase script execution time-limit to 15 min for every table.
238 if ( !ini_get('safe_mode')) @set_time_limit(15*60);
239 //ini_set('memory_limit', '16M');
240 // Create the SQL statements
241 $tbl = "# --------------------------------------------------------\n";
242 $tbl .= "# Table: " . backquote($other_table) . "\n";
243 $tbl .= "# --------------------------------------------------------\n";
244 $tbl .= backup_table($other_table);
245 $sql .= $tbl;
246 $done[] = $other_table;
247 } // foreach
248 } // if other_tables...
249
250 if (is_writable(ABSPATH . $wp_backup_dir)) {
251 if ($gzip) {
252 $sql = gzencode($sql);
253 }
254 $cachefp = fopen(ABSPATH . $wp_backup_dir . $wp_backup_filename, "w");
255 fwrite($cachefp, $sql);
256 fclose($cachefp);
257 }
258
259 if ('' == $wp_backup_error) {
260 return $wp_backup_filename;
261 } else {
262 return FALSE;
263 }
264
265 } //wp_db_backup
266
267 ///////////////////////////
268 function wp_deliver_backup ($filename = '', $delivery = 'http', $recipient = '') {
269 global $wp_backup_dir;
270
271 if ('' == $filename) { return FALSE; }
272
273 $diskfile = ABSPATH . $wp_backup_dir . $filename;
274 if ('http' == $delivery) {
275 header('Content-Description: File Transfer');
276 header('Content-Type: application/octet-stream');
277 header('Content-Length: ' . filesize($diskfile));
278 header("Content-Disposition: attachment; filename=$filename");
279 readfile($diskfile);
280 unlink($diskfile);
281 } elseif ('smtp' == $delivery) {
282 if (! is_email ($recipient)) {
283 $recipient = get_settings('admin_email');
284 }
285 $randomish = md5(time());
286 $boundary = "==WPBACKUP-BY-SKIPPY-$randomish";
287 $fp = fopen($diskfile,"rb");
288 $file = fread($fp,filesize($diskfile));
289 fclose($fp);
290 $data = chunk_split(base64_encode($file));
291 $headers = "MIME-Version: 1.0\n";
292 $headers .= "Content-Type: multipart/mixed; boundary=\"$boundary\"\n";
293 $headers .= 'From: ' . get_settings('admin_email') . "\n";
294
295 $message = __('Attached to this email is', 'wp_backup') . "\n $filename\n". __('Size', 'wp_backup') . ": " . round(filesize($diskfile)/1024) . ' ' . __('kilobytes', 'wp_backup') . "\n";
296 // Add a multipart boundary above the plain message
297 $message = "This is a multi-part message in MIME format.\n\n" .
298 "--{$boundary}\n" .
299 "Content-Type: text/plain; charset=\"iso-8859-1\"\n" .
300 "Content-Transfer-Encoding: 7bit\n\n" .
301 $message . "\n\n";
302
303 // Add file attachment to the message
304 $message .= "--{$boundary}\n" .
305 "Content-Type: application/octet-stream;\n" .
306 " name=\"{$filename}\"\n" .
307 "Content-Disposition: attachment;\n" .
308 " filename=\"{$filename}\"\n" .
309 "Content-Transfer-Encoding: base64\n\n" .
310 $data . "\n\n" .
311 "--{$boundary}--\n";
312
313 mail ($recipient, get_bloginfo('name') . ' ' . __('Database Backup', 'wp_backup'), $message, $headers);
314
315 unlink($diskfile);
316 }
317 return;
318 }
319
320 ////////////////////////////
321 function wp_backup_menu() {
322 global $wp_backup_dir, $wp_backup_error, $table_prefix, $wpdb;
323 $feedback = '';
324 $gzip = FALSE;
325 $WHOOPS = FALSE;
326
327 // first, did we just do a backup? If so, let's report the status
328 if ( (isset($_POST['do_backup'])) && ('DONE' == $_POST['do_backup']) ) {
329 $feedback = '<div class="updated"><p>' . __('Backup Successful', 'wp_backup') . '!';
330 // we stuff the filename into gzip to avoid another global
331 $file = $_POST['gzip'];
332 if ('http' == $_POST['deliver']) {
333 $feedback .= '<br />' . __('Your backup file', 'wp_backup') . ': <a href="' . get_settings('siteurl') . "/$wp_backup_dir$file\">$file</a> " . __('should begin downloading shortly.', 'wp_backup');
334 } elseif ('smtp' == $_POST['deliver']) {
335 $feedback .= '<br />' . __('Your backup has been emailed to ', 'wp_backup');
336 if (! is_email($_POST['backup_recipient'])) {
337 $feedback .= get_settings('admin_email');
338 } else {
339 $feedback .= $_POST['backup_recipient'];
340 }
341 } elseif ('none' == $_POST['deliver']) {
342 $feedback .= '<br />' . __('Your backup file', 'wp_backup') . ' ' . __('is ready for download; right click and select "Save As"', 'wp_backup') . ':<br /> <a href="' . get_settings('siteurl') . "/$wp_backup_dir$file\">$file</a> : " . filesize(ABSPATH . $wp_backup_dir . $file) . __(' bytes', 'wp_backup');
343 }
344 $feedback .= '</p></div>';
345 } elseif ('' != $wp_backup_error) {
346 $feedback = '<div class="updated">' . __('The following errors were reported', 'wp_backup') . ":<br /><pre>$wp_backup_error</pre></div>";
347 }
348
349 // did we just save options for wp-cron?
350 if ( (function_exists('wp_cron_db_backup')) && isset($_POST['wp_cron_backup_options']) ) {
351 update_option('wp_cron_backup_schedule', intval($_POST['cron_schedule']), FALSE);
352 if (is_email($_POST['cron_backup_recipient'])) {
353 update_option('wp_cron_backup_recipient', $_POST['cron_backup_recipient'], FALSE);
354 }
355 $feedback .= '<div class="updated"><p>' . __('Scheduled Backup Options Saved!', 'wp_backup') . '</p></div>';
356 }
357
358 $gzip = FALSE;
359 $wp_backup_default_tables = array ($table_prefix . categories,
360 $table_prefix . comments,
361 $table_prefix . linkcategories,
362 $table_prefix . links,
363 $table_prefix . options,
364 $table_prefix . post2cat,
365 $table_prefix . postmeta,
366 $table_prefix . posts,
367 $table_prefix . users);
368
369 $other_tables = array();
370 $also_backup = array();
371
372 // let's get other tables in this database
373 $all_tables = $wpdb->get_results("SHOW TABLES", ARRAY_N);
374 foreach ($all_tables as $table) {
375 if (! in_array($table[0], $wp_backup_default_tables)) {
376 $other_tables[] = $table[0];
377 }
378 }
379
380 if ('' != $feedback) {
381 echo $feedback;
382 }
383
384 if (! is_writable(ABSPATH . $wp_backup_dir)) {
385 echo '<div class="updated"><p align="center">' . __('WARNING: Your backup directory is <strong>NOT</strong> writable!</strong>', 'wp_backup') . '<br />' . ABSPATH . "$wp_backup_dir</p></div>";
386 $WHOOPS = TRUE;
387 }
388 echo "<div class='wrap'>";
389 echo '<h2>' . __('Backup', 'wp_backup') . '</h2>';
390 echo '<fieldset class="options"><legend>' . __('Tables', 'wp_backup') . '</legend>';
391 echo '<form method="post">';
392 echo '<table align="center" cellspacing="5" cellpadding="5"><tr><td width="50%" align="left" class="alternate">';
393 echo __('These core WordPress tables will always be backed up', 'wp_backup') . ': <br /><ul>';
394 foreach ($wp_backup_default_tables as $table) {
395 echo "<input type='hidden' name='core_tables[]' value='$table' /><li>$table</li>";
396 }
397 echo '</ul></td><td width="50%" align="left">';
398 if (count($other_tables) > 0) {
399 echo __('You may choose to include any of the following tables', 'wp_backup') . ': <br />';
400 foreach ($other_tables as $table) {
401 echo "<input type='checkbox' name='other_tables[]' value='$table' />$table<br />";
402 }
403 }
404 echo '</tr></table></fieldset>';
405 echo '<fieldset class="options"><legend>' . __('Backup Options', 'wp_backup') . '</legend><table width="100%" align="center" cellpadding="5" cellspacing="5">';
406 echo '<tr><td align="center">';
407 echo __('Deliver backup file by', 'wp_backup') . ":<br />";
408 echo '<input type="radio" name="deliver" value="none" /> ' . __('None', 'wp_backup') . '&nbsp;&nbsp;&nbsp;&nbsp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />';
409 echo '<input type="radio" name="deliver" value="smtp" /> ' . __('Email', 'wp_backup') . '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />';
410 echo '<input type="radio" name="deliver" value="http" /> ' . __('Download', 'wp_backup');
411 echo '</td><td align="left">' . __('Email backup to', 'wp_backup') . ':<br /> <input type="text" name="backup_recipient" size="20" value="' . get_settings('admin_email') . '" /></td></tr>';
412 echo '<tr class="alternate"><td colspan="2" align="center">';
413 if (! $WHOOPS) {
414 echo __('Use gzip compression', 'wp_backup') . '? <input type="checkbox" checked="checked" name="gzip" value="gzip" /><br />';
415 echo '<input type="hidden" name="do_backup" value="backup" />';
416 echo '<input type="submit" name="submit" value="' . __('Backup', 'wp_backup') . '!" / >';
417 } else {
418 echo __('WARNING: Your backup directory is <strong>NOT</strong> writable!</strong>', 'wp_backup');
419 }
420 echo '</td></tr></form></table>';
421 echo '</fieldset>';
422
423 // this stuff only displays if wp_cron is installed
424 if (function_exists('wp_cron_db_backup')) {
425 echo '<fieldset class="options"><legend>' . __('Scheduled', 'wp_backup') . ' ' . __('Backup', 'wp_backup') . '</legend>';
426 echo '<p>' . __('Last WP-Cron Daily Execution', 'wp_backup') . ': ' . date('Y-m-d @ h:i', get_option('wp_cron_daily_lastrun')) . '<br />';
427 echo __('Next WP-Cron Daily Execution', 'wp_backup') . ': ' . date('Y-m-d @ h:i', (get_option('wp_cron_daily_lastrun') + 86400)) . '</p>';
428 echo '<form method="post">';
429 echo '<table width="100%" callpadding="5" cellspacing="5">';
430 echo '<tr><td align="center">';
431 echo __('Schedule: ', 'wp_backup');
432 $wp_cron_backup_schedule = get_option('wp_cron_backup_schedule');
433 $schedule = array("None" => 0, "Daily" => 1);
434 foreach ($schedule as $name => $value) {
435 echo ' <input type="radio" name="cron_schedule"';
436 if ($wp_cron_backup_schedule == $value) {
437 echo ' checked="checked" ';
438 }
439 echo 'value="' . $value . '" /> ' . __($name, 'wp_backup');
440 }
441 echo '</td><td align="center">';
442 $cron_recipient = get_option('wp_cron_backup_recipient');
443 if (! is_email($cron_recipient)) {
444 $cron_recipient = get_settings('admin_email');
445 }
446 echo __('Email backup to', 'wp_backup') . ': <input type="text" name="cron_backup_recipient" size="20" value="' . $cron_recipient . '" />';
447 echo '</td></tr>';
448 echo '<tr><td colspan="2" align="center"><input type="hidden" name="wp_cron_backup_options" value="SET" /><input type="submit" name="submit" value="' . __('Submit', 'wp_backup') . '" /></td></tr></table></form>';
449 echo '</fieldset>';
450 }
451 // end of wp_cron section
452
453 echo '</fieldset></div>';
454
455 }// end wp_backup_menu()
456
457 /////////////////////////////
458 function wp_cron_db_backup() {
459
460 $schedule = intval(get_option('wp_cron_backup_schedule'));
461 if (0 == $schedule) {
462 // Scheduled backup is disabled
463 return;
464 }
465
466 global $wp_backup_dir, $wp_backup_error, $table_prefix;
467 $core_tables = array ($table_prefix . categories,
468 $table_prefix . comments,
469 $table_prefix . linkcategories,
470 $table_prefix . links,
471 $table_prefix . options,
472 $table_prefix . post2cat,
473 $table_prefix . postmeta,
474 $table_prefix . posts,
475 $table_prefix . users);
476
477 $recipient = get_option('wp_cron_backup_recipient');
478
479 $backup_file = wp_db_backup(TRUE, $core_tables);
480 if (FALSE !== $backup_file) {
481 wp_deliver_backup ($backup_file, 'smtp', $recipient);
482 }
483
484 return;
485 } // wp_cron_db_backup
486
487 ?>
488