[ Index ]

WordPress Source Cross Reference

title

Body

[close]

/wp-content/plugins/ -> wp-db-backup.php (source)

   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      // Simple table name storage
  34      var    $wp_table_names = array('categories','comments','link2cat','links','options','post2cat','postmeta','posts','users','usermeta');
  35  
  36  	function gzip() {
  37          return function_exists('gzopen');
  38      }
  39  
  40  	function wpdbBackup() {
  41          add_action('wp_cron_daily', array(&$this, 'wp_cron_daily'));
  42  
  43          $this->backup_dir = trailingslashit($this->backup_dir);
  44          $this->basename = preg_replace('/^.*wp-content[\\\\\/]plugins[\\\\\/]/', '', __FILE__);
  45  
  46          if (isset($_POST['do_backup'])) {
  47              if ( !current_user_can('import') ) die(__('You are not allowed to perform backups.'));
  48              switch($_POST['do_backup']) {
  49              case 'backup':
  50                  $this->perform_backup();
  51                  break;
  52              case 'fragments':
  53                  add_action('admin_menu', array(&$this, 'fragment_menu'));
  54                  break;
  55              }
  56          } elseif (isset($_GET['fragment'] )) {
  57              if ( !current_user_can('import') ) die(__('You are not allowed to perform backups.'));
  58              add_action('init', array(&$this, 'init'));
  59          } elseif (isset($_GET['backup'] )) {
  60              if ( !current_user_can('import') ) die(__('You are not allowed to perform backups.'));
  61              add_action('init', array(&$this, 'init'));
  62          } else {
  63              add_action('admin_menu', array(&$this, 'admin_menu'));
  64          }
  65      }
  66  
  67  	function init() {
  68          if ( !current_user_can('import') ) die(__('You are not allowed to perform backups.'));
  69  
  70          if (isset($_GET['backup'])) {
  71              $via = isset($_GET['via']) ? $_GET['via'] : 'http';
  72  
  73              $this->backup_file = $_GET['backup'];
  74  
  75              switch($via) {
  76              case 'smtp':
  77              case 'email':
  78                  $this->deliver_backup ($this->backup_file, 'smtp', $_GET['recipient']);
  79                  echo '
  80                      <!-- ' . $via . ' -->
  81                      <script type="text/javascript"><!--\\
  82                  ';
  83                  if($this->backup_errors) {
  84                      foreach($this->backup_errors as $error) {
  85                          echo "window.parent.addError('$error');\n";
  86                      }
  87                  }
  88                  echo '
  89                      alert("' . __('Backup Complete!') . '");
  90                      </script>
  91                  ';
  92                  break;
  93              default:
  94                  $this->deliver_backup ($this->backup_file, $via);
  95              }
  96              die();
  97          }
  98          if (isset($_GET['fragment'] )) {
  99              list($table, $segment, $filename) = explode(':', $_GET['fragment']);
 100              $this->backup_fragment($table, $segment, $filename);
 101          }
 102  
 103          die();
 104      }
 105  
 106  	function build_backup_script() {
 107          global $wpdb;
 108  
 109          $datum = date("Ymd_B");
 110          $backup_filename = DB_NAME . '_' . $wpdb->prefix . $datum . '.sql';
 111          if ($this->gzip()) $backup_filename .= '.gz';
 112  
 113          echo "<div class='wrap'>";
 114          //echo "<pre>" . print_r($_POST, 1) . "</pre>";
 115          echo '<h2>' . __('Backup') . '</h2>
 116              <fieldset class="options"><legend>' . __('Progress') . '</legend>
 117              <p><strong>' .
 118                  __('DO NOT DO THE FOLLOWING AS IT WILL CAUSE YOUR BACKUP TO FAIL:').
 119              '</strong></p>
 120              <ol>
 121                  <li>'.__('Close this browser').'</li>
 122                  <li>'.__('Reload this page').'</li>
 123                  <li>'.__('Click the Stop or Back buttons in your browser').'</li>
 124              </ol>
 125              <p><strong>' . __('Progress:') . '</strong></p>
 126              <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>
 127              <div id="progress_message"></div>
 128              <div id="errors"></div>
 129              </fieldset>
 130              <iframe id="backuploader" src="about:blank" style="border:0px solid white;height:1em;width:1em;"></iframe>
 131              <script type="text/javascript"><!--//
 132  			function setMeter(pct) {
 133                  var meter = document.getElementById("meter");
 134                  meter.style.width = pct + "%";
 135                  meter.innerHTML = Math.floor(pct) + "%";
 136              }
 137  			function setProgress(str) {
 138                  var progress = document.getElementById("progress_message");
 139                  progress.innerHTML = str;
 140              }
 141  			function addError(str) {
 142                  var errors = document.getElementById("errors");
 143                  errors.innerHTML = errors.innerHTML + str + "<br />";
 144              }
 145  
 146  			function backup(table, segment) {
 147                  var fram = document.getElementById("backuploader");
 148                  fram.src = "' . $_SERVER['REQUEST_URI'] . '&fragment=" + table + ":" + segment + ":' . $backup_filename . '";
 149              }
 150  
 151              var curStep = 0;
 152  
 153  			function nextStep() {
 154                  backupStep(curStep);
 155                  curStep++;
 156              }
 157  
 158  			function finishBackup() {
 159                  var fram = document.getElementById("backuploader");
 160                  setMeter(100);
 161          ';
 162  
 163          $this_basename = preg_replace('/^.*wp-content[\\\\\/]plugins[\\\\\/]/', '', __FILE__);
 164          $download_uri = get_settings('siteurl') . "/wp-admin/edit.php?page={$this_basename}&backup={$backup_filename}";
 165          switch($_POST['deliver']) {
 166          case 'http':
 167              echo '
 168                  setProgress("' . sprintf(__("Backup complete, preparing <a href=\\\"%s\\\">backup</a> for download..."), $download_uri) . '");
 169                  fram.src = "' . $download_uri . '";
 170              ';
 171              break;
 172          case 'smtp':
 173              echo '
 174                  setProgress("' . sprintf(__("Backup complete, sending <a href=\\\"%s\\\">backup</a> via email..."), $download_uri) . '");
 175                  fram.src = "' . $download_uri . '&via=email&recipient=' . $_POST['backup_recipient'] . '";
 176              ';
 177              break;
 178          default:
 179              echo '
 180                  setProgress("' . sprintf(__("Backup complete, download <a href=\\\"%s\\\">here</a>."), $download_uri) . '");
 181              ';
 182          }
 183  
 184          echo '
 185              }
 186  
 187  			function backupStep(step) {
 188                  switch(step) {
 189                  case 0: backup("", 0); break;
 190          ';
 191  
 192          $also_backup = array();
 193          if (isset($_POST['other_tables'])) {
 194              $also_backup = $_POST['other_tables'];
 195          } else {
 196              $also_backup = array();
 197          }
 198          $core_tables = $_POST['core_tables'];
 199          $tables = array_merge($core_tables, $also_backup);
 200          $step_count = 1;
 201          foreach ($tables as $table) {
 202              $rec_count = $wpdb->get_var("SELECT count(*) FROM {$table}");
 203              $rec_segments = ceil($rec_count / ROWS_PER_SEGMENT);
 204              $table_count = 0;
 205              do {
 206                  echo "case {$step_count}: backup(\"{$table}\", {$table_count}); break;\n";
 207                  $step_count++;
 208                  $table_count++;
 209              } while($table_count < $rec_segments);
 210              echo "case {$step_count}: backup(\"{$table}\", -1); break;\n";
 211              $step_count++;
 212          }
 213          echo "case {$step_count}: finishBackup(); break;";
 214  
 215          echo '
 216                  }
 217                  if(step != 0) setMeter(100 * step / ' . $step_count . ');
 218              }
 219  
 220              nextStep();
 221              //--></script>
 222      </div>
 223          ';
 224      }
 225  
 226  	function backup_fragment($table, $segment, $filename) {
 227          global $wpdb;
 228  
 229          echo "$table:$segment:$filename";
 230  
 231          if($table == '') {
 232              $msg = __('Creating backup file...');
 233          } else {
 234              if($segment == -1) {
 235                  $msg = sprintf(__('Finished backing up table \\"%s\\".'), $table);
 236              } else {
 237                  $msg = sprintf(__('Backing up table \\"%s\\"...'), $table);
 238              }
 239          }
 240  
 241          echo '<script type="text/javascript"><!--//
 242          var msg = "' . $msg . '";
 243          window.parent.setProgress(msg);
 244          ';
 245  
 246          if (is_writable(ABSPATH . $this->backup_dir)) {
 247              $this->fp = $this->open(ABSPATH . $this->backup_dir . $filename, 'a');
 248              if(!$this->fp) {
 249                  $this->backup_error(__('Could not open the backup file for writing!'));
 250                  $this->fatal_error = __('The backup file could not be saved.  Please check the permissions for writing to your backup directory and try again.');
 251              }
 252              else {
 253                  if($table == '') {
 254                      //Begin new backup of MySql
 255                      $this->stow("# WordPress MySQL database backup\n");
 256                      $this->stow("#\n");
 257                      $this->stow("# Generated: " . date("l j. F Y H:i T") . "\n");
 258                      $this->stow("# Hostname: " . DB_HOST . "\n");
 259                      $this->stow("# Database: " . $this->backquote(DB_NAME) . "\n");
 260                      $this->stow("# --------------------------------------------------------\n");
 261                  } else {
 262                      if($segment == 0) {
 263                          // Increase script execution time-limit to 15 min for every table.
 264                          if ( !ini_get('safe_mode')) @set_time_limit(15*60);
 265                          //ini_set('memory_limit', '16M');
 266                          // Create the SQL statements
 267                          $this->stow("# --------------------------------------------------------\n");
 268                          $this->stow("# Table: " . $this->backquote($table) . "\n");
 269                          $this->stow("# --------------------------------------------------------\n");
 270                      }
 271                      $this->backup_table($table, $segment);
 272                  }
 273              }
 274          } else {
 275              $this->backup_error(__('The backup directory is not writeable!'));
 276              $this->fatal_error = __('The backup directory is not writeable!  Please check the permissions for writing to your backup directory and try again.');
 277          }
 278  
 279          if($this->fp) $this->close($this->fp);
 280  
 281          if($this->backup_errors) {
 282              foreach($this->backup_errors as $error) {
 283                  echo "window.parent.addError('$error');\n";
 284              }
 285          }
 286          if($this->fatal_error) {
 287              echo '
 288                  alert("' . addslashes($this->fatal_error) . '");
 289                  //--></script>
 290              ';
 291          }
 292          else {
 293              echo '
 294                  window.parent.nextStep();
 295                  //--></script>
 296              ';
 297          }
 298  
 299          die();
 300      }
 301  
 302  	function perform_backup() {
 303          // are we backing up any other tables?
 304          $also_backup = array();
 305          if (isset($_POST['other_tables'])) {
 306              $also_backup = $_POST['other_tables'];
 307          }
 308  
 309          $core_tables = $_POST['core_tables'];
 310          $this->backup_file = $this->db_backup($core_tables, $also_backup);
 311          if (FALSE !== $this->backup_file) {
 312              if ('smtp' == $_POST['deliver']) {
 313                  $this->deliver_backup ($this->backup_file, $_POST['deliver'], $_POST['backup_recipient']);
 314              } elseif ('http' == $_POST['deliver']) {
 315                  $this_basename = preg_replace('/^.*wp-content[\\\\\/]plugins[\\\\\/]/', '', __FILE__);
 316                  header('Refresh: 3; ' . get_settings('siteurl') . "/wp-admin/edit.php?page={$this_basename}&backup={$this->backup_file}");
 317              }
 318              // we do this to say we're done.
 319              $this->backup_complete = true;
 320          }
 321      }
 322  
 323      ///////////////////////////////
 324  	function admin_menu() {
 325          add_management_page(__('Backup'), __('Backup'), 9, basename(__FILE__), array(&$this, 'backup_menu'));
 326      }
 327  
 328  	function fragment_menu() {
 329          add_management_page(__('Backup'), __('Backup'), 9, basename(__FILE__), array(&$this, 'build_backup_script'));
 330      }
 331  
 332      /////////////////////////////////////////////////////////
 333  	function sql_addslashes($a_string = '', $is_like = FALSE)
 334      {
 335              /*
 336                      Better addslashes for SQL queries.
 337                      Taken from phpMyAdmin.
 338              */
 339          if ($is_like) {
 340              $a_string = str_replace('\\', '\\\\\\\\', $a_string);
 341          } else {
 342              $a_string = str_replace('\\', '\\\\', $a_string);
 343          }
 344          $a_string = str_replace('\'', '\\\'', $a_string);
 345  
 346          return $a_string;
 347      } // function sql_addslashes($a_string = '', $is_like = FALSE)
 348  
 349      ///////////////////////////////////////////////////////////
 350  	function backquote($a_name)
 351      {
 352              /*
 353                      Add backqouotes to tables and db-names in
 354                      SQL queries. Taken from phpMyAdmin.
 355              */
 356          if (!empty($a_name) && $a_name != '*') {
 357              if (is_array($a_name)) {
 358                   $result = array();
 359                   reset($a_name);
 360                   while(list($key, $val) = each($a_name)) {
 361                       $result[$key] = '`' . $val . '`';
 362                   }
 363                   return $result;
 364              } else {
 365                  return '`' . $a_name . '`';
 366              }
 367          } else {
 368              return $a_name;
 369          }
 370      } // function backquote($a_name, $do_it = TRUE)
 371  
 372      /////////////
 373  	function open($filename = '', $mode = 'w') {
 374          if ('' == $filename) return false;
 375          if ($this->gzip()) {
 376              $fp = @gzopen($filename, $mode);
 377          } else {
 378              $fp = @fopen($filename, $mode);
 379          }
 380          return $fp;
 381      }
 382  
 383      //////////////
 384  	function close($fp) {
 385          if ($this->gzip()) {
 386              gzclose($fp);
 387          } else {
 388              fclose($fp);
 389          }
 390      }
 391  
 392      //////////////
 393  	function stow($query_line) {
 394          if ($this->gzip()) {
 395              if(@gzwrite($this->fp, $query_line) === FALSE) {
 396                  backup_error(__('There was an error writing a line to the backup script:'));
 397                  backup_error('&nbsp;&nbsp;' . $query_line);
 398              }
 399          } else {
 400              if(@fwrite($this->fp, $query_line) === FALSE) {
 401                  backup_error(__('There was an error writing a line to the backup script:'));
 402                  backup_error('&nbsp;&nbsp;' . $query_line);
 403              }
 404          }
 405      }
 406  
 407  	function backup_error($err) {
 408          if(count($this->backup_errors) < 20) {
 409              $this->backup_errors[] = $err;
 410          } elseif(count($this->backup_errors) == 20) {
 411              $this->backup_errors[] = __('Subsequent errors have been omitted from this log.');
 412          }
 413      }
 414  
 415      /////////////////////////////
 416  	function backup_table($table, $segment = 'none') {
 417          global $wpdb;
 418  
 419          /*
 420          Taken partially from phpMyAdmin and partially from
 421          Alain Wolf, Zurich - Switzerland
 422          Website: http://restkultur.ch/personal/wolf/scripts/db_backup/
 423  
 424          Modified by Scott Merril (http://www.skippy.net/) 
 425          to use the WordPress $wpdb object
 426          */
 427  
 428          $table_structure = $wpdb->get_results("DESCRIBE $table");
 429          if (! $table_structure) {
 430              backup_errors(__('Error getting table details') . ": $table");
 431              return FALSE;
 432          }
 433  
 434          if(($segment == 'none') || ($segment == 0)) {
 435              //
 436              // Add SQL statement to drop existing table
 437              $this->stow("\n\n");
 438              $this->stow("#\n");
 439              $this->stow("# Delete any existing table " . $this->backquote($table) . "\n");
 440              $this->stow("#\n");
 441              $this->stow("\n");
 442              $this->stow("DROP TABLE IF EXISTS " . $this->backquote($table) . ";\n");
 443  
 444              // 
 445              //Table structure
 446              // Comment in SQL-file
 447              $this->stow("\n\n");
 448              $this->stow("#\n");
 449              $this->stow("# Table structure of table " . $this->backquote($table) . "\n");
 450              $this->stow("#\n");
 451              $this->stow("\n");
 452  
 453              $create_table = $wpdb->get_results("SHOW CREATE TABLE $table", ARRAY_N);
 454              if (FALSE === $create_table) {
 455                  $this->backup_error(sprintf(__("Error with SHOW CREATE TABLE for %s."), $table));
 456                  $this->stow("#\n# Error with SHOW CREATE TABLE for $table!\n#\n");
 457              }
 458              $this->stow($create_table[0][1] . ' ;');
 459  
 460              if (FALSE === $table_structure) {
 461                  $this->backup_error(sprintf(__("Error getting table structure of %s"), $table));
 462                  $this->stow("#\n# Error getting table structure of $table!\n#\n");
 463              }
 464  
 465              //
 466              // Comment in SQL-file
 467              $this->stow("\n\n");
 468              $this->stow("#\n");
 469              $this->stow('# Data contents of table ' . $this->backquote($table) . "\n");
 470              $this->stow("#\n");
 471          }
 472  
 473          if(($segment == 'none') || ($segment >= 0)) {
 474              $ints = array();
 475              foreach ($table_structure as $struct) {
 476                  if ( (0 === strpos($struct->Type, 'tinyint')) ||
 477                      (0 === strpos(strtolower($struct->Type), 'smallint')) ||
 478                      (0 === strpos(strtolower($struct->Type), 'mediumint')) ||
 479                      (0 === strpos(strtolower($struct->Type), 'int')) ||
 480                      (0 === strpos(strtolower($struct->Type), 'bigint')) ||
 481                      (0 === strpos(strtolower($struct->Type), 'timestamp')) ) {
 482                          $ints[strtolower($struct->Field)] = "1";
 483                  }
 484              }
 485  
 486  
 487              // Batch by $row_inc
 488  
 489              if($segment == 'none') {
 490                  $row_start = 0;
 491                  $row_inc = ROWS_PER_SEGMENT;
 492              } else {
 493                  $row_start = $segment * ROWS_PER_SEGMENT;
 494                  $row_inc = ROWS_PER_SEGMENT;
 495              }
 496  
 497              do {
 498                  if ( !ini_get('safe_mode')) @set_time_limit(15*60);
 499                  $table_data = $wpdb->get_results("SELECT * FROM $table LIMIT {$row_start}, {$row_inc}", ARRAY_A);
 500  
 501                  /*
 502                  if (FALSE === $table_data) {
 503                      $wp_backup_error .= "Error getting table contents from $table\r\n";
 504                      fwrite($fp, "#\n# Error getting table contents fom $table!\n#\n");
 505                  }
 506                  */
 507  
 508