Armazenar arquivos em modo binário no MySQL usando PHP

Posted by Bento | Posted in Artigos, Banco de Dados, MySQL, PHP | Posted on 13-09-2009-05-2008

26

Olá pessoal, neste artigo vou mostrar como armazenar arquivos em modo binário no MySQL usando o PHP, e como recuperar estes arquivos para usá-los depois.

No banco de dados(MySQL) usaremos o campo do tipo BLOB é utilizado para armazenar arquivos binários e são dividivo em 4 tipos; TINYBLOB, BLOB, MEDIUMBLOB e LONGBLOB, a diferença é a capacidade de armazenar os dados.
Lembrando que podemos usar colunas do tipo TEXT para armazenar informações binarias também, abaixo a comparação.

-TINYBLOB, TINYTEXT – tamanho máximo de 255 – 256 Bytes

-BLOB, TEXT – tamanho máximo de 65535 – 64KB

-MEDIUMBLOB, MEDIUMTEXT – tamanho máximo de 16777215 – 16 MB

-LONGBLOB, LONGTEXT – tamanho máximo de 4294967295 – 4 GB

Observação:
-Na maioria dos servidores de hospedagem compartilhada o tipo LONGBLOB é configurada para suportar entre 50MB a 200 MB para manter o bom funcionamento do servidor.
-E que você deve analisar a real necessidade de armazenar o arquivo dentro do banco, pois isto faria sua base ficar gigante, e na maioria dos casos é gravado somente a URL(caminho do arquivo) no banco.

você poderá ler mais sobre especificaçõe de colunas do MySQL no link:
http://dev.mysql.com/doc/refman/4.1/pt/column-types.html

1° – Passo

O primeiro passo é criarmos o banco de dados e a tabela para armazenar nossos arquivos;
no exemplo o banco será chamado binario

CREATE DATABASE binario;

Agora crie uma tabela com o nome arquivos seguindo a estrutura abaixo;

CREATE TABLE `binario`.`arquivos` (
`Codigo` INT( 10 ) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT 'Codigo',
`NmArquivo` VARCHAR( 150 ) NOT NULL COMMENT 'nome original',
`Descricao` VARCHAR( 200 ) NULL COMMENT 'descrição do arquivo',
`Arquivo` MEDIUMBLOB NOT NULL COMMENT 'dados do arquivo',
`Tipo` VARCHAR( 15 ) NOT NULL COMMENT 'Tipo do arquivo, jpeg, doc, mp3, etc..',
`Tamanho` INT NOT NULL COMMENT 'Tamanho em bytes',
`DtHrEnvio` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Data e Hora de envio'
) ENGINE = MYISAM ;
 
/*
Claro que você deve implementar a tabela conforme a necessidade do seu projeto.
*/

2° – Passo

O proximo passo é criar um formulário HTML, para fazermos UPLOAD do arquivo que será gravado.
Não vou entrar em detalhes dos comandos HTML.

<pre escaped=”true” lang=”html” line=”1″>
form id=”upload” action=”upload_binario.php” enctype=”multipart/form-data” method=”post”

<label>
<input id=”file” name=”file” type=”file” />
</label>

<input id=”enviar” name=”enviar” type=”submit” value=”Enviar arquivo…” />
/form

</pre>

3° – Passo

Este é o ultimo passo para envio do arquivo para o banco de dados.
Antes de prosseguir crie um arquivo para conexao com o banco de dados.

//conexao.inc.php
$conexao = mysql_connect("localhost","root","password");
 mysql_select_db("binario");

Crie um arquivo chamado upload_binario.php

require_once('conexao.inc.php');
 
//recupera os dados enviados atraves do formulário
//NOME TEMPORÁRIO
$file_tmp = $_FILES["file"]["tmp_name"];
 //NOME DO ARQUIVO NO COMPUTADOR
$file_name = $_FILES["file"]["name"];
//TAMANHO DO ARQUIVO
$file_size = $_FILES["file"]["size"];
//MIME DO ARQUIVO
$file_type = $_FILES["file"]["type"];
 
//antes de ler o conteudo do arquivo você pode fazer upload para compactar em .ZIP ou .RAR, no caso de imagem você poderá redimensionar o tamanho antes de gravar no banco. Claro que depende da sua necessidade.
 
