Database Utility - Backups Not Working with MySQLi -Codeigniter Database Utility - Backups Not Working with MySQLi -Codeigniter codeigniter codeigniter

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();