Desenvolvimento - PHP
Upload de Arquivos em PHP
O PHP pode fazer o upload de qualquer tipo de arquivo (texto ou binário). Leia nesse artigo os passos a se seguir e aprenda uma manipulação completa de uploads com o PHP.
por Alfred Reinold BaudischEsse artigo está dividido nos seguintes tópicos:
- Aspectos dos formulários de Upload
- Manipulando com o script PHP os arquivos enviados
- Verificando e limitando os arquivos enviados
- Tamanho dos arquivos
- Tipo dos arquivos
- Nome dos arquivos
1 - Aspectos dos formulários de Upload
Todo formulário de upload deve:
- Ser declarado com o método de envio POST.
- Conter a diretiva enctype="multipart/form-data", para "dizer" ao navegador que está se enviando arquivos e não somente os textos dos campos dos formulário
- Conter pelo menos 1 campo "file".
Isso em prática fica:
<form action="script.php" method="POST" enctype="multipart/form-data"> Seu arquivo: <input name="arquivo" type="file"><BR> [... outros campos do formulário ...] <input type="submit" value="Enviar"> </form> |
2 - Manipulando com o script PHP os arquivos enviados
Assume-se que o formulário acima foi postado enviando um arquivo. Automaticamente em "script.php" (o action do formulário exemplo), será criado as seguintes variáveis:
$_FILES["arquivo"]["name"] - O nome original do arquivo no computador do usuário. $_FILES["arquivo"]["type"] - O tipo mime do arquivo, se o navegador deu esta informação. Exemplo: caso uma imagem GIF tenha sido enviada, o mime será: "image/gif". $_FILES["arquivo"]["size"] - O tamanho em bytes do arquivo. $_FILES["arquivo"]["tmp_name"] - O nome temporário do arquivo, como está guardado no servidor. $_FILES["arquivo"]["error"] - O código de erro associado a este upload de arquivo. Essa opção foi adicionada |
Observações:
- Em versões anteriores do PHP a 4.1.0 use a variável $HTTP_POST_FILES e não a variável superglobal $_FILES que foi introduzida na versão 4.1.0;
- No lugar de "arquivo" use o nome do seu campo "file" do formulário;
- Se a opção de configuração do PHP register_globals estiver como "on", você pode usar uma variável com o nome do campo de formulário, exemplo: $arquivo_name, $arquivo_size, etc. Mas, usar dessa maneira não é o recomendável, procure sempre usar a superglobal $_FILES.
O preferível no começo de "script.php" é passar a $_FILES para outra variável, por exemplo:
$arquivo = isset($_FILES["arquivo"]) ? $_FILES["arquivo"] : FALSE; $arquivo2 = isset($_FILES["arquivo2"]) ? $_FILES["arquivo2"] : FALSE; [... etc ...]
Os arquivos enviados pelo formulário serão guardados no diretório temporário do servidor, a menos que outro lugar seja especificado com a opção upload_tmp_dir no php.ini. E o caminho e nome de cada arquivo, são ditos na $_FILES["arquivo"]["tmp_name"].
Para mover o arquivo para um diretório desejado deve-se usar a função move_uploaded_file() (em versões anteriores a 4.0.3 use a função copy).
Vamos então ao que interessa! O código de "script.php":
<?php // Repassa a variável do upload $arquivo = isset($_FILES["arquivo"]) ? $_FILES["arquivo"] : FALSE; // Caso a variável $arquivo contenha o valor FALSE, esse script foi acessado // diretamente, então mostra um alerta para o usuário if(!$arquivo) { echo "Não acesse esse arquivo diretamente!"; } // Imagem foi enviada, então a move para o diretório desejado else { // Diretório para onde o arquivo será movido $diretorio = "./arquivos/"; // Move o arquivo // Lembrando que se $arquivo não fosse declarado no começo do script, // você estaria usando $_FILES["arquivo"]["tmp_name"] e $_FILES["arquivo"]["name"] if (move_uploaded_file($arquivo["tmp_name"], $diretorio . $arquivo["name"])) { echo "Arquivo Enviado com sucesso!"; } else { echo "Erro ao enviar seu arquivo!"; } } ?> |
Esse é o código mínimo que seu script de upload deve conter. Mas, o mesmo ainda não é seguro, pois não faz nenhuma verificação no arquivo, seja de tamanho, nome, tipo, etc. O próximo tópico aborda isso.
3 - Verificando e limitando os arquivos enviados
3.1 - Tamanho dos arquivos
Existem várias formas de verificar o tamanho de arquivo enviado.
- A primeira limitação que você pode impor nos uploads é colocar o seguinte campo em seu formulário:
<input type="hidden" name="MAX_FILE_SIZE" value="30000">
Essa diretiva diz ao navegador o tamanho máximo de arquivo que pode ser enviado, onde o valor fornecido deve ser em bytes. Mas, é fácil contornar este limite, então não conte que o navegador irá obedecer a sua vontade. Mas você deve adicionar MAX_FILE_SIZE em qualquer caso, já que salva os usuarios que escapam do problema de esperar por um grande arquivo ser transferido e somente depois de tudo descobrir que ele é muito grande.
- Verificando com a variável $_FILES["arquivo"]["size"], onde no seu script haverá por exemplo um if:
<?php // Tamanho máximo do arquivo em bytes $maximo = 50000; // Verificação if($_FILES["arquivo"]["size"] > $maximo) { echo "Erro! O arquivo enviado por você ultrapassa o "; echo "limite máximo de " . $maximo . " bytes! Envie outro arquivo"; } ?> |
- Verificando com a variável $_FILES["arquivo"]["error"]:
Ao enviar um formulário de upload, a variável $_FILES["arquivo"]["error"] poderá conter os seguintes valores:
UPLOAD_ERR_OK Valor: 0; não houve erro, o upload foi bem sucedido. UPLOAD_ERR_INI_SIZE Valor 1; O arquivo no upload é maior do que o limite definido em upload_max_filesize no php.ini. UPLOAD_ERR_FORM_SIZE Valor: 2; O arquivo ultrapassa o limite de tamanho em MAX_FILE_SIZE que foi especificado no formulário html. UPLOAD_ERR_PARTIAL Valor: 3; o upload do arquivo foi feito parcialmente. UPLOAD_ERR_NO_FILE Valor: 4; Não foi feito o upload do arquivo. |
Então, assuma que seu formulário de upload seja:
<form action="script2.php" method="POST" enctype="multipart/form-data"> <input type="hidden" name="MAX_FILE_SIZE" value="30000"> Arquivo: <input name="arquivo" type="file"><BR> <input type="submit" value="Enviar"> </form> |
E o visitante faça um upload de um arquivo maior que o especificado em MAX_FILE_SIZE e maior que o da configuração upload_max_filesize. Seu script PHP (no caso script2.php), conterá as seguintes verificações:
<?php // Tamanho ultrapassa o MAX_FILE_SIZE do formulario if($_FILES["arquivo"]["error"] == UPLOAD_ERR_FORM_SIZE) { echo "O tamanho de seu arquivo ultrapassa o limite dado! Envie outro arquivo"; exit; } // Tamanho ultrapassa o limite da configuração upload_max_filesize do php.ini if($_FILES["arquivo"]["error"] == UPLOAD_ERR_INI_SIZE) { echo "O tamanho de seu arquivo ultrapassa o limite de tamanho de arquivo do PHP! "; echo "Envie outro arquivo"; exit; } ?> |
3.2 - Tipo dos arquivos
Assuma que você possui um site com a área de usuários, onde os mesmos possam enviar suas fotos. O tipo de imagem aceita seria apenas PNG. Mas, como sempre tem os "engraçadinhos" que possam acabar a enviando arquivos não-imagem, você então deve verificar se o arquivo é uma imagem. Para isso, você pode verificar a extensão do nome de arquivo ou o tipo de arquivo.
Mas, conforme expliquei em meu artigo, "Upload de Imagens com Seguranga", verificar a extensão do nome de arquivo não é seguro (leia o artigo citado para mais informações), então o melhor é sempre verificar o mime tipo do arquivo. Para isso, usa-se então a variável $_FILES["arquivo"]["type"] criada no upload de um arquivo.
No nosso exemplo, onde aceitamos apenas imagens PNG o mime tipo é: image/png.
O script que verificaria isso:
<?php // Verifica se o mime-type é de imagem PNG if($_FILES["arquivo"]["type"] !== "image/png") { echo "O arquivo enviado por você não é uma imagem PNG! Envie outro!"; } ?> |
Obs: Caso aceite mais tipos de arquivos, use expressões regulares na verificação. Há um exemplo disso no meu artigo "Upload de Imagens com Segurança".
3.3 - Nome dos arquivos
Vamos continuar com o nosso exemplo onde os usuários enviam suas fotos. Usuários podem acabar enviando arquivos com nomes com espaços, várias letras maiúsculas e minúsculas, etc... É recomendável você definir um padrão para os nomes de arquivos e o melhor é sempre colocar underscores ( _ ) no lugar de espaços e que todas as letras sejam minúsculas.
Assuma também que todas as fotos são salvas no mesmo diretório. Isso tem a falha de fotos de usuários acabarem ficando com o mesmo nome e se sobrescreverem, então 2 usuários diferentes tendo a mesma foto! Você pode verificar se o arquivo com mesmo nome já existe no diretório ou usar uma função que gera nomes únicos para a imagem. Aqui irei mostrar apenas a verificação do diretório, o nome único há no meu artigo "Upload de Imagens com Segurança".
<?php // Repassa a variável do upload $arquivo = isset($_FILES["arquivo"]) ? $_FILES["arquivo"] : FALSE; // Código acima... com as demais verificaçoes... // Diretório para onde o arquivo será movido $diretorio = "./arquivos/"; // Substitui espaços por underscores no nome do arquivo $nome = str_replace(" ", "_", $arquivo["name"]); // Todas as letras em minúsculo $nome = strtolower($nome); // Caminho completo do arquivo $nome = $diretorio . $nome; // Verifica se o arquivo existe no diretório dado if(file_exists($nome)) { echo "Um arquivo com esse nome já foi enviado! Envie outro arquivo!"; exit; } // Tudo ok! Então, move o arquivo if(move_uploaded_file($arquivo["tmp_name"], $nome)) { echo "Arquivo Enviado com sucesso!"; } else { echo "Erro ao enviar seu arquivo!"; } ?> |
Então é isso! Foi dada uma ampla explicação sobre os uploads de arquivos com o PHP. Futuramente estarei publicando um artigo explicando o upload de múltiplos arquivos direto do mesmo formulário.
Obs: Alguns textos e códigos foram pegos do Manual Oficial do PHP:
http://www.php.net/manual/pt_BR/features.file-upload.php
Obs2: Há uma lista ampla de Mime-Types aqui:
http://www.auriumsoft.com.br/mime_types.html
Alfred Reinold Baudisch
Desenvolvedor de Sistemas Web
alfred@auriumsoft.com.br
www.estacaonet.com