Backup zipado automático de toda base MySQL

Postado por Plinio Cruz em 30 de dezembro de 2009 na categoria Banco de Dados, PHP, Programação | 2 Comments to Read

1 Estrela2 Estrela3 Estrela4 Estrela5 Estrela (Sem votos, vote agora!)
Loading...

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
392
393
<?
/*
Programa usado para fazer o dump de uma base de dados do MySQL
 
<span id="more-1800"></span>
 
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
?>

  • Gerson said,

    Perfeito

  • Marcus Guarani said,

    Bom dia, gostaria de saber se vc tem algo desse tipo para SQL SERVER, pois estou precisando

Deixe seu comentário