.
675 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | myphp-backup
2 | ============
3 |
4 | Perform simple and fast MySQL backup/restore using PHP. You can use it to dump a full database or only some tables.
5 |
6 | It requires PHP 5.0.5 or later.
7 |
8 | More information: [Using PHP to backup MySQL databases](http://www.daniloaz.com/en/using-php-to-backup-mysql-databases/)
9 |
10 | Usage
11 | -----
12 |
13 | **Backup:**
14 |
15 | Simply upload *myphp-backup.php* script to the DocumentRoot directory of your web application via FTP or other method and run it accessing http://www.example.com/myphp-backup.php. You can also run it from command line.
16 |
17 | Don't forget to set your database access credentials before performing any backup editing these lines from *myphp-backup.php* script:
18 |
19 | /**
20 | * Define database parameters here
21 | */
22 | define("DB_USER", 'your_username');
23 | define("DB_PASSWORD", 'your_password');
24 | define("DB_NAME", 'your_db_name');
25 | define("DB_HOST", 'localhost');
26 |
27 | define("BACKUP_DIR", 'myphp-backup-files'); // Comment this line to use same script's directory ('.')
28 | define("TABLES", '*'); // Full backup
29 | //define("TABLES", 'table1, table2, table3'); // Partial backup
30 | define("CHARSET", 'utf8');
31 | define("GZIP_BACKUP_FILE", true); // Set to false if you want plain SQL backup files (not gzipped)
32 | define("DISABLE_FOREIGN_KEY_CHECKS", true); // Set to true if you are having foreign key constraint fails
33 |
34 | By default backup files will be called *myphp-backup-{DB_NAME}-YYYYmmdd-HHMMSS.sql.gz* and stored in *myphp-backup-files* subdirectory. Example output backup file:
35 |
36 | myphp-backup-files/myphp-backup-daniloaz-20170828-131745.sql.gz
37 |
38 | **Restore:**
39 |
40 | Upload *myphp-restore.php* script to your DocumentRoot directory and your backup file to a subdirectory called *myphp-backup-files*. Then simply run the script accessing http://www.example.com/myphp-restore.php or from command line.
41 |
42 | You can change the backup filename and subdirectory editing these lines. Don't forget to set your user credentials too!
43 |
44 | /**
45 | * Define database parameters here
46 | */
47 | define("DB_USER", 'your_username');
48 | define("DB_PASSWORD", 'your_password');
49 | define("DB_NAME", 'your_db_name');
50 | define("DB_HOST", 'localhost');
51 | define("BACKUP_DIR", 'myphp-backup-files'); // Comment this line to use same script's directory ('.')
52 | define("BACKUP_FILE", 'your-backup-file.sql.gz'); // Script will autodetect if backup file is gzipped or not based on .gz extension
53 | define("CHARSET", 'utf8');
54 | define("DISABLE_FOREIGN_KEY_CHECKS", true); // Set to true if you are having foreign key constraint fails
55 |
56 | -----
57 | Project at GitHub: https://github.com/daniloaz/myphp-backup
58 |
59 | (c) Daniel López Azaña, 2012-2017 (http://www.daniloaz.com)
60 |
--------------------------------------------------------------------------------
/myphp-backup.php:
--------------------------------------------------------------------------------
1 |
6 | * @version 1.0
7 | */
8 |
9 | /**
10 | * Define database parameters here
11 | */
12 | define("DB_USER", 'your_username');
13 | define("DB_PASSWORD", 'your_password');
14 | define("DB_NAME", 'your_db_name');
15 | define("DB_HOST", 'localhost');
16 | define("BACKUP_DIR", 'myphp-backup-files'); // Comment this line to use same script's directory ('.')
17 | define("TABLES", '*'); // Full backup
18 | //define("TABLES", 'table1, table2, table3'); // Partial backup
19 | define('IGNORE_TABLES',array(
20 | 'tbl_token_auth',
21 | 'token_auth'
22 | )); // Tables to ignore
23 | define("CHARSET", 'utf8');
24 | define("GZIP_BACKUP_FILE", true); // Set to false if you want plain SQL backup files (not gzipped)
25 | define("DISABLE_FOREIGN_KEY_CHECKS", true); // Set to true if you are having foreign key constraint fails
26 | define("BATCH_SIZE", 1000); // Batch size when selecting rows from database in order to not exhaust system memory
27 | // Also number of rows per INSERT statement in backup file
28 |
29 | /**
30 | * The Backup_Database class
31 | */
32 | class Backup_Database {
33 | /**
34 | * Host where the database is located
35 | */
36 | var $host;
37 |
38 | /**
39 | * Username used to connect to database
40 | */
41 | var $username;
42 |
43 | /**
44 | * Password used to connect to database
45 | */
46 | var $passwd;
47 |
48 | /**
49 | * Database to backup
50 | */
51 | var $dbName;
52 |
53 | /**
54 | * Database charset
55 | */
56 | var $charset;
57 |
58 | /**
59 | * Database connection
60 | */
61 | var $conn;
62 |
63 | /**
64 | * Backup directory where backup files are stored
65 | */
66 | var $backupDir;
67 |
68 | /**
69 | * Output backup file
70 | */
71 | var $backupFile;
72 |
73 | /**
74 | * Use gzip compression on backup file
75 | */
76 | var $gzipBackupFile;
77 |
78 | /**
79 | * Content of standard output
80 | */
81 | var $output;
82 |
83 | /**
84 | * Disable foreign key checks
85 | */
86 | var $disableForeignKeyChecks;
87 |
88 | /**
89 | * Batch size, number of rows to process per iteration
90 | */
91 | var $batchSize;
92 |
93 | /**
94 | * Constructor initializes database
95 | */
96 | public function __construct($host, $username, $passwd, $dbName, $charset = 'utf8') {
97 | $this->host = $host;
98 | $this->username = $username;
99 | $this->passwd = $passwd;
100 | $this->dbName = $dbName;
101 | $this->charset = $charset;
102 | $this->conn = $this->initializeDatabase();
103 | $this->backupDir = BACKUP_DIR ? BACKUP_DIR : '.';
104 | $this->backupFile = 'myphp-backup-'.$this->dbName.'-'.date("Ymd_His", time()).'.sql';
105 | $this->gzipBackupFile = defined('GZIP_BACKUP_FILE') ? GZIP_BACKUP_FILE : true;
106 | $this->disableForeignKeyChecks = defined('DISABLE_FOREIGN_KEY_CHECKS') ? DISABLE_FOREIGN_KEY_CHECKS : true;
107 | $this->batchSize = defined('BATCH_SIZE') ? BATCH_SIZE : 1000; // default 1000 rows
108 | $this->output = '';
109 | }
110 |
111 | protected function initializeDatabase() {
112 | try {
113 | $conn = mysqli_connect($this->host, $this->username, $this->passwd, $this->dbName);
114 | if (mysqli_connect_errno()) {
115 | throw new Exception('ERROR connecting database: ' . mysqli_connect_error());
116 | die();
117 | }
118 | if (!mysqli_set_charset($conn, $this->charset)) {
119 | mysqli_query($conn, 'SET NAMES '.$this->charset);
120 | }
121 | } catch (Exception $e) {
122 | print_r($e->getMessage());
123 | die();
124 | }
125 |
126 | return $conn;
127 | }
128 |
129 | /**
130 | * Backup the whole database or just some tables
131 | * Use '*' for whole database or 'table1 table2 table3...'
132 | * @param string $tables
133 | */
134 | public function backupTables($tables = '*') {
135 | try {
136 | /**
137 | * Tables to export
138 | */
139 | if($tables == '*') {
140 | $tables = array();
141 | $result = mysqli_query($this->conn, 'SHOW TABLES');
142 | while($row = mysqli_fetch_row($result)) {
143 | $tables[] = $row[0];
144 | }
145 | } else {
146 | $tables = is_array($tables) ? $tables : explode(',', str_replace(' ', '', $tables));
147 | }
148 |
149 | $sql = 'CREATE DATABASE IF NOT EXISTS `'.$this->dbName.'`'.";\n\n";
150 | $sql .= 'USE `'.$this->dbName."`;\n\n";
151 |
152 | /**
153 | * Disable foreign key checks
154 | */
155 | if ($this->disableForeignKeyChecks === true) {
156 | $sql .= "SET foreign_key_checks = 0;\n\n";
157 | }
158 |
159 | /**
160 | * Iterate tables
161 | */
162 | foreach($tables as $table) {
163 | if( in_array($table, IGNORE_TABLES) )
164 | continue;
165 | $this->obfPrint("Backing up `".$table."` table...".str_repeat('.', 50-strlen($table)), 0, 0);
166 |
167 | /**
168 | * CREATE TABLE
169 | */
170 | $sql .= 'DROP TABLE IF EXISTS `'.$table.'`;';
171 | $row = mysqli_fetch_row(mysqli_query($this->conn, 'SHOW CREATE TABLE `'.$table.'`'));
172 | $sql .= "\n\n".$row[1].";\n\n";
173 |
174 | /**
175 | * INSERT INTO
176 | */
177 |
178 | $row = mysqli_fetch_row(mysqli_query($this->conn, 'SELECT COUNT(*) FROM `'.$table.'`'));
179 | $numRows = $row[0];
180 |
181 | // Split table in batches in order to not exhaust system memory
182 | $numBatches = intval($numRows / $this->batchSize) + 1; // Number of while-loop calls to perform
183 |
184 | for ($b = 1; $b <= $numBatches; $b++) {
185 |
186 | $query = 'SELECT * FROM `' . $table . '` LIMIT ' . ($b * $this->batchSize - $this->batchSize) . ',' . $this->batchSize;
187 | $result = mysqli_query($this->conn, $query);
188 | $realBatchSize = mysqli_num_rows ($result); // Last batch size can be different from $this->batchSize
189 | $numFields = mysqli_num_fields($result);
190 |
191 | if ($realBatchSize !== 0) {
192 | $sql .= 'INSERT INTO `'.$table.'` VALUES ';
193 |
194 | for ($i = 0; $i < $numFields; $i++) {
195 | $rowCount = 1;
196 | while($row = mysqli_fetch_row($result)) {
197 | $sql.='(';
198 | for($j=0; $j<$numFields; $j++) {
199 | if (isset($row[$j])) {
200 | $row[$j] = addslashes($row[$j]);
201 | $row[$j] = str_replace("\n","\\n",$row[$j]);
202 | $row[$j] = str_replace("\r","\\r",$row[$j]);
203 | $row[$j] = str_replace("\f","\\f",$row[$j]);
204 | $row[$j] = str_replace("\t","\\t",$row[$j]);
205 | $row[$j] = str_replace("\v","\\v",$row[$j]);
206 | $row[$j] = str_replace("\a","\\a",$row[$j]);
207 | $row[$j] = str_replace("\b","\\b",$row[$j]);
208 | if ($row[$j] == 'true' or $row[$j] == 'false' or preg_match('/^-?[1-9][0-9]*$/', $row[$j]) or $row[$j] == 'NULL' or $row[$j] == 'null') {
209 | $sql .= $row[$j];
210 | } else {
211 | $sql .= '"'.$row[$j].'"' ;
212 | }
213 | } else {
214 | $sql.= 'NULL';
215 | }
216 |
217 | if ($j < ($numFields-1)) {
218 | $sql .= ',';
219 | }
220 | }
221 |
222 | if ($rowCount == $realBatchSize) {
223 | $rowCount = 0;
224 | $sql.= ");\n"; //close the insert statement
225 | } else {
226 | $sql.= "),\n"; //close the row
227 | }
228 |
229 | $rowCount++;
230 | }
231 | }
232 |
233 | $this->saveFile($sql);
234 | $sql = '';
235 | }
236 | }
237 |
238 | /**
239 | * CREATE TRIGGER
240 | */
241 |
242 | // Check if there are some TRIGGERS associated to the table
243 | /*$query = "SHOW TRIGGERS LIKE '" . $table . "%'";
244 | $result = mysqli_query ($this->conn, $query);
245 | if ($result) {
246 | $triggers = array();
247 | while ($trigger = mysqli_fetch_row ($result)) {
248 | $triggers[] = $trigger[0];
249 | }
250 |
251 | // Iterate through triggers of the table
252 | foreach ( $triggers as $trigger ) {
253 | $query= 'SHOW CREATE TRIGGER `' . $trigger . '`';
254 | $result = mysqli_fetch_array (mysqli_query ($this->conn, $query));
255 | $sql.= "\nDROP TRIGGER IF EXISTS `" . $trigger . "`;\n";
256 | $sql.= "DELIMITER $$\n" . $result[2] . "$$\n\nDELIMITER ;\n";
257 | }
258 |
259 | $sql.= "\n";
260 |
261 | $this->saveFile($sql);
262 | $sql = '';
263 | }*/
264 |
265 | $sql.="\n\n";
266 |
267 | $this->obfPrint('OK');
268 | }
269 |
270 | /**
271 | * Re-enable foreign key checks
272 | */
273 | if ($this->disableForeignKeyChecks === true) {
274 | $sql .= "SET foreign_key_checks = 1;\n";
275 | }
276 |
277 | $this->saveFile($sql);
278 |
279 | if ($this->gzipBackupFile) {
280 | $this->gzipBackupFile();
281 | } else {
282 | $this->obfPrint('Backup file succesfully saved to ' . $this->backupDir.'/'.$this->backupFile, 1, 1);
283 | }
284 | } catch (Exception $e) {
285 | print_r($e->getMessage());
286 | return false;
287 | }
288 |
289 | return true;
290 | }
291 |
292 | /**
293 | * Save SQL to file
294 | * @param string $sql
295 | */
296 | protected function saveFile(&$sql) {
297 | if (!$sql) return false;
298 |
299 | try {
300 |
301 | if (!file_exists($this->backupDir)) {
302 | mkdir($this->backupDir, 0777, true);
303 | }
304 |
305 | file_put_contents($this->backupDir.'/'.$this->backupFile, $sql, FILE_APPEND | LOCK_EX);
306 |
307 | } catch (Exception $e) {
308 | print_r($e->getMessage());
309 | return false;
310 | }
311 |
312 | return true;
313 | }
314 |
315 | /*
316 | * Gzip backup file
317 | *
318 | * @param integer $level GZIP compression level (default: 9)
319 | * @return string New filename (with .gz appended) if success, or false if operation fails
320 | */
321 | protected function gzipBackupFile($level = 9) {
322 | if (!$this->gzipBackupFile) {
323 | return true;
324 | }
325 |
326 | $source = $this->backupDir . '/' . $this->backupFile;
327 | $dest = $source . '.gz';
328 |
329 | $this->obfPrint('Gzipping backup file to ' . $dest . '... ', 1, 0);
330 |
331 | $mode = 'wb' . $level;
332 | if ($fpOut = gzopen($dest, $mode)) {
333 | if ($fpIn = fopen($source,'rb')) {
334 | while (!feof($fpIn)) {
335 | gzwrite($fpOut, fread($fpIn, 1024 * 256));
336 | }
337 | fclose($fpIn);
338 | } else {
339 | return false;
340 | }
341 | gzclose($fpOut);
342 | if(!unlink($source)) {
343 | return false;
344 | }
345 | } else {
346 | return false;
347 | }
348 |
349 | $this->obfPrint('OK');
350 | return $dest;
351 | }
352 |
353 | /**
354 | * Prints message forcing output buffer flush
355 | *
356 | */
357 | public function obfPrint ($msg = '', $lineBreaksBefore = 0, $lineBreaksAfter = 1) {
358 | if (!$msg) {
359 | return false;
360 | }
361 |
362 | if ($msg != 'OK' and $msg != 'KO') {
363 | $msg = date("Y-m-d H:i:s") . ' - ' . $msg;
364 | }
365 | $output = '';
366 |
367 | if (php_sapi_name() != "cli") {
368 | $lineBreak = "
";
369 | } else {
370 | $lineBreak = "\n";
371 | }
372 |
373 | if ($lineBreaksBefore > 0) {
374 | for ($i = 1; $i <= $lineBreaksBefore; $i++) {
375 | $output .= $lineBreak;
376 | }
377 | }
378 |
379 | $output .= $msg;
380 |
381 | if ($lineBreaksAfter > 0) {
382 | for ($i = 1; $i <= $lineBreaksAfter; $i++) {
383 | $output .= $lineBreak;
384 | }
385 | }
386 |
387 |
388 | // Save output for later use
389 | $this->output .= str_replace('
', '\n', $output);
390 |
391 | echo $output;
392 |
393 |
394 | if (php_sapi_name() != "cli") {
395 | if( ob_get_level() > 0 ) {
396 | ob_flush();
397 | }
398 | }
399 |
400 | $this->output .= " ";
401 |
402 | flush();
403 | }
404 |
405 | /**
406 | * Returns full execution output
407 | *
408 | */
409 | public function getOutput() {
410 | return $this->output;
411 | }
412 | /**
413 | * Returns name of backup file
414 | *
415 | */
416 | public function getBackupFile() {
417 | if ($this->gzipBackupFile) {
418 | return $this->backupDir.'/'.$this->backupFile.'.gz';
419 | } else
420 | return $this->backupDir.'/'.$this->backupFile;
421 | }
422 |
423 | /**
424 | * Returns backup directory path
425 | *
426 | */
427 | public function getBackupDir() {
428 | return $this->backupDir;
429 | }
430 |
431 | /**
432 | * Returns array of changed tables since duration
433 | *
434 | */
435 | public function getChangedTables($since = '1 day') {
436 | $query = "SELECT TABLE_NAME,update_time FROM information_schema.tables WHERE table_schema='" . $this->dbName . "'";
437 |
438 | $result = mysqli_query($this->conn, $query);
439 | while($row=mysqli_fetch_assoc($result)) {
440 | $resultset[] = $row;
441 | }
442 | if(empty($resultset))
443 | return false;
444 | $tables = [];
445 | for ($i=0; $i < count($resultset); $i++) {
446 | if( in_array($resultset[$i]['TABLE_NAME'], IGNORE_TABLES) ) // ignore this table
447 | continue;
448 | if(strtotime('-' . $since) < strtotime($resultset[$i]['update_time']))
449 | $tables[] = $resultset[$i]['TABLE_NAME'];
450 | }
451 | return ($tables) ? $tables : false;
452 | }
453 | }
454 |
455 |
456 | /**
457 | * Instantiate Backup_Database and perform backup
458 | */
459 |
460 | // Report all errors
461 | error_reporting(E_ALL);
462 | // Set script max execution time
463 | set_time_limit(900); // 15 minutes
464 |
465 | if (php_sapi_name() != "cli") {
466 | echo '';
467 | }
468 |
469 | $backupDatabase = new Backup_Database(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME, CHARSET);
470 |
471 | // Option-1: Backup tables already defined above
472 | $result = $backupDatabase->backupTables(TABLES) ? 'OK' : 'KO';
473 |
474 | // Option-2: Backup changed tables only - uncomment block below
475 | /*
476 | $since = '1 day';
477 | $changed = $backupDatabase->getChangedTables($since);
478 | if(!$changed){
479 | $backupDatabase->obfPrint('No tables modified since last ' . $since . '! Quitting..', 1);
480 | die();
481 | }
482 | $result = $backupDatabase->backupTables($changed) ? 'OK' : 'KO';
483 | */
484 |
485 |
486 | $backupDatabase->obfPrint('Backup result: ' . $result, 1);
487 |
488 | // Use $output variable for further processing, for example to send it by email
489 | $output = $backupDatabase->getOutput();
490 |
491 | if (php_sapi_name() != "cli") {
492 | echo '
';
493 | }
494 |
--------------------------------------------------------------------------------
/myphp-restore.php:
--------------------------------------------------------------------------------
1 |
6 | * @version 1.0
7 | */
8 |
9 | /**
10 | * Define database parameters here
11 | */
12 | define("DB_USER", 'your_username');
13 | define("DB_PASSWORD", 'your_password');
14 | define("DB_NAME", 'your_db_name');
15 | define("DB_HOST", 'localhost');
16 | define("BACKUP_DIR", 'myphp-backup-files'); // Comment this line to use same script's directory ('.')
17 | define("BACKUP_FILE", 'myphp-backup-your_db_name-20181022_164459.sql.gz'); // Script will autodetect if backup file is gzipped based on .gz extension
18 | define("CHARSET", 'utf8');
19 | define("DISABLE_FOREIGN_KEY_CHECKS", true); // Set to true if you are having foreign key constraint fails
20 |
21 | /**
22 | * The Restore_Database class
23 | */
24 | class Restore_Database {
25 | /**
26 | * Host where the database is located
27 | */
28 | var $host;
29 |
30 | /**
31 | * Username used to connect to database
32 | */
33 | var $username;
34 |
35 | /**
36 | * Password used to connect to database
37 | */
38 | var $passwd;
39 |
40 | /**
41 | * Database to backup
42 | */
43 | var $dbName;
44 |
45 | /**
46 | * Database charset
47 | */
48 | var $charset;
49 |
50 | /**
51 | * Database connection
52 | */
53 | var $conn;
54 |
55 | /**
56 | * Disable foreign key checks
57 | */
58 | var $disableForeignKeyChecks;
59 |
60 | /**
61 | * Constructor initializes database
62 | */
63 | function __construct($host, $username, $passwd, $dbName, $charset = 'utf8') {
64 | $this->host = $host;
65 | $this->username = $username;
66 | $this->passwd = $passwd;
67 | $this->dbName = $dbName;
68 | $this->charset = $charset;
69 | $this->disableForeignKeyChecks = defined('DISABLE_FOREIGN_KEY_CHECKS') ? DISABLE_FOREIGN_KEY_CHECKS : true;
70 | $this->conn = $this->initializeDatabase();
71 | $this->backupDir = defined('BACKUP_DIR') ? BACKUP_DIR : '.';
72 | $this->backupFile = defined('BACKUP_FILE') ? BACKUP_FILE : null;
73 | }
74 |
75 | /**
76 | * Destructor re-enables foreign key checks
77 | */
78 | function __destructor() {
79 | /**
80 | * Re-enable foreign key checks
81 | */
82 | if ($this->disableForeignKeyChecks === true) {
83 | mysqli_query($this->conn, 'SET foreign_key_checks = 1');
84 | }
85 | }
86 |
87 | protected function initializeDatabase() {
88 | try {
89 | $conn = mysqli_connect($this->host, $this->username, $this->passwd, $this->dbName);
90 | if (mysqli_connect_errno()) {
91 | throw new Exception('ERROR connecting database: ' . mysqli_connect_error());
92 | die();
93 | }
94 | if (!mysqli_set_charset($conn, $this->charset)) {
95 | mysqli_query($conn, 'SET NAMES '.$this->charset);
96 | }
97 |
98 | /**
99 | * Disable foreign key checks
100 | */
101 | if ($this->disableForeignKeyChecks === true) {
102 | mysqli_query($conn, 'SET foreign_key_checks = 0');
103 | }
104 |
105 | } catch (Exception $e) {
106 | print_r($e->getMessage());
107 | die();
108 | }
109 |
110 | return $conn;
111 | }
112 |
113 | /**
114 | * Backup the whole database or just some tables
115 | * Use '*' for whole database or 'table1 table2 table3...'
116 | * @param string $tables
117 | */
118 | public function restoreDb() {
119 | try {
120 | $sql = '';
121 | $multiLineComment = false;
122 |
123 | $backupDir = $this->backupDir;
124 | $backupFile = $this->backupFile;
125 |
126 | /**
127 | * Gunzip file if gzipped
128 | */
129 | $backupFileIsGzipped = substr($backupFile, -3, 3) == '.gz' ? true : false;
130 | if ($backupFileIsGzipped) {
131 | if (!$backupFile = $this->gunzipBackupFile()) {
132 | throw new Exception("ERROR: couldn't gunzip backup file " . $backupDir . '/' . $backupFile);
133 | }
134 | }
135 |
136 | /**
137 | * Read backup file line by line
138 | */
139 | $handle = fopen($backupDir . '/' . $backupFile, "r");
140 | if ($handle) {
141 | while (($line = fgets($handle)) !== false) {
142 | $line = ltrim(rtrim($line));
143 | if (strlen($line) > 1) { // avoid blank lines
144 | $lineIsComment = false;
145 | if (preg_match('/^\/\*/', $line)) {
146 | $multiLineComment = true;
147 | $lineIsComment = true;
148 | }
149 | if ($multiLineComment or preg_match('/^\/\//', $line)) {
150 | $lineIsComment = true;
151 | }
152 | if (!$lineIsComment) {
153 | $sql .= $line;
154 | if (preg_match('/;$/', $line)) {
155 | // execute query
156 | if(mysqli_query($this->conn, $sql)) {
157 | if (preg_match('/^CREATE TABLE `([^`]+)`/i', $sql, $tableName)) {
158 | $this->obfPrint("Table succesfully created: `" . $tableName[1] . "`");
159 | }
160 | $sql = '';
161 | } else {
162 | throw new Exception("ERROR: SQL execution error: " . mysqli_error($this->conn));
163 | }
164 | }
165 | } else if (preg_match('/\*\/$/', $line)) {
166 | $multiLineComment = false;
167 | }
168 | }
169 | }
170 | fclose($handle);
171 | } else {
172 | throw new Exception("ERROR: couldn't open backup file " . $backupDir . '/' . $backupFile);
173 | }
174 | } catch (Exception $e) {
175 | print_r($e->getMessage());
176 | return false;
177 | }
178 |
179 | if ($backupFileIsGzipped) {
180 | unlink($backupDir . '/' . $backupFile);
181 | }
182 |
183 | return true;
184 | }
185 |
186 | /*
187 | * Gunzip backup file
188 | *
189 | * @return string New filename (without .gz appended and without backup directory) if success, or false if operation fails
190 | */
191 | protected function gunzipBackupFile() {
192 | // Raising this value may increase performance
193 | $bufferSize = 4096; // read 4kb at a time
194 | $error = false;
195 |
196 | $source = $this->backupDir . '/' . $this->backupFile;
197 | $dest = $this->backupDir . '/' . date("Ymd_His", time()) . '_' . substr($this->backupFile, 0, -3);
198 |
199 | $this->obfPrint('Gunzipping backup file ' . $source . '... ', 1, 1);
200 |
201 | // Remove $dest file if exists
202 | if (file_exists($dest)) {
203 | if (!unlink($dest)) {
204 | return false;
205 | }
206 | }
207 |
208 | // Open gzipped and destination files in binary mode
209 | if (!$srcFile = gzopen($this->backupDir . '/' . $this->backupFile, 'rb')) {
210 | return false;
211 | }
212 | if (!$dstFile = fopen($dest, 'wb')) {
213 | return false;
214 | }
215 |
216 | while (!gzeof($srcFile)) {
217 | // Read buffer-size bytes
218 | // Both fwrite and gzread are binary-safe
219 | if(!fwrite($dstFile, gzread($srcFile, $bufferSize))) {
220 | return false;
221 | }
222 | }
223 |
224 | fclose($dstFile);
225 | gzclose($srcFile);
226 |
227 | // Return backup filename excluding backup directory
228 | return str_replace($this->backupDir . '/', '', $dest);
229 | }
230 |
231 | /**
232 | * Prints message forcing output buffer flush
233 | *
234 | */
235 | public function obfPrint ($msg = '', $lineBreaksBefore = 0, $lineBreaksAfter = 1) {
236 | if (!$msg) {
237 | return false;
238 | }
239 |
240 | $msg = date("Y-m-d H:i:s") . ' - ' . $msg;
241 | $output = '';
242 |
243 | if (php_sapi_name() != "cli") {
244 | $lineBreak = "
";
245 | } else {
246 | $lineBreak = "\n";
247 | }
248 |
249 | if ($lineBreaksBefore > 0) {
250 | for ($i = 1; $i <= $lineBreaksBefore; $i++) {
251 | $output .= $lineBreak;
252 | }
253 | }
254 |
255 | $output .= $msg;
256 |
257 | if ($lineBreaksAfter > 0) {
258 | for ($i = 1; $i <= $lineBreaksAfter; $i++) {
259 | $output .= $lineBreak;
260 | }
261 | }
262 |
263 | if (php_sapi_name() == "cli") {
264 | $output .= "\n";
265 | }
266 |
267 | echo $output;
268 |
269 | if (php_sapi_name() != "cli") {
270 | ob_flush();
271 | }
272 |
273 | flush();
274 | }
275 | }
276 |
277 | /**
278 | * Instantiate Restore_Database and perform backup
279 | */
280 | // Report all errors
281 | error_reporting(E_ALL);
282 | // Set script max execution time
283 | set_time_limit(900); // 15 minutes
284 |
285 | if (php_sapi_name() != "cli") {
286 | echo '';
287 | }
288 |
289 | $restoreDatabase = new Restore_Database(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
290 | $result = $restoreDatabase->restoreDb(BACKUP_DIR, BACKUP_FILE) ? 'OK' : 'KO';
291 | $restoreDatabase->obfPrint("Restoration result: ".$result, 1);
292 |
293 | if (php_sapi_name() != "cli") {
294 | echo '
';
295 | }
296 |
--------------------------------------------------------------------------------