Quinta-feira, 14 de maio de 2009 às 09h00

Manipulação de dados BLOB com PHP e MySQL

Faltam 0 dias! Inscreva-se agora! O maior encontro de profissionais web da américa latina.

Sem dúvida alguma, uma das perguntas mais frequentes em relação ao MySQL é: "como posso armazenar arquivos em uma base de dados?". A resposta é: tens que usar o tipo de dados BLOB. Estes BLOBs (Binary Large Objects) podem armazenar praticamente qualquer tipo de dados, incluindo documentos do MS Word, imagens gif/jpeg, arquivos PDF, mp3, etc.

Neste artigo vamos ver como criar um repositório de arquivos binários usando PHP e MySQL para poder armazenar diferentes tipos de arquivos. Veremos como armazenar cada um dos arquivos em uma base de dados, para posteriormente recuperá-los.

Para testar os exemplos deste artigo, é necessário ter acesso a um servidor com suporte a PHP, além de contar com um servidor MySQL. Assumindo que você conte com os privilégios apropriados para criar a base dados, e que o MySQL está rodando no mesmo servidor que o PHP, vamos iniciar o desenvolvimento.

Criando a base de dados

Nosso repositório de documentos usará uma base dados que contenha unicamente uma tabela para armazenar todos os documentos. O banco de dados será chamado de "repositorio", e a tabela de "arquivos".

Código SQL para criar a tabela

CREATE TABLE arquivos( 
id int not null auto_increment primary key,
nome varchar(50),
titulo varchar(50),
conteudo mediumblob,
tipo varchar(50));

Agora temos uma base chamada repositorio, que contém uma tabela chamada arquivos.

Veja abaixo informações sobre cada campo da tabela arquivos:

  • id - um número inteiro que nos proporcionará um identificador único para cada arquivo que iremos armazenar. Este será incrementado automaticamente cada vez que for inserido um novo registro.
  • nome - o nome original do arquivo, por exemplo, fot.gif, curriculum.doc, etc.
  • titulo - uma breve descrição de cada arquivo que será gravada na tabela, por exemplo "Carta para minha noiva", ou "A foto do meu irmão". Este título será usado posteriormente na visualização dos arquivos do repositório em uma página web.
  • conteudo - um campo do tipo binário (blob) para guardar o conteúdo de cada arquivo. Na nossa tabela usamos um tipo mediumblob, o qual pode armazenar arquivos de até 16Mb.
  • ipo - como veremos mais adiante, cada arquivo (seja um .doc, .gif, .pdf, etc) tem um tipo único. Quando se envia um
    arquivo para o servidor web através de uma página web, o navegar envia ao servidor a informação acerca do tipo de arquivo, o tipo de conteúdo do arquivo, etc. Os tipos de conteúdo são simples cadeias. O tipo de conteúdo para um arquivo MS WORD é "application/msword", o tipo de conteúdo para uma imagem é "image/gif", etc.

Agregando arquivos à base de dados

Agora que temos a base de dados do nosso repositório e sabemos a finalidade de cada campo, vamos criar uma simples página web que permita selecionar um arquivo desde o navegador para posteriormente enviá-lo para um script em PHP que ficará encarregado de armazená-lo em nossa base de dados.A página web será nomeada escolher_arquivo.html e o script em PHP será chamado de guardar_arquivo.php.

A página web pode conter todo o código HTML que se deseje, mas é necessário que se inclua o seguinte formulário para que se tenha a opção de escolher um arquivo e enviá-lo ao servidor.

<!-- ...código anterior -->
<form enctype="multipart/form-data" action="guardar_arquivo.php" method="post">
Descrição <input type="text" name="titulo" size="30">
Arquivo <input type="file" name="arquivo">
<input type="submit" value="Enviar arquivo">
</form>
<!-- ...código posterior -->

Do código que escrevemos temos que frisar o seguinte:

  • o formulário necessita de um atributo enctype com um valor multipart/form-data
  • o método de envio tem que ser POST
  • tem que ser usado pelo menos um campo do tipo FILE

Estes são os três requerimentos básicos que a página HTML deve cumprir para que seja possível enviar o arquivo para o servidor.

