Backup zipado automático de toda base MySQL
Na área de sistemas web uma coisa muito importante é o backup da base de dados, afinal um rotina imprópria no sistema pode alterar o banco de dados de forma errada comprometendo a integridade dos dados ou mesmo a consistência das informações. Além disso nenhuma empresa de hospedagem está livre de um problema sério com um servidor que coloque tudo a perder e como muitas não tiram backup podem criar um grande transtorno para o seu cliente.
Nós, da Trio Interativa, desenvolvemos muitos sistemas de gestão de eventos, muitas vezes, durante o processo de inscrições eletrônicas fazemos de três a quatro backup da base do cliente por dia. Além disse, trabalhamos muitas vezes nos sistemas enquanto são utilizados, ou seja, sempre estamos no risco, um código impróprio e podemos mudar tudo na base, então sempre que atualizamos um novo sistema fazemos backup da base também e os outros que normalmente fazemos ao longo do dia nos ajuda na detecção de erros e possíveis inconsistências nos dados.
Com o crescimento do número de clientes e os inúmeros eventos ocorrendo simultaneamente procuramos uma forma de fazer backup de forma rápida, eficiente e que fosse padronizada. Nas muitas pesquisas que fiz achei a uma rotina excelente do Fabio Berbet de Paula, fiz algumas interações no código para padronizá-las para nossa realidade e hoje qualquer profissional da TRIO tem um link para cada cliente, onde com a penas um clique fazemos o backup integral da base em um arquivo ZIP, perfeito e de forma íntegra. Tudo muito fácil e rápido. Veja o código com comentários e as interações que fiz.
Antes de mais nada agradeço ao Fabio Berbet o desenvolvimento do sistema. Para fazer o download do sistema e da classe clique aqui!.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 | <? /* Programa usado para fazer o dump de uma base de dados do MySQL Por: Fabio Berbert de Paula <fabio@vivaolinux.com.br> Rio de Janeiro, 26 de Novembro de 2002 link: http://www.vivaolinux.com.br/script/Backup-do-MySQL-via-PHP Livres Adaptações: Plínio Cruz - Clube da Informática - Inclusão de arquivo padrão de conexão com a base - rotina "Lista de Tabelas" - Padronização do nome do arquivo a ser gravado */ // classe phpzip.inc.php para criar os arquivos compactados require 'phpzip.inc.php'; // variaveis de banco de dados de acordo com o arquivo padrão de conexão $db_name = ''; //Nome do banco de dados $hostdb = ''; //server do banco de dados $userdb = ''; //Usuário de log do banco de dados $passdb = ''; //senha do usuário do banco de dados /////////////////////////////////////////////////////////////////////////////////////////////////// //Vamos montar a litas das tabelas do banco de dados escolhido //Essa rotina foi incluída a original do Fábio, pois antes tínhamos que nomear as tabelas que //queríamos guardar. Com a nova rotina ele faz o backup do banco como um todo, não precisando //atualizar o sistema cada vez que você altera a base de dados /////////////////////////////////////////////////////////////////////////////////////////////////// $nome = $db_name; $link = mysql_connect("$hostdb","$userdb","$passdb"); $resultado_tabelas = mysql_list_tables($nome); $qntd_tabelas = @mysql_numrows($resultado_tabelas); if($qntd_tabelas == 0) { print "<li>Nenhuma tabela foi encontrada neste banco de bados</li>"; die; //Assim "mato" o sistema quando existe um erro } else { //Aqui vamos criar a rotina para montar a listagem de tabelas for ($i = 0; $i < $qntd_tabelas; $i++) { //Temos que determinar as tabelas que não precisam de backup //no meu caso pode ser tabelas como crm, cep, cidade, estado, etc. //No exemplo não faremos backup da "cep" e concatemos as restantes if (mysql_tablename($resultado_tabelas, $i)!='cep') { $tabelas[]= mysql_tablename($resultado_tabelas, $i); }; }; //Temos a array de tabelas pronta }; // as tabelas que quero //$tabelas = array ('artigos','assuntos'); - Original da rotina do Fabio, onde você montava o array manualmente //com as tabelas que desejava, a rotina acima faz automaticamente só isso $tempdir = "/tmp"; // diretorio temporario //$filename = 'sql.'.time().'.txt'; - Modo do Fabio de construir o nome do arquivo $data = date("dmyhi",time()); $filename = 'nomedocliente.'.$data.'.txt'; //Inclui o nome do banco de dados no nome e a data completa //Isso porque trabalho com phpmyadmin e MySqlFront e os dois trabalham com essa extensão //o conteúdo é o mesmo, portanto não fará diferença na hora da gravação //Na minha opinião facilita para aramazenamento de vários clientes na mesma pasta no servidor local // variaveis do sistema $incluir_insert = 1; // imprime os INSERT's tambem // ---------------------------------------------------- // BLOCO PRINCIPAL // conectar ao banco de dados $con = mysql_pconnect($hostdb,$userdb,$passdb); mysql_select_db($db_name); // imprimir tipo do documento na tela // imprimir o dump do banco de dados //chdir($tempdir); $fp = fopen($filename,"w"); for ($x=0; $x<count($tabelas); $x++) { $saida = getTableDef($db_name, $tabelas[$x], "\n"); fputs($fp,$saida."\n\n"); if ($incluir_insert) { getTableContentFast($db_name, $tabelas[$x], '', ''); fputs($fp,"\n\n"); } } fclose($fp); // gerar o arquivo zipado $zipname = ereg_replace("txt$","zip",$filename); $zip = new PHPZip(); $files[]=$filename; $zip -> Zip($files, $zipname); $tamanho = filesize($zipname); // imprimir arquivo p/ download header("Content-Type: application/zip"); header("Content-Length: $tamanho"); header("Content-Disposition: attachment; filename=$zipname"); header("Content-Transfer-Encoding: binary"); // abrir e enviar o arquivo $fp = fopen("$zipname", "r"); fpassthru($fp); fclose($fp); // remover os arquivos temporarios //unlink($filename); unlink($zipname); // FIM DO PROGRAMA // -------------------------------------------------------- // -------------------------------------------------------- // PROCEDIMENTOS - Baseado no csdigo do phpmyadmin function sqlAddslashes($a_string = '', $is_like = FALSE) { if ($is_like) { $a_string = str_replace('\\', '\\\\\\\\', $a_string); } else { $a_string = str_replace('\\', '\\\\', $a_string); } $a_string = str_replace('\'', '\\\'', $a_string); return $a_string; } // end of the 'sqlAddslashes()' function function backquote($a_name, $do_it = TRUE) { if ($do_it && PMA_MYSQL_INT_VERSION >= 32306 && !empty($a_name) && $a_name != '*') { if (is_array($a_name)) { $result = array(); reset($a_name); while(list($key, $val) = each($a_name)) { $result[$key] = '`' . $val . '`'; } return $result; } else { return '`' . $a_name . '`'; } } else { return $a_name; } } // end of the 'backquote()' function /** * Returns $table's CREATE definition * * @param string the database name * @param string the table name * @param string the end of line sequence * * @return string the CREATE statement on success * * @global boolean whether to add 'drop' statements or not * @global boolean whether to use backquotes to allow the use of special * characters in database, table and fields names or not * * @see PMA_htmlFormat() * * @access public */ function getTableDef($db, $table, $crlf) { global $drop; global $use_backquotes; global $con; $schema_create = ''; if (!empty($drop)) { $schema_create .= 'DROP TABLE IF EXISTS ' . backquote($table) . ';' . $crlf; } // For MySQL < 3.23.20 $schema_create .= 'CREATE TABLE ' . backquote($table) . ' (' . $crlf; $local_query = 'SHOW FIELDS FROM ' . backquote($table) . ' FROM ' . backquote($db); $result = mysql_query($local_query,$con); while ($row = mysql_fetch_array($result)) { $schema_create .= ' ' . backquote($row['Field']) . ' ' . $row['Type']; if (isset($row['Default']) && $row['Default'] != '') { $schema_create .= ' DEFAULT \'' . sqlAddslashes($row['Default']) . '\''; } if ($row['Null'] != 'YES') { $schema_create .= ' NOT NULL'; } if ($row['Extra'] != '') { $schema_create .= ' ' . $row['Extra']; } $schema_create .= ',' . $crlf; } // end while mysql_free_result($result); $schema_create = ereg_replace(',' . $crlf . '$', '', $schema_create); $local_query = 'SHOW KEYS FROM ' . backquote($table) . ' FROM ' . backquote($db); $result = mysql_query($local_query,$con); while ($row = mysql_fetch_array($result)) { $kname = $row['Key_name']; $comment = (isset($row['Comment'])) ? $row['Comment'] : ''; $sub_part = (isset($row['Sub_part'])) ? $row['Sub_part'] : ''; if ($kname != 'PRIMARY' && $row['Non_unique'] == 0) { $kname = "UNIQUE|$kname"; } if ($comment == 'FULLTEXT') { $kname = 'FULLTEXT|$kname'; } if (!isset($index[$kname])) { $index[$kname] = array(); } if ($sub_part > 1) { $index[$kname][] = backquote($row['Column_name']) . '(' . $sub_part . ')'; } else { $index[$kname][] = backquote($row['Column_name']); } } // end while mysql_free_result($result); while (list($x, $columns) = @each($index)) { $schema_create .= ',' . $crlf; if ($x == 'PRIMARY') { $schema_create .= ' PRIMARY KEY ('; } else if (substr($x, 0, 6) == 'UNIQUE') { $schema_create .= ' UNIQUE ' . substr($x, 7) . ' ('; } else if (substr($x, 0, 8) == 'FULLTEXT') { $schema_create .= ' FULLTEXT ' . substr($x, 9) . ' ('; } else { $schema_create .= ' KEY ' . $x . ' ('; } $schema_create .= implode($columns, ', ') . ')'; } // end while $schema_create .= $crlf . ');'; return $schema_create; } // end of the 'getTableDef()' function /** * php >= 4.0.5 only : get the content of $table as a series of INSERT * statements. * After every row, a custom callback function $handler gets called. * * Last revision 13 July 2001: Patch for limiting dump size from * vinay@sanisoft.com & girish@sanisoft.com * * @param string the current database name * @param string the current table name * @param string the 'limit' clause to use with the sql query * @param string the name of the handler (function) to use at the end * of every row. This handler must accept one parameter * ($sql_insert) * * @return boolean always true * * @global boolean whether to use backquotes to allow the use of special * characters in database, table and fields names or not * @global integer the number of records * @global integer the current record position * * @access private * * @see PMA_getTableContent() * * @author staybyte */ function getTableContentFast($db, $table, $add_query = '', $handler) { global $use_backquotes; global $rows_cnt; global $current_row; global $con; global $fp; $local_query = 'SELECT * FROM ' . backquote($db) . '.' . backquote($table) . $add_query; $result = mysql_query($local_query,$con); if ($result != FALSE) { $fields_cnt = mysql_num_fields($result); $rows_cnt = mysql_num_rows($result); // Checks whether the field is an integer or not for ($j = 0; $j < $fields_cnt; $j++) { $field_set[$j] = backquote(mysql_field_name($result, $j), $use_backquotes); $type = mysql_field_type($result, $j); if ($type == 'tinyint' || $type == 'smallint' || $type == 'mediumint' || $type == 'int' || $type == 'bigint' ||$type == 'timestamp') { $field_num[$j] = TRUE; } else { $field_num[$j] = FALSE; } } // end for // Sets the scheme if (isset($GLOBALS['showcolumns'])) { $fields = implode(', ', $field_set); $schema_insert = 'INSERT INTO ' . backquote($table) . ' (' . $fields . ') VALUES ('; } else { $schema_insert = 'INSERT INTO ' . backquote($table) . ' VALUES ('; } $search = array("\x00", "\x0a", "\x0d", "\x1a"); //\x08\\x09, not required $replace = array('\0', '\n', '\r', '\Z'); $current_row = 0; @set_time_limit($GLOBALS['cfg']['ExecTimeLimit']); // loic1: send a fake header to bypass browser timeout if data // are bufferized - part 1 if (!empty($GLOBALS['ob_mode']) || (isset($GLOBALS['zip']) || isset($GLOBALS['bzip']) || isset($GLOBALS['gzip']))) { $time0 = time(); } while ($row = mysql_fetch_row($result)) { $current_row++; for ($j = 0; $j < $fields_cnt; $j++) { if (!isset($row[$j])) { $values[] = 'NULL'; } else if ($row[$j] == '0' || $row[$j] != '') { // a number if ($field_num[$j]) { $values[] = $row[$j]; } else { // a string $values[] = "'" . str_replace($search, $replace, sqlAddslashes($row[$j])) . "'"; } } else { $values[] = "''"; } // end if } // end for // Extended inserts case if (isset($GLOBALS['extended_ins'])) { if ($current_row == 1) { $insert_line = $schema_insert . implode(', ', $values) . ');'; } else { $insert_line = '(' . implode(', ', $values) . ');'; } } else { // Other inserts case $insert_line = $schema_insert . implode(', ', $values) . ');'; } unset($values); // Call the handler fputs($fp,$insert_line . "\n"); // loic1: send a fake header to bypass browser timeout if data // are bufferized - part 2 if (isset($time0)) { $time1 = time(); if ($time1 >= $time0 + 30) { $time0 = $time1; header('X-pmaPing: Pong'); } } // end if } // end while } // end if ($result != FALSE) mysql_free_result($result); return TRUE; } // end of the 'getTableContentFast()' function ?> |








