* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ class DB{ public static $dbHostname = "localhost"; public static $dbUsername = "root"; public static $dbPassword = ""; public static $dbDatabase = ""; public static $excludedTables = array(); public static $debug = 0; public static $recordsPerSession = 10000; public static $dbCompatibility = ""; public static $dbDropSyntax = 0; public static $countRecords = 0; private static $link; private static $db_selected; public static $TEMP_DBPROCESS_FILE = "tmp/.database"; public static $TEMP_DUMP_FILE = "tmp/database-sql.sql"; /* *Return any error * * name: error * @param string $message * @return */ public function error($message, $force = ""){ $return = ""; $date = date("M j, Y @ H:i:s"); if((self::$debug) && ($force)){ //we have debug message as force is 1 printf("Debug(%s) - %s \n", $date, $message); } if(!$force){ //we have an error message printf("Error(%s) - %s \n", $date, $message); } return; } /* * Initialize the database connection * * name: init * @param array $data {'dbHostname', 'dbUsername', 'dbPassword', 'dbDatabase'} * @return */ public function init($data, $start = 0){ self::$dbHostname = $data['dbHostname']; self::$dbUsername = $data['dbUsername']; self::$dbPassword = $data['dbPassword']; self::$dbDatabase = $data['dbDatabase']; self::$excludedTables = $data['excludedTables']; self::$TEMP_DBPROCESS_FILE = $data['TEMP_DBPROCESS_FILE']; self::$TEMP_DUMP_FILE = $data['TEMP_DUMP_FILE']; self::$recordsPerSession = $data['recordsPerSession']; self::$dbCompatibility = $data['dbCompatibility']; self::$dbDropSyntax = $data['dbDropSyntax']; self::connect(); self::headers(); if($start){ @unlink(self::$TEMP_DBPROCESS_FILE); } } /* * Connect to the database * * name: connect * @param * @return */ public function connect(){ self::$link = mysql_connect(self::$dbHostname, self::$dbUsername, self::$dbPassword); if (!self::$link) { self::error('Could not connect: ' . mysql_error()); } if(self::$dbDatabase != ""){ self::$db_selected = mysql_select_db(self::$dbDatabase, self::$link); if (!self::$db_selected) { self::error ('Can\'t use foo : ' . mysql_error()); } } } /* * Disconnect from the database * * name: disconnect * @param * @return */ public function disconnect(){ mysql_close(self::$link); } /* * Send some special headers after the connection is initialized * * name: headers * @param * @return */ private function headers(){ self::query("SET SQL_QUOTE_SHOW_CREATE=1;"); self::query("SET sql_mode = 0;"); mysql_set_charset('utf8', self::$link); if (self::$dbCompatibility) self::query("SET sql_mode=" . self::$dbCompatibility . ";"); } /* * Run a mysql qeury * * name: query * @param string $query Query to run * @return $result or false */ public function query($query){ $result = mysql_query($query.";", self::$link); self::error($query, 1); if (!$result) { self::error('Invalid query: ' . mysql_error()); return false; } else{ return $result; } } /* * Returns an array of tables from a database and mark $2excluded ones * * name: lisTables * @param array $excluded array of tables to mark as excluded * @return array $tablesList */ public function listTables($excluded){ $tablesList = array(""); $inc = 0; $result = self::query("SHOW TABLES in `".self::$dbDatabase."`"); while ($row = mysql_fetch_array($result)){ $tablesList[$inc]['table'] = $row[0]; if(is_array($excluded)) if( in_array($row[0], $excluded) ) $tablesList[$inc]['excluded'] = 1; $inc++; } return $tablesList; } public function writeTempFile(){ $tables = self::listTables(self::$excludedTables); $fp = fopen(self::$TEMP_DBPROCESS_FILE, "a"); if($fp){ fwrite($fp, sprintf("###newdump###\t%s\t%s\n", self::$dbDatabase, self::$TEMP_DUMP_FILE)); // write this to the class and write to $TEMP_DBPROCESS_FILE file as database.table records foreach($tables as $key=>$table) if($table!= ""){ $tables[$key]['records'] = 0; if(!$tables[$key]['excluded']) $tables[$key]['records'] = self::countRecords($tables[$key]['table']); $tmp = sprintf("`%s`.`%s`\t%s\t%s\n", self::$dbDatabase, $tables[$key]['table'], $tables[$key]['records'], $tables[$key]['excluded']); fwrite($fp, $tmp); } fwrite($fp, "###enddump###\n"); fclose($fp); } else{ self::error("Unable to open for writing file ".self::$TEMP_DBPROCESS_FILE); } } /* * Returns the number of records from a table * * name: countRecords * @param string $table - the source table * @return int $count */ public function countRecords($table){ $table = "`".self::$dbDatabase."`.`$table`"; $result = self::query("SELECT count(*) FROM $table;"); $count = mysql_fetch_row($result); return intval($count[0]) ;// not max limit on 32 bit systems 2147483647; on 64 bit 9223372036854775807 } /* * Processing the mysql backup incrementally * * name: processIncremental * @param * int $startAtLine - at which line from the perm.txt file to start reading * int startAtRecord - at which record to start from the table found at $startAtLine * string $dumpfie - where to save the data * string $dbCompatibility - MYSQL40, MYSQ32, none=default * int $dbDropSyntax - check if the DROP TABLE syntax should be added * @return array $return */ public function processIncremental($startAtLine= 0, $startAtRecord = 0, $dumpfile = "", $dbCompatibility= "", $dbDropSyntax= ""){ $count = 0; $return = array(); self::error("Starting new process at line $startAtLine from record $startAtRecord", 1); $fp = fopen(self::$TEMP_DBPROCESS_FILE, "r"); if($fp){ while (($buffer = fgets($fp, 4096)) !== false){ if($count == $startAtLine){ $buffer = str_replace("\n", "", $buffer); $tableInfo =explode("\t", $buffer); //print_r($tableInfo); if($tableInfo[0] == "###newdump###"){ // we create a new mysql dump file if($dumpfile != ""){ // we finished a previous one and write the footers $return['dumpsize'] = self::dataFooters($dumpfile); } $dump = fopen($tableInfo[2], "w"); fwrite($dump, self::dataHeaders($tableInfo[1])); $startAtLine++; fclose($dump); $dumpfile = $tableInfo[2]; $return['newDump'] = 1; //break; } else{ //we export the table if($tableInfo[0] == "###enddump###") $return['endDump'] = 1; $fd = fopen($dumpfile, "a"); if($fd){ $next = $startAtRecord + self::$recordsPerSession; // $tableInfo[1] number of records in the table $table = explode("`.`", $tableInfo[0]); $tableName = str_replace("`", "", $table[1]); $databaseName = str_replace("`", "", $table[0]); //return something to the browser $return['tableName'] = $tableName; $return['databaseName'] = $databaseName; $return['totalRecords'] = $tableInfo[1]; //if(intval($return['totalRecords']) != 0) if(trim($tableName) != "") self::exportTable($databaseName, $tableName, $startAtRecord, self::$recordsPerSession, $fd); fclose($fd); if($next > $tableInfo[1]) //we finished loading the records for next sessions, will go to the new record { $startAtLine ++; $startAtRecord = 0; }else{ $startAtRecord = $startAtRecord + self::$recordsPerSession; } //$return['dbCompatibility'] = self::$dbCompatibility; //$return['dbDropSyntax'] = self::$dbDropSyntax; $return['startAtLine'] = $startAtLine; $return['startAtRecord'] = $startAtRecord; $return['dumpfile'] = $dumpfile; return $return; break; }else{ self::error("Unable to open for writing file $dumpfile"); } } } $count++; } //while is finished, lets go home... if($dumpfile != ""){ // we finished a previous one and write the footers $return['dumpsize'] = self::dataFooters($dumpfile); } $return['finished'] = 1; $return['startAtLine'] = $startAtLine; return $return; }else{ self::error("Unable to open for reading file ".self::$TEMP_DBPROCESS_FILE); } } /* * Exporting the table records * * name: exportTable * @param * string $databaseName - database name of the table * string tableName - table name * int $start - where to start from * int $limit - how many records * handler $fd - file handler where to write the records * @return */ public function exportTable($databaseName, $tableName, $start, $limit, $fd){ if($start == 0) self::dumpStructure($databaseName, $tableName, $fd); $start = intval($start); $limit = intval($limit); //exporting the table content now $result = self::query("SELECT * from `$databaseName`.`$tableName` Limit $start, $limit ;"); if($result){ while($row = mysql_fetch_array($result, MYSQL_ASSOC)){ fwrite($fd, "INSERT INTO `$tableName` VALUES ("); $arr = $row; $buffer = ""; self::$countRecords++; foreach ($arr as $key => $value) { $value = mysql_escape_string($value); $buffer .= "'".$value."', "; } $buffer = rtrim($buffer, ', ') . ");\n"; fwrite($fd, $buffer); unset($buffer); } } } public function dumpStructure($databaseName, $tableName ,$fd){ fwrite($fd, "\n#\n# Table structure for table `$tableName`\n#\n\n"); if (self::$dbDropSyntax) fwrite($fd, "\nDROP table IF EXISTS `$tableName`;\n"); $result = self::query("SHOW CREATE table `$databaseName`.`$tableName`;"); if($result){ $row = mysql_fetch_row($result); fwrite($fd, $row[1].";\n"); } fwrite($fd, "\n#\n# End Structure for table `$tableName`\n#\n\n"); fwrite($fd, "#\n# Dumping data for table `$tableName`\n#\n\n"); return; } public function dataFooters($dumpfile){ // we finished the dump file, not return the size of it $ftemp = fopen($dumpfile, "a"); if($ftemp){ fwrite($ftemp, "\n#\n# Finished at: ".date("M j, Y \a\\t H:i")."\n#"); fclose($ftemp); }else{ self::error("Unable to open file $ftemp for writing"); } return sprintf("%u", filesize($dumpfile)); } public function resetcountRecords(){ self::$countRecords = 0; return self::$countRecords; } public function getcountRecords(){ return self::$countRecords; } public function dataHeaders($database){ $return = ""; $return .= "#\n"; $return .= "# Powered by XCloner Site Backup\n"; $return .= "# http://www.xcloner.com\n"; $return .= "#\n"; $return .= "# Host: " . $_SERVER['HTTP_HOST'] . "\n"; $return .= "# Generation Time: " . date("M j, Y \a\\t H:i") . "\n"; $return .= "# PHP Version: " . phpversion() . "\n"; $return .= "# Mysql Compatibility: ". self::$dbCompatibility . "\n"; $result = self::query("SHOW VARIABLES LIKE \"%version%\";"); if($result){ while($row = mysql_fetch_array($result)){ $return .= "# MYSQL ".$row[0].": ".$row[1]."\n"; } } $return .= "#\n# Database : `" . $database . "`\n# --------------------------------------------------------\n\n"; return $return; } } ?>