Fazer o backup do banco de dados é uma tarefa essencial para recuperar o sistema após um crash de hardware, ataque hacker, invasão alienígena etc...
Pensando nisso estou colocando nas minhas aplicações um botão de backup para que o usuário final possa fazer ele mesmo um backup do banco de dados e salvar em um Pendrive, mandar por e-mail para ele mesmo, ou mandar imprimir em formulário contínuo pra ver se chega na lua, sei lá.
Procurei um bom tanto na internet não achei algo que fosse 100% o que eu queria mas achei algo próximo que me ajudou a lot em http://www.devmedia.com.br/post-3925-Fazendo-backup-de-Mysql-atraves-de-PHP.html
Problema: se um usuário colocasse uma string com um ' no meio, ele fecha a string do sql que usa ' para delimitar a string.
Para isso escapamos as single-quotes ou aspas simples ' com um backslash ou barra invertida \ antes.
Um erro parecido acontece se no banco houver uma string que termina com backslash, pois isso anularia a single quote que fecha a string, então antes de backslash, deve-se colocar outro backslash.
Sem entrar em maiores detalhes sobre ordem dos fatores fiz uma outra adção para quem usa UTF-8 e quer validar os caracteres, erros com importações mal feitas podem ocasionar alguns erros na geração do script esse $checkUtf, se true remove caracteres que não sejam UTF-8 evitando esse pau.
Segue o código, com certeza aceito comentários e sugestões de melhoria.
<?php
// código baseado em http://www.devmedia.com.br/post-3925-Fazendo-backup-de-Mysql-atraves-de-PHP.html
// com melhorias dos comentários do mesmo post
// com adicional de escape string por Marcos Fedato marcosfedato.blogspot.com.br
// com checagem de caracteres UTF-8 por http://stackoverflow.com/questions/1401317/remove-non-utf8-characters-from-string
$usuario = "user";
$senha = "123";
$dbname = "mydb";
// use true se quiser remover caracteres que não sejam utf-8
$checkUtf = false;
// conectando ao banco
mysql_connect("localhost", $usuario, $senha) or die(mysql_error());
mysql_select_db($dbname) or die(mysql_error());
// gerando um arquivo sql. Como?
// a função fopen, abre um arquivo, que no meu caso, será chamado como: nomedobanco.sql
// note que eu estou concatenando dinamicamente o nome do banco com a extensão .sql.
$back = fopen($dbname . ".sql", "w");
// aqui, listo todas as tabelas daquele banco selecionado acima
$res = mysql_list_tables($dbname) or die(mysql_error());
// ultra importante para não dar erro nos primeiros inserts
// principalmente de usar InnoDB e relacionar as tabelas
fwrite($back, "set foreign_key_checks=0;\n\n");
// regex para ver se o char é UTF-8
// Link: http://stackoverflow.com/questions/1401317/remove-non-utf8-characters-from-string
$regex1 = <<<'END'
/
( [\x00-\x7F] # single-byte sequences 0xxxxxxx
| [\xC0-\xDF][\x80-\xBF] # double-byte sequences 110xxxxx 10xxxxxx
| [\xE0-\xEF][\x80-\xBF]{2} # triple-byte sequences 1110xxxx 10xxxxxx * 2
| [\xF0-\xF7][\x80-\xBF]{3} # quadruple-byte sequence 11110xxx 10xxxxxx * 3
)
| . # anything else
/x
END;
// resgato cada uma das tabelas, num loop
while ($row = mysql_fetch_row($res))
{
$table = $row[0];
// usando a função SHOW CREATE TABLE do mysql, exibo as funções de criação da tabela,
// exportando também isso, para nosso arquivo de backup
$res2 = mysql_query("SHOW CREATE TABLE $table");
// digo que o comando acima deve ser feito em cada uma das tabelas
while ($lin = mysql_fetch_row($res2)) {
// instruções que serão gravadas no arquivo de backup
fwrite($back, "\n#\n# Criação da Tabela : $table\n#\n\n");
fwrite($back, "$lin[1] ;\n\n#\n# Dados a serem incluídos na tabela\n#\n\n");
// seleciono todos os dados de cada tabela pega no while acima
// e depois gravo no arquivo .sql, usando comandos de insert
$res3 = mysql_query("SELECT * FROM $table");
$first = true;
while ($r = mysql_fetch_row($res3))
{
if ($first)
{
$sql = "INSERT INTO $table VALUES ";
$first = false;
}
else
{
$sql .= ',';
}
$sql .= "('";
$imploded = '';
$firstImplode = true;
foreach ($r as $reg)
{
if ($firstImplode)
{
$firstImplode = false;
}
else
{
$imploded .= "', '";
}
if ($checkUtf)
{
$escaped = str_replace('\'', "\\'", str_replace('\\', "\\\\", preg_replace($regex1, '$1', $reg)));
}
else
{
$escaped = str_replace('\'', "\\'", str_replace('\\', "\\\\", $reg));
}
$imploded .= $escaped;
}
$sql .= $imploded;
$sql .= "')\n";
}
if (!$first)
{
$sql .= ";\n";
fwrite($back, $sql);
}
}
}
// fechar o arquivo que foi gravado
fclose($back);
// gerando o arquivo para download, com o nome do banco e extensão sql.
$arquivo = $dbname . ".sql";
Header("Content-type: application/sql");
Header("Content-Disposition: attachment; filename=$arquivo");
// lê e exibe o conteúdo do arquivo gerado
readfile($arquivo);
?>
Blog que trata de assuntos relacionados ao dia-a-dia do desenvolvimento de sistemas, como melhores práticas de programação, testes, frameworks e assuntos relacionados
Mostrando postagens com marcador php. Mostrar todas as postagens
Mostrando postagens com marcador php. Mostrar todas as postagens
segunda-feira, 19 de setembro de 2011
quarta-feira, 31 de agosto de 2011
Desenvolvimento PHP no mundo real
Esse post tem o objetivo de mostrar o dia-a-dia de um desenvolvedor com uma nova línguagem e amedrontar os estudantes e possíveis estudantes na área de sistemas.
Veja a lista de problemas que tivemos na Evodata em um único projeto PHP.
Instalamos o WAMP, baixamos o NetBeans 7 (muito bom pra PHP e Javascript, integra legal com o jQuery), as bibilhotecas jQuery, jQuery UI e beleza.
Fizemos as primeiras telas do sistema, apresentamos ao cliente, ele gostou e pediu para colocarmos em um servidor dele para ele poder apresentar ao cliente dele.
Descobrimos primeiro que o servidor utilizado pelo nosso cliente estava configurado com opções não recomendadas, o pior foi o bendito REGISTER_GLOBALS, ele mistura variáveis globais com os atributos da SESSION os parametros GET e POST do PHP.
Explicando melhor o problema 1)
A sessão tinha uma variavel idioma (que grava o id do idioma do usuário logado), quando um usuário admin cadastrava um usuário (que tinha um campo idioma que era enviado via post no formulário) o idioma da sessão se tornava o idioma do usuário recém cadastrado.
Resolver é fácil, desligue o REGISTER_GLOBALS, mas o cliente tinha uma hospedagem windows na locaweb e ele usa outros sistemas em ASP e ASP.net (a locaweb não deixa desligar o REGISTER_GLOBALS na hospedagem windows)
Com a fase inicial funcionando, passamos as novas funcionalidades do sistema, fizemos testamos e apresentamos ao cliente.
Ele novamente aprovou, e fomos subir no servidor dele novamente e adivinhe, a versão do PHP do servidor era bem antiga e não suportava comandos como o __DIR__ que haviamos usado.
Como o cliente queria muito o sistema dele no ar ele decidiu por comprar um serviço de cloud server na propria locaweb.
Ele veio com um linux beeem estranho, e foi um parto conseguir instalar todos os pacotes nele, por sorte essa parte de infra-estrutura era por parte do cliente, mas o TI dele passou alguns dias até deixar o ambiente ok.
Até que enfim subimos o sistema no servidor novo e adivinhem! Novo problema, as tabelas estavam com nome minusculo mas nossas SQL's estavam referenciando elas em upcase.
No windows isso não faz diferença (da para configurar para ser case-sensitive, mas não é o padrão), já no Linux o padrão é case-sensitive.
Alteramos todos os nomes de todas as 60 tabelas do sistema para upcase e sistema rodando.
Como antes de PHP desenvolviamos em Java, estavamos acostumados a usar parametros com placeholders como o "?", usado pelo JDBC, nossa sorte é que o PDO tem um esquema similar e usamos isto em todas as funções de banco.
Isso além de deixar as coisas um pouco mais separadas, ajuda a proteger o sistema contra SQL-Injection, então esse foi um ponto muito positivo.
Desde o começo do projeto tivemos dúvidas sobre segurança, sabiamos que usando os bindParam e bindValue estavamos protegidos contra SQL-Injection, mas isso é tudo?
Foi ai que nos deparamos com o XSS, pesquisamos e testamos várias técnicas de combate ao XSS e achamos a função htmlspecialchars(), que transforma as tags como <> em < e > e o
Isso faz com que se alguem tentar colocar um código javascript dentro de um form do seu sistema, ele será escapado e mostrado como texto.
E depois veio roubo de id da sessão e por assim vai...
Fato é, você só aprende a desenvolver desenvolvendo.
Veja a lista de problemas que tivemos na Evodata em um único projeto PHP.
Instalamos o WAMP, baixamos o NetBeans 7 (muito bom pra PHP e Javascript, integra legal com o jQuery), as bibilhotecas jQuery, jQuery UI e beleza.
Fizemos as primeiras telas do sistema, apresentamos ao cliente, ele gostou e pediu para colocarmos em um servidor dele para ele poder apresentar ao cliente dele.
Descobrimos primeiro que o servidor utilizado pelo nosso cliente estava configurado com opções não recomendadas, o pior foi o bendito REGISTER_GLOBALS, ele mistura variáveis globais com os atributos da SESSION os parametros GET e POST do PHP.
Explicando melhor o problema 1)
A sessão tinha uma variavel idioma (que grava o id do idioma do usuário logado), quando um usuário admin cadastrava um usuário (que tinha um campo idioma que era enviado via post no formulário) o idioma da sessão se tornava o idioma do usuário recém cadastrado.
Resolver é fácil, desligue o REGISTER_GLOBALS, mas o cliente tinha uma hospedagem windows na locaweb e ele usa outros sistemas em ASP e ASP.net (a locaweb não deixa desligar o REGISTER_GLOBALS na hospedagem windows)
Com a fase inicial funcionando, passamos as novas funcionalidades do sistema, fizemos testamos e apresentamos ao cliente.
Ele novamente aprovou, e fomos subir no servidor dele novamente e adivinhe, a versão do PHP do servidor era bem antiga e não suportava comandos como o __DIR__ que haviamos usado.
Como o cliente queria muito o sistema dele no ar ele decidiu por comprar um serviço de cloud server na propria locaweb.
Ele veio com um linux beeem estranho, e foi um parto conseguir instalar todos os pacotes nele, por sorte essa parte de infra-estrutura era por parte do cliente, mas o TI dele passou alguns dias até deixar o ambiente ok.
Até que enfim subimos o sistema no servidor novo e adivinhem! Novo problema, as tabelas estavam com nome minusculo mas nossas SQL's estavam referenciando elas em upcase.
No windows isso não faz diferença (da para configurar para ser case-sensitive, mas não é o padrão), já no Linux o padrão é case-sensitive.
Alteramos todos os nomes de todas as 60 tabelas do sistema para upcase e sistema rodando.
Como antes de PHP desenvolviamos em Java, estavamos acostumados a usar parametros com placeholders como o "?", usado pelo JDBC, nossa sorte é que o PDO tem um esquema similar e usamos isto em todas as funções de banco.
Isso além de deixar as coisas um pouco mais separadas, ajuda a proteger o sistema contra SQL-Injection, então esse foi um ponto muito positivo.
Desde o começo do projeto tivemos dúvidas sobre segurança, sabiamos que usando os bindParam e bindValue estavamos protegidos contra SQL-Injection, mas isso é tudo?
Foi ai que nos deparamos com o XSS, pesquisamos e testamos várias técnicas de combate ao XSS e achamos a função htmlspecialchars(), que transforma as tags como <> em < e > e o
Isso faz com que se alguem tentar colocar um código javascript dentro de um form do seu sistema, ele será escapado e mostrado como texto.
E depois veio roubo de id da sessão e por assim vai...
Fato é, você só aprende a desenvolver desenvolvendo.
Assinar:
Postagens (Atom)