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"); }
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)) { ...
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);
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)