Database Utility - Backups Not Working with MySQLi -Codeigniter
This hapend to me, then i open file "system\database\drivers\mysqli\mysqli_utility.php" and change function "_backup" to this:
/** * MySQLi Export * * @access private * @param array Preferences * @return mixed */function _backup($params = array()){ // Currently unsupported //---return $this->db->display_error('db_unsuported_feature'); if (count($params) == 0) { return FALSE; } // Extract the prefs for simplicity extract($params); // Build the output $output = ''; foreach ((array)$tables as $table) { // Is the table in the "ignore" list? if (in_array($table, (array)$ignore, TRUE)) { continue; } // Get the table schema $query = $this->db->query("SHOW CREATE TABLE `".$this->db->database.'`.`'.$table.'`'); // No result means the table name was invalid if ($query === FALSE) { continue; } // Write out the table schema $output .= '#'.$newline.'# TABLE STRUCTURE FOR: '.$table.$newline.'#'.$newline.$newline; if ($add_drop == TRUE) { $output .= 'DROP TABLE IF EXISTS '.$table.';'.$newline.$newline; } $i = 0; $result = $query->result_array(); foreach ($result[0] as $val) { if ($i++ % 2) { $output .= $val.';'.$newline.$newline; } } // If inserts are not needed we're done... if ($add_insert == FALSE) { continue; } // Grab all the data from the current table $query = $this->db->query("SELECT * FROM $table"); if ($query->num_rows() == 0) { continue; } // Fetch the field names and determine if the field is an // integer type. We use this info to decide whether to // surround the data with quotes or not $i = 0; $field_str = ''; $is_int = array(); while ($field = mysqli_fetch_field($query->result_id)) { // Most versions of MySQL store timestamp as a string $is_int[$i] = (in_array( //strtolower(mysqli_field_type($query->result_id, $i)), strtolower($field->type), array('tinyint', 'smallint', 'mediumint', 'int', 'bigint'), //, 'timestamp'), TRUE) ) ? TRUE : FALSE; // Create a string of field names $field_str .= '`'.$field->name.'`, '; $i++; } // Trim off the end comma $field_str = preg_replace( "/, $/" , "" , $field_str); // Build the insert string foreach ($query->result_array() as $row) { $val_str = ''; $i = 0; foreach ($row as $v) { // Is the value NULL? if ($v === NULL) { $val_str .= 'NULL'; } else { // Escape the data if it's not an integer if ($is_int[$i] == FALSE) { $val_str .= $this->db->escape($v); } else { $val_str .= $v; } } // Append a comma $val_str .= ', '; $i++; } // Remove the comma at the end of the string $val_str = preg_replace( "/, $/" , "" , $val_str); // Build the INSERT string $output .= 'INSERT INTO '.$table.' ('.$field_str.') VALUES ('.$val_str.');'.$newline; } $output .= $newline.$newline; } return $output;}
If you need what change....
change all "mysql_..." to "mysqli..."
and the line
strtolower(mysqli_field_type($query->result_id, $i)),
To this
strtolower($field->type),
And viola! thats WORKS great...
Here is an extension to the function to backup all databases of any size.
This code will remove the PHP memory limits on exporting databases by utilising the file system (cache folder) and SQL LIMITS.
I hope this is useful to someone.
Replacement for function _backup($params = array())
FILE: system/drivers/mysqli/mysqli_utility.php
/** * MySQLi Export * * @access private * @param array Preferences * @return mixed */function _backup_old($params = array()){ // Currently unsupported return $this->db->display_error('db_unsuported_feature');}/*** MySQLi Export** @access private* @param array Preferences* @return mixed*/function _backup($params = array()){ // Currently unsupported //---return $this->db->display_error('db_unsuported_feature'); if (count($params) == 0) { return FALSE; } // Extract the prefs for simplicity extract($params); // Build the output $output = ''; foreach ((array)$tables as $table) { // Temp file to reduce change of OOM Killer $tempfilepath = APPPATH . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR; $tempfile = $tempfilepath . 'dbbkp_tmp_' . time() . '.sql'; // Is the table in the "ignore" list? if (in_array($table, (array)$ignore, TRUE)) { continue; } // Get the table schema $query = $this->db->query("SHOW CREATE TABLE `".$this->db->database.'`.`'.$table.'`'); // No result means the table name was invalid if ($query === FALSE) { continue; } // Write out the table schema $output .= '#'.$newline.'# TABLE STRUCTURE FOR: '.$table.$newline.'#'.$newline.$newline; if ($add_drop == TRUE) { $output .= 'DROP TABLE IF EXISTS '.$table.';'.$newline.$newline; } $i = 0; $result = $query->result_array(); foreach ($result[0] as $val) { if ($i++ % 2) { $output .= $val.';'.$newline.$newline; } } // Write $output to the $filename file file_put_contents( $filename, $output, LOCK_EX ); $output = ''; // If inserts are not needed we're done... if ($add_insert == FALSE) { continue; } // Grab all the data from the current table //$query = $this->db->query("SELECT * FROM $table"); // OLD $countResult = $this->db->query("SELECT COUNT(*) AS `count` FROM " . $table . ";"); $countReturn = $countResult->result_array(); $totalCount = $countReturn[0]['count']; //if ($query->num_rows() == 0) // OLD if ($totalCount == 0) { continue; } // Chunk Vars $chunkSize = 10000; $from = 0; $resultArray = array(); if (isset($chunk_size)) { $chunkSize = $chunk_size; } // Write out the table schema $output .= '#'.$newline.'# TABLE DATA FOR: '.$table.$newline.'#'.$newline.$newline; // Write $output to the $filename file file_put_contents( $filename, $output, FILE_APPEND | LOCK_EX ); // Fetch the field names and determine if the field is an // integer type. We use this info to decide whether to // surround the data with quotes or not $query = $this->db->query("SELECT * FROM " . $table . " LIMIT 1;"); $i = 0; $field_str = ''; $is_int = array(); while ($field = mysqli_fetch_field($query->result_id)) { // Most versions of MySQL store timestamp as a string $is_int[$i] = (in_array( //strtolower(mysqli_field_type($query->result_id, $i)), strtolower($field->type), array('tinyint', 'smallint', 'mediumint', 'int', 'bigint'), //, 'timestamp'), TRUE) ) ? TRUE : FALSE; // Create a string of field names $field_str .= '`'.$field->name.'`, '; $i++; } // Trim off the end comma $field_str = preg_replace( "/, $/" , "" , $field_str); // Pull the data in chunks while($from < $totalCount) { // empty $output $output = ''; // Execute a limited query: $dataChunkQuery = $this->db->query('SELECT * FROM ' . $table . ' LIMIT ' . $from . ', ' . $chunkSize . ';'); $dataChunkRows = $dataChunkQuery->result_array(); // Increase $from: $from += $chunkSize; // Build the insert string //foreach ($query->result_array() as $row) // OLD //var_dump($resultArray); die(); foreach ($dataChunkRows as $row) { $val_str = ''; $i = 0; foreach ($row as $v) { // Is the value NULL? if ($v === NULL) { $val_str .= 'NULL'; } else { // Escape the data if it's not an integer if ($is_int[$i] == FALSE) { $val_str .= $this->db->escape($v); } else { $val_str .= $v; } } // Append a comma $val_str .= ', '; $i++; } // Remove the comma at the end of the string $val_str = preg_replace( "/, $/" , "" , $val_str); // Build the INSERT string $output .= 'INSERT INTO '.$table.' ('.$field_str.') VALUES ('.$val_str.');'.$newline; } // Write $output to the $filename file file_put_contents( $filename, $output, FILE_APPEND | LOCK_EX ); sleep(1); // used to help reduce the CPU load } } if( file_exists($filename) ) { return true; } else { return false; }}
CI Model built for DB Backups
FILE: models/databasebackup_model.php
<?php/*** Database Backup* - Used to make backups of the database system* @author Adan Rehtla <adan.rehtla@aamcommercial.com.au>*/class Databasebackup_model extends API_Model { private $CI; private $lpFilePath = APPPATH . 'cache/backup/'; // Tables to ignore when doing a backup private $laIgnoreTables = array( 'ci_sessions', 'any_other_tables_to_ignore' ); /** * Constructor * @author Adan Rehtla <adan.rehtla@aamcommercial.com.au> */ function __construct() { parent::__construct(); $this->CI = &get_instance(); } /** * Check and empty the cache location for storing the backups during transit * @author Adan Rehtla <adan.rehtla@aamcommercial.com.au> * @return json Result */ public function check_cache() { $arrRet = false; if( ! file_exists( $this->lpFilePath ) ) { $arrRet = mkdir( $this->lpFilePath ); $arrRet = true; } $files = glob( $this->lpFilePath . '*' ); // get all file names present in folder foreach( $files as $file ){ // iterate files if( is_file( $file ) ) unlink( $file ); // delete the file } return (object) $arrRet; } /** * Build a list of tables to backup * @author Adan Rehtla <adan.rehtla@aamcommercial.com.au> * @return json Result */ public function find_tables() { $arrRet = false; if( $this->database('db_read') ) { $this->db_read->_protect_identifiers = FALSE; $this->db_read->start_cache(); $this->db_read->distinct(); $this->db_read->select("table_name"); $this->db_read->from("information_schema.columns"); $this->db_read->where("table_schema", $this->db->dbprefix . $this->db->database); $this->db_read->stop_cache(); // Get List of all tables to backup $laTableNameResult = $this->db_read->get()->result(); $this->db_read->flush_cache(); if( !empty($laTableNameResult) ) { foreach($laTableNameResult as $loTableName) { if( ! in_array( $loTableName->table_name, $this->laIgnoreTables ) ) { $arrRet[] = $loTableName->table_name; } } } $this->db_read->_protect_identifiers = TRUE; } return (object) $arrRet; } /** * Backup the database to Amazon S3 * @author Adan Rehtla <adan.rehtla@aamcommercial.com.au> * @param interger $lpUserId Logged in User ID * @return json Result */ public function backup() { ini_set('max_execution_time', 3600); // 3600 seconds = 60 minutes ini_set('memory_limit', '-1'); // unlimited memory //error_reporting(E_ALL); // show errors //ini_set('display_errors', 1); // display errors $arrRet = array(); $lpBackupCount = 0; $zipNumFiles = 0; $zipStatus = 0; if( $this->database('db_read') ) { $this->db->save_queries = false; $this->load->dbutil( $this->db_read, TRUE ); $laBackupTables = $this->find_tables(); if( !empty($laBackupTables) && $this->check_cache() ) { foreach($laBackupTables as $lpTableName) { $lpFilename = $this->lpFilePath . 'backup-' . $lpTableName . '-' . date('Ymd-His') . '.sql'; $prefs = array( 'tables' => $lpTableName, 'format' => 'sql', 'filename' => $lpFilename, 'add_drop' => TRUE, 'add_insert' => TRUE, 'newline' => "\n", 'foreign_key_checks' => TRUE, 'chunk_size' => 1000 ); if( !file_exists( $lpFilename ) ){ if( $this->dbutil->backup( $prefs ) ) { $lpBackupCount++; } } sleep(1); // used to help reduce the CPU load //break; // used to debug and testing to only process the first database table } try { // ZIP up all the individual GZIPs $zip = new ZipArchive(); $zip_file = $this->lpFilePath . '-' . date('Ymd-His') . '.zip'; $zip_files = glob( $this->lpFilePath . 'backup-*' ); // get all file names present in folder starting with 'backup-' if( $zip->open( $zip_file, ZIPARCHIVE::CREATE ) !== TRUE ) { exit("cannot open <$zip_file>\n"); } if( !empty($zip_files) ) { foreach( $zip_files as $file_to_zip ) { // iterate files $zip->addFile( $file_to_zip, basename( $file_to_zip ) ); } } $zipNumFiles = $zip->numFiles; $zipStatus = $zip->status; $zip->close(); } catch (Vi_exception $e) { print( strip_tags( $e->errorMessage() ) ); } // Upload the file to Amazon S3 // REMOVED AWS S3 UPLOAD CODE // REMOVED AWS S3 UPLOAD CODE // REMOVED AWS S3 UPLOAD CODE // Clean up cache files $this->check_cache(); } $this->db->save_queries = true; } if( !empty($lpBackupCount) && !empty($zip) && !empty($zip_file) ) { return (object) array( 'success'=>true, 'totalTables'=>$lpBackupCount, 'zipNumFiles'=>$zipNumFiles, 'zipStatus'=>$zipStatus, 'zipFile'=>$zip_file ); } else { return (object) array( 'success'=>false ); } }}
USAGE:
$this->load->model('databasebackup_model');$laResult = $this->databasebackup_model->backup();
Your mysqli driver does n't support this feature.
Refer this: http://ellislab.com/forums/viewthread/194645/#979255