WordPress.org

Plugin Directory

Changeset 595353


Ignore:
Timestamp:
09/06/12 12:09:33 (20 months ago)
Author:
joehoyle
Message:

Fixed themes in 3.4+, use latest HM_Backup

File:
1 edited

Legend:

Unmodified
Added
Removed
  • wpremote/trunk/hm-backup/hm-backup.php

    r521280 r595353  
    44 * Generic file and database backup class 
    55 * 
    6  * @version 1.5.1 
     6 * @version 2.0 Beta 
    77 */ 
    88class HM_Backup { 
     
    1212     * 
    1313     * @string 
    14      * @access public 
    15      */ 
    16     public $path; 
    17  
    18     /** 
    19      * Whether the backup should be files only 
    20      * 
    21      * @bool 
    22      * @access public 
    23      */ 
    24     public $files_only; 
    25  
    26     /** 
    27      * Whether the backup should be database only 
    28      * 
    29      * @bool 
    30      * @access public 
    31      */ 
    32     public $database_only; 
     14     * @access private 
     15     */ 
     16    private $path = ''; 
     17 
     18    /** 
     19     * The backup type, must be either complete, file or database 
     20     * 
     21     * @string 
     22     * @access private 
     23     */ 
     24    private $type = ''; 
    3325 
    3426    /** 
     
    3628     * 
    3729     * @string 
    38      * @access public 
    39      */ 
    40     public $archive_filename; 
     30     * @access private 
     31     */ 
     32    private $archive_filename = ''; 
    4133 
    4234    /** 
     
    4436     * 
    4537     * @string 
    46      * @access public 
    47      */ 
    48     public $database_dump_filename; 
     38     * @access private 
     39     */ 
     40    private $database_dump_filename = ''; 
    4941 
    5042    /** 
     
    5244     * 
    5345     * @string 
    54      * @access public 
    55      */ 
    56     public $zip_command_path; 
     46     * @access private 
     47     */ 
     48    private $zip_command_path; 
    5749 
    5850    /** 
     
    6052     * 
    6153     * @string 
    62      * @access public 
    63      */ 
    64     public $mysqldump_command_path; 
     54     * @access private 
     55     */ 
     56    private $mysqldump_command_path; 
    6557 
    6658    /** 
     
    6860     * 
    6961     * @array 
    70      * @access public 
    71      */ 
    72     public $excludes; 
     62     * @access private 
     63     */ 
     64    private $excludes = array(); 
    7365 
    7466    /** 
     
    7668     * 
    7769     * @var string 
    78      * @access public 
    79      */ 
    80     public $root; 
     70     * @access private 
     71     */ 
     72    private $root = ''; 
    8173 
    8274    /** 
     
    8981 
    9082    /** 
    91      * Store the current backup instance 
    92      * 
    93      * @var object 
     83     * An array of all the files in root 
     84     * excluding excludes and unreadable files 
     85     * 
     86     * @var array 
     87     * @access private 
     88     */ 
     89    private $files = array(); 
     90 
     91    /** 
     92     * An array of all the files in root 
     93     * that match the exclude rules 
     94     * 
     95     * @var array 
     96     * @access private 
     97     */ 
     98    private $excluded_files = array(); 
     99 
     100    /** 
     101     * An array of all the files in root 
     102     * that are unreadable 
     103     * 
     104     * @var array 
     105     * @access private 
     106     */ 
     107    private $unreadable_files = array(); 
     108 
     109    /** 
     110     * Contains an array of errors 
     111     * 
     112     * @var mixed 
     113     * @access private 
     114     */ 
     115    private $errors = array(); 
     116 
     117    /** 
     118     * Contains an array of warnings 
     119     * 
     120     * @var mixed 
     121     * @access private 
     122     */ 
     123    private $warnings = array(); 
     124 
     125    /** 
     126     * The archive method used 
     127     * 
     128     * @var string 
     129     * @access private 
     130     */ 
     131    private $archive_method = ''; 
     132 
     133    /** 
     134     * The mysqldump method used 
     135     * 
     136     * @var string 
     137     * @access private 
     138     */ 
     139    private $mysqldump_method = ''; 
     140 
     141    /** 
     142     * Check whether safe mode is active or not 
     143     * 
     144     * @access public 
    94145     * @static 
    95      * @access public 
    96      */ 
    97     private static $instance; 
    98  
    99     /** 
    100      * An array of all the files in root 
    101      * excluding excludes 
    102      * 
    103      * @var array 
    104      * @access private 
    105      */ 
    106     private $files; 
    107  
    108     /** 
    109      * Contains an array of errors 
    110      * 
    111      * @var mixed 
    112      * @access private 
    113      */ 
    114     private $errors; 
    115  
    116     /** 
    117      * Contains an array of warnings 
    118      * 
    119      * @var mixed 
    120      * @access private 
    121      */ 
    122     private $warnings; 
    123  
    124     /** 
    125      * The archive method used 
    126      * 
    127      * @var string 
    128      * @access private 
    129      */ 
    130     private $archive_method; 
    131  
    132     /** 
    133      * The mysqldump method used 
    134      * 
    135      * @var string 
    136      * @access private 
    137      */ 
    138     private $mysqldump_method; 
     146     * @return bool 
     147     */ 
     148    public static function is_safe_mode_active() { 
     149 
     150        if ( ( $safe_mode = @ini_get( 'safe_mode' ) ) && strtolower( $safe_mode ) != 'off' ) 
     151            return true; 
     152 
     153        return false; 
     154 
     155    } 
     156 
     157    /** 
     158     * Check whether shell_exec has been disabled. 
     159     * 
     160     * @access public 
     161     * @static 
     162     * @return bool 
     163     */ 
     164    public static function is_shell_exec_available() { 
     165 
     166        // Are we in Safe Mode 
     167        if ( self::is_safe_mode_active() ) 
     168            return false; 
     169 
     170        // Is shell_exec disabled? 
     171        if ( in_array( 'shell_exec', array_map( 'trim', explode( ',', @ini_get( 'disable_functions' ) ) ) ) ) 
     172            return false; 
     173 
     174        // Can we issue a simple echo command? 
     175        if ( ! @shell_exec( 'echo backupwordpress' ) ) 
     176            return false; 
     177 
     178        return true; 
     179 
     180    } 
     181 
     182 
     183    /** 
     184     * Attempt to work out the root directory of the site, that 
     185     * is, the path equivelant of home_url(). 
     186     * 
     187     * @access public 
     188     * @static 
     189     * @return string $home_path 
     190     */ 
     191    public static function get_home_path() { 
     192 
     193        $home = get_option( 'home' ); 
     194        $siteurl = get_option( 'siteurl' ); 
     195 
     196        $home_path = ABSPATH; 
     197 
     198        if ( ! empty( $home ) && $home !== $siteurl ) 
     199            $home_path = trailingslashit( substr( ABSPATH, 0, strrpos( ABSPATH, str_replace( $home, '', $siteurl ) ) ) ); 
     200 
     201        return self::conform_dir( $home_path ); 
     202 
     203    } 
     204 
     205    /** 
     206     * Sanitize a directory path 
     207     * 
     208     * @access public 
     209     * @static 
     210     * @param string $dir 
     211     * @param bool $rel. (default: false) 
     212     * @return string $dir 
     213     */ 
     214    public static function conform_dir( $dir, $recursive = false ) { 
     215 
     216        // Assume empty dir is root 
     217        if ( ! $dir ) 
     218            $dir = '/'; 
     219 
     220        // Replace single forward slash (looks like double slash because we have to escape it) 
     221        $dir = str_replace( '\\', '/', $dir ); 
     222        $dir = str_replace( '//', '/', $dir ); 
     223 
     224        // Remove the trailing slash 
     225        if ( $dir !== '/' ) 
     226            $dir = untrailingslashit( $dir ); 
     227 
     228        // Carry on until completely normalized 
     229        if ( ! $recursive && self::conform_dir( $dir, true ) != $dir ) 
     230            return self::conform_dir( $dir ); 
     231 
     232        return (string) $dir; 
     233 
     234    } 
    139235 
    140236    /** 
     
    142238     * 
    143239     * @access public 
    144      * @return null 
    145240     */ 
    146241    public function __construct() { 
    147242 
    148         // Raise the memory limit and max_execution_time time 
     243        // Raise the memory limit and max_execution time 
    149244        @ini_set( 'memory_limit', apply_filters( 'admin_memory_limit', WP_MAX_MEMORY_LIMIT ) ); 
    150245        @set_time_limit( 0 ); 
    151246 
    152         $this->errors = array(); 
    153  
     247        // Set a custom error handler so we can track errors 
    154248        set_error_handler( array( &$this, 'error_handler' ) ); 
    155249 
    156         // Defaults 
    157         $this->root = $this->conform_dir( ABSPATH ); 
    158  
    159         $this->path = $this->conform_dir( WP_CONTENT_DIR . '/backups' ); 
    160  
    161         $this->database_dump_filename = 'database_' . DB_NAME . '.sql'; 
    162  
    163         $this->archive_filename = strtolower( sanitize_file_name( get_bloginfo( 'name' ) . '.backup.' . date( 'Y-m-d-H-i-s', time() + ( current_time( 'timestamp' ) - time() ) ) . '.zip' ) ); 
    164  
    165         $this->mysqldump_command_path = $this->guess_mysqldump_command_path(); 
    166         $this->zip_command_path = $this->guess_zip_command_path(); 
    167  
    168         $this->database_only = false; 
    169         $this->files_only = false; 
    170  
    171     } 
    172  
    173     /** 
    174      * Return the current instance 
    175      * 
    176      * @access public 
    177      * @static 
    178      * @return object 
    179      */ 
    180     public static function get_instance() { 
    181  
    182         if ( empty( self::$instance ) ) 
    183             self::$instance = new HM_Backup(); 
    184  
    185         return self::$instance; 
    186  
    187     } 
    188  
    189     /** 
    190      * The full filepath to the archive file. 
     250    } 
     251 
     252    /** 
     253     * Get the full filepath to the archive file 
    191254     * 
    192255     * @access public 
    193256     * @return string 
    194257     */ 
    195     public function archive_filepath() { 
    196         return trailingslashit( $this->path() ) . $this->archive_filename(); 
    197     } 
    198  
    199     /** 
    200      * The full filepath to the archive file. 
     258    public function get_archive_filepath() { 
     259 
     260        return trailingslashit( $this->get_path() ) . $this->get_archive_filename(); 
     261 
     262    } 
     263 
     264    /** 
     265     * Get the filename of the archive file 
    201266     * 
    202267     * @access public 
    203268     * @return string 
    204269     */ 
    205     public function archive_filename() { 
    206         return strtolower( sanitize_file_name( remove_accents( $this->archive_filename ) ) ); 
    207     } 
    208  
    209     /** 
    210      * The full filepath to the database dump file. 
     270    public function get_archive_filename() { 
     271 
     272        if ( empty( $this->archive_filename ) ) 
     273            $this->set_archive_filename( strtolower( sanitize_file_name( implode( '-', array( get_bloginfo( 'name' ), 'backup', date( 'Y-m-d-H-i-s', current_time( 'timestamp' ) ) ) ) ) ) . '.zip' ); 
     274 
     275        return $this->archive_filename; 
     276 
     277    } 
     278 
     279    /** 
     280     * Set the filename of the archive file 
     281     * 
     282     * @access public 
     283     * @param string $filename 
     284     */ 
     285    public function set_archive_filename( $filename ) { 
     286 
     287        if ( empty( $filename ) || ! is_string( $filename ) ) 
     288            throw new Exception( 'archive filename must be a non empty string' ); 
     289 
     290        if ( pathinfo( $filename, PATHINFO_EXTENSION ) !== 'zip' ) 
     291            throw new Exception( 'invalid file extension for archive filename <code>' . $filename . '</code>' ); 
     292 
     293        $this->archive_filename = strtolower( sanitize_file_name( remove_accents( $filename ) ) ); 
     294 
     295    } 
     296 
     297    /** 
     298     * Get the full filepath to the database dump file. 
    211299     * 
    212300     * @access public 
    213301     * @return string 
    214302     */ 
    215     public function database_dump_filepath() { 
    216         return trailingslashit( $this->path() ) . $this->database_dump_filename(); 
    217     } 
    218  
    219     public function database_dump_filename() { 
    220         return strtolower( sanitize_file_name( remove_accents( $this->database_dump_filename ) ) ); 
    221     } 
    222  
    223     public function root() { 
    224         return $this->conform_dir( $this->root ); 
     303    public function get_database_dump_filepath() { 
     304 
     305        return trailingslashit( $this->get_path() ) . $this->get_database_dump_filename(); 
     306 
     307    } 
     308 
     309    /** 
     310     * Get the filename of the database dump file 
     311     * 
     312     * @access public 
     313     * @return string 
     314     */ 
     315    public function get_database_dump_filename() { 
     316 
     317        if ( empty( $this->database_dump_filename ) ) 
     318            $this->set_database_dump_filename( strtolower( sanitize_file_name( remove_accents(  'database_' . DB_NAME . '.sql' ) ) ) ); 
     319 
     320        return $this->database_dump_filename; 
     321 
     322    } 
     323 
     324    /** 
     325     * Set the filename of the database dump file 
     326     * 
     327     * @access public 
     328     * @param string $filename 
     329     */ 
     330    public function set_database_dump_filename( $filename ) { 
     331 
     332        if ( empty( $filename ) || ! is_string( $filename ) ) 
     333            throw new Exception( 'database dump filename must be a non empty string' ); 
     334 
     335        if ( pathinfo( $filename, PATHINFO_EXTENSION ) !== 'sql' ) 
     336            throw new Exception( 'invalid file extension for database dump filename <code>' . $filename . '</code>' ); 
     337 
     338        $this->database_dump_filename = strtolower( sanitize_file_name( remove_accents( $filename ) ) ); 
     339 
     340    } 
     341 
     342    /** 
     343     * Get the root directory to backup from 
     344     * 
     345     * Defaults to the root of the path equivalent of your home_url 
     346     * 
     347     * @access public 
     348     * @return string 
     349     */ 
     350    public function get_root() { 
     351 
     352        if ( empty( $this->root ) ) 
     353            $this->set_root( $this->conform_dir( self::get_home_path() ) ); 
     354 
     355        return $this->root; 
     356 
    225357    } 
    226358 
    227     public function path() { 
    228         return $this->conform_dir( $this->path ); 
     359    /** 
     360     * Set the root directory to backup from 
     361     * 
     362     * @access public 
     363     * @param string $path 
     364     * @return null 
     365     */ 
     366    public function set_root( $path ) { 
     367 
     368        if ( empty( $path ) || ! is_string( $path ) || ! is_dir ( $path ) ) 
     369            throw new Exception( 'Invalid root path <code>' . $path . '</code> must be a valid directory path' ); 
     370 
     371        $this->root = $this->conform_dir( $path ); 
     372 
    229373    } 
    230374 
    231     public function archive_method() { 
     375    /** 
     376     * Get the directory backups are saved to 
     377     * 
     378     * @access public 
     379     * @return string 
     380     */ 
     381    public function get_path() { 
     382 
     383        if ( empty( $this->path ) ) 
     384            $this->set_path( $this->conform_dir( WP_CONTENT_DIR . '/backups' ) ); 
     385 
     386        return $this->path; 
     387 
     388    } 
     389 
     390    /** 
     391     * Set the directory backups are saved to 
     392     * 
     393     * @access public 
     394     * @param string $path 
     395     * @return null 
     396     */ 
     397    public function set_path( $path ) { 
     398 
     399        if ( empty( $path ) || ! is_string( $path ) ) 
     400            throw new Exception( 'Invalid backup path <code>' . $path . '</code> must be a non empty (string)' ); 
     401 
     402        $this->path = $this->conform_dir( $path ); 
     403 
     404    } 
     405 
     406    /** 
     407     * Get the archive method that was used for the backup 
     408     * 
     409     * Will be either zip, ZipArchive or PclZip 
     410     * 
     411     * @access public 
     412     */ 
     413    public function get_archive_method() { 
    232414        return $this->archive_method; 
    233415    } 
    234416 
    235     public function mysqldump_method() { 
     417    /** 
     418     * Get the database dump method that was used for the backup 
     419     * 
     420     * Will be either mysqldump or mysqldump_fallback 
     421     * 
     422     * @access public 
     423     */ 
     424    public function get_mysqldump_method() { 
    236425        return $this->mysqldump_method; 
    237426    } 
    238427 
    239428    /** 
    240      * Kick off a backup 
    241      * 
    242      * @access public 
    243      * @return bool 
    244      */ 
    245     public function backup() { 
    246  
    247         do_action( 'hmbkp_backup_started', $this ); 
    248  
    249         // Backup database 
    250         if ( ! $this->files_only ) 
    251             $this->mysqldump(); 
    252  
    253         // Zip everything up 
    254         $this->archive(); 
    255  
    256         do_action( 'hmbkp_backup_complete', $this ); 
    257  
    258     } 
    259  
    260     /** 
    261      * Create the mysql backup 
    262      * 
    263      * Uses mysqldump if available, falls back to PHP 
    264      * if not. 
    265      * 
    266      * @access public 
    267      * @return null 
    268      */ 
    269     public function mysqldump() { 
    270  
    271         do_action( 'hmbkp_mysqldump_started' ); 
    272  
    273         $this->mysqldump_method = 'mysqldump'; 
    274  
    275         // Use mysqldump if we can 
    276         if ( $this->mysqldump_command_path ) { 
    277  
    278             $host = reset( explode( ':', DB_HOST ) ); 
    279             $port = strpos( DB_HOST, ':' ) ? end( explode( ':', DB_HOST ) ) : ''; 
    280  
    281             // Path to the mysqldump executable 
    282             $cmd = escapeshellarg( $this->mysqldump_command_path ); 
    283  
    284             // No Create DB command 
    285             $cmd .= ' --no-create-db'; 
    286  
    287             // Make sure binary data is exported properly 
    288             $cmd .= ' --hex-blob'; 
    289  
    290             // Username 
    291             $cmd .= ' -u ' . escapeshellarg( DB_USER ); 
    292  
    293             // Don't pass the password if it's blank 
    294             if ( DB_PASSWORD ) 
    295                 $cmd .= ' -p'  . escapeshellarg( DB_PASSWORD ); 
    296  
    297             // Set the host 
    298             $cmd .= ' -h ' . escapeshellarg( $host ); 
    299  
    300             // Set the port if it was set 
    301             if ( ! empty( $port ) ) 
    302                 $cmd .= ' -P ' . $port; 
    303  
    304             // The file we're saving too 
    305             $cmd .= ' -r ' . escapeshellarg( $this->database_dump_filepath() ); 
    306  
    307             // The database we're dumping 
    308             $cmd .= ' ' . escapeshellarg( DB_NAME ); 
    309  
    310             // Pipe STDERR to STDOUT 
    311             $cmd .= ' 2>&1'; 
    312  
    313             // Store any returned data in warning 
    314             $this->warning( $this->mysqldump_method, shell_exec( $cmd ) ); 
     429     * Get the backup type 
     430     * 
     431     * Defaults to complete 
     432     * 
     433     * @access public 
     434     */ 
     435    public function get_type() { 
     436 
     437        if ( empty( $this->type ) ) 
     438            $this->set_type( 'complete' ); 
     439 
     440        return $this->type; 
     441 
     442    } 
     443 
     444    /** 
     445     * Set the backup type 
     446     * 
     447     * $type must be one of complete, database or file 
     448     * 
     449     * @access public 
     450     * @param string $type 
     451     */ 
     452    public function set_type( $type ) { 
     453 
     454        if ( ! is_string( $type ) || ! in_array( $type, array( 'file', 'database', 'complete' ) ) ) 
     455            throw new Exception( 'Invalid backup type <code>' . $type . '</code> must be one of (string) file, database or complete' ); 
     456 
     457        $this->type = $type; 
     458 
     459    } 
     460 
     461    /** 
     462     * Get the path to the mysqldump bin 
     463     * 
     464     * If not explicitly set will attempt to work 
     465     * it out by checking common locations 
     466     * 
     467     * @access public 
     468     * @return string 
     469     */ 
     470    public function get_mysqldump_command_path() { 
     471 
     472        // Check shell_exec is available 
     473        if ( ! self::is_shell_exec_available() ) 
     474            return ''; 
     475 
     476        // Return now if it's already been set 
     477        if ( isset( $this->mysqldump_command_path ) ) 
     478            return $this->mysqldump_command_path; 
     479 
     480        $this->mysqldump_command_path = ''; 
     481 
     482        // Does mysqldump work 
     483        if ( is_null( shell_exec( 'hash mysqldump 2>&1' ) ) ) { 
     484 
     485            // If so store it for later 
     486            $this->set_mysqldump_command_path( 'mysqldump' ); 
     487 
     488            // And return now 
     489            return $this->mysqldump_command_path; 
    315490 
    316491        } 
    317  
    318         // If not or if the shell mysqldump command failed, use the PHP fallback 
    319         if ( ! file_exists( $this->database_dump_filepath() ) ) 
    320             $this->mysqldump_fallback(); 
    321  
    322         do_action( 'hmbkp_mysqldump_finished' ); 
    323  
    324     } 
    325  
    326     /** 
    327      * PHP mysqldump fallback functions, exports the database to a .sql file 
    328      * 
    329      * @access public 
    330      * @return null 
    331      */ 
    332     public function mysqldump_fallback() { 
    333  
    334         $this->errors_to_warnings( $this->mysqldump_method ); 
    335  
    336         $this->mysqldump_method = 'mysqldump_fallback'; 
    337  
    338         $this->db = mysql_pconnect( DB_HOST, DB_USER, DB_PASSWORD ); 
    339  
    340         mysql_select_db( DB_NAME, $this->db ); 
    341         mysql_set_charset( DB_CHARSET, $this->db ); 
    342  
    343         // Begin new backup of MySql 
    344         $tables = mysql_query( 'SHOW TABLES' ); 
    345  
    346         $sql_file  = "# WordPress : " . get_bloginfo( 'url' ) . " MySQL database backup\n"; 
    347         $sql_file .= "#\n"; 
    348         $sql_file .= "# Generated: " . date( 'l j. F Y H:i T' ) . "\n"; 
    349         $sql_file .= "# Hostname: " . DB_HOST . "\n"; 
    350         $sql_file .= "# Database: " . $this->sql_backquote( DB_NAME ) . "\n"; 
    351         $sql_file .= "# --------------------------------------------------------\n"; 
    352  
    353         for ( $i = 0; $i < mysql_num_rows( $tables ); $i++ ) { 
    354  
    355             $curr_table = mysql_tablename( $tables, $i ); 
    356  
    357             // Create the SQL statements 
    358             $sql_file .= "# --------------------------------------------------------\n"; 
    359             $sql_file .= "# Table: " . $this->sql_backquote( $curr_table ) . "\n"; 
    360             $sql_file .= "# --------------------------------------------------------\n"; 
    361  
    362             $this->make_sql( $sql_file, $curr_table ); 
    363  
    364         } 
    365  
    366     } 
    367  
    368     /** 
    369      * Zip up all the files. 
    370      * 
    371      * Attempts to use the shell zip command, if 
    372      * thats not available then it fallsback to 
    373      * PHP ZipArchive and finally PclZip. 
    374      * 
    375      * @access public 
    376      * @return null 
    377      */ 
    378     public function archive() { 
    379  
    380         do_action( 'hmbkp_archive_started' ); 
    381  
    382         // Do we have the path to the zip command 
    383         if ( $this->zip_command_path ) 
    384             $this->zip(); 
    385  
    386         // If not or if the shell zip failed then use ZipArchive 
    387         if ( empty( $this->archive_verified ) && class_exists( 'ZipArchive' ) && empty( $this->skip_zip_archive ) ) 
    388             $this->zip_archive(); 
    389  
    390         // If ZipArchive is unavailable or one of the above failed 
    391         if ( empty( $this->archive_verified ) ) 
    392             $this->pcl_zip(); 
    393  
    394         // Delete the database dump file 
    395         if ( file_exists( $this->database_dump_filepath() ) ) 
    396             unlink( $this->database_dump_filepath() ); 
    397  
    398         do_action( 'hmbkp_archive_finished' ); 
    399  
    400     } 
    401  
    402     /** 
    403      * Zip using the native zip command 
    404      * 
    405      * @access public 
    406      * @return null 
    407      */ 
    408     public function zip() { 
    409  
    410         $this->archive_method = 'zip'; 
    411  
    412         // Zip up $this->root with excludes 
    413         if ( ! $this->database_only && $this->exclude_string( 'zip' ) ) 
    414             $this->warning( $this->archive_method, shell_exec( 'cd ' . escapeshellarg( $this->root() ) . ' && ' . escapeshellarg( $this->zip_command_path ) . ' -rq ' . escapeshellarg( $this->archive_filepath() ) . ' ./' . ' -x ' . $this->exclude_string( 'zip' ) . ' 2>&1' ) ); 
    415  
    416         // Zip up $this->root without excludes 
    417         elseif ( ! $this->database_only ) 
    418             $this->warning( $this->archive_method, shell_exec( 'cd ' . escapeshellarg( $this->root() ) . ' && ' . escapeshellarg( $this->zip_command_path ) . ' -rq ' . escapeshellarg( $this->archive_filepath() ) . ' ./' . ' 2>&1' ) ); 
    419  
    420         // Add the database dump to the archive 
    421         if ( ! $this->files_only ) 
    422             $this->warning( $this->archive_method, shell_exec( 'cd ' . escapeshellarg( $this->path() ) . ' && ' . escapeshellarg( $this->zip_command_path ) . ' -uq ' . escapeshellarg( $this->archive_filepath() ) . ' ' . escapeshellarg( $this->database_dump_filename() ) . ' 2>&1' ) ); 
    423  
    424         $this->check_archive(); 
    425  
    426     } 
    427  
    428     /** 
    429      * Fallback for creating zip archives if zip command is 
    430      * unnavailable. 
    431      * 
    432      * @access public 
    433      * @param string $path 
    434      */ 
    435     public function zip_archive() { 
    436  
    437         $this->errors_to_warnings( $this->archive_method ); 
    438         $this->archive_method = 'ziparchive'; 
    439  
    440         $zip = new ZipArchive(); 
    441  
    442         if ( ! class_exists( 'ZipArchive' ) || ! $zip->open( $this->archive_filepath(), ZIPARCHIVE::CREATE ) ) 
    443             return; 
    444  
    445         if ( ! $this->database_only ) { 
    446  
    447             $files_added = 0; 
    448  
    449             foreach ( $this->files() as $file ) { 
    450  
    451                 if ( is_dir( trailingslashit( $this->root() ) . $file ) ) 
    452                     $zip->addEmptyDir( trailingslashit( $file ) ); 
    453  
    454                 elseif ( is_file( trailingslashit( $this->root() ) . $file ) ) 
    455                     $zip->addFile( trailingslashit( $this->root() ) . $file, $file ); 
    456  
    457                 if ( ++$files_added % 500 === 0 ) 
    458                     if ( ! $zip->close() || ! $zip->open( $this->archive_filepath(), ZIPARCHIVE::CREATE ) ) 
    459                         return; 
    460  
    461             } 
    462  
    463         } 
    464  
    465         // Add the database 
    466         if ( ! $this->files_only ) 
    467             $zip->addFile( $this->database_dump_filepath(), $this->database_dump_filename() ); 
    468  
    469         if ( $zip->status ) 
    470             $this->warning( $this->archive_method, $zip->status ); 
    471  
    472         if ( $zip->statusSys ) 
    473             $this->warning( $this->archive_method, $zip->statusSys ); 
    474  
    475         $zip->close(); 
    476  
    477         $this->check_archive(); 
    478  
    479     } 
    480  
    481     /** 
    482      * Fallback for creating zip archives if zip command and ZipArchive are 
    483      * unnavailable. 
    484      * 
    485      * Uses the PclZip library that ships with WordPress 
    486      * 
    487      * @access public 
    488      * @param string $path 
    489      */ 
    490     public function pcl_zip() { 
    491  
    492         $this->errors_to_warnings( $this->archive_method ); 
    493         $this->archive_method = 'pclzip'; 
    494  
    495         global $_hmbkp_exclude_string; 
    496  
    497         $_hmbkp_exclude_string = $this->exclude_string( 'regex' ); 
    498  
    499         $this->load_pclzip(); 
    500  
    501         $archive = new PclZip( $this->archive_filepath() ); 
    502  
    503         // Zip up everything 
    504         if ( ! $this->database_only ) 
    505             if ( ! $archive->add( $this->root(), PCLZIP_OPT_REMOVE_PATH, $this->root(), PCLZIP_CB_PRE_ADD, 'hmbkp_pclzip_callback' ) ) 
    506                 $this->warning( $this->archive_method, $archive->errorInfo( true ) ); 
    507  
    508         // Add the database 
    509         if ( ! $this->files_only ) 
    510             if ( ! $archive->add( $this->database_dump_filepath(), PCLZIP_OPT_REMOVE_PATH, $this->path() ) ) 
    511                 $this->warning( $this->archive_method, $archive->errorInfo( true ) ); 
    512  
    513         unset( $GLOBALS['_hmbkp_exclude_string'] ); 
    514  
    515         $this->check_archive(); 
    516  
    517     } 
    518  
    519     /** 
    520      * Verify that the archive is valid and contains all the files it should contain. 
    521      * 
    522      * @access public 
    523      * @return bool 
    524      */ 
    525     public function check_archive() { 
    526  
    527         // If we've already passed then no need to check again 
    528         if ( ! empty( $this->archive_verified ) ) 
    529             return true; 
    530  
    531         if ( ! file_exists( $this->archive_filepath() ) ) 
    532             $this->error( $this->archive_method(), __( 'The backup file was not created', 'hmbkp' ) ); 
    533  
    534         // Verify using the zip command if possible 
    535         if ( $this->zip_command_path ) { 
    536  
    537             $verify = shell_exec( escapeshellarg( $this->zip_command_path ) . ' -T ' . escapeshellarg( $this->archive_filepath() ) . ' 2> /dev/null' ); 
    538  
    539             if ( strpos( $verify, 'OK' ) === false ) 
    540                 $this->error( $this->archive_method(), $verify ); 
    541  
    542         } 
    543  
    544         // If there are errors delete the backup file. 
    545         if ( $this->errors( $this->archive_method() ) && file_exists( $this->archive_filepath() ) ) 
    546             unlink( $this->archive_filepath() ); 
    547  
    548         if ( $this->errors( $this->archive_method() ) ) 
    549             return false; 
    550  
    551         return $this->archive_verified = true; 
    552  
    553     } 
    554  
    555     /** 
    556      * Generate the array of files to be backed up by looping through 
    557      * root, ignored unreadable files and excludes 
    558      * 
    559      * @access public 
    560      * @return array 
    561      */ 
    562     public function files() { 
    563  
    564         if ( ! empty( $this->files ) ) 
    565             return $this->files; 
    566  
    567         $this->files = array(); 
    568  
    569         if ( defined( 'RecursiveDirectoryIterator::FOLLOW_SYMLINKS' ) ) { 
    570  
    571             $filesystem = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $this->root(), RecursiveDirectoryIterator::FOLLOW_SYMLINKS ), RecursiveIteratorIterator::SELF_FIRST, RecursiveIteratorIterator::CATCH_GET_CHILD ); 
    572  
    573             $excludes = $this->exclude_string( 'regex' ); 
    574  
    575             foreach ( $filesystem as $file ) { 
    576  
    577                 if ( ! $file->isReadable() ) { 
    578                     $this->unreadable_files[] = $file->getPathName(); 
    579                     continue; 
    580                 } 
    581  
    582                 $pathname = str_ireplace( trailingslashit( $this->root() ), '', $this->conform_dir( $file->getPathname() ) ); 
    583  
    584                 // Excludes 
    585                 if ( $excludes && preg_match( '(' . $excludes . ')', $pathname ) ) 
    586                     continue; 
    587  
    588                 // Don't include database dump as it's added separately 
    589                 if ( basename( $pathname ) == $this->database_dump_filename() ) 
    590                     continue; 
    591  
    592                 $this->files[] = $pathname; 
    593  
    594             } 
    595  
    596         } else { 
    597  
    598             $this->files = $this->files_fallback( $this->root() ); 
    599  
    600         } 
    601  
    602         if ( ! empty( $this->unreadable_files ) ) 
    603             $this->warning( $this->archive_method(), __( 'The following files are unreadable and couldn\'t be backed up: ', 'hmbkp' ) . implode( ', ', $this->unreadable_files ) ); 
    604  
    605         return $this->files; 
    606  
    607     } 
    608  
    609     /** 
    610      * Fallback function for generating a filesystem 
    611      * array 
    612      * 
    613      * Used if RecursiveDirectoryIterator::FOLLOW_SYMLINKS isn't available 
    614      * 
    615      * @access private 
    616      * @param stromg $dir 
    617      * @param array $files. (default: array()) 
    618      * @return array 
    619      */ 
    620     private function files_fallback( $dir, $files = array() ) { 
    621  
    622         $handle = opendir( $dir ); 
    623  
    624         $excludes = $this->exclude_string( 'regex' ); 
    625  
    626         while ( $file = readdir( $handle ) ) : 
    627  
    628             // Ignore current dir and containing dir and any unreadable files or directories 
    629             if ( $file == '.' || $file == '..' ) 
    630                 continue; 
    631  
    632             $filepath = $this->conform_dir( trailingslashit( $dir ) . $file ); 
    633             $file = str_ireplace( trailingslashit( $this->root() ), '', $filepath ); 
    634  
    635             if ( ! is_readable( $filepath ) ) { 
    636                 $this->unreadable_files[] = $filepath; 
    637                 continue; 
    638             } 
    639  
    640             // Skip the backups dir and any excluded paths 
    641             if ( ( $excludes && preg_match( '(' . $excludes . ')', $file ) ) ) 
    642                 continue; 
    643  
    644             $files[] = $file; 
    645  
    646             if ( is_dir( $filepath ) ) 
    647                 $files = $this->files_fallback( $filepath, $files ); 
    648  
    649         endwhile; 
    650  
    651         return $files; 
    652  
    653     } 
    654  
    655     private function load_pclzip() { 
    656  
    657         // Load PclZip 
    658         if ( ! defined( 'PCLZIP_TEMPORARY_DIR' ) ) 
    659             define( 'PCLZIP_TEMPORARY_DIR', trailingslashit( $this->path() ) ); 
    660  
    661         require_once( ABSPATH . 'wp-admin/includes/class-pclzip.php' ); 
    662  
    663     } 
    664  
    665     /** 
    666      * Attempt to work out the path to mysqldump 
    667      * 
    668      * @access public 
    669      * @return bool 
    670      */ 
    671     public function guess_mysqldump_command_path() { 
    672  
    673         if ( ! $this->shell_exec_available() ) 
    674             return ''; 
    675492 
    676493        // List of possible mysqldump locations 
     
    693510        ); 
    694511 
    695         if ( is_null( shell_exec( 'hash mysqldump 2>&1' ) ) ) 
    696             return 'mysqldump'; 
    697  
    698512        // Find the one which works 
    699513        foreach ( $mysqldump_locations as $location ) 
    700             if ( @file_exists( $this->conform_dir( $location ) ) ) 
    701                 return $location; 
    702  
    703         return ''; 
    704  
    705     } 
    706  
    707     /** 
    708      * Attempt to work out the path to the zip command 
    709      * 
    710      * @access public 
    711      * @return bool 
    712      */ 
    713     public function guess_zip_command_path() { 
    714  
    715         // Check shell_exec is available and hasn't been explicitly bypassed 
    716         if ( ! $this->shell_exec_available() ) 
     514            if ( is_executable( $this->conform_dir( $location ) ) ) 
     515                $this->set_mysqldump_command_path( $location ); 
     516 
     517        return $this->mysqldump_command_path; 
     518 
     519    } 
     520 
     521    /** 
     522     * Set the path to the mysqldump bin 
     523     * 
     524     * Setting the path to false will cause the database 
     525     * dump to use the php fallback 
     526     * 
     527     * @access public 
     528     * @param mixed $path 
     529     */ 
     530    public function set_mysqldump_command_path( $path ) { 
     531 
     532        $this->mysqldump_command_path = $path; 
     533 
     534    } 
     535 
     536    /** 
     537     * Get the path to the zip bin 
     538     * 
     539     * If not explicitly set will attempt to work 
     540     * it out by checking common locations 
     541     * 
     542     * @access public 
     543     * @return string 
     544     */ 
     545    public function get_zip_command_path() { 
     546 
     547        // Check shell_exec is available 
     548        if ( ! self::is_shell_exec_available() ) 
    717549            return ''; 
     550 
     551        // Return now if it's already been set 
     552        if ( isset( $this->zip_command_path ) ) 
     553            return $this->zip_command_path; 
     554 
     555        $this->zip_command_path = ''; 
     556 
     557        // Does zip work 
     558        if ( is_null( shell_exec( 'hash zip 2>&1' ) ) ) { 
     559 
     560            // If so store it for later 
     561            $this->set_zip_command_path( 'zip' ); 
     562 
     563            // And return now 
     564            return $this->zip_command_path; 
     565 
     566        } 
    718567 
    719568        // List of possible zip locations 
     
    722571        ); 
    723572 
    724         if ( is_null( shell_exec( 'hash zip 2>&1' ) ) ) 
    725             return 'zip'; 
    726  
    727573        // Find the one which works 
    728574        foreach ( $zip_locations as $location ) 
    729             if ( @file_exists( $this->conform_dir( $location ) ) ) 
    730                 return $location; 
    731  
    732         return ''; 
     575            if ( is_executable( $this->conform_dir( $location ) ) ) 
     576                $this->set_zip_command_path( $location ); 
     577 
     578        return $this->zip_command_path; 
     579 
     580    } 
     581 
     582    /** 
     583     * Set the path to the zip bin 
     584     * 
     585     * Setting the path to false will cause the database 
     586     * dump to use the php fallback 
     587     * 
     588     * @access public 
     589     * @param mixed $path 
     590     */ 
     591    public function set_zip_command_path( $path ) { 
     592 
     593        $this->zip_command_path = $path; 
     594 
     595    } 
     596 
     597    protected function do_action( $action ) { 
     598 
     599        do_action( $action, $this ); 
     600 
     601    } 
     602 
     603    /** 
     604     * Kick off a backup 
     605     * 
     606     * @access public 
     607     * @return bool 
     608     */ 
     609    public function backup() { 
     610 
     611        $this->do_action( 'hmbkp_backup_started' ); 
     612 
     613        // Backup database 
     614        if ( $this->get_type() !== 'file' ) 
     615            $this->dump_database(); 
     616 
     617        // Zip everything up 
     618        $this->archive(); 
     619 
     620        $this->do_action( 'hmbkp_backup_complete' ); 
     621 
     622    } 
     623 
     624    /** 
     625     * Create the mysql backup 
     626     * 
     627     * Uses mysqldump if available, falls back to PHP 
     628     * if not. 
     629     * 
     630     * @access public 
     631     */ 
     632    public function dump_database() { 
     633 
     634        $this->do_action( 'hmbkp_mysqldump_started' ); 
     635 
     636        if ( $this->get_mysqldump_command_path() ) 
     637            $this->mysqldump(); 
     638 
     639        if ( empty( $this->mysqldump_verified ) ) 
     640            $this->mysqldump_fallback(); 
     641 
     642        $this->do_action( 'hmbkp_mysqldump_finished' ); 
     643 
     644    } 
     645 
     646    public function mysqldump() { 
     647 
     648        $this->mysqldump_method = 'mysqldump'; 
     649 
     650        $host = reset( explode( ':', DB_HOST ) ); 
     651        $port = strpos( DB_HOST, ':' ) ? end( explode( ':', DB_HOST ) ) : ''; 
     652 
     653        // Path to the mysqldump executable 
     654        $cmd = escapeshellarg( $this->get_mysqldump_command_path() ); 
     655 
     656        // No Create DB command 
     657        $cmd .= ' --no-create-db'; 
     658 
     659        // Make sure binary data is exported properly 
     660        $cmd .= ' --hex-blob'; 
     661 
     662        // Username 
     663        $cmd .= ' -u ' . escapeshellarg( DB_USER ); 
     664 
     665        // Don't pass the password if it's blank 
     666        if ( DB_PASSWORD ) 
     667            $cmd .= ' -p'  . escapeshellarg( DB_PASSWORD ); 
     668 
     669        // Set the host 
     670        $cmd .= ' -h ' . escapeshellarg( $host ); 
     671 
     672        // Set the port if it was set 
     673        if ( ! empty( $port ) ) 
     674            $cmd .= ' -P ' . $port; 
     675 
     676        // The file we're saving too 
     677        $cmd .= ' -r ' . escapeshellarg( $this->get_database_dump_filepath() ); 
     678 
     679        // The database we're dumping 
     680        $cmd .= ' ' . escapeshellarg( DB_NAME ); 
     681 
     682        // Pipe STDERR to STDOUT 
     683        $cmd .= ' 2>&1'; 
     684 
     685        // Store any returned data in warning 
     686        $this->warning( $this->get_mysqldump_method(), shell_exec( $cmd ) ); 
     687 
     688        $this->verify_mysqldump(); 
     689 
     690    } 
     691 
     692    /** 
     693     * PHP mysqldump fallback functions, exports the database to a .sql file 
     694     * 
     695     * @access public 
     696     */ 
     697    public function mysqldump_fallback() { 
     698 
     699        $this->errors_to_warnings( $this->get_mysqldump_method() ); 
     700 
     701        $this->mysqldump_method = 'mysqldump_fallback'; 
     702 
     703        $this->db = mysql_pconnect( DB_HOST, DB_USER, DB_PASSWORD ); 
     704 
     705        mysql_select_db( DB_NAME, $this->db ); 
     706        mysql_set_charset( DB_CHARSET, $this->db ); 
     707 
     708        // Begin new backup of MySql 
     709        $tables = mysql_query( 'SHOW TABLES' ); 
     710 
     711        $sql_file  = "# WordPress : " . get_bloginfo( 'url' ) . " MySQL database backup\n"; 
     712        $sql_file .= "#\n"; 
     713        $sql_file .= "# Generated: " . date( 'l j. F Y H:i T' ) . "\n"; 
     714        $sql_file .= "# Hostname: " . DB_HOST . "\n"; 
     715        $sql_file .= "# Database: " . $this->sql_backquote( DB_NAME ) . "\n"; 
     716        $sql_file .= "# --------------------------------------------------------\n"; 
     717 
     718        for ( $i = 0; $i < mysql_num_rows( $tables ); $i++ ) { 
     719 
     720            $curr_table = mysql_tablename( $tables, $i ); 
     721 
     722            // Create the SQL statements 
     723            $sql_file .= "# --------------------------------------------------------\n"; 
     724            $sql_file .= "# Table: " . $this->sql_backquote( $curr_table ) . "\n"; 
     725            $sql_file .= "# --------------------------------------------------------\n"; 
     726 
     727            $this->make_sql( $sql_file, $curr_table ); 
     728 
     729        } 
     730 
     731    } 
     732 
     733    /** 
     734     * Zip up all the files. 
     735     * 
     736     * Attempts to use the shell zip command, if 
     737     * thats not available then it falls back to 
     738     * PHP ZipArchive and finally PclZip. 
     739     * 
     740     * @access public 
     741     */ 
     742    public function archive() { 
     743 
     744        $this->do_action( 'hmbkp_archive_started' ); 
     745 
     746        // Do we have the path to the zip command 
     747        if ( $this->get_zip_command_path() ) 
     748            $this->zip(); 
     749 
     750        // If not or if the shell zip failed then use ZipArchive 
     751        if ( empty( $this->archive_verified ) && class_exists( 'ZipArchive' ) && empty( $this->skip_zip_archive ) ) 
     752            $this->zip_archive(); 
     753 
     754        // If ZipArchive is unavailable or one of the above failed 
     755        if ( empty( $this->archive_verified ) ) 
     756            $this->pcl_zip(); 
     757 
     758        // Delete the database dump file 
     759        if ( file_exists( $this->get_database_dump_filepath() ) ) 
     760            unlink( $this->get_database_dump_filepath() ); 
     761 
     762        $this->do_action( 'hmbkp_archive_finished' ); 
     763 
     764    } 
     765 
     766    /** 
     767     * Zip using the native zip command 
     768     * 
     769     * @access public 
     770     */ 
     771    public function zip() { 
     772 
     773        $this->archive_method = 'zip'; 
     774 
     775        // Zip up $this->root with excludes 
     776        if ( $this->get_type() !== 'database' && $this->exclude_string( 'zip' ) ) 
     777            $this->warning( $this->archive_method, shell_exec( 'cd ' . escapeshellarg( $this->get_root() ) . ' && ' . escapeshellarg( $this->get_zip_command_path() ) . ' -rq ' . escapeshellarg( $this->get_archive_filepath() ) . ' ./' . ' -x ' . $this->exclude_string( 'zip' ) . ' 2>&1' ) ); 
     778 
     779        // Zip up $this->root without excludes 
     780        elseif ( $this->get_type() !== 'database' ) 
     781            $this->warning( $this->archive_method, shell_exec( 'cd ' . escapeshellarg( $this->get_root() ) . ' && ' . escapeshellarg( $this->get_zip_command_path() ) . ' -rq ' . escapeshellarg( $this->get_archive_filepath() ) . ' ./' . ' 2>&1' ) ); 
     782 
     783        // Add the database dump to the archive 
     784        if ( $this->get_type() !== 'file' ) 
     785            $this->warning( $this->archive_method, shell_exec( 'cd ' . escapeshellarg( $this->get_path() ) . ' && ' . escapeshellarg( $this->get_zip_command_path() ) . ' -uq ' . escapeshellarg( $this->get_archive_filepath() ) . ' ' . escapeshellarg( $this->get_database_dump_filename() ) . ' 2>&1' ) ); 
     786 
     787        $this->verify_archive(); 
     788 
     789    } 
     790 
     791    /** 
     792     * Fallback for creating zip archives if zip command is 
     793     * unavailable. 
     794     * 
     795     * @access public 
     796     * @param string $path 
     797     */ 
     798    public function zip_archive() { 
     799 
     800        $this->errors_to_warnings( $this->archive_method ); 
     801        $this->archive_method = 'ziparchive'; 
     802 
     803        $zip = new ZipArchive(); 
     804 
     805        if ( ! class_exists( 'ZipArchive' ) || ! $zip->open( $this->get_archive_filepath(), ZIPARCHIVE::CREATE ) ) 
     806            return; 
     807 
     808        if ( $this->get_type() !== 'database' ) { 
     809 
     810            $files_added = 0; 
     811 
     812            foreach ( $this->get_files() as $file ) { 
     813 
     814                if ( $file->isDir() ) 
     815                    $zip->addEmptyDir( trailingslashit( str_ireplace( trailingslashit( $this->get_root() ), '', $this->conform_dir( $file->getPathname() ) ) ) ); 
     816 
     817                elseif ( $file->isFile() ) 
     818                    $zip->addFile( $file->getPathname(), str_ireplace( trailingslashit( $this->get_root() ), '', $this->conform_dir( $file->getPathname() ) ) ); 
     819 
     820                if ( ++$files_added % 500 === 0 ) 
     821                    if ( ! $zip->close() || ! $zip->open( $this->get_archive_filepath(), ZIPARCHIVE::CREATE ) ) 
     822                        return; 
     823 
     824            } 
     825 
     826        } 
     827 
     828        // Add the database 
     829        if ( $this->get_type() !== 'file' ) 
     830            $zip->addFile( $this->get_database_dump_filepath(), $this->get_database_dump_filename() ); 
     831 
     832        if ( $zip->status ) 
     833            $this->warning( $this->archive_method, $zip->status ); 
     834 
     835        if ( $zip->statusSys ) 
     836            $this->warning( $this->archive_method, $zip->statusSys ); 
     837 
     838        $zip->close(); 
     839 
     840        $this->verify_archive(); 
     841 
     842    } 
     843 
     844    /** 
     845     * Fallback for creating zip archives if zip command and ZipArchive are 
     846     * unavailable. 
     847     * 
     848     * Uses the PclZip library that ships with WordPress 
     849     * 
     850     * @access public 
     851     * @param string $path 
     852     */ 
     853    public function pcl_zip() { 
     854 
     855        $this->errors_to_warnings( $this->archive_method ); 
     856        $this->archive_method = 'pclzip'; 
     857 
     858        global $_hmbkp_exclude_string; 
     859 
     860        $_hmbkp_exclude_string = $this->exclude_string( 'regex' ); 
     861 
     862        $this->load_pclzip(); 
     863 
     864        $archive = new PclZip( $this->get_archive_filepath() ); 
     865 
     866        // Zip up everything 
     867        if ( $this->get_type() !== 'database' ) 
     868            if ( ! $archive->add( $this->get_root(), PCLZIP_OPT_REMOVE_PATH, $this->get_root(), PCLZIP_CB_PRE_ADD, 'hmbkp_pclzip_callback' ) ) 
     869                $this->warning( $this->archive_method, $archive->errorInfo( true ) ); 
     870 
     871        // Add the database 
     872        if ( $this->get_type() !== 'file' ) 
     873            if ( ! $archive->add( $this->get_database_dump_filepath(), PCLZIP_OPT_REMOVE_PATH, $this->get_path() ) ) 
     874                $this->warning( $this->archive_method, $archive->errorInfo( true ) ); 
     875 
     876        unset( $GLOBALS['_hmbkp_exclude_string'] ); 
     877 
     878        $this->verify_archive(); 
     879 
     880    } 
     881 
     882    public function verify_mysqldump() { 
     883 
     884        // If we've already passed then no need to check again 
     885        if ( ! empty( $this->mysqldump_verified ) ) 
     886            return true; 
     887 
     888        if ( ! file_exists( $this->get_database_dump_filepath() ) ) 
     889            $this->error( $this->get_mysqldump_method(), __( 'The mysqldump file was not created', 'hmbkp' ) ); 
     890 
     891        if ( $this->get_errors( $this->get_mysqldump_method() ) ) 
     892            return false; 
     893 
     894        return $this->mysqldump_verified = true; 
     895 
     896 
     897    } 
     898 
     899    /** 
     900     * Verify that the archive is valid and contains all the files it should contain. 
     901     * 
     902     * @access public 
     903     * @return bool 
     904     */ 
     905    public function verify_archive() { 
     906 
     907        // If we've already passed then no need to check again 
     908        if ( ! empty( $this->archive_verified ) ) 
     909            return true; 
     910 
     911        if ( ! file_exists( $this->get_archive_filepath() ) ) 
     912            $this->error( $this->get_archive_method(), __( 'The backup file was not created', 'hmbkp' ) ); 
     913 
     914        // Verify using the zip command if possible 
     915        if ( $this->get_zip_command_path() && $this->get_archive_method() === 'zip' ) { 
     916 
     917            $verify = shell_exec( escapeshellarg( $this->get_zip_command_path() ) . ' -T ' . escapeshellarg( $this->get_archive_filepath() ) . ' 2> /dev/null' ); 
     918 
     919            if ( strpos( $verify, 'OK' ) === false ) 
     920                $this->error( $this->get_archive_method(), $verify ); 
     921 
     922        } 
     923 
     924        // If there are errors delete the backup file. 
     925        if ( $this->get_errors( $this->get_archive_method() ) && file_exists( $this->get_archive_filepath() ) ) 
     926            unlink( $this->get_archive_filepath() ); 
     927 
     928        if ( $this->get_errors( $this->get_archive_method() ) ) 
     929            return false; 
     930 
     931        return $this->archive_verified = true; 
     932 
     933    } 
     934 
     935    /** 
     936     * Generate the array of files to be backed up by looping through 
     937     * root, ignore unreadable files and excludes 
     938     * 
     939     * @access public 
     940     * @return array 
     941     */ 
     942    public function get_files() { 
     943 
     944        if ( ! empty( $this->files ) ) 
     945            return $this->files; 
     946 
     947        $this->files = array(); 
     948 
     949        if ( defined( 'RecursiveDirectoryIterator::FOLLOW_SYMLINKS' ) ) { 
     950 
     951            $filesystem = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $this->get_root(), RecursiveDirectoryIterator::FOLLOW_SYMLINKS ), RecursiveIteratorIterator::SELF_FIRST, RecursiveIteratorIterator::CATCH_GET_CHILD ); 
     952 
     953            $excludes = $this->exclude_string( 'regex' ); 
     954 
     955            foreach ( $filesystem as $file ) { 
     956 
     957                /* 
     958                 * Ignore current dir and containing dir 
     959                 * 
     960                 * Required because in PHP 5.2 these aren't skipped automatically by RecursiveDirectoryIterator, they are skipped in PHP > 5.3 
     961                 */ 
     962                if ( $file === '.' || $file === '..' ) 
     963                    continue; 
     964 
     965                // Track & skip unreadable files 
     966                if ( ! $file->isReadable() && $this->unreadable_files[] = $file ) 
     967                    continue; 
     968 
     969                $pathname = str_ireplace( trailingslashit( $this->get_root() ), '', $this->conform_dir( $file->getPathname() ) ); 
     970 
     971                // Excludes 
     972                if ( $excludes && preg_match( '(' . $excludes . ')', $pathname ) && $this->excluded_files[] = $file ) 
     973                    continue; 
     974 
     975                $this->files[] = $file; 
     976 
     977            } 
     978 
     979        } else { 
     980 
     981            $this->files = $this->files_fallback( $this->get_root() ); 
     982 
     983        } 
     984 
     985        if ( ! empty( $this->unreadable_files ) ) 
     986            $this->warning( $this->get_archive_method(), __( 'The following files are unreadable and couldn\'t be backed up: ', 'hmbkp' ) . implode( ', ', $this->unreadable_files ) ); 
     987 
     988        return $this->files; 
     989 
     990    } 
     991 
     992    /** 
     993     * Fallback function for generating a filesystem 
     994     * array 
     995     * 
     996     * Used if RecursiveDirectoryIterator::FOLLOW_SYMLINKS isn't available 
     997     * 
     998     * @access private 
     999     * @param string $dir 
     1000     * @param array $files. (default: array()) 
     1001     * @return array 
     1002     */ 
     1003    private function files_fallback( $dir, $files = array() ) { 
     1004 
     1005        $handle = opendir( $dir ); 
     1006 
     1007        $excludes = $this->exclude_string( 'regex' ); 
     1008 
     1009        while ( $file = readdir( $handle ) ) : 
     1010 
     1011            // Ignore current dir and containing dir and any unreadable files or directories 
     1012            if ( $file === '.' || $file === '..' ) 
     1013                continue; 
     1014 
     1015            $filepath = $this->conform_dir( trailingslashit( $dir ) . $file ); 
     1016            $file = str_ireplace( trailingslashit( $this->get_root() ), '', $filepath ); 
     1017 
     1018            // Track & skip unreadable files 
     1019            if ( ! is_readable( $filepath ) && $this->unreadable_files[] = new SplFileInfo( $filepath ) ) 
     1020                continue; 
     1021 
     1022            // Skip the backups dir and any excluded paths 
     1023            if ( ( $excludes && preg_match( '(' . $excludes . ')', $file ) ) && $this->excluded_files[] = new SplFileInfo( $filepath ) ) 
     1024                continue; 
     1025 
     1026            $files[] = new SplFileInfo( $filepath ); 
     1027 
     1028            if ( is_dir( $filepath ) ) 
     1029                $files = $this->files_fallback( $filepath, $files ); 
     1030 
     1031        endwhile; 
     1032 
     1033        return $files; 
     1034 
     1035    } 
     1036 
     1037    /** 
     1038     * Returns an array of files that match the exclude rules. 
     1039     * 
     1040     * @access public 
     1041     * @return array 
     1042     */ 
     1043    public function get_excluded_files() { 
     1044 
     1045        if ( empty( $this->files ) ) 
     1046            $this->get_files(); 
     1047 
     1048        if ( ! empty( $this->excluded_files ) ) 
     1049            return $this->excluded_files; 
     1050 
     1051        return array(); 
     1052 
     1053    } 
     1054 
     1055    /** 
     1056     * Returns an array of unreadable files. 
     1057     * 
     1058     * @access public 
     1059     * @return array 
     1060     */ 
     1061    public function get_unreadable_files() { 
     1062 
     1063        if ( empty( $this->files ) ) 
     1064            $this->get_files(); 
     1065 
     1066        if ( ! empty( $this->unreadable_files ) ) 
     1067            return $this->unreadable_files; 
     1068 
     1069        return array(); 
     1070 
     1071    } 
     1072 
     1073    private function load_pclzip() { 
     1074 
     1075        // Load PclZip 
     1076        if ( ! defined( 'PCLZIP_TEMPORARY_DIR' ) ) 
     1077            define( 'PCLZIP_TEMPORARY_DIR', trailingslashit( $this->get_path() ) ); 
     1078 
     1079        require_once( ABSPATH . 'wp-admin/includes/class-pclzip.php' ); 
     1080 
     1081    } 
     1082 
     1083    /** 
     1084     * Get an array of exclude rules 
     1085     * 
     1086     * The backup path is automatically excluded 
     1087     * 
     1088     * @access public 
     1089     * @return array 
     1090     */ 
     1091    public function get_excludes() { 
     1092 
     1093        $excludes = array(); 
     1094 
     1095        if ( isset( $this->excludes ) ) 
     1096            $excludes = $this->excludes; 
     1097 
     1098        // If path() is inside root(), exclude it 
     1099        if ( strpos( $this->get_path(), $this->get_root() ) !== false ) 
     1100            $excludes[] = trailingslashit( $this->get_path() ); 
     1101 
     1102        return array_unique( $excludes ); 
     1103 
     1104    } 
     1105 
     1106    /** 
     1107     * Set the excludes, expects and array 
     1108     * 
     1109     * @access public 
     1110     * @param  Array $excludes 
     1111     * @param Bool $append 
     1112     */ 
     1113    public function set_excludes( $excludes, $append = false ) { 
     1114 
     1115        if ( is_string( $excludes ) ) 
     1116            $excludes = explode( ',', $excludes ); 
     1117 
     1118        if ( $append ) 
     1119            $excludes = array_merge( $this->excludes, $excludes ); 
     1120 
     1121        $this->excludes = array_filter( array_unique( array_map( 'trim', $excludes ) ) ); 
    7331122 
    7341123    } 
     
    7441133     * @return string 
    7451134     */ 
    746     public function exclude_string( $context = 'zip' ) { 
     1135    private function exclude_string( $context = 'zip' ) { 
    7471136 
    7481137        // Return a comma separated list by default 
     
    7511140 
    7521141        // The zip command 
    753         if ( $context == 'zip' ) { 
     1142        if ( $context === 'zip' ) { 
    7541143            $wildcard = '*'; 
    7551144            $separator = ' -x '; 
    7561145 
    7571146        // The PclZip fallback library 
    758         } elseif ( $context == 'regex' ) { 
     1147        } elseif ( $context === 'regex' ) { 
    7591148            $wildcard = '([\s\S]*?)'; 
    7601149            $separator = '|'; 
     
    7621151        } 
    7631152 
    764         // Sanitize the excludes 
    765         $excludes = array_filter( array_unique( array_map( 'trim', (array) $this->excludes ) ) ); 
    766  
    767         // If path() is inside root(), exclude it 
    768         if ( strpos( $this->path(), $this->root() ) !== false ) 
    769             $excludes[] = trailingslashit( $this->path() ); 
     1153        $excludes = $this->get_excludes(); 
    7701154 
    7711155        foreach( $excludes as $key => &$rule ) { 
     
    7861170 
    7871171            // Strip $this->root and conform 
    788             $rule = str_ireplace( $this->root(), '', untrailingslashit( $this->conform_dir( $rule ) ) ); 
     1172            $rule = str_ireplace( $this->get_root(), '', untrailingslashit( $this->conform_dir( $rule ) ) ); 
    7891173 
    7901174            // Strip the preceeding slash 
     
    7931177 
    7941178            // Escape string for regex 
    795             if ( $context == 'regex' ) 
     1179            if ( $context === 'regex' ) 
    7961180                $rule = str_replace( '.', '\.', $rule ); 
    7971181 
    7981182            // Convert any existing wildcards 
    799             if ( $wildcard != '*' && strpos( $rule, '*' ) !== false ) 
     1183            if ( $wildcard !== '*' && strpos( $rule, '*' ) !== false ) 
    8001184                $rule = str_replace( '*', $wildcard, $rule ); 
    8011185 
    8021186            // Wrap directory fragments and files in wildcards for zip 
    803             if ( $context == 'zip' && ( $fragment || $file ) ) 
     1187            if ( $context === 'zip' && ( $fragment || $file ) ) 
    8041188                $rule = $wildcard . $rule . $wildcard; 
    8051189 
    8061190            // Add a wildcard to the end of absolute url for zips 
    807             if ( $context == 'zip' && $absolute ) 
     1191            if ( $context === 'zip' && $absolute ) 
    8081192                $rule .= $wildcard; 
    8091193 
    8101194            // Add and end carrot to files for pclzip but only if it doesn't end in a wildcard 
    811             if ( $file && $context == 'regex' ) 
     1195            if ( $file && $context === 'regex' ) 
    8121196                $rule .= '$'; 
    8131197 
    8141198            // Add a start carrot to absolute urls for pclzip 
    815             if ( $absolute && $context == 'regex' ) 
     1199            if ( $absolute && $context === 'regex' ) 
    8161200                $rule = '^' . $rule; 
    8171201 
     
    8191203 
    8201204        // Escape shell args for zip command 
    821         if ( $context == 'zip' ) 
     1205        if ( $context === 'zip' ) 
    8221206            $excludes = array_map( 'escapeshellarg', array_unique( $excludes ) ); 
    8231207 
     
    8271211 
    8281212    /** 
    829      * Check whether safe mode is active or not 
    830      * 
    831      * @access private 
    832      * @return bool 
    833      */ 
    834     public function is_safe_mode_active() { 
    835  
    836         if ( $safe_mode = ini_get( 'safe_mode' ) && strtolower( $safe_mode ) != 'off' ) 
    837             return true; 
    838  
    839         return false; 
    840  
    841     } 
    842  
    843     /** 
    844      * Check whether shell_exec has been disabled. 
    845      * 
    846      * @access private 
    847      * @return bool 
    848      */ 
    849     private function shell_exec_available() { 
    850  
    851         // Are we in Safe Mode 
    852         if ( $this->is_safe_mode_active() ) 
    853             return false; 
    854  
    855         // Is shell_exec disabled? 
    856         if ( in_array( 'shell_exec', array_map( 'trim', explode( ',', ini_get( 'disable_functions' ) ) ) ) ) 
    857             return false; 
    858  
    859         // Can we issue a simple command 
    860         if ( ! @shell_exec( 'pwd' ) ) 
    861             return false; 
    862  
    863         return true; 
    864  
    865     } 
    866  
    867     /** 
    868      * Sanitize a directory path 
    869      * 
    870      * @access public 
    871      * @param string $dir 
    872      * @param bool $rel. (default: false) 
    873      * @return string $dir 
    874      */ 
    875     public function conform_dir( $dir, $recursive = false ) { 
    876  
    877         // Assume empty dir is root 
    878         if ( ! $dir ) 
    879             $dir = '/'; 
    880  
    881         // Replace single forward slash (looks like double slash because we have to escape it) 
    882         $dir = str_replace( '\\', '/', $dir ); 
    883         $dir = str_replace( '//', '/', $dir ); 
    884  
    885         // Remove the trailing slash 
    886         if ( $dir !== '/' ) 
    887             $dir = untrailingslashit( $dir ); 
    888  
    889         // Carry on until completely normalized 
    890         if ( ! $recursive && $this->conform_dir( $dir, true ) != $dir ) 
    891             return $this->conform_dir( $dir ); 
    892  
    893         return (string) $dir; 
    894  
    895     } 
    896  
    897     /** 
    8981213     * Add backquotes to tables and db-names inSQL queries. Taken from phpMyAdmin. 
    8991214     * 
     
    9031218    private function sql_backquote( $a_name ) { 
    9041219 
    905         if ( ! empty( $a_name ) && $a_name != '*' ) { 
     1220        if ( ! empty( $a_name ) && $a_name !== '*' ) { 
    9061221 
    9071222            if ( is_array( $a_name ) ) { 
     
    10021317            $type = mysql_field_type( $result, $j ); 
    10031318 
    1004             if ( $type == 'tinyint' || $type == 'smallint' || $type == 'mediumint' || $type == 'int' || $type == 'bigint'  || $type == 'timestamp') 
     1319            if ( $type === 'tinyint' || $type === 'smallint' || $type === 'mediumint' || $type === 'int' || $type === 'bigint'  || $type === 'timestamp') 
    10051320                $field_num[$j] = true; 
    10061321 
     
    10271342                    $values[]     = 'NULL'; 
    10281343 
    1029                 } elseif ( $row[$j] == '0' || $row[$j] != '' ) { 
     1344                } elseif ( $row[$j] === '0' || $row[$j] !== '' ) { 
    10301345 
    10311346                    // a number 
     
    10461361 
    10471362            // write the rows in batches of 100 
    1048             if ( $batch_write == 100 ) { 
     1363            if ( $batch_write === 100 ) { 
    10491364                $batch_write = 0; 
    10501365                $this->write_sql( $sql_file ); 
     
    11001415    private function write_sql( $sql ) { 
    11011416 
    1102         $sqlname = $this->database_dump_filepath(); 
     1417        $sqlname = $this->get_database_dump_filepath(); 
    11031418 
    11041419        // Actually write the sql file 
     
    11231438     * 
    11241439     * @access public 
    1125      * @return null 
    1126      */ 
    1127     public function errors( $context = null ) { 
     1440     */ 
     1441    public function get_errors( $context = null ) { 
    11281442 
    11291443        if ( ! empty( $context ) ) 
     
    11411455     * @param string $context 
    11421456     * @param mixed $error 
    1143      * @return null 
    11441457     */ 
    11451458    private function error( $context, $error ) { 
     
    11571470     * @access private 
    11581471     * @param string $context. (default: null) 
    1159      * @return null 
    11601472     */ 
    11611473    private function errors_to_warnings( $context = null ) { 
    11621474 
    1163         $errors = empty( $context ) ? $this->errors() : array( $context => $this->errors( $context ) ); 
     1475        $errors = empty( $context ) ? $this->get_errors() : array( $context => $this->get_errors( $context ) ); 
    11641476 
    11651477        if ( empty( $errors ) ) 
     
    11821494     * 
    11831495     * @access public 
    1184      * @return null 
    1185      */ 
    1186     public function warnings( $context = null ) { 
     1496     */ 
     1497    public function get_warnings( $context = null ) { 
    11871498 
    11881499        if ( ! empty( $context ) ) 
     
    12001511     * @param string $context 
    12011512     * @param mixed $warning 
    1202      * @return null 
    12031513     */ 
    12041514    private function warning( $context, $warning ) { 
     
    12201530     * @param string $file 
    12211531     * @param string $line 
    1222      * @return null 
    12231532     */ 
    12241533    public function error_handler( $type ) { 
    12251534 
    1226         if ( ( defined( 'E_DEPRECATED' ) && $type == E_DEPRECATED ) || ( defined( 'E_STRICT' ) && $type == E_STRICT ) || error_reporting() === 0 ) 
     1535        if ( ( defined( 'E_DEPRECATED' ) && $type === E_DEPRECATED ) || ( defined( 'E_STRICT' ) && $type === E_STRICT ) || error_reporting() === 0 ) 
    12271536            return false; 
    12281537 
Note: See TracChangeset for help on using the changeset viewer.