//Para fazer UPLOAD poderá usar COPY ou MOVE_UPLOADED_FILE
//copy($file_tmp, "caminho/pasta/$file_name");
//move_uploaded_file($file_tmp,"caminho/pasta/$file_name");
 
//lemos o  conteudo do arquivo usando afunção do PHP  file_get_contents
$binario = file_get_contents($file_tmp);
// evitamos erro de sintaxe do MySQL
$binario = mysql_real_escape_string($binario);
 
//montamos o SQL para envio dos dados
$sql = "INSERT INTO `binario`.`arquivos` (`Codigo` ,`NmArquivo` ,`Descricao` , `Arquivo` ,`Tipo` ,`Tamanho` ,`DtHrEnvio`)
VALUES ('NULL', 'foto.jpg', '$file_name', '$binario', '$file_type', '$file_size', CURRENT_TIMESTAMP)";
//executamos a instução SQL
mysql_query("$sql") or die (mysql_error());
?

Exibindo ou baixando o arquivo do banco de dados.
Vamos criar um arquivo chamado listar.php para mostrar todos arquivos gravados em nossa tabela arquivos e o link para visualizar o arquivo.

require_once('conexao.inc.php');
 
$consulta = "SELECT `Codigo`,`NmArquivo`,`Descricao`,`Tipo`,`Tamanho` 	FROM `arquivos`";
$resultado = mysql_query($consulta);
 
while($dados = mysql_fetch_array($resultado)){
$Codigo = $dados['Codigo'];
echo " | Arquivo: " . $dados['NmArquivo'];
echo " | Descriçao:" . $dados['Descricao'];
echo " | Tipo:" . $dados['Tipo'];
echo " | Tamanho:" . $dados['Tamanho']; // você pode fazer divisão por 1024 para mostrar em MB
echo " &gt;&gt; <a href="ver_arquivo.php?codigo=$Codigo" target="_blank">Ver arquivo</a>";
}
 
?

Agora criaremos o arquivo ver_arquivo.php que será responsável por mostrar o arquivo do banco de dados, selecionado

require_once('conexao.inc.php');
 
//recuperar o codigo do arquivo atraves do metodo GET
$codigo= $_GET['codigo'];
 
$consulta = "SELECT `Arquivo`,`Tipo` FROM `arquivos` WHERE Codigo= ' ".$codigo." ' ";
$resultado = mysql_query($consulta);
 
$dados = mysql_fetch_array($resultado);
$tipo = $dados['Tipo'];
$Arquivo = $dados['Arquivo'];
 
   //EXIBE ARQUIVO  - se o navegador não oferecer suporte para a extensão sera solicita dowload do arquivo
   header("Content-type: ".$tipo."");
   echo $Arquivo;
 
?

file_get_contents — Lê todo o conteúdo de um arquivo para uma string
mysql_real_escape_string — Escapa os caracteres especiais numa string para usar em um comando SQL, levando em conta o
copy — Copia arquivo
move_uploaded_file — Move um arquivo enviado para uma nova localização

Download – banco
binario.sql

Pessoal basicamente é isto, um script que poderá ser usado de várias maneiras e melhorado por você conforme sua necessidade.

Comments posted (26)

Ótimo tutorial, amigo me será bem util.

Valeu pelo apoio Talles =))

Fabiano, voce poderia postar um exemplo pratico funcional?

Marcos, gostaria de saber qual é sua dúvida, pois é o exemplo acima já está bem detalhado.

Marcos, quando o navegador n tem suporte ele n esta baixando o arquivo, ele esta baixando o binário do arquivo

Para arquivos com mais de 2 MB estou tendo problemas para salvar no banco de dados:

Warning: file_get_contents() [function.file-get-contents]: Filename cannot be empty in C:wampwwwtesteupload_binario.php on line 23

o meu também está acontecendo isso, mas com arquvos com mais de 7.0MB :/

Matheus,
Este erro, ocorreu porque não foi enviado nenhum arquivo pelo formulário.
Caso o erro persista, faça um teste usando um arquivo que não tenha espaços em branco no nome ou algum tipo de acentuação ou caractere especial.

Faça dois testes primeiro, acrescente na primeira linha do arquivo de upload o comando abaixo;

set_time_limit(0);

caso ainda não funcione, altere as configurações do mysql.
Localize o arquivo de configuração do mysql my.ini

