<?php /** * Define database parameters here */ $upload_dir = wp_upload_dir(); $backup_dirname = $upload_dir['basedir'].'/wp-file-manager-pro/fm_backup'; define("BACKUP_DIR", $backup_dirname); // Comment this line to use same script's directory ('.') define("TABLES", '*'); // Full backup define("CHARSET", 'utf8'); define("GZIP_BACKUP_FILE", true); // Set to false if you want plain SQL backup files (not gzipped) define("DISABLE_FOREIGN_KEY_CHECKS", true); // Set to true if you are having foreign key constraint fails define("BATCH_SIZE", 1000); // Batch size when selecting rows from database in order to not exhaust system memory // Also number of rows per INSERT statement in backup file /** * The Backup_Database class */ class Backup_Database { /** * Host where the database is located */ var $host; /** * Username used to connect to database */ var $username; /** * Password used to connect to database */ var $passwd; /** * Database to backup */ var $dbName; /** * Database charset */ var $charset; /** * Database connection */ var $conn; /** * Backup directory where backup files are stored */ var $backupDir; /** * Output backup file */ var $backupFile; /** * Use gzip compression on backup file */ var $gzipBackupFile; /** * Content of standard output */ var $output; /** * Disable foreign key checks */ var $disableForeignKeyChecks; /** * Batch size, number of rows to process per iteration */ var $batchSize; /** * Constructor initializes database */ public function __construct($filename) { $this->host = DB_HOST; $this->username = DB_USER; $this->passwd = DB_PASSWORD; $this->dbName = DB_NAME; $this->charset = DB_CHARSET; $this->conn = $this->initializeDatabase(); $this->backupDir = BACKUP_DIR ? BACKUP_DIR : '.'; $this->backupFile = $filename.'-db.sql'; $this->gzipBackupFile = defined('GZIP_BACKUP_FILE') ? GZIP_BACKUP_FILE : true; $this->disableForeignKeyChecks = defined('DISABLE_FOREIGN_KEY_CHECKS') ? DISABLE_FOREIGN_KEY_CHECKS : true; $this->batchSize = defined('BATCH_SIZE') ? BATCH_SIZE : 1000; // default 1000 rows $this->output = ''; } protected function initializeDatabase() { try { $conn = mysqli_connect($this->host, $this->username, $this->passwd, $this->dbName); if (mysqli_connect_errno()) { throw new Exception('ERROR connecting database: ' . mysqli_connect_error()); die(); } if (!mysqli_set_charset($conn, $this->charset)) { mysqli_query($conn, 'SET NAMES '.$this->charset); } } catch (Exception $e) { print_r($e->getMessage()); die(); } return $conn; } /** * Backup the whole database or just some tables * Use '*' for whole database or 'table1 table2 table3...' * @param string $tables */ public function backupTables($tables = '*', $bkpDir="") { try { /** * Tables to export */ if($tables == '*') { $tables = array(); $result = mysqli_query($this->conn, 'SHOW TABLES'); while($row = mysqli_fetch_row($result)) { $tables[] = $row[0]; } } else { $tables = is_array($tables) ? $tables : explode(',', str_replace(' ', '', $tables)); } $sql = 'CREATE DATABASE IF NOT EXISTS `'.$this->dbName."`;\n\n"; $sql .= 'USE `'.$this->dbName."`;\n\n"; /** * Disable foreign key checks */ if ($this->disableForeignKeyChecks === true) { $sql .= "SET foreign_key_checks = 0;\n\n"; } /** * Iterate tables */ foreach($tables as $table) { $this->obfPrint("Backing up `".$table."` table...".str_repeat('.', 50-strlen($table)), 0, 0); /** * CREATE TABLE */ $sql .= 'DROP TABLE IF EXISTS `'.$table.'`;'; $row = mysqli_fetch_row(mysqli_query($this->conn, 'SHOW CREATE TABLE `'.$table.'`')); $sql .= "\n\n".$row[1].";\n\n"; /** * INSERT INTO */ $row = mysqli_fetch_row(mysqli_query($this->conn, 'SELECT COUNT(*) FROM `'.$table.'`')); $numRows = $row[0]; // Split table in batches in order to not exhaust system memory $numBatches = intval($numRows / $this->batchSize) + 1; // Number of while-loop calls to perform for ($b = 1; $b <= $numBatches; $b++) { $query = 'SELECT * FROM `' . $table . '` LIMIT ' . ($b * $this->batchSize - $this->batchSize) . ',' . $this->batchSize; $result = mysqli_query($this->conn, $query); $realBatchSize = mysqli_num_rows ($result); // Last batch size can be different from $this->batchSize $numFields = mysqli_num_fields($result); if ($realBatchSize !== 0) { $sql .= 'INSERT INTO `'.$table.'` VALUES '; for ($i = 0; $i < $numFields; $i++) { $rowCount = 1; while($row = mysqli_fetch_row($result)) { $sql.='('; for($j=0; $j<$numFields; $j++) { if (isset($row[$j])) { $row[$j] = addslashes($row[$j]); $row[$j] = str_replace("\n","\\n",$row[$j]); $row[$j] = str_replace("\r","\\r",$row[$j]); $row[$j] = str_replace("\f","\\f",$row[$j]); $row[$j] = str_replace("\t","\\t",$row[$j]); $row[$j] = str_replace("\v","\\v",$row[$j]); $row[$j] = str_replace("\a","\\a",$row[$j]); $row[$j] = str_replace("\b","\\b",$row[$j]); if (preg_match('/^-?[0-9]+$/', $row[$j]) or $row[$j] == 'NULL' or $row[$j] == 'null') { $sql .= $row[$j]; } else { $sql .= '"'.$row[$j].'"' ; } } else { $sql.= 'NULL'; } if ($j < ($numFields-1)) { $sql .= ','; } } if ($rowCount == $realBatchSize) { $rowCount = 0; $sql.= ");\n"; //close the insert statement } else { $sql.= "),\n"; //close the row } $rowCount++; } } $this->saveFile($sql); $sql = ''; } } $sql.="\n\n"; $this->obfPrint('OK'); } /** * Re-enable foreign key checks */ if ($this->disableForeignKeyChecks === true) { $sql .= "SET foreign_key_checks = 1;\n"; } $this->saveFile($sql); if ($this->gzipBackupFile) { $this->gzipBackupFile(); } else { $this->obfPrint('Backup file succesfully saved to ' . $this->backupDir.'/'.$this->backupFile, 1, 1); } } catch (Exception $e) { print_r($e->getMessage()); return false; } return true; } /** * Save SQL to file * @param string $sql */ protected function saveFile(&$sql) { if (!$sql) return false; try { if (!file_exists($this->backupDir)) { mkdir($this->backupDir, 0777, true); } file_put_contents($this->backupDir.'/'.$this->backupFile, $sql, FILE_APPEND | LOCK_EX); } catch (Exception $e) { print_r($e->getMessage()); return false; } return true; } /* * Gzip backup file * * @param integer $level GZIP compression level (default: 9) * @return string New filename (with .gz appended) if success, or false if operation fails */ protected function gzipBackupFile($level = 9) { if (!$this->gzipBackupFile) { return true; } $source = $this->backupDir . '/' . $this->backupFile; $dest = $source . '.gz'; $this->obfPrint('Gzipping backup file to ' . $dest . '... ', 1, 0); $mode = 'wb' . $level; if ($fpOut = gzopen($dest, $mode)) { if ($fpIn = fopen($source,'rb')) { while (!feof($fpIn)) { gzwrite($fpOut, fread($fpIn, 1024 * 256)); } fclose($fpIn); } else { return false; } gzclose($fpOut); if(!unlink($source)) { return false; } } else { return false; } $this->obfPrint('OK'); return $dest; } /** * Prints message forcing output buffer flush * */ public function obfPrint ($msg = '', $lineBreaksBefore = 0, $lineBreaksAfter = 1) { if (!$msg) { return false; } if ($msg != 'OK' and $msg != 'KO') { $msg = date("Y-m-d H:i:s") . ' - ' . $msg; } $output = ''; if (php_sapi_name() != "cli") { $lineBreak = "<br />"; } else { $lineBreak = "\n"; } if ($lineBreaksBefore > 0) { for ($i = 1; $i <= $lineBreaksBefore; $i++) { $output .= $lineBreak; } } $output .= $msg; if ($lineBreaksAfter > 0) { for ($i = 1; $i <= $lineBreaksAfter; $i++) { $output .= $lineBreak; } } // Save output for later use $this->output .= str_replace('<br />', '\n', $output); return $output; if (php_sapi_name() != "cli") { if( ob_get_level() > 0 ) { ob_flush(); } } $this->output .= " "; flush(); } /** * Returns full execution output * */ public function getOutput() { return $this->output; } }