Desenvolvimento - PHP

PHP: Formulários e upload de múltiplos arquivos e fotos

Veja como montar um formulário para upload de múltiplos arquivos e como processá-lo com o PHP, usando o exemplo de uma galeria de fotos em que é enviada uma quantidade variável de fotos.

por Alfred Reinold Baudisch



Publiquei três artigos ensinando como processar dados de formulário com o PHP, sendo dois deles sobre o upload de arquivos. Mas, pelos e-mails e comentários que recebi, percebi que não foi suficiente para o pessoal ir além do básico. Por isso, nesse artigo explico como criar formulários para envio de vários arquivos e principalmente, como processar esse envio com o PHP.

O artigo está dividido da seguinte maneira:
1) Introdução

2) Montando o formulário
3) Processamento do upload
4) Conclusão

1) Introdução
Praticamente em qualquer tipo de site e sistema há a necessidade de se fazer o upload de algum tipo de arquivo, principalmente imagens e documentos.

Vamos tomar como exemplo um site de uma agência promotora de eventos. Esse site tem as seções Galeria de Fotos de Eventos (vamos chamar de Galeria) e Envio de Currículos (também vamos chamar apenas de Currículos).
Manipulando dados de Formulário com PHP – Parte 1
2) Manipulando dados de Formulário com PHP – Parte 2 (Upload de arquivos)
3) Upload de Imagens com Segurança
[]
(abre e fecha colchetes) no final do nome, transformando o campo de upload em um array de campos. Parece complicado? Mas não é, pois tenho certeza que você já está careca de fazer isso. É o mesmo que acontece com um checkbox e selectbox de múltiplas opções (ver Manipulando dados de Formulário com PHP – Parte 1).

Também não esquecer que upload de arquivos só é possível via método POST e que sempre deve ser colocado o atributo enctype="multipart/form-data" na declaração do formulário.

Para criar os múltiplos campos de upload, vamos para o CASO 1, em que a quantidade é variável. São necessárias então duas ações para gerar o formulário: definir a quantidade de campos e imprimí-los dentro de um formulário.


A melhor maneira é colocar tudo numa mesma página, mas como isso é um artigo e precisamos ser ágeis, vamos dividir em dois arquivos: form_conta.php – irá pedir a quantidade de campos e form_gera.php – irá gerar o formulário.

Vamos ao código de ambos e logo após as explicações.

form_conta.php
<form action="form_gera.php" method="post">

<b>Envio das fotos</b><br />

Qual a quantidade de imagens do Evento?<br /><br />

<input type="text" name="quantidade" size="5"/><br />

<input type="submit" value="OK"/>

</form>

form_gera.php
<?php

// Obtém quantidade enviada. Perceba que é verificado se foi fornecido um número inteiro,
// caso contrário é usada uma quantidade padrão, 5.
$Quantidade = (isset($_POST["quantidade"]) && is_int(intval($_POST["quantidade"]))) ? (int)$_POST["quantidade"] : 5;

// Abre formulário de upload
echo "<form action="processa_upload.php" method="POST" enctype="multipart/form-data">";
echo
"<b>Envio das fotos</b><br />";

// Imprime os campos para upload, de acordo com a quantidade pedida
for($i = 1; $i <= $Quantidade; ++$i)
{
echo
"Foto #" . $i . ": <input type="file" name="fotos[]" /><br/>";
}

// Fecha formulário
echo "<br /><input type="submit" value="OK"/>";
echo
"</form>";

?>

- Após você enviar seu formulário pedindo dados comuns (não é mostrado aqui, porque é o pré-requisito para que você leia esse artigo), no nosso caso o nome do evento, local e data, deve ser chamado form_conta.php. Nada mais é que um campo text de formulário que pede para o usuário digitar um número, no caso a quantidade de fotos a ser enviada.

- form_conta.php chama form_gera.php, que imprimirá o nosso formulário de. O ponto chave é o loop que itera até completar a quantidade fornecida, imprimindo os campos para upload da foto. Deve-se notar o nome dos campos é sempre o mesmo, fotos[], dessa maneira, o PHP saberá que estará recebendo vários arquivos no upload (será criado um array chamado $_FILES[‘fotos’]).

- E por último, form_gera.php chama processa_upload.php, que como o nome diz, irá processar a validação e o envio dos arquivos. É o que veremos na próxima seção.

3) Processamento do upload

O nosso arquivo de processamento do formulário é o processa_upload.php. O que ele faz é obter o campo de upload, que é um array, e iterar sobre esse array fazendo a validação e o envio arquivo por arquivo, de acordo com o que estiver no array:

processa_upload.php

<?php

A) // Pasta de destino das fotos
$Destino = "./eventoxyz/fotos/";
B) // Obtém dados do upload
$Fotos = $_FILES["fotos"];
// Contagem de fotos enviadas
$Conta = 0;

C) // Itera sobre as enviadas e processa as validações e upload
for($i = 0; $i < sizeof($Fotos); $i++)
{
D) // Passa valores da iteração atual
$Nome = $Fotos["name"][$i];
$Tamanho = $Fotos["size"][$i];
$Tipo = $Fotos["type"][$i];
$Tmpname = $Fotos["tmp_name"][$i];