Antes de escrever o código do script guarda_arquivo.php, vamos comentar algo acerca da forma como serão recebidos os dados do arquivo em questão.

Desde a versão 4.1 do PHP é recomendada a utilização da variável $_FILES para a leitura dos dados do arquivo que está sendo enviado ao servidor. Abaixo estão listadas os índices e parâmetros recebidos pela variável. Note que o nome dos índices depende de como é nomeado o campo do tipo FILE no formulário.

$_FILES['arquivo']['name']

Nome original do arquivo
$_FILES['arquivo']['type']

O tipo MIME do arquivo, ... image/gif, application/pdf, application/msword,.. etc
$_FILES['arquivo']['size']
O tamanho do arquivo em bytes
$_FILES['arquivo']['tmp_name']

O local do arquivo temporário que se cria quando o arquivo é enviado ao servidor. É nesta variável que são lidos todos os dados do arquivo em si. Se estes dados não são copiados ou movidos para outro lugar, ou em nosso caso, armazenados em uma base de dados, podem ser perdidos, já que o PHP elimina esses arquivos depois de um determinado tempo.

Por exemplo, estes são os possíveis valores para um arquivo j-odbc.zip que foi enviado ao servidor:

$_FILES["arquivo"][name] => j-jdbc.zip
$_FILES["arquivo"][type] => application/zip
$_FILES["arquivo"][tmp_name] => /tmp/phpvXQpqP
$_FILES["arquivo"][size] => 337945

Vale ressaltar que devem ser revistos e, se necessário modificar as seguintes variáveis no arquivo de configuração do PHP para que você possa fazer o upload dos arquivos para o servidor, e pode ser gerida por um script PHP.

  • file_uploads - diz ao PHP se pode ou não ser feito o envio de arquivos para o servidor. Essa variável deve ter o valor  "On".
  • upload_max_filesize - diz ao PHP qual o tamanho máximo do arquivo que pode ser enviado ao servidor. Pode ser utilizado o sufixo "M" para indicar o valor em Megabytes, por exemplo, com um valor 2M se aceita um arquivo máximo de 2 Megabytes.
  • upload_tmp_dir - é o diretório para onde será copiado temporariamente o conteúdo do arquivo quando for enviado ao
    servidor.

Agora é o momento de mostrar o código PHP que vai armazenar o arquivo em nossa base de dados.

/* guardar_arquivo.php */

require("dbconnect.inc.php");

$arquiivo = $_FILES["arquivo"]["tmp_name"];
$tamanho = $_FILES["arquivo"]["size"];
$tipo    = $_FILES["arquivo"]["type"];
$nome  = $_FILES["arquivo"]["name"];
$titulo  = $_POST["titulo"];

if ( $arquivo != "none" )
{
$fp = fopen($arquivo, "rb");
$conteudo = fread($fp, $tamanho);
$conteudo = addslashes($conteudo);
fclose($fp);

$qry = "INSERT INTO arquivos VALUES
(0,'$nome','$titulo','$conteudo','$tipo')";

mysql_query($qry);

if(mysql_affected_rows($conn) > 0)
print "O arquivo foi gravado na base de dados.";
else
print "Não foi possível gravar o arquivo na base de dados.";
}
else
print "Não foi possível carregar o arquivo para o servidor.";

O arquivo dbconnetc.inc.php contém unicamente as instruções para conexão ao MySQL e selecionar a base de dados que será utilizada.

/* dbconnect.inc.php */

$conn = mysql_connect("localhost","usuário","senha");
mysql_select_db("repositorio");

Listando os arquivos da base de dados

Já que gravamos alguns arquivos no nosso repositório, agora podemos listar as informações deles, para posteriomente fazermos o download. 

/* listar_arquivos.php */

require("dbconnect.inc.php");

$qry = "SELECT id, nome, titulo, tipo FROM arquivos";
$res = mysql_query($qry);

while($fila = mysql_fetch_array($res))
{
print "$fila[titulo]
<br>
$fila[nome] ($fila[tipo])
<br>
<a href='baixar_arquivo.php?id=$fila[id]'>Fazer Download</a>
<br>
<br>";
}

