Função PHP para upload de arquivos
Postado em Tecnologia | 01 Fevereiro, 2013
imagem_2_1.jpg

Os artigos da área "Coddes's Codes" são voltados para desenvolvedores. Se você é leigo, não se assuste!

Uma boa função de upload de arquivos em PHP parece simples: basta pegar o arquivo e jogar em uma determinada pasta. Porém, esta simplicidade cai quando você descobre que precisa validar o tipo de arquivo, o formato, as possibilidades de erros diferentes do padrão, entre outros.

Uma boa função não deve só fazer o básico, ou seja, pegar o arquivo e enviar para a pasta desejada. Mas também precisa: validar o tipo de arquivo e, caso possível, verificar se o conteúdo desse arquivo é o indicado pela extensão (muitas pessoas mudam a extensão de imagens, por exemplo); verificar também se o arquivo de imagem será suportado pelo GD; além de proteger contra upload de scripts.

Já que pode fazer isso tudo, porque não usá-la também para transferir arquivos dentro do próprio script, como uma chamava virtual de upload? O script que você pode baixar no final deste artigo contém todos estes testes. Originalmente, também podia gerar thumbnails, mas por questões de otimização acabou sendo reduzido para lidar apenas com o proposto: upload de arquivos.

Confira abaixo o que cada parte do script faz e por que. Entenda a complexidade que surge em uma tarefa tão simples como fazer upload.


1. Controle de tipo

A primeira parte do script (até a linha 71) verifica, opcionalmente, se o arquivo é das extensões pretendidas. Além de aceitar uma lista de extensões no parâmetro $type no formato "udef:extensão,...,extensão", também aceita alguns tipos pré-definidos como "image", "html" ou "docs". Aqui, apenas um teste simples da extensão do arquivo é feita.

foreach($type as $x => $text) {
	if (preg_match("/^(.*)(.".$text.")$/i",$file['name'],$regs)==1) $desiredExtension = ($isauto?".".$regs[3]:".$text");
}
O script procura a extensão do arquivo usando preg_match


2. Controle de tipo interno

Muitos leigos trocam o nome dos arquivos, pensando que assim o tipo de arquivo mudará automaticamente. Isso é algo comum, principalmente entre arquivos .zip e .rar, mas também em imagens.

Nas linhas 72 a 106, o script verifica o conteúdo do arquivo, validando se ele realmente é um JPG, GIF, BMP, PNG, ZIP ou RAR. Note que, para as imagens, é usada a biblioteca GD (linha 75 e 76), que também garante que o script conseguirá ler os arquivos. Já nas linhas 85 à 101, os 5 primeiros bytes do arquivo são lidos para verificar a presença do indicador de arquivo zip (PK, de PKzip, o criador do formato) ou rar, mas isto não garante que serão legíveis. Você poderia abrir o arquivo zip com zip_open para ter um teste melhor, mas neste caso seria alocada memória para todo o arquivo, o que não é produtivo aqui. Note que você pode adicionar outros testes, como para arquivos PDF (começa com %PDF) etc...

$i = @getimagesize($file['tmp_name']);
if ($i===false || !isset($i[2]) || ($i[2] != IMAGETYPE_JPEG && $i[2] != IMAGETYPE_PNG && $i[2] != IMAGETYPE_GIF && $i[2] != IMAGETYPE_BMP)) {
...
O script verifica se o arquivo é uma imagem válida


3. Controle de hacks e scripts

Não seria nada interessante permitir que alguém faça upload de um arquivo .php ou .asp, caso seja um servidor Windows; ou um arquivo com extensão que possibilita alguns tipos de hacks de apache. Portanto, nas linhas 113 à 129, o nome do arquivo é testado e, no caso de scripts reconhecidos, alterado para .html.


4. Chamadas virtuais

Às vezes você pode querer estas funcionalidades de forma interna: manipulando um arquivo via script, mas não enviado via upload. A diferença mais importante é o modo de mover o arquivo da pasta temporária. Nas linhas 133 à 137, se o array do arquivo possuir a chave "virtual", ele é copiado como um arquivo comum; caso contrário, movido como um arquivo de upload.

if (isset($file['virtual']))
	$ok = copy($file['tmp_name'],$desiredFilename.$desiredExtension);
else
	$ok = move_uploaded_file($file['tmp_name'],$desiredFilename.$desiredExtension);
O script copia ou move o arquivo dependendo do tipo de chamada: virtual ou "real" (upload)


5. "Upload" per se

Com os testes concluídos, você pode alterar o chmod (para garantir acesso via FTP, apache ou o próprio php), dependendo de como está configurado o servidor. Note que a função safe_chmod não está inclusa, mas basicamente altera via chmod as permissões do arquivo mantendo o umask. As linhas finais do script garantem isto e fazem a limpeza de possíveis arquivos temporários que restaram.

Resultados

A função retorna, além das variáveis padrão de erro de upload, alguns erros a mais:

0 - Upload ok
1 - ERRO - Arquivo maior do que o permitido pelo servidor (configurações do php.ini)
2 - ERRO - Arquivo maior do que o permitido pelo formulário (especificado pelo campo MAX_FILE_SIZE)
3 - ERRO - Upload incompleto (abortado), ou um erro de permissão no envio (problema de permissão de arquivos na pasta temporária, ou o formulário não tinha multipart encode)
4 - Nada enviado
5 - ERRO - Arquivo de extensão inválida
7 - ERRO - O conteúdo real do arquivo não é o que a extensão indica (imagem, zip ou rar inválidos)

Faça o download deste script da Codde clicando aqui - DOWNLOAD (6k)

COMENTÁRIOS