b2evolution PHP Cross Reference Blogging Systems

Source: /inc/maintenance/model/_backup.class.php - 652 lines - 16173 bytes - Summary - Text - Print

Description: This file is part of b2evolution - {@link http://b2evolution.net/} See also {@link http://sourceforge.net/projects/evocms/}.

   1  <?php
   2  /**
   3   * This file is part of b2evolution - {@link http://b2evolution.net/}
   4   * See also {@link http://sourceforge.net/projects/evocms/}.
   5   *
   6   * @copyright (c)2009-2014 by Francois PLANQUE - {@link http://fplanque.net/}
   7   * Parts of this file are copyright (c)2009 by The Evo Factory - {@link http://www.evofactory.com/}.
   8   *
   9   * Released under GNU GPL License - {@link http://b2evolution.net/about/license.html}
  10   *
  11   * {@internal Open Source relicensing agreement:
  12   * The Evo Factory grants Francois PLANQUE the right to license
  13   * The Evo Factory's contributions to this file and the b2evolution project
  14   * under any OSI approved OSS license (http://www.opensource.org/licenses/).
  15   * }}
  16   *
  17   * @package maintenance
  18   *
  19   * {@internal Below is a list of authors who have contributed to design/coding of this file: }}
  20   * @author efy-maxim: Evo Factory / Maxim.
  21   * @author fplanque: Francois Planque.
  22   *
  23   * @version $Id: _backup.class.php 6202 2014-03-14 11:40:48Z yura $
  24   */
  25  if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' );
  26  
  27  
  28  /**
  29   * @var strings base application paths
  30   */
  31  global $basepath, $conf_subdir, $skins_subdir, $adminskins_subdir;
  32  global $plugins_subdir, $media_subdir, $backup_subdir, $upgrade_subdir;
  33  
  34  /**
  35   * @var array backup paths
  36   */
  37  global $backup_paths;
  38  
  39  /**
  40   * @var array backup tables
  41   */
  42  global $backup_tables;
  43  
  44  
  45  /**
  46   * Backup folder/files default settings
  47   * - 'label' checkbox label
  48   * - 'note' checkbox note
  49   * - 'path' path to folder or file
  50   * - 'included' true if folder or file must be in backup
  51   * @var array
  52   */
  53  $backup_paths = array(
  54      'application_files'   => array(
  55          'label'    => T_('Application files'), /* It is files root. Please, don't remove it. */
  56          'path'     => '*',
  57          'included' => true ),
  58  
  59      'configuration_files' => array(
  60          'label'    => T_('Configuration files'),
  61          'path'     => $conf_subdir,
  62          'included' => true ),
  63  
  64      'skins_files'         => array(
  65          'label'    => T_('Skins'),
  66          'path'     => array( $skins_subdir,
  67                              $adminskins_subdir ),
  68          'included' => true ),
  69  
  70      'plugins_files'       => array(
  71          'label'    => T_('Plugins'),
  72          'path'     => $plugins_subdir,
  73          'included' => true ),
  74  
  75      'media_files'         => array(
  76          'label'    => T_('Media folder'),
  77          'path'     => $media_subdir,
  78          'included' => false ),
  79  
  80      'backup_files'        => array(
  81          'label'    => NULL,        // Don't display in form. Just exclude from backup.
  82          'path'     => $backup_subdir,
  83          'included' => false ),
  84  
  85      'upgrade_files'        => array(
  86          'label'    => NULL,        // Don't display in form. Just exclude from backup.
  87          'path'     => $upgrade_subdir,
  88          'included' => false ) );
  89  
  90  /**
  91   * Backup database tables default settings
  92   * - 'label' checkbox label
  93   * - 'note' checkbox note
  94   * - 'tables' tables list
  95   * - 'included' true if database tables must be in backup
  96   * @var array
  97   */
  98  $backup_tables = array(
  99      'content_tables'      => array(
 100          'label'    => T_('Content tables'), /* It means collection of all of the tables. Please, don't remove it. */
 101          'table'   => '*',
 102          'included' => true ),
 103  
 104      'logs_stats_tables'   => array(
 105          'label'    => T_('Logs & stats tables'),
 106          'table'   => array(
 107              'T_sessions',
 108              'T_hitlog',
 109              'T_basedomains',
 110              'T_track__goalhit',
 111              'T_track__keyphrase',
 112          ),
 113          'included' => false ) );
 114  
 115  
 116  /**
 117   * Backup class
 118   * This class is responsible to backup application files and data.
 119   *
 120   */
 121  class Backup
 122  {
 123      /**
 124       * All of the paths and their 'included' values defined in backup configuration file
 125       * @var array
 126       */
 127      var $backup_paths;
 128  
 129      /**
 130       * All of the tables and their 'included' values defined in backup configuration file
 131       * @var array
 132       */
 133      var $backup_tables;
 134  
 135      /**
 136       * True if pack backup files
 137       * @var boolean
 138       */
 139      var $pack_backup_files;
 140  
 141  
 142      /**
 143       * Constructor
 144       */
 145  	function Backup()
 146      {
 147          global $backup_paths, $backup_tables;
 148  
 149          // Set default settings defined in backup configuration file
 150  
 151          // Set backup folders/files default settings
 152          $this->backup_paths = array();
 153          foreach( $backup_paths as $name => $settings )
 154          {
 155              $this->backup_paths[$name] = $settings['included'];
 156          }
 157  
 158          // Set backup tables default settings
 159          $this->backup_tables = array();
 160          foreach( $backup_tables as $name => $settings )
 161          {
 162              $this->backup_tables[$name] = $settings['included'];
 163          }
 164  
 165          $this->pack_backup_files = true;
 166      }
 167  
 168  
 169      /**
 170       * Load settings from request
 171       */
 172  	function load_from_Request()
 173      {
 174          global $backup_paths, $backup_tables, $Messages;
 175  
 176          // Load folders/files settings from request
 177          foreach( $backup_paths as $name => $settings )
 178          {
 179              if( array_key_exists( 'label', $settings ) && !is_null( $settings['label'] ) )
 180              {    // We can set param
 181                  $this->backup_paths[$name] = param( 'bk_'.$name, 'boolean' );
 182              }
 183          }
 184  
 185          // Load tables settings from request
 186          foreach( $backup_tables as $name => $settings )
 187          {
 188              $this->backup_tables[$name] = param( 'bk_'.$name, 'boolean' );
 189          }
 190  
 191          $this->pack_backup_files = param( 'bk_pack_backup_files', 'boolean', 0 );
 192  
 193          // Check are there something to backup
 194          if( !$this->has_included( $this->backup_paths ) && !$this->has_included( $this->backup_tables ) )
 195          {
 196              $Messages->add( T_('You have not selected anything to backup.'), 'error' );
 197              return false;
 198          }
 199  
 200          return true;
 201      }
 202  
 203  
 204      /**
 205       * Start backup
 206       */
 207  	function start_backup()
 208      {
 209          global $basepath, $backup_path, $servertimenow;
 210  
 211          // Create current backup path
 212          $cbackup_path = $backup_path.date( 'Y-m-d-H-i-s', $servertimenow ).'/';
 213  
 214          echo '<p>'.sprintf( T_('Starting backup to: &laquo;%s&raquo; ...'), $cbackup_path ).'</p>';
 215          evo_flush();
 216  
 217          // Prepare backup directory
 218          $success = prepare_maintenance_dir( $backup_path, true );
 219  
 220          // Backup directories and files
 221          if( $success && $this->has_included( $this->backup_paths ) )
 222          {
 223              $backup_files_path = $this->pack_backup_files ? $cbackup_path : $cbackup_path.'files/';
 224  
 225              // Prepare files backup directory
 226              if( $success = prepare_maintenance_dir( $backup_files_path, false ) )
 227              {    // We can backup files
 228                  $success = $this->backup_files( $backup_files_path );
 229              }
 230          }
 231  
 232          // Backup database
 233          if( $success && $this->has_included( $this->backup_tables ) )
 234          {
 235              $backup_tables_path = $this->pack_backup_files ? $cbackup_path : $cbackup_path.'db/';
 236  
 237              // Prepare database backup directory
 238              if( $success = prepare_maintenance_dir( $backup_tables_path, false ) )
 239              {    // We can backup database
 240                  $success = $this->backup_database( $backup_tables_path );
 241              }
 242          }
 243  
 244          if( $success )
 245          {
 246              echo '<p>'.sprintf( T_('Backup complete. Directory: &laquo;%s&raquo;'), $cbackup_path ).'</p>';
 247              evo_flush();
 248  
 249              return true;
 250          }
 251  
 252          @rmdir_r( $cbackup_path );
 253          return false;
 254      }
 255  
 256  
 257      /**
 258       * Backup files
 259       * @param string backup directory path
 260       */
 261  	function backup_files( $backup_dirpath )
 262      {
 263          global $basepath, $backup_paths, $inc_path;
 264  
 265          echo '<h4>'.T_('Creating folders/files backup...').'</h4>';
 266          evo_flush();
 267  
 268          // Find included and excluded files
 269  
 270          $included_files = array();
 271  
 272          if( $root_included = $this->backup_paths['application_files'] )
 273          {
 274              $filename_params = array(
 275                      'recurse'            => false,
 276                      'basename'            => true,
 277                      'trailing_slash'    => true,
 278                      //'inc_evocache'    => true, // Uncomment to backup ?evocache directories
 279                  );
 280              $included_files = get_filenames( $basepath, $filename_params );
 281          }
 282  
 283          // Prepare included/excluded paths
 284          $excluded_files = array();
 285  
 286          foreach( $this->backup_paths as $name => $included )
 287          {
 288              foreach( $this->path_to_array( $backup_paths[$name]['path'] ) as $path )
 289              {
 290                  if( $root_included && !$included )
 291                  {
 292                      $excluded_files[] = $path;
 293                  }
 294                  elseif( !$root_included && $included )
 295                  {
 296                      $included_files[] = $path;
 297                  }
 298              }
 299          }
 300  
 301          // Remove excluded list from included list
 302          $included_files = array_diff( $included_files, $excluded_files );
 303  
 304          if( $this->pack_backup_files )
 305          {    // Create ZIPped backup
 306              $zip_filepath = $backup_dirpath.'files.zip';
 307  
 308              // Pack using 'zlib' extension and PclZip wrapper
 309  
 310              if( ! defined( 'PCLZIP_TEMPORARY_DIR' ) )
 311              { // Set path for temp files of PclZip
 312                  define( 'PCLZIP_TEMPORARY_DIR', $backup_dirpath );
 313              }
 314              // Load PclZip class (PHP4):
 315              load_class( '_ext/pclzip/pclzip.lib.php', 'PclZip' );
 316  
 317              $PclZip = new PclZip( $zip_filepath );
 318  
 319              echo sprintf( T_('Archiving files to &laquo;<strong>%s</strong>&raquo;...'), $zip_filepath ).'<br/>';
 320              evo_flush();
 321  
 322              foreach( $included_files as $included_file )
 323              {
 324                  echo sprintf( T_('Backing up &laquo;<strong>%s</strong>&raquo; ...'), $basepath.$included_file );
 325                  evo_flush();
 326  
 327                  $file_list = $PclZip->add( no_trailing_slash( $basepath.$included_file ), PCLZIP_OPT_REMOVE_PATH, no_trailing_slash( $basepath ) );
 328                  if( $file_list == 0 )
 329                  {
 330                      echo '<p style="color:red">'.sprintf( T_('Unable to create &laquo;%s&raquo;'), $zip_filepath ).'</p>';
 331                      evo_flush();
 332  
 333                      return false;
 334                  }
 335                  else
 336                  {
 337                      echo ' OK.<br />';
 338                      evo_flush();
 339                  }
 340              }
 341          }
 342          else
 343          {    // Copy directories and files to backup directory
 344              foreach( $included_files as $included_file )
 345              {
 346                  $this->recurse_copy( no_trailing_slash( $basepath.$included_file ),
 347                                          no_trailing_slash( $backup_dirpath.$included_file ) );
 348              }
 349          }
 350  
 351          return true;
 352      }
 353  
 354  
 355      /**
 356       * Backup database
 357       *
 358       * @param string backup directory path
 359       */
 360  	function backup_database( $backup_dirpath )
 361      {
 362          global $DB, $db_config, $backup_tables, $inc_path;
 363  
 364          echo '<h4>'.T_('Creating database backup...').'</h4>';
 365          evo_flush();
 366  
 367          // Collect all included tables
 368          $ready_to_backup = array();
 369          foreach( $this->backup_tables as $name => $included )
 370          {
 371              if( $included )
 372              {
 373                  $tables = aliases_to_tables( $backup_tables[$name]['table'] );
 374                  if( is_array( $tables ) )
 375                  {
 376                      $ready_to_backup = array_merge( $ready_to_backup, $tables );
 377                  }
 378                  elseif( $tables == '*' )
 379                  {
 380                      foreach( $DB->get_results( 'SHOW TABLES', ARRAY_N ) as $row )
 381                      {
 382                          $ready_to_backup[] = $row[0];
 383                      }
 384                  }
 385                  else
 386                  {
 387                      $ready_to_backup[] = $tables;
 388                  }
 389              }
 390          }
 391  
 392          // Ensure there are no duplicated tables
 393          $ready_to_backup = array_unique( $ready_to_backup );
 394  
 395          // Exclude tables
 396          foreach( $this->backup_tables as $name => $included )
 397          {
 398              if( !$included )
 399              {
 400                  $tables = aliases_to_tables( $backup_tables[$name]['table'] );
 401                  if( is_array( $tables ) )
 402                  {
 403                      $ready_to_backup = array_diff( $ready_to_backup, $tables );
 404                  }
 405                  elseif( $tables != '*' )
 406                  {
 407                      $index = array_search( $tables, $ready_to_backup );
 408                      if( $index )
 409                      {
 410                          unset( $ready_to_backup[$index] );
 411                      }
 412                  }
 413              }
 414          }
 415  
 416          // Create and save created SQL backup script
 417          $backup_sql_filename = 'db.sql';
 418          $backup_sql_filepath = $backup_dirpath.$backup_sql_filename;
 419  
 420          // Check if backup file exists
 421          if( file_exists( $backup_sql_filepath ) )
 422          {    // Stop tables backup, because backup file exists
 423              echo '<p style="color:red">'.sprintf( T_('Unable to write database dump. Database dump already exists: &laquo;%s&raquo;'), $backup_sql_filepath ).'</p>';
 424              evo_flush();
 425  
 426              return false;
 427          }
 428  
 429          $f = @fopen( $backup_sql_filepath , 'w+' );
 430          if( $f == false )
 431          {    // Stop backup, because it can't open backup file for writing
 432              echo '<p style="color:red">'.sprintf( T_('Unable to write database dump. Could not open &laquo;%s&raquo; for writing.'), $backup_sql_filepath ).'</p>';
 433              evo_flush();
 434  
 435              return false;
 436          }
 437  
 438          echo sprintf( T_('Dumping tables to &laquo;<strong>%s</strong>&raquo;...'), $backup_sql_filepath ).'<br/>';
 439          evo_flush();
 440  
 441          // Create and save created SQL backup script
 442          foreach( $ready_to_backup as $table )
 443          {
 444              // progressive display of what backup is doing
 445              echo sprintf( T_('Backing up table &laquo;<strong>%s</strong>&raquo; ...'), $table );
 446              evo_flush();
 447  
 448              $row_table_data = $DB->get_row( 'SHOW CREATE TABLE '.$table, ARRAY_N );
 449              fwrite( $f, $row_table_data[1].";\n\n" );
 450  
 451              $page = 0;
 452              $page_size = 500;
 453              $is_insert_sql_started = false;
 454              $is_first_insert_sql_value = true;
 455              while( ! empty( $rows ) || $page == 0 )
 456              { // Get the records by page(500) in order to save memory and avoid fatal error
 457                  $rows = $DB->get_results( 'SELECT * FROM '.$table.' LIMIT '.( $page * $page_size ).', '.$page_size, ARRAY_N );
 458  
 459                  if( $page == 0 && ! $is_insert_sql_started && ! empty( $rows ) )
 460                  { // Start SQL INSERT clause
 461                      fwrite( $f, 'INSERT INTO '.$table.' VALUES ' );
 462                      $is_insert_sql_started = true;
 463                  }
 464  
 465                  foreach( $rows as $row )
 466                  {
 467                      $values = '(';
 468                      $num_fields = count( $row );
 469                      for( $index = 0; $index < $num_fields; $index++ )
 470                      {
 471                          if( isset( $row[$index] ) )
 472                          {
 473                              $row[$index] = str_replace("\n","\\n", addslashes( $row[$index] ) );
 474                              $values .= '\''.$row[$index].'\'' ;
 475                          }
 476                          else
 477                          { // The $row[$index] value is not set or is NULL
 478                              $values .= 'NULL';
 479                          }
 480  
 481                          if( $index<( $num_fields-1 ) )
 482                          {
 483                              $values .= ',';
 484                          }
 485                      }
 486                      $values .= ')';
 487                      if( $is_first_insert_sql_value )
 488                      { // Don't write a comma before first row values
 489                          $is_first_insert_sql_value = false;
 490                      }
 491                      else
 492                      { // Write a comma between row values
 493                          $values = ','.$values;
 494                      }
 495  
 496                      fwrite( $f, $values );
 497                  }
 498                  unset( $rows );
 499                  $page++;
 500              }
 501  
 502              if( $is_insert_sql_started )
 503              { // End SQL INSERT clause
 504                  fwrite( $f, ";\n\n" );
 505              }
 506  
 507              // Flush the output to a file
 508              if( fflush( $f ) )
 509              {
 510                  echo ' OK.';
 511              }
 512              echo '<br />';
 513              evo_flush();
 514          }
 515  
 516          // Close backup file input stream
 517          fclose( $f );
 518  
 519          if( $this->pack_backup_files )
 520          { // Pack created backup SQL script
 521  
 522              // Pack using 'zlib' extension and PclZip wrapper
 523  
 524              if( ! defined( 'PCLZIP_TEMPORARY_DIR' ) )
 525              { // Set path for temp files of PclZip
 526                  define( 'PCLZIP_TEMPORARY_DIR', $backup_dirpath );
 527              }
 528              // Load PclZip class (PHP4):
 529              load_class( '_ext/pclzip/pclzip.lib.php', 'PclZip' );
 530  
 531              $zip_filepath = $backup_dirpath.'db.zip';
 532              $PclZip = new PclZip( $zip_filepath );
 533  
 534              $file_list = $PclZip->add( $backup_dirpath.$backup_sql_filename, PCLZIP_OPT_REMOVE_PATH, no_trailing_slash( $backup_dirpath ) );
 535              if( $file_list == 0 )
 536              {
 537                  echo '<p style="color:red">'.sprintf( T_('Unable to create &laquo;%s&raquo;'), $zip_filepath ).'</p>';
 538                  evo_flush();
 539  
 540                  return false;
 541              }
 542  
 543              unlink( $backup_sql_filepath );
 544          }
 545  
 546          return true;
 547      }
 548  
 549  
 550      /**
 551       * Copy directory recursively
 552       * @param string source directory
 553       * @param string destination directory
 554       * @param array excluded directories
 555       */
 556  	function recurse_copy( $src, $dest, $root = true )
 557      {
 558          if( is_dir( $src ) )
 559          {
 560              if( ! ( $dir = opendir( $src ) ) )
 561              {
 562                  return false;
 563              }
 564              if( ! evo_mkdir( $dest ) )
 565              {
 566                  return false;
 567              }
 568              while( false !== ( $file = readdir( $dir ) ) )
 569              {
 570                  if( ( $file != '.' ) && ( $file != '..' ) )
 571                  {
 572                      $srcfile = $src.'/'.$file;
 573                      if( is_dir( $srcfile ) )
 574                      {
 575                          if( $root )
 576                          { // progressive display of what backup is doing
 577                              echo sprintf( T_('Backing up &laquo;<strong>%s</strong>&raquo; ...'), $srcfile ).'<br/>';
 578                              evo_flush();
 579                          }
 580                          $this->recurse_copy( $srcfile, $dest . '/' . $file, false );
 581                      }
 582                      else
 583                      { // Copy file
 584                          copy( $srcfile, $dest.'/'. $file );
 585                      }
 586                  }
 587              }
 588              closedir( $dir );
 589          }
 590          else
 591          {
 592              copy( $src, $dest );
 593          }
 594      }
 595  
 596  
 597      /**
 598       * Include all of the folders and tables to backup.
 599       */
 600  	function include_all()
 601      {
 602          global $backup_paths, $backup_tables;
 603  
 604          foreach( $backup_paths as $name => $settings )
 605          {
 606              if( array_key_exists( 'label', $settings ) && !is_null( $settings['label'] ) )
 607              {
 608                  $this->backup_paths[$name] = true;
 609              }
 610          }
 611  
 612          foreach( $backup_tables as $name => $settings )
 613          {
 614              $this->backup_tables[$name] = true;
 615          }
 616      }
 617  
 618  
 619      /**
 620       * Check has data list included directories/files or tables
 621       * @param array list
 622       * @return boolean
 623       */
 624  	function has_included( & $data_list )
 625      {
 626          foreach( $data_list as $included )
 627          {
 628              if( $included )
 629              {
 630                  return true;
 631              }
 632          }
 633          return false;
 634      }
 635  
 636  
 637      /**
 638       * Convert path to array
 639       * @param mixed path
 640       * @return array
 641       */
 642  	function path_to_array( $path )
 643      {
 644          if( is_array( $path ) )
 645          {
 646              return $path;
 647          }
 648          return array( $path );
 649      }
 650  }
 651  
 652  ?>

title

Description

title

Description

title

Description

title

title

Body