Návrh databázové třídy - díl IV: Export databáze
Dnešní pokračování pohádky o databázové třídě si vezme pod lupu pár konkrétních metod. Půjde o funkce na export celé databáze s možností force download nebo postupného ukládání do souboru. O možnostech exportu databáze moc článků napsáno nebylo, navíc se nejedná o úplně triviální algoritmus s pár vnořenými cykly. V následujícím článku vám předvedu, jak problém vyřešit s elegancí.
Kostra řešení bude poměrně jednoduchá:
SHOW TABLES
foreach ($tables) {
SHOW CREATE TABLE
SELECT * FROM $table
while (FETCH_ROW) {
foreach ($row) {
mysql_real_escape_string($row);
}
$export .= "INSERT INTO $table VALUES implode(, $row)"
}
}
Nejdříve zjistíme, jaké tabulky exportujeme, následně od každé z nich získáme strukturu přes SHOW CREATE TABLE, vybereme hvězdičku, provedeme escapování a uložíme znění SQL dotazu na insert.
Metody na export databáze budou 2. Budou si podobné, protože v rámci zachování čitelnosti kódu není dobry nápad cpát do už tak velké funkce hromadu podmínek. První metoda uloží celý export do proměnné a nabídne soubor k uložení, druhá bude data postupně ukládat do souboru, který si pak můžeme stáhnout přes FTP klienta.
Před uvedením výsledné funkce si ale nejprve ukážeme pár podpůrných metod, jenž se nám budou hodit. O prováděném exportu chceme samozřejmě mít nějaké zběžné informace, které nám poskytnou následující funkce.
private function prepareBackupInfo() {
$this->backupInfo['date_pattern'] = @date('Y-m-d_H.i.s');
$this->backupInfo['timestamp'] = strtr($this->backupInfo['date_pattern'], array('_' => ' ', '.' => ':'));
$this->backupInfo['start_time'] = $this->startTime();
$this->backupInfo['queries'] = 0;
$this->backupInfo['written'] = 0;
}
private function appendBackupInfo() {
$output = "";
$output .= "\n";
$output .= "--\n";
$output .= "-- Queries contained: ".$this->backupInfo['queries']."\n";
$output .= "-- Shots to file: ".$this->backupInfo['written']."\n";
$output .= "-- Total time: ".$this->stopTime($this->backupInfo['start_time'])."\n";
$output .= "-- Timestamp start: ".$this->backupInfo['timestamp']."\n";
$output .= "--\n";
return $output;
}
Metoda DB::downloadHeaders() zašle potřebné hlavičky pro force download, naproti tomu Db::writeToFile() bude obsluhovat průběžný zápis do souboru. Nakonec uvedu ještě funkci Db::addExportCondition(), kterou využijeme v případě, když budeme chtít exportovat pouze některé tabulky nebo jejich části.
private function downloadHeaders($file_size, $file_type, $file_name) {
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private", false);
header("Content-Transfer-Encoding: binary");
header("Content-Type: ".$file_type);
header("Content-Length: ".$file_size);
header("Content-Disposition: attachment; filename=".$file_name);
}
/**
* používáno na několika místech v záloze
* zápis do souboru
* @param string $file_name
* @param string $content
* @return null abych si automaticky vynulloval proměnnou
**/
private function writeToFile($file_name, $content) {
$file = fopen($file_name, 'a');
fwrite($file, $content);
fclose($file);
return null;
}
public function addExportCondition($table, $where = null) {
$this->exportConditions[$table] = $where;
}
Nyní už se můžeme pustit do exportu. Funkci uvedu pouze jednu, metodu Db::dumpAndSave() - tu složitější. Tělo pouze kopíruje úvodní vzor, přidaná je podmínka na kontrolu nastavení exportu (konkrétní tabulky a vnitřní podmínky).
public function dumpAndSave() {
$limit = 5000000;
$this->prepareBackupInfo();
$file_name = $this->backupFolder.$this->database.'_'.$this->backupInfo['date_pattern'].'.sql';
if ($this->backupFolder && !is_dir($this->backupFolder)) {
mkdir($this->backupFolder, '0777');
}
$_tables = array();
$_select = $this->query('SHOW TABLES');
while ($t = $_select->fetch(FETCH_ROW)) {
$_tables[] = $t[0];
}
unset($_select);
$_output = null;
$_output = "--\n-- Database: `".$this->database."`\n--\n\n-- --------------------------------------------------------\n\n";
$_output = $this->writeToFile($file_name, $_output);
// záloha po jedné tabulce
foreach ($_tables as $value) {
if (!count($this->exportConditions) || (count($this->exportConditions) && isset($this->exportConditions[$value]))) {
// show create table
$_select_ct = $this->query("SHOW CREATE TABLE `{$value}`");
$_row = $_select_ct->fetch(FETCH_ROW);
// ukládame do souboru show create table
$_output = null;
$_output .= "--\n";
$_output .= "-- `".$_row[0]."`\n";
$_output .= "--\n\n";
$_output .= $_row[1]." ;\n\n";
$_output = $this->writeToFile($file_name, $_output);
unset($_select_ct);
++$this->backupInfo['queries'];
if (isset($this->exportConditions[$value])) {
$_select = $this->query("SELECT * FROM `{$value}` {$this->exportConditions[$value]}");
} else {
$_select = $this->query("SELECT * FROM `{$value}`");
}
while ($t = $_select->fetch(FETCH_ROW)) {
foreach ($t as $k => $i) {
$t[$k] = "'".$this->escape($i)."'";
}
$_output .= "INSERT INTO `{$value}` VALUES (".implode(',', $t).");\n";
++$this->backupInfo['queries'];
// co 5 mega, to zápis do souboru a vynulování proměnné. abych neshazoval server
if (strlen($_output) > $limit) {
$_output = $this->writeToFile($file_name, $_output);
++$this->backupInfo['written'];
}
}
unset($_select);
// pokud tu jsou nějaké resty. zbavime se jich. tady už těch 5 mega fakt testovat nebudu a rovnou to zapíšu
if ($_output) {
$_output = $this->writeToFile($file_name, $_output);
++$this->backupInfo['written'];
}
}
}
$_output .= $this->appendBackupInfo();
$_output = $this->writeToFile($file_name, $_output);
}
Aplikace metod bude opět naprosto triviální. Zakomentované řádky nastaví, že se exportuje celá tabulka s kategoriemi a tabulka s produkty zařazenými do kategorie 1, 2 nebo 3.
$db = new Db;
// $db->addExportCondition('shop_categories', '');
// $db->addExportCondition('shop_products', 'WHERE category_id IN (1,2,3)');
$db->dumpAndSave();
Znění druhé funkce si většina z vás jistě domyslí. Ostatní si budou muset počkat na zveřejnění zdrojového kódu, které je naplánováno na šestý díl. Příště si povíme něco o logování změn.
Související články |
Tematické okruhy |





Filip
1/4 Pátek 12. Listopadu 2010, 19:59 | Google Chrome, Windows XP
Na komentář reagovali: @Mike ↓ Reaguj ↓
Mike
2/4 Sobota 13. Listopadu 2010, 18:27 | Opera 10.63, Windows XP
Reaguj ↓
Vladimir Kasik
3/4 Pátek 7. Ledna 2011, 15:11 | Firefox 3.6.13, Windows Vista
Na komentář reagovali: @Mike ↓ Reaguj ↓
Mike
4/4 Pondělí 10. Ledna 2011, 23:38 | Opera 11.00, Windows XP
Reaguj ↓