Fazendo o download dos arquivos da base de dados

Como se pode observar no código anterior, foi colocado um link para cada arquivo, chamado baixar_arquivo.php. A funcionalidade deste script será ler os dados dos arquivos que estão gravados na base de dados e enviá-los ao navegador. 

Dependendo do tipo de arquivo da qual se trate, o navegador poderá mostrá-lo por ele mesmo o conteúdo do arquivo.

/* Script baixar_arquivo.php */

require("dbconnect.inc.php");

$qry = "SELECT tipo, conteudo FROM arquivos WHERE id=$id";
$res = mysql_query($qry);
$tipo = mysql_result($res, 0, "tipo");
$conteudo = mysql_result($res, 0, "conteudo");

header("Content-type: $tipo");
print $conteudo;

Comentário Finais

Como se pode observar, o código PHP dos scripts é bem simples, e não tem nenhum grau de dificuldade. O código foi desenvolvido com o propósito mais simples possível, para que possa ser melhorado e utilizado em aplicações mais robustas.

7 comentários

 Vinícius Borriello
14/05/2009 09h50

Vinícius Borriello

Sempre quis saber como isso era possível. Muito bom!

Apesar de fazer o upload do arquivo para uma pasta no servidor e armazenar no MySQL somente o nome do arquivo ser mais fácil e (acredito eu) sobrecarrega menos o servidor MySQl.
Qual seria a vantagem do método BLOB sobre o que citei acima?

Abraço!
Vinícius

 rogerio machado
16/05/2009 10h36

Sem querer fazer flames, mas post é de como fazer e não e onde utilizar.
De resto gostaria de parabenizar o autor pela objetividade da matéria.

 Anderson Mateus Carneiro Carneiro
25/05/2009 17h49

erro

olá, fiz alguns testes mais o arquivo não baixa.

 gileno montanha
26/05/2009 12h31

Alguns detalhes

Muito boa a matéria, gostaria de compartilhar minha experiência sobre upload. Além dos elementos citados, é necessário (dependendo do tamanho dos arquivos, claro) ajustar ainda, no php.ini:
post_max_size (deve ser igual ou maior que o valor de
upload_max_filesize)
e também:
session.gc_maxlifetime (valor em segundos, do tempo da sessão, prevendo arquivos grandes e/ou conexões lentas)

Valeu, grande abraço!

 Eduardo Vilarinho
02/09/2009 22h24

Nome do arquivo

Gostei muito do seu tutorial, mas como faz para que o nome do arquivo baixado seja o mesmo nome do arquivo que foi feito o upload?

 Paulo Roberto de Paula Oliveira
11/09/2009 17h25

Eu encontrei a solução para seu problema Eduardo.
coloquei esse header a mais no arquivo baixar_arquivo.php dê uma olhada, o meu funcionou.. até

<?
$id=$_GET["id"];
require("dbconnect.inc.php");

$qry = "SELECT tipo, conteudo,nome FROM arquivos WHERE id='$id'";
$res = mysql_query($qry);
$tipo = mysql_result($res, 0, "tipo");
$conteudo = mysql_result($res, 0, "conteudo");
$nome = mysql_result($res, 0, "nome");

<b>header("Content-Disposition: attachment; filename= $nome");</b>
header("Content-type: $tipo");

echo $conteudo;
?>

 Edimar Zacchi
13/09/2009 12h58

Sem aceitaçao para arquivos maiores do que um mega

Tenho uns arquivos parecidos para fazer o upload e download, porem o servidor mysql nao aceita arquivo maiores do que um mega de tamanho e cai...

Será que tem como resolver isso????

Cancelar resposta

Qual a sua opinião?

Faça login abaixo ou cadastre-se rapidamente.


Sobre o Autor
Jonathan Lamim trabalha com desenvolvimento web/desktop desde 2005, porém abandonou o desenvolvimento desktop em 2006 para se dedicar somente ao desenvolvimento web. Atualmente é programador da Fivecom - Soluções em web 2.0, editor do blog jlamim.com.br e graduando em Sistemas de Informação na UNISA.

2001 - iMasters FFPA Informática Ltda - Todos os direitos reservados.