This is an old revision of the document!
Yii 2 Database Backup
Add the actionBackupDatabase()
to the app\controllers\SiteController.php
file:
class SiteController extends Controller { ... /** * Get host name or database name from database connection string in * Yii::$app->db->dsn: * [dsn] => 'mysql:host=localhost;dbname=acme_mydatabase' * Usage: * $db = Yii::$app->getDb(); * $dbName = $this->getDsnAttribute('dbname', $db->dsn); */ private function getDsnAttribute($name, $dsn) { if (preg_match('/' . $name . '=([^;]*)/', $dsn, $match)) { return $match[1]; } else { return null; } } /** * Dumps the MySQL database that this controller's model is attached to. * Serve the sql file as a download so that the user can save the backup to their local computer. * * @param string $tables Comma separated list of tables to download, or '*' to download them all. */ function actionBackupDatabase($tables = '*') { $return = ''; $db = Yii::$app->getDb(); $databaseName = $this->getDsnAttribute('dbname', $db->dsn); // Do a short header $return .= '-- Database: `' . $databaseName . '`' . "\n"; $return .= '-- Generation time: ' . date('D jS M Y H:i:s') . "\n\n\n"; if ($tables == '*') { $tables = array(); $result = $db->createCommand('SHOW TABLES')->queryAll(); foreach($result as $resultKey => $resultValue) { $tables[] = $resultValue['Tables_in_'.$databaseName]; } } else { $tables = is_array($tables) ? $tables : explode(',', $tables); } // Run through all the tables foreach ($tables as $table) { $tableData = $db->createCommand('SELECT * FROM `' . $table . '`')->queryAll(); $return .= 'DROP TABLE IF EXISTS `' . $table . '`;'; $createTableResult = $db->createCommand('SHOW CREATE TABLE `' . $table . '`')->queryAll(); $createTableEntry = current($createTableResult); $return .= "\n\n" . $createTableEntry['Create Table'] . ";\n\n"; // Output the table data foreach($tableData as $tableDataIndex => $tableDataDetails) { $return .= 'INSERT INTO `' . $table . '` VALUES('; foreach($tableDataDetails as $dataKey => $dataValue) { if(is_null($dataValue)) { $escapedDataValue = 'NULL'; } else { // Convert the encoding //$escapedDataValue = mb_convert_encoding( $dataValue, "UTF-8", "ISO-8859-1" ); $escapedDataValue = $dataValue; // no char conversion (keep it as UTF-8) // Escape any apostrophes using the datasource of the model. $escapedDataValue = str_replace("'", "\'", $escapedDataValue); // escape apostrophes //if (stripos($escapedDataValue, ' ') !== false) { // $escapedDataValue = "'" . $escapedDataValue . "'"; // quote string if spaces found //} //if (!is_numeric($escapedDataValue)) { // $escapedDataValue = "'" . $escapedDataValue . "'"; // quote string if non-numeric //} $escapedDataValue = "'" . $escapedDataValue . "'"; // quote string for all fields w/o NULL } $tableDataDetails[$dataKey] = $escapedDataValue; } $return .= implode(',', $tableDataDetails); $return .= ");\n"; } $return .= "\n\n\n"; } // Set the default file name $fileName = $databaseName . '-backup-' . date('Y-m-d_H-i-s') . '.sql'; // Serve the file as a download header("Content-Type: text/x-sql"); header('Content-Disposition: attachment; filename="'. $fileName . '"'); // File will be called $fileName echo $return; } /** * Dumps the MySQL database that this controller's model is attached to. * This action will serve the sql file as a download so that the user can save the backup to their local computer. * * @param string $tables Comma separated list of tables you want to download, or '*' if you want to download them all. */ function actionBackupDatabaseLarge($tables = '*') { Yii::$app->response->format = Response::FORMAT_RAW; // Raw for Text output $db = Yii::$app->getDb(); $databaseName = $this->getDsnAttribute('dbname', $db->dsn); // Set the default file name $fileName = $databaseName . '-backup-' . date('Y-m-d_H-i-s') . '.sql'; // Serve the file as a download header("Content-Type: text/x-sql"); header('Content-Disposition: attachment; filename="'. $fileName . '"'); // File will be called $fileName // Do a short header echo '-- Database: `' . $databaseName . '`' . "\n"; echo '-- Generation time: ' . date('D jS M Y H:i:s') . "\n\n\n"; if ($tables == '*') { $tables = array(); $result = $db->createCommand('SHOW TABLES')->queryAll(); foreach($result as $resultKey => $resultValue) { $tables[] = $resultValue['Tables_in_'.$databaseName]; } //echo "Tables: " . print_r($tables, true); //debug } else { $tables = is_array($tables) ? $tables : explode(',', $tables); } // Run through all the tables foreach ($tables as $table) { $tableCountData = $db->createCommand('SELECT COUNT(*) AS total FROM `' . $table . "`")->queryAll(); $totalRecs = $tableCountData[0]['total']; //echo "Total: " . print_r($tableCountData, true); //debug // SQL CREATE code echo 'DROP TABLE IF EXISTS `' . $table . '`;'; $createTableResult = $db->createCommand('SHOW CREATE TABLE `' . $table . '`')->queryAll(); $createTableEntry = current($createTableResult); echo "\n\n" . $createTableEntry['Create Table'] . ";\n\n"; // Process table data in chunks to avoid running out of memory for($startIdx = 0, $chunkSize = 10000; $startIdx < $totalRecs; $startIdx += $chunkSize) { $tableData = $db->createCommand('SELECT * FROM `' . $table . "` LIMIT {$startIdx},{$chunkSize}")->queryAll(); // Output the table data foreach($tableData as $tableDataIndex => $tableDataDetails) { echo 'INSERT INTO `' . $table . '` VALUES('; foreach($tableDataDetails as $dataKey => $dataValue) { if(is_null($dataValue)) { $escapedDataValue = 'NULL'; } else { // Convert the encoding //$escapedDataValue = mb_convert_encoding( $dataValue, "UTF-8", "ISO-8859-1" ); $escapedDataValue = $dataValue; // no char conversion (keep it as UTF-8) // Escape any apostrophes using the datasource of the model. $escapedDataValue = str_replace("'", "\'", $escapedDataValue); // escape apostrophes //if (stripos($escapedDataValue, ' ') !== false) { // $escapedDataValue = "'" . $escapedDataValue . "'"; // quote string if spaces found //} //if (!is_numeric($escapedDataValue)) { // $escapedDataValue = "'" . $escapedDataValue . "'"; // quote string if non-numeric //} $escapedDataValue = "'" . $escapedDataValue . "'"; // quote string for all fields without NULL } $tableDataDetails[$dataKey] = $escapedDataValue; } echo implode(',', $tableDataDetails); echo ");\n"; } } echo "\n\n\n"; } } }
Add a call to action BackupDatabase in app\views\layouts\main.php
file:
<?php echo Nav::widget([ 'options' => ['class' => 'navbar-nav navbar-right'], 'items' => [ ['label' => 'Home', 'url' => ['/site/index']], // Admin menu only !Yii::$app->user->isGuest && Yii::$app->user->identity->username === 'admin' ? ['label' => 'Admin', 'url' => ['/site/admin'], 'items' => [ ['label' => 'Backup Database', 'url' => ['/site/backup-database']] ['label' => 'Backup Database (Large)', 'url' => ['/site/backup-database-large']] ]] : '', ], ... ]); NavBar::end(); ?>