Ao trabalharmos com desenvolvimento de sites e sistemas utilizando PHP e MySQL, podemos ter uma forma mais simples de trabalharmos com o armazenamento de imagens. A um tempo atrás, o gerenciamento de imagens no banco de dados relacional era, de certa forma, uma tarefa complexa, onde tornava-se necessário apenas o armazenamento de dados textuais, como é o caso do caminho do arquivo da imagem que seria salva externamente ao banco de dados em um determinado diretório. Neste artigo veremos as vantagens de realizarmos o salvamento das imagens direto na base de dados e apresentação de uma aplicação simples. Mostraremos como podemos realizar a inserção das imagens num formato específico e como recuperá-las da base de dados.

Durante muito tempo vêm sendo discutida essa questão com relação ao que seria melhor: salvarmos as imagens direto na base de dados ou salvá-las externamente em diretórios e apenas manter o endereço (caminho) da imagem na base de dados? Neste caso, torna-se mais uma questão de escolha e necessidade de cada projeto, onde os fatos que podemos apresentar é de que os métodos de armazenamento binário são muito bem sucedidos e apresentam mais vantagens que a forma de armazenagem em sistemas de arquivos. Dentre as vantagens que podemos citar, temos as seguintes:

  • Integridade referencial (Consistência ACID);
  • Facilidade de cópia de segurança;
  • Facilidade na categorização das imagens;
  • Baixa quantidade de conflito de nomes (ou nenhum);
  • Armazenamento de Meta Data;
  • Replicação em vários servidores.

Alguns dos problemas mais citados com relação ao armazenamento de imagens numa base de dados e outros dados binários é referente a criação de muita sobrecarga numa busca na base de dados. O que podemos perceber é que esse problema pode ser gerado por outros fatores, como por exemplo, o próprio desenvolvedor, ao realizar uma busca na base para retornar todos os dados, como a seguinte:


Select * from fotos_festa;

Quando na realidade, a única informação necessária para a obtenção da imagem seria o Id. Além disso, devemos nos lembrar também que os sistemas de arquivos não são imunes a restrições. A maioria dos argumentos encontrados contra o armazenamento de imagens ou dados binários em um banco de dados tem como foco o desempenho. Isso não quer dizer que o sistema de arquivos não seja uma boa opção. O maior constrangimento que podemos passar é pela falta de inciativa e inovação, onde colocamos obstáculos com relação a mudanças tecnológicas. O que é necessário aqui é a ponderação do que é realmente preciso e balancear o que será melhor de utilizarmos para a nossa aplicação.

Como vimos em relação a algumas vantagens, não poderíamos deixar de lado a questão das desvantagens de armazenarmos dados multimídia na base de dados, onde muitas vezes é preferível não atribuirmos permissões de arquivo para as aplicações. Ao armazenarmos imagens ou dados binários no banco de dados, o acesso pode ser limitado ao código da aplicação e dos privilégios do sistema de arquivos que não estão disponíveis de forma escalar. Com base nessa questão, existem várias razões também para não armazenarmos imagens ou outros dados binários em um banco de dados, das quais podemos citar:

  • Melhor armazenamento de cache;
  • Utilização de proxies externos;
  • O MySQL poderá armazenar dados textuais de melhor forma;
  • Velocidade de recuperação dos dados.

Por isso, precisamos definir as prioridades referentes a aplicação, o que a tornará melhor. Dependendo do objetivo do nosso aplicativo é que podemos decidir qual o melhor meio de armazenamento/recuperação será a melhor opção. Tendo essa breve explanação, veremos agora, através de um exemplo simples de armazenamento de imagens referente a eventos, como podemos inserir arquivos do tipo Blob na base de dados.

Utilizando o formato Blob para armazenamento de imagens

No MySQL, temos um tipo de dados chamado BLOB, o qual pode ser utilizado para realizar o armazenamento de dados binários, podendo estes ser imagens, arquivos pdf, word, além de poder armazenar vídeos, dentre outros formatos. Um campo do tipo BLOB (Binary Large Objects) é na realidade uma coleção de dados binários armazenados como uma única entidade em um sistema de gerenciamento de banco de dados. Os Blobs são normalmente arquivos de imagens, áudio ou mesmo, outros objetos do tipo blob multimídia. Temos atualmente presentes no MySQL quatro tipos definidos do BLOB, onde a diferença entre eles é basicamente com relação ao tamanho que eles possuem para armazenagem de informações, os quais podemos citar:

  • Tinyblob;
  • Blob;
  • Mediumblob;
  • Longblob.

