[editado] Uma versão mais recente e explicativa sobre Upload Múltiplo pode ser vista neste meu artigo no ULTIMATE PHP Blog   - Beraldo [/editado]     Olá, pessoal.

Vejo muitas dúvidas sobre upload múltiplo de arquivos. Há vários scripts prontos, mas achei que seria interessante criar um artigo para mostrar como esse processo ocorre, a fim de evitar o tradicional CTRL + C CTRL + V. :D


Antes de tudo, recomendo ler o capítulo sobre uploads do Manual do PHP:
http://www.php.net/manual/pt_BR/features.file-upload.php


Comecemos pelo formulário. Dois pontos importantes devem ser ressaltados:
O atributo enctype sempre deve estar presente num formulário de upload. Caso contrário, o(s) arquivo(s) não será(ão) enviado(s); Como estamos trabalhando ocm upload múltiplo, devemos definir o atributo name do input file semelhantemente a um array: arquivo[]. Dessa forma, o PHP interpretará $_FILES['arquivo'] como sendo um array. Assim, não importa o número de arquivos enviados. Tanto faz enviar um ou vinte arquivos; a forma de tratar o upload é a mesma.
form.html
<form name="upload" id="upload" action="upload.php" method="post" enctype="multipart/form-data"> <ul> <li> <input type="file" name="arquivo[]" /> </li> <li> <input type="file" name="arquivo[]" /> </li> <li> <input type="file" name="arquivo[]" /> </li> <li> <input type="submit" value="Enviar" /> </li> </ul> </form> Inseri somente três campos, mas poderia haver dez, vinte ou mais.


Antes de começarmos a manipular os arquivos, vamos ver como o PHP gera o array $_FILES. Para isso, no arquivo upload.php, insira este código:

upload.php <?php echo "<pre>"; print_r($_FILES); echo "</pre>"; ?> O resultado será: Array ( [arquivo] => Array ( [name] => Array ( [0] => arquivo1.txt [1] => arquivo2.txt [2] => arquivo3.txt ) [type] => Array ( [0] => text/plain [1] => text/plain [2] => text/plain ) [tmp_name] => Array ( [0] => C:\WINDOWS\TEMP\php8.tmp [1] => C:\WINDOWS\TEMP\php9.tmp [2] => C:\WINDOWS\TEMP\phpA.tmp ) [error] => Array ( [0] => 0 [1] => 0 [2] => 0 ) [size] => Array ( [0] => 621 [1] => 455 [2] => 579 ) ) )
O arquivo de upload:
upload.php <?php // diretório de destino dos arquivos enviados // a constante DIRECTORY_SEPARATOR contém o separador de diretório padrão de cada Sistema Operacional $dir = 'uploads' . DIRECTORY_SEPARATOR; // Para facilitar, atribuimos a $arquivo o valor $_FILES['arquivo'] // sobre o operador ternário: http://www.php.net/manual/pt_BR/language.operators.comparison.php $arquivo = isset($_FILES['arquivo']) ? $_FILES['arquivo'] : FALSE; // no count(), tanto faz colocar $arquivo['name'], $arquivo['size'] // ou outro índice gerado, pois todos têm o mesmo número de chaves. for ($i = 0; $i < count($arquivo['name']); $i++) { if (move_uploaded_file($arquivo['tmp_name'][$i], $dir . $arquivo['name'][$i])) { echo "<p><strong>Enviado: </strong> " . $arquivo['name'][$i] . " | " . round($arquivo['size'][$i] / 1024, 2) . " kB | " . $arquivo['type'][$i] . "</p>"; } else { echo "<p><strong>Não enviado: </strong> " . $arquivo['name'][$i] . " | " . round($arquivo['size'][$i] / 1024, 2) . " kB | " . $arquivo['type'][$i] . "</p>"; } } ?> 1 kB = 1024 bytes, por isso usei 1024 e não 1000. 24 bytes parecem insignificantes, mas não são, mesmo para um arquivo pequeno. Veja:

50 kB = 50 * 1024 = 51200 != 50000
900 kB = 900 * 1024 = 921600 bytes != 900000

Por isso convém definir o tamanho máximo dos arquivos sempre da forma mostrada acima: multiplicando o tamanho máximo, em kB, por 1024, a fim de obter o valor exato.


A vantagem de criar scripts assim é que o número de arquivos não importa. Faça o teste com somente um campo file. Verá que também funciona. Ou seja, um script com essa estrutura envia um, dois, dez ou quantos arquivos forem necessários. :D


O código que mostrei não possui nenhuma validação de tipo, tamanho, erro etc, pois esse não é o foco do artigo. Quero apenas demonstrar como manipular o envio dos arquivos. As verificações são apresentadas em diversos outros artigos. Basta adicioná-las dentro do loop.

Abraços,
Beraldo