e altere as linhas de configuração;
key_buffer = 384M
max_allowed_packet = 64M
table_cache = 4096
sort_buffer_size = 2M
read_buffer_size = 2M
read_rnd_buffer_size = 64M
myisam_sort_buffer_size = 64M

Cara, o script funcionou perfeitamente. 😉
Mas tive um probleminha, quanto faço upload de arquivo com tamanho acima de 1 mb ele da o seguinte erro:

====================================
Warning: mysql_query(): MySQL server has gone away in C:Program Files (x86)EasyPHP-12.1wwwenviar_recuperar_arq_dbupload_binario.php on line 29

Warning: mysql_query(): Error reading result set’s header in C:Program Files (x86)EasyPHP-12.1wwwenviar_recuperar_arq_dbupload_binario.php on line 29
MySQL server has gone away
===================================

Tem como vc me dizer o q tem de errado?

Rapaz esse comandinho mysql_real_scape_string foi o que deu certo aqui e seu post é o único que realmente funciona e grava arquivo no bd mysql.

Parabéns! Abraço

Muito bom e simples, obrigado amigo.

Boa noite, consigo gravar 2 imagens no bd mysql

onde uma é foto1 longblob e a segunda foto2 longblob

Quando vou pegar essas imagens, só me retorna a primeira no meu while, mais se eu coloco a segunda no local da primeira ela apareceex:

while($row = mysql_fetch_array($query)){

header(“content-type: image/jpg”);

echo $row = $row[‘foto1’]; so exibe essa imagem
echo $row = $row[‘foto2’]; se eu coloco esse echo primeiro ele é que aparece e o 1 não

}

Claudio, você precisa usar algo como

E no arquivo foto.php recuperar essa informação GET, e buscar o arquivo no banco.

Bento, obrigado pelo post, parabéns, foi muito útil para mim.
Ele envia todos os arquivos para o bd mas dá este erro. Será que vc poderia dar uma dica para sumir com este erro:
( ! ) Warning: file_get_contents(C:\wamp\tmp\phpC8DE.tmp) [function.file-get-contents]: failed to open stream: No such file or directory in C:\wamp\www\cpc\uploadbd2.php on line 165
Call Stack
# Time Memory Function Location
1 0.0006 693560 {main}( ) ..\uploadbd2.php:0
2 1.0129 707056 file_get_contents ( ) ..\uploadbd2.php:165

Estas são as linhas que dão o erro:

$diretorio = ‘/wamp/www/cpc/uploads/’;
move_uploaded_file($file_tmp,$diretorio.$file_name);

//lemos o conteudo do arquivo usando afunção do PHP file_get_contents
$binario = file_get_contents($file_tmp);

Milton,
O erro é devido o script não encontrar o arquivo no diretório.
Tente informar o caminho absoluto (Windows: c:\pasta | Linux: \home\user\pasta) ou apenas o nome do diretório na variável $diretório.

Esse é o cara ! funcionou. Obrigado.

Muito bom seu script, eu já tinha um que fazia o upload e zipava, mas agora estou querendo inserir o arquivo zipado no banco e não estou conseguindo, poderia fazer um exemplo zipando e inserindo no banco?
Grato.

Excelente tutorial, e como eu posso estar lendo os dados gravados no banco e gerando todo conteudo em um único arquivo PDF? tem como?

Junior, pelo que entendi você quer gravar os arquivos em uma extensão talvez JPG e depois gerar um arquivo PDF com todas as imagens. Par isto seria necessário converter o arquivo para a extensão PDF antes de gravar no banco, depois seria apenas necessário exibir.

Não necessariamente, existem já ferramentas prontas que faz a conversão jpg para pdf, a maior dificuldade seria agrupar todas imagens.. mas com certeza tem algo por ai pronto também!

Ao clicar em ver arquivo, ele abre outra página mas não carrega a foto.

Renan no exemplo tem o comando target=”_blank”, do HTML que é para abrir nova página, se não está carregando a imagem oriento que veja o arquivo de conexão com o banco e confirme se realmente a imagem foi salva no banco de dados.

Muito obrigado, deu certo. Mas tenho um problema com certas extensoes de arquivo. Imagens e pdf abriram normalmente, mas arquivo tipo doc ele tenta baixar e baixa um arquivo “ver_arquivo.php” e nao é acessivel.

Edy, faz uma chamada para o link target=”_blank”

Write a comment