4c92a7f608b634d22892cd5d1e3b3bfe4d141f25
[autoinstalls/wordpress.git] / wp-content / plugins / wp-db-backup.php
1 <?php
2 /*
3 Plugin Name: WordPress Database Backup
4 Plugin URI: http://www.skippy.net/blog/plugins/
5 Description: On-demand backup of your WordPress database.
6 Author: Scott Merrill
7 Version: 1.7
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 Many thanks to Owen (http://asymptomatic.net/wp/) for his patch
14    http://dev.wp-plugins.org/ticket/219
15 */
16
17 // CHANGE THIS IF YOU WANT TO USE A 
18 // DIFFERENT BACKUP LOCATION
19
20 $rand = substr( md5( md5( DB_PASSWORD ) ), -5 );
21
22 define('WP_BACKUP_DIR', 'wp-content/backup-' . $rand);
23
24 define('ROWS_PER_SEGMENT', 100);
25
26 class wpdbBackup {
27
28         var $backup_complete = false;
29         var $backup_file = '';
30         var $backup_dir = WP_BACKUP_DIR;
31         var $backup_errors = array();
32         var $basename;
33
34         function gzip() {
35                 return function_exists('gzopen');
36         }
37
38         function wpdbBackup() {
39                 add_action('wp_cron_daily', array(&$this, 'wp_cron_daily'));
40
41                 $this->backup_dir = trailingslashit($this->backup_dir);
42                 $this->basename = preg_replace('/^.*wp-content[\\\\\/]plugins[\\\\\/]/', '', __FILE__);
43         
44                 if (isset($_POST['do_backup'])) {
45                         if ( !current_user_can('import') ) die(__('You are not allowed to perform backups.'));
46                         switch($_POST['do_backup']) {
47                         case 'backup':
48                                 $this->perform_backup();
49                                 break;
50                         case 'fragments':
51                                 add_action('admin_menu', array(&$this, 'fragment_menu'));
52                                 break;                          
53                         }
54                 } elseif (isset($_GET['fragment'] )) {
55                         if ( !current_user_can('import') ) die(__('You are not allowed to perform backups.'));
56                         add_action('init', array(&$this, 'init'));
57                 } elseif (isset($_GET['backup'] )) {
58                         if ( !current_user_can('import') ) die(__('You are not allowed to perform backups.'));
59                         add_action('init', array(&$this, 'init'));
60                 } else {
61                         add_action('admin_menu', array(&$this, 'admin_menu'));
62                 }
63         }
64         
65         function init() {
66                 if ( !current_user_can('import') ) die(__('You are not allowed to perform backups.'));
67
68                 if (isset($_GET['backup'])) {
69                         $via = isset($_GET['via']) ? $_GET['via'] : 'http';
70                         
71                         $this->backup_file = $_GET['backup'];
72                         
73                         switch($via) {
74                         case 'smtp':
75                         case 'email':
76                                 $this->deliver_backup ($this->backup_file, 'smtp', $_GET['recipient']);
77                                 echo '
78                                         <!-- ' . $via . ' -->
79                                         <script type="text/javascript"><!--\\
80                                 ';
81                                 if($this->backup_errors) {
82                                         foreach($this->backup_errors as $error) {
83                                                 echo "window.parent.addError('$error');\n";
84                                         }
85                                 }
86                                 echo '
87                                         alert("' . __('Backup Complete!') . '");
88                                         </script>
89                                 ';
90                                 break;
91                         default:
92                                 $this->deliver_backup ($this->backup_file, $via);
93                         }
94                         die();
95                 }
96                 if (isset($_GET['fragment'] )) {
97                         list($table, $segment, $filename) = explode(':', $_GET['fragment']);
98                         $this->backup_fragment($table, $segment, $filename);
99                 }
100
101                 die();
102         }
103         
104         function build_backup_script() {
105                 global $table_prefix, $wpdb;
106         
107                 $datum = date("Ymd_B");
108                 $backup_filename = DB_NAME . "_$table_prefix$datum.sql";
109                 if ($this->gzip()) $backup_filename .= '.gz';
110                 
111                 echo "<div class='wrap'>";
112                 //echo "<pre>" . print_r($_POST, 1) . "</pre>";
113                 echo '<h2>' . __('Backup') . '</h2>
114                         <fieldset class="options"><legend>' . __('Progress') . '</legend>
115                         <p><strong>' .
116                                 __('DO NOT DO THE FOLLOWING AS IT WILL CAUSE YOUR BACKUP TO FAIL:').
117                         '</strong></p>
118                         <ol>
119                                 <li>'.__('Close this browser').'</li>
120                                 <li>'.__('Reload this page').'</li>
121                                 <li>'.__('Click the Stop or Back buttons in your browser').'</li>
122                         </ol>
123                         <p><strong>' . __('Progress:') . '</strong></p>
124                         <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>
125                         <div id="progress_message"></div>
126                         <div id="errors"></div>
127                         </fieldset>
128                         <iframe id="backuploader" src="about:blank" style="border:0px solid white;height:1em;width:1em;"></iframe>
129                         <script type="text/javascript"><!--//
130                         function setMeter(pct) {
131                                 var meter = document.getElementById("meter");
132                                 meter.style.width = pct + "%";
133                                 meter.innerHTML = Math.floor(pct) + "%";
134                         }
135                         function setProgress(str) {
136                                 var progress = document.getElementById("progress_message");
137                                 progress.innerHTML = str;
138                         }
139                         function addError(str) {
140                                 var errors = document.getElementById("errors");
141                                 errors.innerHTML = errors.innerHTML + str + "<br />";
142                         }
143
144                         function backup(table, segment) {
145                                 var fram = document.getElementById("backuploader");                             
146                                 fram.src = "' . $_SERVER['REQUEST_URI'] . '&fragment=" + table + ":" + segment + ":' . $backup_filename . '";
147                         }
148                         
149                         var curStep = 0;
150                         
151                         function nextStep() {
152                                 backupStep(curStep);
153                                 curStep++;
154                         }
155                         
156                         function finishBackup() {
157                                 var fram = document.getElementById("backuploader");                             
158                                 setMeter(100);
159                 ';
160
161                 $this_basename = preg_replace('/^.*wp-content[\\\\\/]plugins[\\\\\/]/', '', __FILE__);
162                 $download_uri = get_settings('siteurl') . "/wp-admin/edit.php?page={$this_basename}&backup={$backup_filename}";
163                 switch($_POST['deliver']) {
164                 case 'http':
165                         echo '
166                                 setProgress("' . sprintf(__("Backup complete, preparing <a href=\\\"%s\\\">backup</a> for download..."), $download_uri) . '");
167                                 fram.src = "' . $download_uri . '";
168                         ';
169                         break;
170                 case 'smtp':
171                         echo '
172                                 setProgress("' . sprintf(__("Backup complete, sending <a href=\\\"%s\\\">backup</a> via email..."), $download_uri) . '");
173                                 fram.src = "' . $download_uri . '&via=email&recipient=' . $_POST['backup_recipient'] . '";
174                         ';
175                         break;
176                 default:
177                         echo '
178                                 setProgress("' . sprintf(__("Backup complete, download <a href=\\\"%s\\\">here</a>."), $download_uri) . '");
179                         ';
180                 }
181                 
182                 echo '
183                         }
184                         
185                         function backupStep(step) {
186                                 switch(step) {
187                                 case 0: backup("", 0); break;
188                 ';
189                 
190                 $also_backup = array();
191                 if (isset($_POST['other_tables'])) {
192                         $also_backup = $_POST['other_tables'];
193                 } else {
194                         $also_backup = array();
195                 }
196                 $core_tables = $_POST['core_tables'];
197                 $tables = array_merge($core_tables, $also_backup);
198                 $step_count = 1;
199                 foreach ($tables as $table) {
200                         $rec_count = $wpdb->get_var("SELECT count(*) FROM {$table}");
201                         $rec_segments = ceil($rec_count / ROWS_PER_SEGMENT);
202                         $table_count = 0;
203                         do {
204                                 echo "case {$step_count}: backup(\"{$table}\", {$table_count}); break;\n";
205                                 $step_count++;
206                                 $table_count++;
207                         } while($table_count < $rec_segments);
208                         echo "case {$step_count}: backup(\"{$table}\", -1); break;\n";
209                         $step_count++;
210                 }
211                 echo "case {$step_count}: finishBackup(); break;";
212                 
213                 echo '
214                                 }
215                                 if(step != 0) setMeter(100 * step / ' . $step_count . ');
216                         }
217
218                         nextStep();
219                         //--></script>
220         </div>
221                 ';
222         }
223
224         function backup_fragment($table, $segment, $filename) {
225                 global $table_prefix, $wpdb;
226                         
227                 echo "$table:$segment:$filename";
228                 
229                 if($table == '') {
230                         $msg = __('Creating backup file...');
231                 } else {
232                         if($segment == -1) {
233                                 $msg = sprintf(__('Finished backing up table \\"%s\\".'), $table);
234                         } else {
235                                 $msg = sprintf(__('Backing up table \\"%s\\"...'), $table);
236                         }
237                 }
238                 
239                 echo '<script type="text/javascript"><!--//
240                 var msg = "' . $msg . '";
241                 window.parent.setProgress(msg);
242                 ';
243                         
244                 if (is_writable(ABSPATH . $this->backup_dir)) {
245                         $this->fp = $this->open(ABSPATH . $this->backup_dir . $filename, 'a');
246                         if(!$this->fp) {
247                                 $this->backup_error(__('Could not open the backup file for writing!'));
248                                 $this->fatal_error = __('The backup file could not be saved.  Please check the permissions for writing to your backup directory and try again.');
249                         }
250                         else {
251                                 if($table == '') {              
252                                         //Begin new backup of MySql
253                                         $this->stow("# WordPress MySQL database backup\n");
254                                         $this->stow("#\n");
255                                         $this->stow("# Generated: " . date("l j. F Y H:i T") . "\n");
256                                         $this->stow("# Hostname: " . DB_HOST . "\n");
257                                         $this->stow("# Database: " . $this->backquote(DB_NAME) . "\n");
258                                         $this->stow("# --------------------------------------------------------\n");
259                                 } else {
260                                         if($segment == 0) {
261                                                 // Increase script execution time-limit to 15 min for every table.
262                                                 if ( !ini_get('safe_mode')) @set_time_limit(15*60);
263                                                 //ini_set('memory_limit', '16M');
264                                                 // Create the SQL statements
265                                                 $this->stow("# --------------------------------------------------------\n");
266                                                 $this->stow("# Table: " . $this->backquote($table) . "\n");
267                                                 $this->stow("# --------------------------------------------------------\n");
268                                         }                       
269                                         $this->backup_table($table, $segment);
270                                 }
271                         }
272                 } else {
273                         $this->backup_error(__('The backup directory is not writeable!'));
274                         $this->fatal_error = __('The backup directory is not writeable!  Please check the permissions for writing to your backup directory and try again.');
275                 }
276
277                 if($this->fp) $this->close($this->fp);
278                 
279                 if($this->backup_errors) {
280                         foreach($this->backup_errors as $error) {
281                                 echo "window.parent.addError('$error');\n";
282                         }
283                 }
284                 if($this->fatal_error) {
285                         echo '
286                                 alert("' . addslashes($this->fatal_error) . '");
287                                 //--></script>
288                         ';
289                 }
290                 else {
291                         echo '
292                                 window.parent.nextStep();
293                                 //--></script>
294                         ';
295                 }
296                 
297                 die();
298         }
299
300         function perform_backup() {
301                 // are we backing up any other tables?
302                 $also_backup = array();
303                 if (isset($_POST['other_tables'])) {
304                         $also_backup = $_POST['other_tables'];
305                 }
306                 
307                 $core_tables = $_POST['core_tables'];
308                 $this->backup_file = $this->db_backup($core_tables, $also_backup);
309                 if (FALSE !== $this->backup_file) {
310                         if ('smtp' == $_POST['deliver']) {
311                                 $this->deliver_backup ($this->backup_file, $_POST['deliver'], $_POST['backup_recipient']);
312                         } elseif ('http' == $_POST['deliver']) {
313                                 $this_basename = preg_replace('/^.*wp-content[\\\\\/]plugins[\\\\\/]/', '', __FILE__);
314                                 header('Refresh: 3; ' . get_settings('siteurl') . "/wp-admin/edit.php?page={$this_basename}&backup={$this->backup_file}");
315                         }
316                         // we do this to say we're done.
317                         $this->backup_complete = true;
318                 }
319         }
320         
321         ///////////////////////////////
322         function admin_menu() {
323                 add_management_page(__('Backup'), __('Backup'), 'import', basename(__FILE__), array(&$this, 'backup_menu'));
324         }
325
326         function fragment_menu() {
327                 add_management_page(__('Backup'), __('Backup'), 'import', basename(__FILE__), array(&$this, 'build_backup_script'));
328         }
329
330         /////////////////////////////////////////////////////////
331         function sql_addslashes($a_string = '', $is_like = FALSE)
332         {
333                 /*
334                         Better addslashes for SQL queries.
335                         Taken from phpMyAdmin.
336                 */
337             if ($is_like) {
338                 $a_string = str_replace('\\', '\\\\\\\\', $a_string);
339             } else {
340                 $a_string = str_replace('\\', '\\\\', $a_string);
341             }
342             $a_string = str_replace('\'', '\\\'', $a_string);
343
344             return $a_string;
345         } // function sql_addslashes($a_string = '', $is_like = FALSE)
346
347         ///////////////////////////////////////////////////////////
348         function backquote($a_name)
349         {
350                 /*
351                         Add backqouotes to tables and db-names in
352                         SQL queries. Taken from phpMyAdmin.
353                 */
354             if (!empty($a_name) && $a_name != '*') {
355                 if (is_array($a_name)) {
356                      $result = array();
357                      reset($a_name);
358                      while(list($key, $val) = each($a_name)) {
359                          $result[$key] = '`' . $val . '`';
360                      }
361                      return $result;
362                 } else {
363                     return '`' . $a_name . '`';
364                 }
365             } else {
366                 return $a_name;
367             }
368         } // function backquote($a_name, $do_it = TRUE)
369
370         /////////////
371         function open($filename = '', $mode = 'w') {
372                 if ('' == $filename) return false;
373                 if ($this->gzip()) {
374                         $fp = @gzopen($filename, $mode);
375                 } else {
376                         $fp = @fopen($filename, $mode);
377                 }
378                 return $fp;
379         }
380
381         //////////////
382         function close($fp) {
383                 if ($this->gzip()) {
384                         gzclose($fp);
385                 } else {
386                         fclose($fp);
387                 }
388         }
389         
390         //////////////
391         function stow($query_line) {
392                 if ($this->gzip()) {
393                         if(@gzwrite($this->fp, $query_line) === FALSE) {
394                                 backup_error(__('There was an error writing a line to the backup script:'));
395                                 backup_error('&nbsp;&nbsp;' . $query_line);
396                         }
397                 } else {
398                         if(@fwrite($this->fp, $query_line) === FALSE) {
399                                 backup_error(__('There was an error writing a line to the backup script:'));
400                                 backup_error('&nbsp;&nbsp;' . $query_line);
401                         }
402                 }
403         }
404         
405         function backup_error($err) {
406                 if(count($this->backup_errors) < 20) {
407                         $this->backup_errors[] = $err;
408                 } elseif(count($this->backup_errors) == 20) {
409                         $this->backup_errors[] = __('Subsequent errors have been omitted from this log.');
410                 }
411         }
412         
413         /////////////////////////////
414         function backup_table($table, $segment = 'none') {
415                 global $wpdb;
416                 
417                 /*
418                 Taken partially from phpMyAdmin and partially from
419                 Alain Wolf, Zurich - Switzerland
420                 Website: http://restkultur.ch/personal/wolf/scripts/db_backup/
421                 
422                 Modified by Scott Merril (http://www.skippy.net/) 
423                 to use the WordPress $wpdb object
424                 */
425
426                 $table_structure = $wpdb->get_results("DESCRIBE $table");
427                 if (! $table_structure) {
428                         backup_errors(__('Error getting table details') . ": $table");
429                         return FALSE;
430                 }
431         
432                 if(($segment == 'none') || ($segment == 0)) {
433                         //
434                         // Add SQL statement to drop existing table
435                         $this->stow("\n\n");
436                         $this->stow("#\n");
437                         $this->stow("# Delete any existing table " . $this->backquote($table) . "\n");
438                         $this->stow("#\n");
439                         $this->stow("\n");
440                         $this->stow("DROP TABLE IF EXISTS " . $this->backquote($table) . ";\n");
441                         
442                         // 
443                         //Table structure
444                         // Comment in SQL-file
445                         $this->stow("\n\n");
446                         $this->stow("#\n");
447                         $this->stow("# Table structure of table " . $this->backquote($table) . "\n");
448                         $this->stow("#\n");
449                         $this->stow("\n");
450                         
451                         $create_table = $wpdb->get_results("SHOW CREATE TABLE $table", ARRAY_N);
452                         if (FALSE === $create_table) {
453                                 $this->backup_error(sprintf(__("Error with SHOW CREATE TABLE for %s."), $table));
454                                 $this->stow("#\n# Error with SHOW CREATE TABLE for $table!\n#\n");
455                         }
456                         $this->stow($create_table[0][1] . ' ;');
457                         
458                         if (FALSE === $table_structure) {
459                                 $this->backup_error(sprintf(__("Error getting table structure of %s"), $table));
460                                 $this->stow("#\n# Error getting table structure of $table!\n#\n");
461                         }
462                 
463                         //
464                         // Comment in SQL-file
465                         $this->stow("\n\n");
466                         $this->stow("#\n");
467                         $this->stow('# Data contents of table ' . $this->backquote($table) . "\n");
468                         $this->stow("#\n");
469                 }
470                 
471                 if(($segment == 'none') || ($segment >= 0)) {
472                         $ints = array();
473                         foreach ($table_structure as $struct) {
474                                 if ( (0 === strpos($struct->Type, 'tinyint')) ||
475                                         (0 === strpos(strtolower($struct->Type), 'smallint')) ||
476                                         (0 === strpos(strtolower($struct->Type), 'mediumint')) ||
477                                         (0 === strpos(strtolower($struct->Type), 'int')) ||
478                                         (0 === strpos(strtolower($struct->Type), 'bigint')) ||
479                                         (0 === strpos(strtolower($struct->Type), 'timestamp')) ) {
480                                                 $ints[strtolower($struct->Field)] = "1";
481                                 }
482                         }
483                         
484                         
485                         // Batch by $row_inc
486                         
487                         if($segment == 'none') {
488                                 $row_start = 0;
489                                 $row_inc = ROWS_PER_SEGMENT;
490                         } else {
491                                 $row_start = $segment * ROWS_PER_SEGMENT;
492                                 $row_inc = ROWS_PER_SEGMENT;
493                         }
494                         
495                         do {    
496                                 if ( !ini_get('safe_mode')) @set_time_limit(15*60);
497                                 $table_data = $wpdb->get_results("SELECT * FROM $table LIMIT {$row_start}, {$row_inc}", ARRAY_A);
498
499                                 /*
500                                 if (FALSE === $table_data) {
501                                         $wp_backup_error .= "Error getting table contents from $table\r\n";
502                                         fwrite($fp, "#\n# Error getting table contents fom $table!\n#\n");
503                                 }
504                                 */
505                                         
506                                 $entries = 'INSERT INTO ' . $this->backquote($table) . ' VALUES (';     
507                                 //    \x08\\x09, not required
508                                 $search = array("\x00", "\x0a", "\x0d", "\x1a");
509                                 $replace = array('\0', '\n', '\r', '\Z');
510                                 if($table_data) {
511                                         foreach ($table_data as $row) {
512                                                 $values = array();
513                                                 foreach ($row as $key => $value) {
514                                                         if ($ints[strtolower($key)]) {
515                                                                 $values[] = $value;
516                                                         } else {
517                                                                 $values[] = "'" . str_replace($search, $replace, $this->sql_addslashes($value)) . "'";
518                                                         }
519                                                 }
520                                                 $this->stow(" \n" . $entries . implode(', ', $values) . ') ;');
521                                         }
522                                         $row_start += $row_inc;
523                                 }
524                         } while((count($table_data) > 0) and ($segment=='none'));
525                 }
526                 
527                 
528                 if(($segment == 'none') || ($segment < 0)) {
529                         // Create footer/closing comment in SQL-file
530                         $this->stow("\n");
531                         $this->stow("#\n");
532                         $this->stow("# End of data contents of table " . $this->backquote($table) . "\n");
533                         $this->stow("# --------------------------------------------------------\n");
534                         $this->stow("\n");
535                 }
536                 
537         } // end backup_table()
538         
539         function return_bytes($val) {
540            $val = trim($val);
541            $last = strtolower($val{strlen($val)-1});
542            switch($last) {
543                // The 'G' modifier is available since PHP 5.1.0
544                case 'g':
545                    $val *= 1024;
546                case 'm':
547                    $val *= 1024;
548                case 'k':
549                    $val *= 1024;
550            }
551         
552            return $val;
553         }
554         
555         ////////////////////////////
556         function db_backup($core_tables, $other_tables) {
557                 global $table_prefix, $wpdb;
558                 
559                 $datum = date("Ymd_B");
560                 $wp_backup_filename = DB_NAME . "_$table_prefix$datum.sql";
561                         if ($this->gzip()) {
562                                 $wp_backup_filename .= '.gz';
563                         }
564                 
565                 if (is_writable(ABSPATH . $this->backup_dir)) {
566                         $this->fp = $this->open(ABSPATH . $this->backup_dir . $wp_backup_filename);
567                         if(!$this->fp) {
568                                 $this->backup_error(__('Could not open the backup file for writing!'));
569                                 return false;
570                         }
571                 } else {
572                         $this->backup_error(__('The backup directory is not writeable!'));
573                         return false;
574                 }
575                 
576                 //Begin new backup of MySql
577                 $this->stow("# WordPress MySQL database backup\n");
578                 $this->stow("#\n");
579                 $this->stow("# Generated: " . date("l j. F Y H:i T") . "\n");
580                 $this->stow("# Hostname: " . DB_HOST . "\n");
581                 $this->stow("# Database: " . $this->backquote(DB_NAME) . "\n");
582                 $this->stow("# --------------------------------------------------------\n");
583                 
584                         if ( (is_array($other_tables)) && (count($other_tables) > 0) )
585                         $tables = array_merge($core_tables, $other_tables);
586                 else
587                         $tables = $core_tables;
588                 
589                 foreach ($tables as $table) {
590                         // Increase script execution time-limit to 15 min for every table.
591                         if ( !ini_get('safe_mode')) @set_time_limit(15*60);
592                         // Create the SQL statements
593                         $this->stow("# --------------------------------------------------------\n");
594                         $this->stow("# Table: " . $this->backquote($table) . "\n");
595                         $this->stow("# --------------------------------------------------------\n");
596                         $this->backup_table($table);
597                 }
598                                 
599                 $this->close($this->fp);
600                 
601                 if (count($this->backup_errors)) {
602                         return false;
603                 } else {
604                         return $wp_backup_filename;
605                 }
606                 
607         } //wp_db_backup
608         
609         ///////////////////////////
610         function deliver_backup ($filename = '', $delivery = 'http', $recipient = '') {
611                 if ('' == $filename) { return FALSE; }
612                 
613                 $diskfile = ABSPATH . $this->backup_dir . $filename;
614                 if ('http' == $delivery) {
615                         if (! file_exists($diskfile)) {
616                                 $msg = sprintf(__('File not found:%s'), "<br /><strong>$filename</strong><br />");
617                                 $this_basename = preg_replace('/^.*wp-content[\\\\\/]plugins[\\\\\/]/', '', __FILE__);
618                                 $msg .= '<br /><a href="' . get_settings('siteurl') . "/wp-admin/edit.php?page={$this_basename}" . '">' . __('Return to Backup');
619                         die($msg);
620                         }
621                         header('Content-Description: File Transfer');
622                         header('Content-Type: application/octet-stream');
623                         header('Content-Length: ' . filesize($diskfile));
624                         header("Content-Disposition: attachment; filename=$filename");
625                         readfile($diskfile);
626                         unlink($diskfile);
627                 } elseif ('smtp' == $delivery) {
628                         if (! file_exists($diskfile)) return false;
629
630                         if (! is_email ($recipient)) {
631                                 $recipient = get_settings('admin_email');
632                         }
633                         $randomish = md5(time());
634                         $boundary = "==WPBACKUP-BY-SKIPPY-$randomish";
635                         $fp = fopen($diskfile,"rb");
636                         $file = fread($fp,filesize($diskfile)); 
637                         $this->close($fp);
638                         $data = chunk_split(base64_encode($file));
639                         $headers = "MIME-Version: 1.0\n";
640                         $headers .= "Content-Type: multipart/mixed; boundary=\"$boundary\"\n";
641                         $headers .= 'From: ' . get_settings('admin_email') . "\n";
642                 
643                         $message = sprintf(__("Attached to this email is\n   %1s\n   Size:%2s kilobytes\n"), $filename, round(filesize($diskfile)/1024));
644                         // Add a multipart boundary above the plain message
645                         $message = "This is a multi-part message in MIME format.\n\n" .
646                                 "--{$boundary}\n" .
647                                 "Content-Type: text/plain; charset=\"utf-8\"\n" .
648                                 "Content-Transfer-Encoding: 7bit\n\n" .
649                                 $message . "\n\n";
650                         
651                         // Add file attachment to the message
652                         $message .= "--{$boundary}\n" .
653                                 "Content-Type: application/octet-stream;\n" .
654                                 " name=\"{$filename}\"\n" .
655                                 "Content-Disposition: attachment;\n" .
656                                 " filename=\"{$filename}\"\n" .
657                                 "Content-Transfer-Encoding: base64\n\n" .
658                                 $data . "\n\n" .
659                                 "--{$boundary}--\n";
660                         
661                         if (function_exists('wp_mail')) {
662                                 wp_mail ($recipient, get_bloginfo('name') . ' ' . __('Database Backup'), $message, $headers);
663                         } else {
664                                 mail ($recipient, get_bloginfo('name') . ' ' . __('Database Backup'), $message, $headers);
665                         }
666                         
667                         unlink($diskfile);
668                 }
669                 return;
670         }
671         
672         ////////////////////////////
673         function backup_menu() {
674                 global $table_prefix, $wpdb;
675                 $feedback = '';
676                 $WHOOPS = FALSE;
677                 
678                 // did we just do a backup?  If so, let's report the status
679                 if ( $this->backup_complete ) {
680                         $feedback = '<div class="updated"><p>' . __('Backup Successful') . '!';
681                         $file = $this->backup_file;
682                         switch($_POST['deliver']) {
683                         case 'http':
684                                 $feedback .= '<br />' . sprintf(__('Your backup file: <a href="%1s">%2s</a> should begin downloading shortly.'), get_settings('siteurl') . "/{$this->backup_dir}{$this->backup_file}", $this->backup_file);
685                                 break;
686                         case 'smtp':
687                                 if (! is_email($_POST['backup_recipient'])) {
688                                         $feedback .= get_settings('admin_email');
689                                 } else {
690                                         $feedback .= $_POST['backup_recipient'];
691                                 }
692                                 $feedback = '<br />' . sprintf(__('Your backup has been emailed to %s'), $feedback);
693                                 break;
694                         case 'none':
695                                 $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"');
696                                 $feedback .= ':<br /> <a href="' . get_settings('siteurl') . "/{$this->backup_dir}$file\">$file</a> : " . sprintf(__('%s bytes'), filesize(ABSPATH . $this->backup_dir . $file));
697                         }
698                         $feedback .= '</p></div>';
699                 }
700                 
701                 if (count($this->backup_errors)) {
702                         $feedback .= '<div class="updated error">' . __('The following errors were reported:') . "<pre>";
703                         foreach($this->backup_errors as $error) {
704                                 $feedback .= "{$error}\n";  //Errors are already localized
705                         }
706                         $feedback .= "</pre></div>";
707                 }
708                 
709                 // did we just save options for wp-cron?
710                 if ( (function_exists('wp_cron_init')) && isset($_POST['wp_cron_backup_options']) ) {
711                         update_option('wp_cron_backup_schedule', intval($_POST['cron_schedule']), FALSE);
712                         update_option('wp_cron_backup_tables', $_POST['wp_cron_backup_tables']);
713                         if (is_email($_POST['cron_backup_recipient'])) {
714                                 update_option('wp_cron_backup_recipient', $_POST['cron_backup_recipient'], FALSE);
715                         }
716                         $feedback .= '<div class="updated"><p>' . __('Scheduled Backup Options Saved!') . '</p></div>';
717                 }
718                 
719                 // Simple table name storage
720                 $wp_table_names = explode(',','categories,comments,linkcategories,links,options,post2cat,postmeta,posts,users,usermeta');
721                 // Apply WP DB prefix to table names
722                 $wp_table_names = array_map(create_function('$a', 'global $table_prefix;return "{$table_prefix}{$a}";'), $wp_table_names);
723                 
724                 $other_tables = array();
725                 $also_backup = array();
726         
727                 // Get complete db table list   
728                 $all_tables = $wpdb->get_results("SHOW TABLES", ARRAY_N);
729                 $all_tables = array_map(create_function('$a', 'return $a[0];'), $all_tables);
730                 // Get list of WP tables that actually exist in this DB (for 1.6 compat!)
731                 $wp_backup_default_tables = array_intersect($all_tables, $wp_table_names);
732                 // Get list of non-WP tables
733                 $other_tables = array_diff($all_tables, $wp_backup_default_tables);
734                 
735                 if ('' != $feedback) {
736                         echo $feedback;
737                 }
738
739                 // Give the new dirs the same perms as wp-content.
740                 $stat = stat( ABSPATH . 'wp-content' );
741                 $dir_perms = $stat['mode'] & 0000777; // Get the permission bits.
742
743                 if ( !file_exists( ABSPATH . $this->backup_dir) ) {
744                         if ( @ mkdir( ABSPATH . $this->backup_dir) ) {
745                                 @ chmod( ABSPATH . $this->backup_dir, $dir_perms);
746                         } else {
747                                 echo '<div class="updated error"><p align="center">' . __('WARNING: Your wp-content directory is <strong>NOT</strong> writable! We can not create the backup directory.') . '<br />' . ABSPATH . $this->backup_dir . "</p></div>";
748                         $WHOOPS = TRUE;
749                         }
750                 }
751                 
752                 if ( !is_writable( ABSPATH . $this->backup_dir) ) {
753                         echo '<div class="updated error"><p align="center">' . __('WARNING: Your backup directory is <strong>NOT</strong> writable! We can not create the backup directory.') . '<br />' . ABSPATH . "</p></div>";
754                 }
755
756                 if ( !file_exists( ABSPATH . $this->backup_dir . 'index.php') ) {
757                         @ touch( ABSPATH . $this->backup_dir . "index.php");
758                 }
759
760                 echo "<div class='wrap'>";
761                 echo '<h2>' . __('Backup') . '</h2>';
762                 echo '<fieldset class="options"><legend>' . __('Tables') . '</legend>';
763                 echo '<form method="post">';
764                 echo '<table align="center" cellspacing="5" cellpadding="5"><tr><td width="50%" align="left" class="alternate" valign="top">';
765                 echo __('These core WordPress tables will always be backed up:') . '<br /><ul>';
766                 foreach ($wp_backup_default_tables as $table) {
767                         echo "<li><input type='hidden' name='core_tables[]' value='$table' />$table</li>";
768                 }
769                 echo '</ul></td><td width="50%" align="left" valign="top">';
770                 if (count($other_tables) > 0) {
771                         echo __('You may choose to include any of the following tables:') . ' <br />';
772                         foreach ($other_tables as $table) {
773                                 echo "<label style=\"display:block;\"><input type='checkbox' name='other_tables[]' value='{$table}' /> {$table}</label>";
774                         }
775                 }
776                 echo '</tr></table></fieldset>';
777                 echo '<fieldset class="options"><legend>' . __('Backup Options') . '</legend>';
778                 echo __('What to do with the backup file:') . "<br />";
779                 echo '<label style="display:block;"><input type="radio" name="deliver" value="none" /> ' . __('Save to server') . " ({$this->backup_dir})</label>";
780                 echo '<label style="display:block;"><input type="radio" checked="checked" name="deliver" value="http" /> ' . __('Download to your computer') . '</label>';
781                 echo '<div><input type="radio" name="deliver" id="do_email" value="smtp" /> ';
782                 echo '<label for="do_email">'.__('Email backup to:').'</label><input type="text" name="backup_recipient" size="20" value="' . get_settings('admin_email') . '" />';
783                 
784                 // Check DB dize.
785                 $table_status = $wpdb->get_results("SHOW TABLE STATUS FROM " . $this->backquote(DB_NAME));
786                 $core_size = $db_size = 0;
787                 foreach($table_status as $table) {
788                         $table_size = $table->Data_length - $table->Data_free;
789                         if(in_array($table->Name, $wp_backup_default_tables)) {
790                                 $core_size += $table_size;      
791                         }
792                         $db_size += $table_size;
793                 }
794                 $mem_limit = ini_get('memory_limit');
795                 $mem_limit = $this->return_bytes($mem_limit);
796                 $mem_limit = ($mem_limit == 0) ? 8*1024*1024 :  $mem_limit - 2000000;
797                 
798                 if (! $WHOOPS) {
799                         echo '<input type="hidden" name="do_backup" id="do_backup" value="backup" /></div>';
800                         echo '<p class="submit"><input type="submit" name="submit" onclick="document.getElementById(\'do_backup\').value=\'fragments\';" value="' . __('Backup') . '!" / ></p>';
801                 } else {
802                         echo '<p class="alternate">' . __('WARNING: Your backup directory is <strong>NOT</strong> writable!') . '</p>';
803                 }
804                 echo '</fieldset>';
805                 echo '</form>';
806                 
807                 // this stuff only displays if wp_cron is installed
808                 if (function_exists('wp_cron_init')) {
809                         echo '<fieldset class="options"><legend>' . __('Scheduled Backup') . '</legend>';
810                         $datetime = get_settings('date_format') . ' @ ' . get_settings('time_format');
811                         echo '<p>' . __('Last WP-Cron Daily Execution') . ': ' . date($datetime, get_option('wp_cron_daily_lastrun')) . '<br />';
812                         echo __('Next WP-Cron Daily Execution') . ': ' . date($datetime, (get_option('wp_cron_daily_lastrun') + 86400)) . '</p>';
813                         echo '<form method="post">';
814                         echo '<table width="100%" callpadding="5" cellspacing="5">';
815                         echo '<tr><td align="center">';
816                         echo __('Schedule: ');
817                         $wp_cron_backup_schedule = get_option('wp_cron_backup_schedule');
818                         $schedule = array(0 => __('None'), 1 => __('Daily'));
819                         foreach ($schedule as $value => $name) {
820                                 echo ' <input type="radio" name="cron_schedule"';
821                                 if ($wp_cron_backup_schedule == $value) {
822                                         echo ' checked="checked" ';
823                                 }
824                                 echo 'value="' . $value . '" /> ' . __($name);
825                         }
826                         echo '</td><td align="center">';
827                         $cron_recipient = get_option('wp_cron_backup_recipient');
828                         if (! is_email($cron_recipient)) {
829                                 $cron_recipient = get_settings('admin_email');
830                         }
831                         echo __('Email backup to:') . ' <input type="text" name="cron_backup_recipient" size="20" value="' . $cron_recipient . '" />';
832                         echo '</td></tr>';
833                         $cron_tables = get_option('wp_cron_backup_tables');
834                         if (! is_array($cron_tables)) {
835                                 $cron_tables = array();
836                         }
837                         if (count($other_tables) > 0) {
838                                 echo '<tr><td colspan="2" align="left">' . __('Tables to include:') . '<br />';
839                                 foreach ($other_tables as $table) {
840                                         echo '<input type="checkbox" ';
841                                         if (in_array($table, $cron_tables)) {
842                                                 echo 'checked=checked ';
843                                         }
844                                         echo "name='wp_cron_backup_tables[]' value='{$table}' /> {$table}<br />";
845                                 }
846                                 echo '</td></tr>';
847                         }
848                         echo '<tr><td colspan="2" align="center"><input type="hidden" name="wp_cron_backup_options" value="SET" /><input type="submit" name="submit" value="' . __('Submit') . '" /></td></tr></table></form>';
849                         echo '</fieldset>';
850                 }
851                 // end of wp_cron section
852                 
853                 echo '</div>';
854                 
855         }// end wp_backup_menu()
856         
857         /////////////////////////////
858         function wp_cron_daily() {
859                 
860                 $schedule = intval(get_option('wp_cron_backup_schedule'));
861                 if (0 == $schedule) {
862                         // Scheduled backup is disabled
863                         return;
864                 }
865                 
866                 global $table_prefix, $wpdb;
867
868                 $wp_table_names = explode(',','categories,comments,linkcategories,links,options,post2cat,postmeta,posts,users,usermeta');
869                 $wp_table_names = array_map(create_function('$a', 'global $table_prefix;return "{$table_prefix}{$a}";'), $wp_table_names);
870                 $all_tables = $wpdb->get_results("SHOW TABLES", ARRAY_N);
871                 $all_tables = array_map(create_function('$a', 'return $a[0];'), $all_tables);
872                 $core_tables = array_intersect($all_tables, $wp_table_names);
873                 $other_tables = get_option('wp_cron_backup_tables');
874                 
875                 $recipient = get_option('wp_cron_backup_recipient');
876                 
877                 $backup_file = $this->db_backup($core_tables, $other_tables);
878                 if (FALSE !== $backup_file) {
879                         $this->deliver_backup ($backup_file, 'smtp', $recipient);
880                 }
881                 
882                 return;
883         } // wp_cron_db_backup
884 }
885
886 function wpdbBackup_init() {
887         global $mywpdbbackup;
888
889         if ( !current_user_can('import') ) return;
890
891         $mywpdbbackup = new wpdbBackup();       
892 }
893
894 add_action('plugins_loaded', 'wpdbBackup_init');
895
896 ?>