Começando pelo menor, temos o Tinyblob, onde este é um campo com armazenamento máximo de 255 caracteres, o que equivale a 8 bits. Já com relação ao Blob, a sua capacidade de armazenamento é em torno dos 16000 caracteres, equivalendo a 16 bits. Em seguida, temos o MediumBlob, que tem uma capacidade de armazenamento superior a 16 milhões de caracteres, o que equivale a mais ou menos 24 bits. Por último, temos o formato LongBlob que pode realizar o armazenamento de mais de 4 bilhões de caracteres, equivalente a 32 bits. Como qualquer recurso de banco de dados, os campos do tipo Blob possuem suas particularidades, dentre as quais podemos destacar que eles não podem ser atribuídos como chaves primárias, exceto o TinyBlob, além do fato de que para estes campos, não podemos utilizar os comandos GROUP e SORT.

A partir de agora, criaremos um exemplo simples no qual abordaremos a inserção de imagens na base de dados e também a recuperação das mesmas para visualização em tela. Para o exemplo que iremos apresentar, criaremos uma nova base de dados chamada de imagens_devmedia e uma tabela de testes chamada tabela_imagens no MySQL. Esta tabela irá conter sete colunas, como apresentamos de acordo com a Listagem 1.


CREATE DATABASE imagens_devmedia;
CREATE TABLE IF NOT EXISTS `tabela_imagens` (
`codigo` int(10) NOT NULL,
`evento` varchar(50) NOT NULL,
`descricao` varchar(255) NOT NULL,
`nome_imagem` varchar(25) NOT NULL,
`tamanho_imagem` varchar(25) NOT NULL,
`tipo_imagem` varchar(25) NOT NULL,
`imagem` longblob NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
Listagem 1. Criando a base de dados e tabela

O que temos aqui são campos simples onde o código age como a chave primária, sendo esta auto incrementável, o segundo campo responsável pela obtenção do nome do evento referente a foto, além de uma breve descrição do evento e os dados pertencentes a própria imagem: o nome da imagem, o tamanho e a imagem em si, que é um campo do tipo Blob, o qual utilizaremos para armazenar os dados da imagem.

Criando o formulário de inserção

Como temos a nossa base de dados já criada, criaremos primeiramente a nossa página index.php, que será o nosso formulário de envio das imagens. O código da página será apresentado de acordo com a Listagem 2.


<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>Armazenando imagens no banco de dados Mysql</title>
</head>
<body>
<h2>Selecione um novo arquivo de imagem</h2>
 
<form enctype="multipart/form-data" action="upload.php" method="post">
<div><input name="nome_evento" type="text"/></div>
<div><input name="descricao_evento" type="textarea"/></div>    
<input type="hidden" name="MAX_FILE_SIZE" value="99999999"/>
    <div><input name="imagem" type="file"/></div>
    <div><input type="submit" value="Salvar"/></div>
</form>
</body>
</html>
Listagem 2. Criando a página inicial, a index.php

De acordo com o formulário apresentado, percebemos que este é bem simples, no qual temos apenas um campo para passarmos o nome do evento, uma breve descrição, um campo para envio das imagens e um botão para envio das informações. Neste mesmo formulário temos uma informação do tipo hidden, a qual informaremos o tamanho máximo do arquivo que pode ser enviado, sendo este definido pelo name MAX_FILE_SIZE. Podemos aplicar qualquer tamanho que desejarmos nesse momento.

A próxima classe que iremos criar será a classe de conexão, a qual chamaremos de conecta.php, onde teremos as informações básicas de acesso ao banco de dados para utilizarmos nos nossos formulários de upload e de busca pelas imagens, como apresentamos de acordo com a Listagem 3.


<?php
$conexao = mysql_connect("localhost", "root", "");
 
if($conexao)
{
$baseSelecionada = mysql_select_db("imagens_devmedia");
if (!$baseSelecionada) {
    die ('Não foi possível conectar a base de dados: ' . mysql_error());
} } else {
    die('Não conectado : ' . mysql_error());
}
?>
Listagem 3. Criação da classe conecta.php

Devemos criar agora a classe que será responsável pelo upload das imagens para o banco de dado. Esta classe, a qual chamaremos de upload.php terá o código apresentado de acordo com a Listagem 4.


<?php
require("conecta.php");
$nomeEvento = $_POST['nome_evento'];
$descricaoEvento = $_POST['descricao_evento'];
$imagem = $_FILES['imagem']['tmp_name'];
$tamanho = $_FILES['imagem']['size'];
$tipo = $_FILES['imagem']['type'];
$nome = $_FILES['imagem']['name'];
 
if ( $imagem != "none" )
{
    $fp = fopen($imagem, "rb");
    $conteudo = fread($fp, $tamanho);
    $conteudo = addslashes($conteudo);
    fclose($fp);
 
$queryInsercao = "INSERT INTO tabela_imagens (nome_evento, 
descrição_evento, nome_imagem, 
tamanho_imagem, tipo_imagem, imagem) VALUES ('$nomeEvento', 
'$descricaoEvento','$nome','$tamanho', '$tipo','$conteudo')";
 
 mysql_query($queryInsercao) or die("Algo deu errado ao inserir 
 o registro. Tente novamente.");
echo 'Registro inserido com sucesso!'; 
header('Location: index.php');
 if(mysql_affected_rows($conexao) > 0)
     print "A imagem foi salva na base de dados.";
 else
     print "Não foi possível salvar a imagem na base de dados.";
 }
else
    print "Não foi possível carregar a imagem.";
?>
Listagem 4. Criação da classe de upload.php

Temos logo no começo a utilização da variável $_FILES que é utilizada para a leitura de dados dos arquivos que serão enviados para o servidor. Dentre os parâmetros utilizados por esta variável, podemos destacar os parâmetros “name”, “type”, “size” e “tmp_name”, os quais são responsáveis por nos passar as informações do nome do arquivo, o tipo que está sendo passado, o tamanho e um local temporário que é criado quando o arquivo é enviado. Percebam que como estamos tratando aqui de um array de informações, é necessário passarmos sempre a variável com dois parâmetros, onde um deles é o nome que demos ao name no formulário de envio e o outro contendo as informações que queremos obter, como é o caso de $nome = $_FILES['imagem']['name'].

Em seguida, fazemos uma verificação para saber se temos um arquivo sendo enviado e após isso, utilizamos o comando fopen para abrir um arquivo, que no nosso caso, por ser um arquivo binário, precisamos da opção “b” em conjunto com o “r”, onde o “r” significa a leitura do arquivo e o “b” força a abertura do arquivo em modo binário. Em seguida, utilizamos o comando Fread() que lê os dados de um arquivo externo e o informa de volta para o arquivo PHP. Este comando é passado como fread (variável que contém a informação do fopen(), tamanho). O arquivo é então aberto na variável $conteudo e o comprimento é medido em bytes, com um tamanho máximo de 8192 bytes. Prosseguimos então com a verificação do nosso código e tentamos inserir as informações na base de dados. Caso tudo ocorra bem, receberemos uma mensagem na tela informando que os dados foram salvos com sucesso.

Agora que realizamos a inserção das imagens na base de dados, precisaremos visualizar os dados armazenados, e para isso, faremos uma pequena modificação no formulário base para adicionarmos uma tabela, na qual teremos as informações pertencentes as imagens cadastradas e um link que nos levará para a página ver_imagens.php, a qual está sendo apresentada de acordo com a Listagem 6. Para isso, realizaremos também uma conexão a base de dados e nossa página inicial alterada será apresentada de acordo com a Listagem 5.


<?php
require_once("conecta.php");
?>
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>Armazenando imagens no banco de dados Mysql</title>
</head>
<body>
<h2>Selecione um novo arquivo de imagem</h2>
 
<form enctype="multipart/form-data" action="upload.php" method="post">
    <input type="hidden" name="MAX_FILE_SIZE" value="99999999"/>
    <div><input name="nome_evento" type="text"/></div>
    <div><input name="descricao_evento" type="textarea"/></div>
    <div><input name="imagem" type="file"/></div>
    <div><input type="submit" value="Salvar"/></div>
</form>
<br />
<table border="1">
    <tr>
        <td align="center">
            Código
        </td>
        <td align="center">
            Evento
        </td>
        <td align="center">
            Descrição
        </td>
        <td align="center">
            Nome da imagem
        </td>
        <td align="center">
            Tamanho
        </td>
        <td align="center">
            Visualizar imagem
        </td>
<td align="center">
            Excluir imagem
        </td>
    </tr>
    <?php
 
    $querySelecao = "SELECT codigo, nome_evento, descricao_evento, 
    nome_imagem, tamanho_imagem, imagem FROM tabela_imagens";
    $resultado = mysql_query($querySelecao);
 
    while ($aquivos = mysql_fetch_array($resultado)) { ?>
        <td align="center">
        <?php echo $aquivos[‘codigo’]; ?>
    </td>
        <td align="center">
        <?php echo $aquivos['nome_evento']; ?>
    </td>
        <td align="center">
        <?php echo $aquivos['descricao_evento']; ?>
    </td>
        <td align="center">
        <?php echo $aquivos['nome_imagem']; ?>
    </td>
        <td align="center">
        <?php echo $aquivos['tamanho_imagem']; ?>
    </td>
        <td align="center">
        <?php echo '<a href="ver_imagem.php?id='.$aquivos[‘codigo’].
        '">Imagem '.$aquivos[‘codigo’].'</a>'; ?>
    </td>
    <td align="center">
        <?php echo '<a href="excluir_imagem.php?id='.$aquivos[‘codigo’].
        '">Imagem '.$aquivos[‘codigo’].'</a>'; ?>
    </td>
    <?php } ?>
</table>
</body>
</html>
Listagem 5. Criação da classe de listar imagens criadas na base de dados

Como podemos perceber, adicionamos aqui uma tabela na qual estamos passando os dados referentes as imagens que cadastramos na base de dados, como podemos citar, o nome do evento, o tipo de arquivo e o seu tamanho. Nesse momento realizamos uma consulta na base de dados para que possamos recuperar os dados e em seguida apresentar na tela, junto com um link para visualizarmos as imagens que armazenamos na base de dados. A visualização da imagem é dada com base na pesquisa pelo código que é passado via get utilizando o parâmetro $_GET[], como apresentado de acordo com a Listagem 6.


<?php
require("conecta.php");
 
$id_imagem = $_GET[‘codigo’];
$querySelecionaPorCodigo = "SELECT codigo, 
imagem FROM tabela_imagens WHERE codigo = $id_imagem";
$resultado = mysql_query($querySelecionaPorCodigo);
$imagem = mysql_fetch_object($resultado);
Header( "Content-type: image/gif");
echo $imagem->imagem;
Listagem 6. Criação da classe de visualização das imagens de acordo com o código

Estamos usando aqui a variável $_GET para que possamos recuperar o código que foi passado pelo formulário anterior e passamos ele na nossa consulta, o que nos retorna um único valor. Ao obtermos o resultado de nossa consulta, utilizamos aqui a função mysql_fetch_object() que tem por objetivo retornar os dados como um objeto, diferente do que utilizamos na Listagem 5, que foi o mysql_fetch_array() que retorna os dados em forma de array. Em seguida, para apresentarmos a imagem precisamos adicionar o Header(“contente-type: image/gif”), pois sem a utilização dele, o que veremos em tela será o binário da imagem, ou seja, o que armazenamos na nossa base de dados. Por último, damos um echo e passando a nossa imagem como objeto.

Além da visualização das imagens cadastradas, podemos não querer mais que elas sejam armazenadas na base de dados e para isso, excluiremos elas definitivamente através do link presente que representa a exclusão, que será apresentado de acordo com a Listagem 7.


<?php
require("conecta.php");
$codigo = $_GET["codigo"];
$sqlExclusao = "DELETE FROM tabela_imagens WHERE codigo = '$codigo' ";
$queryExclusao = mysql_query($sqlExclusao) 
or die("Algo deu errado ao excluir a imagem. Tente novamente.");
echo 'Imagem excluída com sucesso!'; 
header('Location: index.php');
?>
Listagem 7. Exclusão dos registros da base de dados

A exclusão dos registros existentes na tabela de imagens será realizada com a utilização do $_GET para que possamos pegar o código daquele determinado registro, assim como foi realizado para a seleção do mesmo registro. Em seguida, ao finalizarmos o processo de exclusão, apresentamos uma mensagem de sucesso e redirecionamos para a página principal utilizando a instrução Header(‘Location’).

Com isso finalizamos este artigo, onde apresentamos os conceitos com relação aos tipos de armazenamento Blob para as imagens na base de dados, não só imagens, pois também podemos estar armazenando outros tipos de multimídia, como arquivos de áudio ou vídeo, além disso, apresentamos também alguns pontos referentes a vantagens e a desvantagens com relação ao armazenamento de imagens diretamente na base de dados. Para finalizar, criamos um simples exemplo de cadastramento de imagens, realizando uma busca por elas através do seu código de identificação na base de dados para que desta forma, possamos visualizar os registros que foram armazenados e por último, fizemos a exclusão dos registros. Como nosso foco era mais em razão da forma de armazenamento, não nos preocupamos muito com validações, mas sim com a forma de realizarmos as operações básicas no momento de trabalharmos com arquivos BLOB. Esperamos que tenham gostado e que seja útil para o seu desenvolvimento.