Salvar imagem no banco de dados com PHP/MySQL

Quando precisamos fazer o upload de uma imagem, geralmente temos duas opções:

  • 1 – Copiar a imagem em uma pasta no servidor e salvar apenas o caminho no banco de dados, como é feito nesse artigo.
  • 2 – Converter a imagem para binário e salvá-la diretamente no banco de dados.

O primeiro método é o mais comum, pois é mais fácil de ser implementado, além de ter melhor desempenho. Porém, em alguns casos torna-se necessário salvar a imagem diretamente no banco de dados, e assim recorremos ao segundo método. A desvantagem é que é um pouco mais trabalhoso de ser implementado e o desempenho é menor se comparado ao primeiro método, pois será necessário converter a imagem de binário para seu formato original toda vez que for necessário mostrá-la ao usuário.
Nesse artigo veremos como implementar o segundo método. Criaremos um cadastro de fotos sem contexto, apenas para demostrar a ideia, vamos nessa?
Confira o exemplo em funcionamento, clicando aqui.

Banco de dados

Primeiramente, vamos criar nossa tabela.

  • Conteúdo: campo do tipo BLOB (utilizado para armazenar informações de arquivos em formato binário) e será utilizado para armazenar a foto;
  • Tipo: será utilizado para armazenar o tipo do arquivo, pois no nosso exemplo será permitido fazer upload de diferentes tipos (jpg, gif, png, bmp) e no momento de exibir a imagem iremos utilizá-lo;
  • Tamanho: O tamanho do arquivo em bytes.

O formulário de cadastro

Em seguida, vamos criar o formulário para cadastrar uma foto.

O lado cliente

Para ficar mais interessante, vamos fazer o envio desse formulário utilizando AJAX.

Uma explicação mais detalhada:

  • Linha 5, 6 e 7: Apenas armazenamos os objetos da página para ficar mais fácil e rápido de utilizá-los posteriormente. Por exemplo, ao invés de utilizar $("#mensagem").attr(), utilizamos mensagem.attr();
  • Linha 11: Utilizando um recurso do Bootstrap, exibimos a mensagem de carregamento definida na propriedade data-loading-text do botão, para que assim o usuário saiba que a foto está sendo enviada;
  • Linha 14: Utilizando o JQuery Form Plugin, fazemos o envio do formulário;
  • Linha 20: Se a requisição foi recebida e processada pelo servidor com sucesso, esse método será chamado;
  • Linha 23: O servidor irá retornar um JSON com as propriedades sucesso e mensagem(veremos isso mais adiante). Portanto, verificamos se a propriedade sucesso é verdadeira, que significa que a foto foi salva com sucesso no banco de dados;
  • Linha 25 e 28: Utilizamos um estilo do Bootstrap para a mensagem e limpamos o formulário para que o usuário possa enviar outra imagem;
  • Linha 36 e 39: Já definido o estilo da mensagem (sucesso ou erro), exibimos a mensagem retornada pelo servidor e então escondemos o indicador de carregamento do botão, pois o processamento acabou;
  • Linha 44 até 54: Esse método somente será chamado caso ocorra algum erro no servidor. Definimos o estilo de erro, exibimos uma mensagem genérica de erro e escondemos o indicador de carregamento.

O lado servidor

Conexão

Arquivo responsável pela conexão com o banco de dados utilizando PDO.

Caso você esteja se perguntando porque de não utilizar a função mysql_connect, recomendo a leitura dessa página.

Utilidade

Nesse arquivo vamos apenas criar uma função para facilitar a mensagem de retorno da requisição AJAX.

Salvar

Em seguida, criaremos o arquivo PHP responsável por receber, validar e incluir a foto no banco de dados.

Algumas observações:

  • Linha 9: Criamos uma constante com o tamanho máximo da foto em bytes, no caso 2 MB;
  • Linha 40: Através da função file_get_contents() pegamos o conteúdo do arquivo, no caso como é uma imagem, será retornado o conteúdo binário dela;
  • Linha 43 até 49: Montamos o nosso comando SQL e passamos as informações da foto nos parâmetros. Vale ressaltar que devemos utilizar o tipo PDO::PARAM_LOB para o conteúdo pois a coluna no banco de dados é do tipo BLOB;
  • Linha 52: Executamos o comando SQL e testamos o resultado com o operador ternário do PHP; se for executado com sucesso retornamos o JSON {"sucesso":true,"mensagem":"Foto cadastrada com sucesso"} com a ajuda da função retorno() que foi criada anteriormente, caso contrário será retornado a mensagem de erro. Vale ressaltar que em ambiente de produção o ideal seria registrar essa mensagem em um arquivo de log e retornar uma mensagem de erro genérica ao usuário;

Convertendo imagem

Com os procedimento acima já conseguimos incluir as fotos em nosso banco de dados. Agora precisamos mostrá-las ao usuário, para isso é necessário converter o conteúdo binário para arquivo. O seguinte script será responsável por isso.

Em resumo, recuperamos o ID da foto que é passado pelo método GET e buscamos o conteúdo e tipo da foto no banco de dados. Se encontrado a foto, utiliza a função header() para informar ao navegador que a saída desse script vai ser o tipo de arquivo da foto. Por fim, retorna o conteúdo da foto.
Dessa forma, podemos mostrar a imagem simplesmente incluindo uma tag img passando o ID da imagem, por exemplo:

Consulta

Para finalizar, vamos fazer uma consulta que vai buscar as fotos no banco de dados e mostrar para o usuário.

Basicamente, selecionamos as fotos cadastradas no banco de dados, percorremos elas e utilizando o script imagem.php que criamos anteriormente carregamos cada foto. Para ficar com uma aparência melhor, utilizamos o recurso de Thumbnail do Bootstrap.

Conclusão

O objetivo deste artigo foi apresentar uma solução para quem necessita gravar fotos no banco de dados utilizando PHP e MySQL. É bom lembrar que em um ambiente de produção o ideal seria reduzir o tamanho da imagem caso seja muito grande e gerar uma miniatura também, mas isso é assunto para outro artigo.
Outro detalhe é que esse método é válido para qualquer tipo de arquivo, só muda a validação, pois o que importa na hora da conversão é o tipo do arquivo.
Particularmente não recomento esse método, pois como foi dito no inicio, o desempenho normalmente é menor e a quantidade de fotos impacta no tamanho do banco de dados. Porém em determinados casos é uma boa saída. Portanto, se essa for sua necessidade, espero que este artigo tenha sido útil para você.
Código fonte disponível em: https://github.com/rafaelcouto/Post1119