// Verifica se tem arquivo enviado
if($Tamanho > 0 && strlen($Nome) > 1)
{
E) // Verifica se é uma imagem
if(preg_match("/^image\/(gif|jpeg|jpg|png)$/", $Tipo))
{
// Caminho completo de destino da foto
$Caminho = $Destino . $Nome;

F) // Tudo OK! Move o upload!
if(move_uploaded_file($Tmpname, $Caminho))
{
echo
"Foto #" . ($i+1) . " enviada.<br/>";

// Faz contagem de enviada com sucesso
$Conta++;
}
else
// Erro no envio
{
// $i+1 porque $i começa em zero
echo "Não foi possível enviar a foto #" . ($i+1) . "<br/>";
}
}
}
}

if(
$Conta) // Imagens foram enviadas, ok!
{
echo
"<br/>Foi(am) enviada(s) " . $Conta . " foto(s).";
}
else
// Nenhuma imagem enviada, faz alguma ação
{
echo
"Você não enviou fotos!";
}

?>
A)
Primeiro é definida a pasta para onde irão as fotos.

B) Obtém-se o array de fotos enviadas, passando para a variável
$Fotos. O ponto chave é que o PHP transforma um campo de formulário nome[] em um array de sub-arrays para cada um dos indíces (name, type, size, tmp_name e error).

Exemplificando:
a) Quando é apenas um campo, digamos,
documento, o PHP cria o array:
$_FILES["documento"], que por sua vez é um array que contém os índices:
- name, size, tmp_name, type e error.

b) O PONTO PRINCIPAL DO ARTIGO: Quando é um campo array,
fotos[], e digamos que tenham sido enviadas 2 fotos, o PHP cria um array $_FILES[‘fotos’], contendo os mesmo índices de sempre, mas cada indice desse é um novo array, cada uma com a informação de cada uma das fotos:

$_FILES["fotos"] = array(
"name" => array("nome1.jpg", "nome2.jpg"),
"size" => array(12345, 53223),
"tmp_name" => array("dir/bla/img.tmp", "dir/bla/img2.tmp"),
"error" => array(0, 0)
);


Deu para entender? Quando são múltiplos envios a variável que identifica o campo de upload é a mesma quando é um arquivo, acontece que cada índice é um novo array, de acordo com a quantidade de campos de upload. Se eu quero saber o nome e tamanho do segundo arquivo, simplesmente atuo num array normalmente:

$_FILES["fotos"]["name"][0];

$_FILES["fotos"]["size"][0];

C) Como as informações do upload estão num array, é iterado normalmente por ela (usando um loop for) como se fosse um outro array qualquer!

D) Para cada índice, é passado o valor da iteração para novas variáveis:
$Nome, $Tamanho, $Tipo e $Tmpname, que contêm informações diretas sobre o arquivo, como se fosse o upload de um só arquivo:

$Foto[‘name’] = nome do arquivo
$Foto[‘size’] = tamanho em bytes do arquivo
$Foto[‘type’] = MIME Type do arquivo
$Foto[‘tmp_name’] = local do upload, para usar na função move_uploaded_file

$Foto[‘error’] = código de erro, não usado nesse artigo

E) Verifica se é uma imagem (através da checagem de MIME/TYPE – caso queira enviar um documento, basta mudar esse tupo de checagem). Assim, caso “aprovada” é copiada para a pasta desejada (em F).


Assim, move-se para a próxima foto (próximo item do array
$Fotos).

ATENÇÃO: Note que só entra nos próximos passos, caso verificado que tenha sido enviado um arquivo naquele campo, através do if (verificando tamanho e nome) :

if($Tamanho > 0 && strlen($Nome) > 1)

Pois como é um array de campos, se forem 10 campos, mas o usuário colocar algum arquivo em só 2 deles, de qualquer forma o PHP retornará um array com 10 itens. Por isso, é importante certificar de que realmente foi enviado arquivo naquela iteração.

Por exemplo: se o usuário enviar uma foto no campo 1 e somente outra no campo 5, os dados serão enviados corretamente devido à checagem de envio.

4) Conclusão


Para o caso 2 (envio de documentos e uma foto), é o mesmo processamento contido em processa_upload.php, com a diferença que em D em vez de checar por imagem, coloque para checar por tipo de documento, mude:

if(preg_match("/^(.*)\.(doc|txt|pdf|xls|htm|html|rtf)$/", $Nome))


E após o loop de processamento dos documentos, para enviar a foto do usuário, simplesmente coloque um processamento simples de upload (conforme estão carecas de saber!).

Usem as informações contidas nos meus 4 artigos sobre formulário e upload e poderão fazer um sistema eficiente e seguro.


É isso! O próximo artigo que tratará de formulários, falará sobre o envio em tempo real dos dados usando AJAX, bem como upload de fotos e documentos com AJAX.
E estou preparando um artigo que ensina a criação de uma galeria de fotos completa. Fiquem antenados!

O código fonte desse artigo pode ser baixado clicando aqui.

Até o próximo!
Qualquer dúvida, basta me contatar!


Alfred Reinold Baudisch
alfred@auriumsoft.com.br

www.auriumsoft.com.br/blog/

Auriumsoft – Inteligência, Tecnologia e Vídeo
www.auriumsoft.com.br

AuriumHost – Hospedagem de qualquer tecnologia e banco de dados!
www.auriumhost.com.br

Alfred Reinold Baudisch

Alfred Reinold Baudisch - Desenvolvedor web freelance, com atuação na área há 7 anos. Experiência avançada em PHP, SQL e modelagem de sistemas multi-camadas. Atualmente dedicado ao aprendizado em desenvolvimento mobile, especificamente mobile games, com J2ME. Apaixonado e conhecedor do mercado financeiro, gestão e estratégias de novos negócios, visão constantemente empreendedora. Editor dos blogs Jornada Imperial e O Desenvolvedor PHP.