OwlCyberSecurity - MANAGER
Edit File: class-wpvivid-mysqldump2.php
<?php if (!defined('WPVIVID_PLUGIN_DIR')) { die; } use Exception as Exception; class CompressTest_2 { private $fileHandler = null; /** * @param string $filename */ public function open($filename) { $this->fileHandler = fopen($filename, "wb"); if (false === $this->fileHandler) { throw new Exception("Output file is not writable"); } return true; } public function write($str) { if (false === ($bytesWritten = fwrite($this->fileHandler, $str))) { throw new Exception("Writting to file failed! Probably, there is no more free space left?"); } return $bytesWritten; } public function close() { return fclose($this->fileHandler); } public function get_size() { $fstat = fstat($this->fileHandler); return $fstat['size']; } } class WPvivid_Mysqldump2 { // Same as mysqldump const MAXLINESIZE = 1000000; // Available compression methods as constants const GZIP = 'Gzip'; const BZIP2 = 'Bzip2'; const NONE = 'None'; // Available connection strings const UTF8 = 'utf8'; const UTF8MB4 = 'utf8mb4'; /** * Database username * @var string */ public $user; /** * Database password * @var string */ public $pass; /** * Destination filename, defaults to stdout * @var string */ public $fileName = 'php://output'; // Internal stuff private $tables = array(); //private $dbHandler = null; private $dbType; private $compressManager; private $typeAdapter; private $dumpSettings = array(); private $version; private $tableColumnTypes = array(); public $log=false; public $task_id=''; /** * database name, parsed from dsn * @var string */ private $dbName; /** * host name, parsed from dsn * @var string */ private $host; public $last_query_string=''; public $task = false; public $file_index=1; public $tmp_file_name=''; public $current_size=0; public $files=array(); public $backup_tables; public $find_zero_date=false; public function __construct($task,$dump_setting) { if(is_a($task, 'WPvivid_Backup_Task_2')) { $this->task=$task; } else { throw new Exception('not as wpvivid task type'); } $dumpSettingsDefault = array( 'include-tables' => array(), 'exclude-tables' => array(), 'compress' => WPvivid_Mysqldump2::NONE, 'init_commands' => array(), 'no-data' => array(), 'reset-auto-increment' => false, 'add-drop-database' => false, 'add-drop-table' => true, 'add-drop-trigger' => true, 'add-locks' => true, 'complete-insert' => false, 'default-character-set' => WPvivid_Mysqldump2::UTF8, 'disable-keys' => true, 'extended-insert' => false, 'events' => false, 'hex-blob' => true, /* faster than escaped content */ 'net_buffer_length' => self::MAXLINESIZE, 'no-autocommit' => false, 'no-create-info' => false, 'lock-tables' => false, 'routines' => false, 'single-transaction' => true, 'skip-triggers' => false, 'skip-tz-utc' => false, 'skip-comments' => false, 'skip-dump-date' => false, 'where' => '', ); if(defined('DB_CHARSET')) { $dumpSettingsDefault['default-character-set']=DB_CHARSET; } $this->dumpSettings = $this->array_replace_recursive($dumpSettingsDefault, $dump_setting); $this->dumpSettings['init_commands'][] = "SET NAMES " . WPvivid_Mysqldump2::UTF8MB4; if (false === $this->dumpSettings['skip-tz-utc']) { $this->dumpSettings['init_commands'][] = "SET TIME_ZONE='+00:00'"; } // Create a new compressManager to manage compressed output $this->compressManager = new CompressTest_2(); $this->backup_tables=0; } public function connect() { $dbType=$this->dumpSettings['db_connect_method']; $host=$this->dumpSettings['host']; $user=$this->dumpSettings['user']; $pass=$this->dumpSettings['pass']; $database=$this->dumpSettings['database']; $this->typeAdapter = WPvividTypeAdapterFactory::create($dbType, null); $this->typeAdapter->connect($host,$database,$user,$pass,$this->dumpSettings['init_commands']); } public function write_header() { // Write some basic info to output file $upload_dir = wp_upload_dir(); $site_url=$this->dumpSettings['site_url']; $home_url=$this->dumpSettings['home_url']; $content_url=$this->dumpSettings['content_url']; $upload_url=$upload_dir['baseurl']; $this->compressManager->write('/* # site_url: '.$site_url.' */;'.PHP_EOL); $this->compressManager->write('/* # home_url: '.$home_url.' */;'.PHP_EOL); $this->compressManager->write('/* # content_url: '.$content_url.' */;'.PHP_EOL); $this->compressManager->write('/* # upload_url: '.$upload_url.' */;'.PHP_EOL); if(isset($this->dumpSettings['prefix'])) { $table_prefix=$this->dumpSettings['prefix']; $this->compressManager->write('/* # table_prefix: '.$table_prefix.' */;'.PHP_EOL.PHP_EOL.PHP_EOL); } // Store server settings and use sanner defaults to dump $this->compressManager->write( $this->typeAdapter->backup_parameters($this->dumpSettings) ); } public function write_footer() { // Restore saved parameters $this->compressManager->write( $this->typeAdapter->restore_parameters($this->dumpSettings) ); } public function init_job() { $tables=$this->list_tables(); if(empty($tables)) { return false; } usort($tables, function ($a, $b) { if ($a['size'] == $b['size']) return 0; if ($a['size'] > $b['size']) return 1; else return -1; }); $jobs=array(); foreach ($tables as $table) { $jobs[$table['name']]['index']=0; $jobs[$table['name']]['finished']=0; $jobs[$table['name']]['created']=0; $jobs[$table['name']]['name']=$table['name']; $jobs[$table['name']]['size']=$table['size']; $jobs[$table['name']]['rows']=$table['rows']; } $this->task->update_current_sub_job($jobs); return $jobs; } public function start_jobs() { $this->tables= $this->task->get_current_sub_job(); return $this->exportTables(); } public function list_tables() { $tables=array(); $views=array(); global $wpdb; $resultSet=$wpdb->get_results('SHOW TABLE STATUS', ARRAY_A); $resultViews=$wpdb->get_results('SHOW FULL TABLES WHERE table_type = \'VIEW\'', ARRAY_A); if(!is_null($resultViews)) { foreach ($resultViews as $view) { $name = 'Tables_in_'.DB_NAME; $views[] = $view[$name]; } } if (is_null($resultSet)) { return $tables; } if(isset($this->dumpSettings['prefix'])&&!empty($this->dumpSettings['prefix'])) { $exclude = array('/^(?!' . $this->dumpSettings['prefix'] . ')/i'); } else { $exclude=array(); } foreach ($resultSet as $row) { if(isset($row['Comment']) && $row['Comment'] === 'VIEW') { continue; } if ( $this->matches($row['Name'], $this->dumpSettings['include-tables']) ) { $table['name']=$row['Name']; $table['size']= ($row["Data_length"] + $row["Index_length"]); $table['rows']=$row['Rows']; $tables[]=$table; continue; } if(!empty($exclude)) { if ( $this->matches($row['Name'], $exclude) ) { continue; } } if ( $this->matches($row['Name'], $this->dumpSettings['exclude-tables']) ) { continue; } if(!empty($views)) { if ( $this->matches($row['Name'], $views) ) { continue; } } $table['name']=$row['Name']; $table['size']= ($row["Data_length"] + $row["Index_length"]); $table['rows']=$row['Rows']; $tables[]=$table; } return $tables; } /** * Compare if $table name matches with a definition inside $arr * @param $table string * @param $arr array with strings or patterns * @return bool */ private function matches($table, $arr) { $match = false; if(empty($arr)) { return false; } foreach ($arr as $pattern) { if ( '/' != $pattern[0] ) { continue; } if ( 1 == preg_match($pattern, $table) ) { $match = true; } } return in_array($table, $arr) || $match; } public function check_tmp_file() { $max_file_size=$this->dumpSettings['max_file_size']; $max_backup_tables=5000; if($max_file_size==0) return; $this->current_size=$this->compressManager->get_size(); $path=$this->dumpSettings['path']; if( $this->current_size>$max_file_size||$this->backup_tables>=$max_backup_tables) { $this->current_size=0; $this->backup_tables=0; $this->close_tmp_file(); $name_file_name=$this->dumpSettings['file_prefix'].'.part'.sprintf('%03d',($this->file_index)).'.sql'; $this->file_index++; rename($this->tmp_file_name,$path.DIRECTORY_SEPARATOR.$name_file_name); $this->task->update_current_sub_job($this->tables); $this->task->add_mysql_dump_files($name_file_name); $this->open_tmp_file(); } } public function open_tmp_file($b_delete=false) { if($b_delete) @wp_delete_file( $this->tmp_file_name); $this->compressManager->open($this->tmp_file_name); } public function close_tmp_file() { $this->compressManager->close(); } private function exportTables() { global $wpvivid_plugin; //tmp_file_name $path=$this->dumpSettings['path']; $this->tmp_file_name=$path.DIRECTORY_SEPARATOR.$this->dumpSettings['file_prefix'].'_tmp.sql'; $this->open_tmp_file(); $this->write_header(); /* if(file_exists($this->tmp_file_name)) { $this->open_tmp_file(); } else { $this->open_tmp_file(); $this->write_header(); }*/ // Exporting tables one by one $this->file_index=$this->task->get_current_mysql_file_index(); $this->current_size=0; $tables=$this->tables; $i=0; $i_step=0; $this->backup_tables=0; if($this->task->task_id!=='') { $size = $this->task->get_backup_jobs(); if(sizeof($size) > 0) { $i_step = intval(1 / (sizeof($size)) * 100); } } foreach ($tables as $name=>$table) { if($this->task->check_cancel_backup()) { die(); } if($table['finished']==1) { continue; } $index=$table['index']; $table_name=$table['name']; $message='Preparing to dump table '.$table_name; $wpvivid_plugin->wpvivid_log->WriteLog($message,'notice'); $this->task->update_sub_task_progress($message); if($table['created']==0) { $this->getTableStructure($table_name); $this->tables[$name]['created']=1; //$this->task->update_current_sub_job($this->tables); } $this->tableColumnTypes[$table_name] = $this->getTableColumnTypes($table_name); if($this->tableColumnTypes[$table_name]===false) { continue; } $this->listValues($table_name,$index); $this->check_tmp_file(); $this->tables[$name]['finished']=1; $this->backup_tables++; //$this->task->update_current_sub_job($this->tables); $i++; if($this->task->task_id!=='') { $i_progress=intval($i/sizeof($this->tables)*$i_step); $this->task->update_database_progress($i_progress); } } $this->current_size=$this->compressManager->get_size(); if($this->current_size>0) { $this->close_tmp_file(); $name_file_name=$this->dumpSettings['file_prefix'].'.part'.sprintf('%03d',($this->file_index)).'.sql'; $this->file_index++; rename($this->tmp_file_name,$path.DIRECTORY_SEPARATOR.$name_file_name); $this->task->add_mysql_dump_files($name_file_name); } else { $this->close_tmp_file(); } $ret['result']='success'; return $ret; } /** * Table structure extractor * * @param string $tableName Name of table to export * @return null */ private function getTableStructure($tableName) { if (!$this->dumpSettings['no-create-info']) { $ret = ''; if (!$this->dumpSettings['skip-comments']) { $ret = "--" . PHP_EOL . "-- Table structure for table `$tableName`" . PHP_EOL . "--" . PHP_EOL . PHP_EOL; } $stmt = $this->typeAdapter->show_create_table($tableName); foreach ($this->query($stmt) as $r) { $this->compressManager->write($ret); if ($this->dumpSettings['add-drop-table']) { $this->compressManager->write( $this->typeAdapter->drop_table($tableName) ); } $this->compressManager->write( $this->typeAdapter->create_table($r, $this->dumpSettings) ); break; } } return; } /** * Store column types to create data dumps and for Stand-In tables * * @param string $tableName Name of table to export * @return array type column types detailed */ private function getTableColumnTypes($tableName) { $columnTypes = array(); $columns = $this->query( $this->typeAdapter->show_columns($tableName) ); if($columns===false) { $error=$this->typeAdapter->errorInfo(); if(isset($error[2])){ $error = 'Error: '.$error[2]; } else{ $error = ''; } $columns = $this->query( 'DESCRIBE '.$tableName ); if($columns===false) { $error=$this->typeAdapter->errorInfo(); if(isset($error[2])){ $error = 'Error: '.$error[2]; } else{ $error = ''; } return false; } } foreach($columns as $key => $col) { $types = $this->typeAdapter->parseColumnType($col); $columnTypes[$col['Field']] = array( 'is_numeric'=> $types['is_numeric'], 'is_blob' => $types['is_blob'], 'type' => $types['type'], 'type_sql' => $col['Type'], 'is_virtual' => $types['is_virtual'] ); } return $columnTypes; } /** * Escape values with quotes when needed * * @param string $tableName Name of table which contains rows * @param array $row Associative array of column names and values to be quoted * * @return array */ private function escape($tableName, $row) { $ret = array(); $columnTypes = $this->tableColumnTypes[$tableName]; foreach ($row as $colName => $colValue) { if (is_null($colValue)) { $ret[] = "NULL"; } elseif ($this->dumpSettings['hex-blob'] && $columnTypes[$colName]['is_blob']) { if ($columnTypes[$colName]['type'] == 'bit' || !empty($colValue)) { $ret[] = "0x{$colValue}"; } else { $ret[] = "''"; } } elseif ($columnTypes[$colName]['is_numeric']) { $ret[] = $colValue; } else { $ret[] = $this->typeAdapter->quote($colValue); } } return $ret; } private function listValues($tableName,$index) { global $wpvivid_plugin; $this->prepareListValues($tableName); $onlyOnce = true; $lineSize = 0; $colStmt = $this->getColumnStmt($tableName); global $wpdb; $prefix=$wpdb->base_prefix; $dbType=$this->dumpSettings['db_connect_method']; $start=$index; $limit_count=5000; //$sum =$wpdb->get_var("SELECT COUNT(1) FROM `{$tableName}`"); $sum=0; $resultSet = $this->query("SELECT COUNT(1) FROM `{$tableName}`"); foreach ($resultSet as $row) { $sum=$row['COUNT(1)']; } $this->typeAdapter->closeCursor($resultSet); if($dbType=='wpdb') { $b_options=false; if(substr($tableName, strlen($prefix))=='options') { $b_options=true; } $stmt = "SELECT " . implode(",", $colStmt) . " FROM `$tableName`"; if ($this->dumpSettings['where']) { $stmt .= " WHERE {$this->dumpSettings['where']}"; } $i=0; $i_check_cancel=0; $count=0; while($sum > $start) { $limit = " LIMIT {$limit_count} OFFSET {$start}"; $query=$stmt.$limit; $resultSet = $this->query($query); if($resultSet===false) { $error=$this->typeAdapter->errorInfo(); if(isset($error[2])){ $error = 'Error: '.$error[2]; } else{ $error = ''; } $this->endListValues($tableName); return ; } foreach ($resultSet as $row) { $i++; $skip=false; $vals = $this->escape($tableName, $row); foreach($vals as $key => $value) { if($value === '\'0000-00-00 00:00:00\'') { //$vals[$key] = '\'1999-01-01 00:00:00\''; $this->find_zero_date=true; } if($b_options) { if($value=="'wpvivid_task_list'") { $skip=true; } } } if($skip) continue; if ($onlyOnce || !$this->dumpSettings['extended-insert']) { if ($this->dumpSettings['complete-insert']) { $lineSize += $this->compressManager->write( "INSERT INTO `$tableName` (" . implode(", ", $colStmt) . ") VALUES (" . implode(",", $vals) . ")" ); } else { $lineSize += $this->compressManager->write( "INSERT INTO `$tableName` VALUES (" . implode(",", $vals) . ")" ); } $onlyOnce = false; } else { $lineSize += $this->compressManager->write(",(" . implode(",", $vals) . ")"); } if (($lineSize > $this->dumpSettings['net_buffer_length']) || !$this->dumpSettings['extended-insert']) { $onlyOnce = true; $lineSize = $this->compressManager->write(";" . PHP_EOL); } if($i>=200000) { $count+=$i; $i=0; if($this->task->task_id!=='') { $i_check_cancel++; if($i_check_cancel>5) { $i_check_cancel=0; $this->task->check_cancel_backup(); } $message='Dumping table '.$tableName.', rows dumped: '.$count.' rows.'; $this->task->update_sub_task_progress($message); } } } $this->typeAdapter->closeCursor($resultSet); $start += $limit_count; $this->tables[$tableName]['index']=$start; //$this->task->update_current_sub_job($this->tables); $this->check_tmp_file(); } if (!$onlyOnce) { $this->compressManager->write(";" . PHP_EOL); } $this->endListValues($tableName); } else { $b_options=false; if(substr($tableName, strlen($prefix))=='options') { $b_options=true; } $stmt = "SELECT " . implode(",", $colStmt) . " FROM `$tableName`"; if ($this->dumpSettings['where']) { $stmt .= " WHERE {$this->dumpSettings['where']}"; } $i=0; $i_check_cancel=0; $count=0; while($sum > $start) { $limit = " LIMIT {$limit_count} OFFSET {$start}"; $query=$stmt.$limit; $resultSet = $this->query($query); if($resultSet===false) { $error=$this->typeAdapter->errorInfo(); if(isset($error[2])){ $error = 'Error: '.$error[2]; } else{ $error = ''; } $this->endListValues($tableName); return ; } foreach ($resultSet as $row) { $skip=false; $vals = $this->escape($tableName, $row); foreach($vals as $key => $value) { if($value === '\'0000-00-00 00:00:00\'') { //$vals[$key] = '\'1999-01-01 00:00:00\''; $this->find_zero_date=true; } if($b_options) { if($value=="'wpvivid_task_list'") { $skip=true; } } } if($skip) continue; if ($onlyOnce || !$this->dumpSettings['extended-insert']) { if ($this->dumpSettings['complete-insert']) { var_dump('test1'); $lineSize += $this->compressManager->write( "INSERT INTO `$tableName` (" . implode(", ", $colStmt) . ") VALUES (" . implode(",", $vals) . ")" ); } else { $lineSize += $this->compressManager->write( "INSERT INTO `$tableName` VALUES (" . implode(",", $vals) . ")" ); } $onlyOnce = false; } else { $lineSize += $this->compressManager->write(",(" . implode(",", $vals) . ")"); } if (($lineSize > $this->dumpSettings['net_buffer_length']) || !$this->dumpSettings['extended-insert']) { $onlyOnce = true; $lineSize = $this->compressManager->write(";" . PHP_EOL); } if($i>=200000) { $count+=$i; $i=0; if($this->task->task_id!=='') { $i_check_cancel++; if($i_check_cancel>5) { $i_check_cancel=0; $this->task->check_cancel_backup(); } $message='Dumping table '.$tableName.', rows dumped: '.$count.' rows.'; $this->task->update_sub_task_progress($message); } } } $this->typeAdapter->closeCursor($resultSet); $start += $limit_count; $this->tables[$tableName]['index']=$start; //$this->task->update_current_sub_job($this->tables); $this->check_tmp_file(); } if (!$onlyOnce) { $this->compressManager->write(";" . PHP_EOL); } $this->endListValues($tableName); } //$this->current_size+=$table['size']; } /** * Table rows extractor, append information prior to dump * * @param string $tableName Name of table to export * * @return null */ function prepareListValues($tableName) { if (!$this->dumpSettings['skip-comments']) { $this->compressManager->write( "--" . PHP_EOL . "-- Dumping data for table `$tableName`" . PHP_EOL . "--" . PHP_EOL . PHP_EOL ); } if ($this->dumpSettings['single-transaction']) { $this->exec($this->typeAdapter->setup_transaction()); $this->exec($this->typeAdapter->start_transaction()); } if ($this->dumpSettings['lock-tables']) { $this->typeAdapter->lock_table($tableName); //if($this -> privileges['LOCK TABLES'] == 0) //{ //global $wpvivid_plugin; // $wpvivid_plugin->wpvivid_log->WriteLog('The lack of LOCK TABLES privilege, the backup will skip lock_tables() to continue.','notice'); //}else{ // $this->typeAdapter->lock_table($tableName); //} } if ($this->dumpSettings['add-locks']) { $this->compressManager->write( $this->typeAdapter->start_add_lock_table($tableName) ); } if ($this->dumpSettings['disable-keys']) { $this->compressManager->write( $this->typeAdapter->start_add_disable_keys($tableName) ); } // Disable autocommit for faster reload if ($this->dumpSettings['no-autocommit']) { $this->compressManager->write( $this->typeAdapter->start_disable_autocommit() ); } return; } /** * Table rows extractor, close locks and commits after dump * * @param string $tableName Name of table to export * * @return null */ function endListValues($tableName) { if ($this->dumpSettings['disable-keys']) { $this->compressManager->write( $this->typeAdapter->end_add_disable_keys($tableName) ); } if ($this->dumpSettings['add-locks']) { $this->compressManager->write( $this->typeAdapter->end_add_lock_table($tableName) ); } if ($this->dumpSettings['single-transaction']) { $this->exec($this->typeAdapter->commit_transaction()); } if ($this->dumpSettings['lock-tables']) { $this->typeAdapter->unlock_table($tableName); } // Commit to enable autocommit if ($this->dumpSettings['no-autocommit']) { $this->compressManager->write( $this->typeAdapter->end_disable_autocommit() ); } $this->compressManager->write(PHP_EOL); return; } /** * Build SQL List of all columns on current table * * @param string $tableName Name of table to get columns * * @return string SQL sentence with columns */ function getColumnStmt($tableName) { $colStmt = array(); foreach($this->tableColumnTypes[$tableName] as $colName => $colType) { if ($colType['type'] == 'bit' && $this->dumpSettings['hex-blob']) { $colStmt[] = "LPAD(HEX(`{$colName}`),2,'0') AS `{$colName}`"; } else if ($colType['is_blob'] && $this->dumpSettings['hex-blob']) { $colStmt[] = "HEX(`{$colName}`) AS `{$colName}`"; } else if ($colType['is_virtual']) { $this->dumpSettings['complete-insert'] = true; continue; } else { $colStmt[] = "`{$colName}`"; } } return $colStmt; } /** * Custom array_replace_recursive to be used if PHP < 5.3 * Replaces elements from passed arrays into the first array recursively * * @param array $array1 The array in which elements are replaced * @param array $array2 The array from which elements will be extracted * * @return array Returns an array, or NULL if an error occurs. */ public function array_replace_recursive($array1, $array2) { if (function_exists('array_replace_recursive')) { return array_replace_recursive($array1, $array2); } foreach ($array2 as $key => $value) { if (is_array($value)) { $array1[$key] = $this->array_replace_recursive($array1[$key], $value); } else { $array1[$key] = $value; } } return $array1; } public function query($query_string) { $this->last_query_string=$query_string; return $this->typeAdapter->query($query_string); } private function exec($query_string) { $this->last_query_string=$query_string; return $this->typeAdapter->query($query_string); } public function is_has_zero_date() { if($this->find_zero_date) { return true; } else { return false; } } }