Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
systems:yii2:database_backup [2018/02/23 12:04]
smayr created
systems:yii2:database_backup [2018/03/16 12:45] (current)
smayr
Line 110: Line 110:
     function actionBackupDatabaseLarge($tables = '*'     function actionBackupDatabaseLarge($tables = '*'
     {     {
 +        //ini_set('memory_limit','64M');  // limit memory to 64MB
 +        ini_set('memory_limit','-1');     // no memory limit
 +        
         Yii::$app->response->format = Response::FORMAT_RAW;  // Raw for Text output         Yii::$app->response->format = Response::FORMAT_RAW;  // Raw for Text output
 +        
 +        $strReturn = "";
                  
         $db = Yii::$app->getDb();         $db = Yii::$app->getDb();
         $databaseName = $this->getDsnAttribute('dbname', $db->dsn);         $databaseName = $this->getDsnAttribute('dbname', $db->dsn);
 +    
         // Set the default file name         // Set the default file name
         $fileName = $databaseName . '-backup-' . date('Y-m-d_H-i-s') . '.sql';         $fileName = $databaseName . '-backup-' . date('Y-m-d_H-i-s') . '.sql';
Line 120: Line 125:
         // Serve the file as a download         // Serve the file as a download
         header("Content-Type: text/x-sql");         header("Content-Type: text/x-sql");
-        header('Content-Disposition: attachment; filename="'$fileName '"');  // File will be called $fileName+        header("Content-Disposition: attachment; filename='{$fileName}'");  // File will be called $fileName 
 +        // Disable caching - HTTP 1.1 
 +        header("Cache-Control: no-cache, no-store, must-revalidate"); 
 +        // Disable caching - HTTP 1.0 
 +        header("Pragma: no-cache"); 
 +        // Disable caching - Proxies 
 +        header("Expires: 0");
                  
-        // Do a short header +        // Do a short SQL header 
-        echo '-- Database: `' . $databaseName . '`' . "\n"; +        $strReturn .= "-- Database: `{$databaseName}`\n"; 
-        echo '-- Generation time: . date('D jS M Y H:i:s') . "\n\n\n"; +        $strReturn .= "-- Generation time: . date('D jS M Y H:i:s') . "\n\n\n"; 
 +     
 +        //----------------- 
 +        // Tables & Views 
 +        //-----------------
         if ($tables == '*') {         if ($tables == '*') {
             $tables = array();             $tables = array();
             $result = $db->createCommand('SHOW TABLES')->queryAll();             $result = $db->createCommand('SHOW TABLES')->queryAll();
             foreach($result as $resultKey => $resultValue) {             foreach($result as $resultKey => $resultValue) {
-                $tables[] = $resultValue['Tables_in_'.$databaseName];+                $tables[] = $resultValue["Tables_in_{$databaseName}"];
             }             }
-            //echo "Tables: " . print_r($tables, true);  //debug+            //$strReturn .= "Tables: " . print_r($tables, true);  //debug
         } else {         } else {
             $tables = is_array($tables) ? $tables : explode(',', $tables);             $tables = is_array($tables) ? $tables : explode(',', $tables);
         }         }
 +    
         // Run through all the tables         // Run through all the tables
         foreach ($tables as $table) {         foreach ($tables as $table) {
-            $tableCountData = $db->createCommand('SELECT COUNT(*) AS total FROM `' . $table . "`")->queryAll(); +            if ($is_data_included) { 
-            $totalRecs = $tableCountData[0]['total']; +                $tableCountData = $db->createCommand("SELECT COUNT(*) AS total FROM `{$table}`")->queryAll(); 
-            //echo "Total: " . print_r($tableCountData, true);  //debug+                $totalRecs = $tableCountData[0]['total']; 
 +                //$strReturn .= "Total: " . print_r($tableCountData, true);  //debug 
 +            }
                          
             // SQL CREATE code             // SQL CREATE code
-            echo 'DROP TABLE IF EXISTS `' . $table . '`;'+            $strReturn .= "DROP TABLE IF EXISTS `{$table}`;"; 
-            $createTableResult = $db->createCommand('SHOW CREATE TABLE `' . $table . '`')->queryAll(); +            
-            $createTableEntry = current($createTableResult); +            // Tables 
-            echo "\n\n" . $createTableEntry['Create Table'] . ";\n\n";+            try { 
 +                $createTableResult = $db->createCommand("SHOW CREATE TABLE `{$table}`")->queryAll(); 
 +                $createTableEntry = current($createTableResult); 
 +                if (!empty($createTableEntry['Create Table'])) { 
 +                    $strReturn .= "\n\n" . $createTableEntry['Create Table'] . ";\n\n"; 
 +                } 
 +            } catch (\Exception $e) { 
 +                //throw new \Exception($e->getMessage() . ":\n" . json_encode($dumped), 0, $e); 
 +                $strReturn .= "\n\n-- No table definition for '{$table}'\n\n"; 
 +            } 
 +             
 +            // Views 
 +            try { 
 +                $createViewResult = $db->createCommand("SHOW CREATE VIEW `{$table}`")->queryAll(); 
 +                $createViewEntry = current($createViewResult); 
 +                if (!empty($createViewEntry['Create View'])) { 
 +                    $strReturn .= "\n\n" . $createViewEntry['Create View'] . ";\n\n"; 
 +                } 
 +            } catch (\Exception $e) { 
 +                //throw new \Exception($e->getMessage() . ":\n" . json_encode($dumped), 0, $e); 
 +                //$strReturn .= "\n\n-- No view definition for '" . $table . "'\n\n"; 
 +            }
                          
-            // Process table data in chunks to avoid running out of memory +            if ($is_data_included) { 
-            for($startIdx = 0, $chunkSize = 10000; $startIdx < $totalRecs; $startIdx += $chunkSize) { +                // Process table data in chunks to avoid running out of memory 
-                $tableData = $db->createCommand('SELECT * FROM `' . $table . "` LIMIT {$startIdx},{$chunkSize}")->queryAll(); +                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) { +                    // Output the table data 
-                    echo 'INSERT INTO `' . $table . '` VALUES('; +                    foreach($tableData as $tableRowIndex => $tableRow) { 
-                 +                        $strReturn .= "INSERT INTO `{$table}` VALUES("
-                    foreach($tableDataDetails as $dataKey => $dataValue) { +                     
-                        if(is_null($dataValue)) { +                        foreach($tableRow as $fieldName => $fieldValue) { 
-                            $escapedDataValue = 'NULL'; +                            if(is_null($fieldValue)) { 
-                        } else { +                                $escapedFieldValue = 'NULL'; 
-                            // Convert the encoding +                            } else { 
-                            //$escapedDataValue = mb_convert_encoding( $dataValue, "UTF-8", "ISO-8859-1" ); +                                // Convert the encoding 
-                            $escapedDataValue = $dataValue;  // no char conversion (keep it as UTF-8) +                                //$escapedFieldValue = mb_convert_encoding( $fieldValue, "UTF-8", "ISO-8859-1" ); 
-                 +                                $escapedFieldValue = $fieldValue;  // no char conversion (keep it as UTF-8) 
-                            // Escape any apostrophes using the datasource of the model. +                     
-                            $escapedDataValue = str_replace("'", "\'", $escapedDataValue);  // escape apostrophes +                                // Escape any apostrophes using the datasource of the model. 
-                            //if (stripos($escapedDataValue, ' ') !== false) { +                                $escapedFieldValue = str_replace("'", "\'", $escapedFieldValue);  // escape apostrophes 
-                            //    $escapedDataValue = "'" . $escapedDataValue . "'";  // quote string if spaces found +                                //if (stripos($escapedFieldValue, ' ') !== false) { 
-                            //} +                                //    $escapedFieldValue = "'{$escapedFieldValue}'";  // quote string if spaces found 
-                            //if (!is_numeric($escapedDataValue)) { +                                //} 
-                            //    $escapedDataValue = "'" . $escapedDataValue . "'";  // quote string if non-numeric +                                //if (!is_numeric($escapedFieldValue)) { 
-                            //} +                                //    $escapedFieldValue = "'{$escapedFieldValue}'";  // quote string if non-numeric 
-                            $escapedDataValue = "'" . $escapedDataValue . "'";        // quote string for all fields without NULL+                                //} 
 +                                $escapedFieldValue = "'{$escapedFieldValue}'";        // quote string for all fields without NULL 
 +                            } 
 +                     
 +                            $tableRow[$fieldName] = $escapedFieldValue;
                         }                         }
-                 +                        $strReturn .= implode(',', $tableRow); 
-                        $tableDataDetails[$dataKey] $escapedDataValue;+                     
 +                        $strReturn .");\n";
                     }                     }
-                    echo implode(',', $tableDataDetails); 
-                 
-                    echo ");\n"; 
                 }                 }
             }             }
                          
-            echo "\n\n\n";+            $strReturn .= "\n\n\n";
         }         }
 +        
 +        $strReturn .= "\n\n\n";
 +        
 +        //-----------------
 +        // Triggers
 +        //-----------------
 +        if ($triggers == '*') {
 +            $triggers = array();
 +            $result = $db->createCommand('SHOW TRIGGERS')->queryAll();
 +            foreach($result as $resultKey => $resultValue) {
 +                $triggers[] = $resultValue['Trigger'];
 +            }
 +        } else {
 +            $triggers = is_array($triggers) ? $triggers : explode(',', $triggers);
 +        }
 +
 +        // Run through all the triggers
 +        $strReturn .= "\n\n-- Triggers \n\n";
 +        foreach ($triggers as $trigger) {
 +            $strReturn .= "DROP TRIGGER IF EXISTS `{$trigger}`;";
 +            // Triggers
 +            $createTriggerResult = $db->createCommand("SHOW CREATE TRIGGER `{$trigger}`")->queryAll();
 +            $createTriggerEntry = current($createTriggerResult);
 +            //if (!empty($createTriggerEntry['sql_mode'])) {
 +            //    $strReturn .= "\n\n" . $createTriggerEntry['sql_mode'] . ";\n\n";
 +            //}
 +            if (!empty($createTriggerEntry['SQL Original Statement'])) {
 +                $strReturn .= "\n\n" . $createTriggerEntry['SQL Original Statement'] . ";\n\n";
 +            }
 +            //if (!empty($createTriggerEntry['character_set_client'])) {
 +            //    $strReturn .= "\n\n" . $createTriggerEntry['character_set_client'] . ";\n\n";
 +            //}
 +            //if (!empty($createTriggerEntry['collation_connection'])) {
 +            //    $strReturn .= "\n\n" . $createTriggerEntry['collation_connection'] . ";\n\n";
 +            //}
 +            //if (!empty($createTriggerEntry['Database Collation'])) {
 +            //    $strReturn .= "\n\n" . $createTriggerEntry['Database Collation'] . ";\n\n";
 +            //}
 +
 +            $strReturn .= "\n\n\n";
 +        }
 +        
 +        //return $strReturn;
 +        Yii::$app->response->data = $strReturn;
     }     }
 }     }    
Line 202: Line 285:
             ['label' => 'Admin', 'url' => ['/site/admin'],              ['label' => 'Admin', 'url' => ['/site/admin'], 
                 'items' => [                 'items' => [
-                    ['label' => 'Backup Database', 'url' => ['/site/backup-database']] +                    ['label' => 'Backup Database', 'url' => ['/site/backup-database']], 
-                    ['label' => 'Backup Database (Large)', 'url' => ['/site/backup-database-large']]+                    ['label' => 'Backup Database Large', 'url' => ['/site/backup-database-large']]
 +                    ['label' => 'Backup Database (Structure)', 'url' => [ 
 +                        'site/backup-database-large',  
 +                        'is_data_included' => 0  
 +                    ]],
             ]] :              ]] : 
             '',             '',