|
Gravando Arquivos Binários no PostgreSQL
por Eduardo Lundgren (braeker)
O armazenamento de arquivos em banco de dados possui vantagens em relação à organização já que tudo estaria armazenado no banco. A integridade e segurança também estariam sendo garantidas pelo SGBD, porém existem as desvantagens. Confira neste artigo quando dou todos os detalhes de como gravar
|
O armazenamento de arquivos em banco de dados Objeto-Relacional possui vantagens em relação à organização já que tudo estaria armazenado no banco. A integridade e segurança também estariam sendo garantidas pelo SGBD, porém existem as desvantagens. É o caso de precisar do seu código para visualização do arquivo. Caso você tenha armazenado uma imagem no banco, para visualizar você teria que utilizar um script que permitisse a interpretação do binário no browser, por exemplo.
Imagine um site que possui arquivos restritos a certo grupo de usuários. Se estes arquivos estivessem armazenados diretamente no HD do servidor juntamente com os códigos html e php, você poderia utilizar um cliente FTP ou até mesmo a barra de endereço do browser para ter acesso a eles, isso se você conhecer o diretório onde os documentos se encontram. Porém com os arquivos armazenados no Banco isso não seria possível, pois o usuário precisaria de um script que acessasse a base de dados e lhe fornecesse o binário deste arquivo.
Vou utilizar no exemplo o banco de dados PostgreSQL por ser um banco Objeto-Relacional, além de ser o mais avançado banco de dados de código livre disponível.
Existem algumas maneiras de inserir códigos binários de arquivos em banco de dados não relacionais. No MySQL uma solução é o campo BLOB (Binary Large Object), porém você tem que utilizar alguns artifícios para o armazenamento. Há caracteres que são “rejeitados” por esse tipo de campo, se for inserido o binário sem que esses caracteres sejam escapados, provavelmente a integridade do arquivo será afetada.
Uma solução encontrada por mim, não sei se é a mais correta, mas foi converter pra uma tabela de criptografia mais simples, como a Base64, que transforma qualquer caractere de 8 bits num sub-grupo de 6 bits presentes na maioria das tabelas de codificação. Isso reduz a quantidade de caracteres possíveis para [A-za-z0-9+/=] que é facilmente entendido pelo campo BLOB, mas o arquivo fica salvo com um tamanho 33% maior do que numa tabela normal de 8-bits.
[Nota do Editor: O comando correto para se usar com o MySQL é o addslashes()]
No PostgreSQL também é possível usar um campo semelhante ao BLOB o ByteA. A vantagem em relação ao uso do MySQL é que para o postgresql o php possui uma função chamada pg_escape_bytea(), esta função exige PostgreSQL 7.2 ou superior, que retorna valores de byte octais prefixados por \ (ex.: \032). Os usuários devem converter de volta para binários quando quiserem recuperar os dados com o comando pg_unescape_bytea(). Desconheço se o MySQL possui um comando semelhando a este.
Vamos agora mostrar a maneira de se armazenar arquivos como objetos relacionais no PostgreSQL.
Como inserir a imagem no banco?
Imagine um Banco com a seguinte estrutura:
Tabela arquivo:
- nome_foto (Campo String)
- foto_oid (Campo OID)
O raciocínio básico de como inserir uma imagem no banco de dados é bastante simples. Primeiro você tem que abrir uma conexão com o banco de dados, em seguida dizer à essa conexão que será criado um objeto nela. É nesse objeto que será inserido os dados binários do arquivo. Na tabela “arquivo” serão inseridos apenas o nome da foto como string e a referencia ao objeto, esta referencia nada mais é do que um número identificador que aponta para objeto.
O código PHP abaixo explica passo a passo.
<?php
// Conectando ao Banco de Dados
$conexao = pg_connect("host=localhost port=5432 user=postgres dbname=teste");
// Abrindo o arquivo em modo de leitura e carregando o
// binário em uma variável, no Windows é necessário abrir
// com o modo "rb" no linux só precisa do modo "r".
$arquivo = fopen("imagem.jpeg","rb");
$dados = fread($arquivo,filesize("imagem.jpeg"));
fclose($arquivo);
// Note que será feita uma Transação ACID
// (Atômica, Consistente, Isolada e Durável) com o banco,
// ou seja, tudo ou nada. Uma transação inicia-se com uma
// Query passando o comando BEGIN e finaliza-se com
// um comando COMMIT.
// Iniciando Transação com o banco
pg_query($conexao, "BEGIN");
// Agora tem que dizer pra conexão aberta ($conexao) que
// será criado um objeto nela e referenciado pra uma
// variável chamada de $oid, ou seja, a variavel $oid
// recebe apenas um numero que é o caminho para o
// objeto. (Ex: $oid = 12345;)
// Criando o Objeto na conexao $conexao.
$oid = pg_lo_create($conexao);
// O que será inserido no campo "foto" do banco não é o
// binário do arquivo e sim a referencia para o objeto.
// Imagine que o objeto foi criado na seção 12345 do
// engenho interno. Só será salvo no campo apenas o
// numero 12345 que referencia o objeto.
// Inserindo referencia ($oid) do arquivo no banco.
pg_query($conexao,"INSERT INTO arquivo (nome_foto,foto_oid) values('imagem.jpeg',$oid)");
// Agora o objeto tem que ser aberto com o modo de
// escrita para poder ser inserido os dados binarios
// do mesmo, que foi carregado usando-se um fread().
// Abrindo o objeto
$objeto = pg_lo_open($conexao,$oid,"w");
// Inserindo Dados no arquivo
pg_lo_write($objeto,$dados);
// Fechando a conexao com o objeto
pg_lo_close($objeto);
// Finalizando Transação
pg_query($conexao, "COMMIT");
?>
|
Como visuazar a imagem ou arquivo?
O código comentado segue abaixo.
<?php
// Conectando ao Banco de Dados
$conexao = pg_connect("host=localhost port=5432 user=postgres dbname=teste");
// Pegando informações sobre a imagem que foi salva no banco
// Esta consulta não retornará o dado binário da imagem
// juntamente com outras informações da tabela, mas sim
// a referencia (o identificador) do objeto. Imagine que
// o código da imagem na tabela seja 7.
$consulta = pg_query($conexao,"SELECT * FROM arquivo where codigo=7");
$resultado = pg_fetch_array($consulta);
// Seta o identificador do objeto que veio do campo foto no banco.
$identificador = $resultado["foto_oid"];
// Iniciando Transação para carregar o arquivo
pg_query($conexao, "BEGIN");
// Abrindo o objeto no modo leitura "r" passando como
// parâmetro o OID, ou seja, o identificador do objeto.
$objeto = pg_lo_open($conexao,$identificador,"r");
// Setando Cabeçalho do browser para interpretar que o
// binário que será carregado é de uma foto do tipo JPEG.
header("Content-Type: image/jpeg");
// Lendo binário da foto passando como referencia a
// conexão com o objeto ($objeto).
pg_lo_read_all($objeto);
// Fechando Objeto que foi aberto para leitura
pg_lo_close($objeto);
// Finalizando Transação
pg_query($conexao, "COMMIT");
?>
|
Como deletar o objeto?
O código comentado segue abaixo.
<?php
// Conectando ao Banco de Dados
$conexao = pg_connect("host=localhost port=5432 user=postgres dbname=teste");
// Pegando informações sobre a imagem que foi salva no banco
// Esta consulta não retornará o dado binário da imagem
// juntamente com outras informações da tabela, mas sim a
// referencia (o identificador) do objeto. Imagine que o
// código da imagem na tabela seja 7.
$consulta = pg_query($conexao,"SELECT * FROM arquivo where codigo=7");
$resultado = pg_fetch_array($consulta);
// Seta o identificador (oid) do objeto que veio do campo foto no banco.
$identificador = $resultado["foto_oid"];
// Iniciando Transação para deletar o arquivo
pg_query($conexao, "BEGIN");
// Quando você deletar o registro da tabela, se ela possuir
// um campo oid o objeto relacionado a ela será apagado
// simultaneamente, não precisando dar o pg_lo_unlink();
// Deletando registro da tabela
pg_query(“delete from arquivo where codigo=7”);
// Finalizando transação
pg_query($conexao, "COMMIT");
// Fechando o objeto
pg_lo_close($objeto);
// Fechando conexão
pg_close();
?>
|
Obs: Caso você deseje apagar diretamente o objeto use o pg_lo_unlink(), porém se torna desnecessário porque ao apagar o registro da tabela o objeto também é apagado.
// Deletando objeto. Passe como parâmetro a conexão e o identificador (oid) do objeto:
<?php
pg_lo_unlink ($conexao, $identificador);
?>
|
Este é o primeiro artigo da minha vida e tentei ser o mais claro possível. Espero que tenham gostado! Qualquer duvida, chingamento ou sugestão enviem um comentário abaixo!
Abraços,
Eduardo Lundgren
|
|
|