W3docs

Upload de Arquivos em PHP

Aprenda a realizar uploads de arquivos em PHP com $_FILES, move_uploaded_file() e validação segura de tipo e tamanho.

O upload de arquivos é um requisito comum no desenvolvimento web. Seja uma foto de perfil, um documento PDF ou uma importação CSV, permitir que os usuários enviem arquivos para o servidor é uma funcionalidade essencial na maioria das aplicações. Em PHP, isso é feito com a função move_uploaded_file() em conjunto com o array superglobal $_FILES.

Este capítulo cobre todo o fluxo de upload: configurar o formulário HTML, ler os metadados do arquivo enviado a partir de $_FILES, validá-los com segurança e mover o arquivo para seu destino final. Também aborda os códigos de erro de upload e as configurações do PHP que controlam os limites de upload.

Como funciona o upload de arquivos em PHP

O upload de um arquivo ocorre em três etapas:

  1. O navegador envia o arquivo em uma requisição POST do tipo multipart/form-data.
  2. O PHP recebe o arquivo e o grava em um local temporário no disco, expondo os detalhes sobre ele no array $_FILES.
  3. O script valida o arquivo e o move do local temporário para um local permanente com move_uploaded_file().

O arquivo temporário é excluído automaticamente ao final da requisição se você não o mover, portanto, é necessário processá-lo durante a mesma requisição.

O superglobal $_FILES

Quando um arquivo é enviado, as informações sobre ele são armazenadas no array superglobal $_FILES. Para um campo de formulário chamado userfile, o array contém as seguintes chaves:

  • $_FILES['userfile']['name'] - O nome original do arquivo enviado.
  • $_FILES['userfile']['type'] - O tipo MIME do arquivo enviado.
  • $_FILES['userfile']['size'] - O tamanho do arquivo enviado em bytes.
  • $_FILES['userfile']['tmp_name'] - O local temporário do arquivo enviado no servidor.
  • $_FILES['userfile']['error'] - Um código de erro indicando se houve algum problema durante o upload (veja os códigos de erro abaixo).

Passo 1: O formulário HTML

O atributo enctype do formulário deve ser definido como multipart/form-data, e o método deve ser POST. Sem multipart/form-data, o navegador envia apenas o nome do arquivo, não o seu conteúdo, e $_FILES ficará vazio.

<form action="upload.php" method="POST" enctype="multipart/form-data">
  <input type="file" name="userfile">
  <input type="submit" value="Upload">
</form>

Passo 2: Validar o upload

Nunca confie em um arquivo enviado. Antes de movê-lo, verifique três coisas: se o upload foi bem-sucedido, se o tamanho está dentro do limite definido e se o arquivo realmente é do tipo esperado.

Verificar o código de erro

Sempre inspecione $_FILES['userfile']['error'] primeiro. O PHP define constantes nomeadas para os possíveis valores:

ConstanteValorSignificado
UPLOAD_ERR_OK0Sem erros, o arquivo foi enviado com sucesso.
UPLOAD_ERR_INI_SIZE1O arquivo excede upload_max_filesize no php.ini.
UPLOAD_ERR_FORM_SIZE2O arquivo excede o campo MAX_FILE_SIZE do formulário.
UPLOAD_ERR_PARTIAL3O arquivo foi enviado apenas parcialmente.
UPLOAD_ERR_NO_FILE4Nenhum arquivo foi enviado.
UPLOAD_ERR_NO_TMP_DIR6Pasta temporária ausente.
UPLOAD_ERR_CANT_WRITE7Falha ao gravar o arquivo no disco.

Validar tipo e tamanho com segurança

Não confie em $_FILES['userfile']['type']. Esse valor é fornecido pelo navegador e pode ser facilmente falsificado por um atacante. Em vez disso, detecte o tipo MIME real a partir do conteúdo do arquivo com a extensão finfo e aplique um limite de tamanho você mesmo:

$file = $_FILES['userfile'];

// 1. Did the upload succeed?
if ($file['error'] !== UPLOAD_ERR_OK) {
  exit("Upload failed with error code " . $file['error']);
}

// 2. Enforce a maximum size (2 MB here).
$maxBytes = 2 * 1024 * 1024;
if ($file['size'] > $maxBytes) {
  exit("File is too large.");
}

// 3. Detect the real MIME type, not the client-supplied one.
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime  = $finfo->file($file['tmp_name']);

$allowed = [
  'image/jpeg' => 'jpg',
  'image/png'  => 'png',
  'image/gif'  => 'gif',
];

if (!isset($allowed[$mime])) {
  exit("Only JPEG, PNG, and GIF images are allowed.");
}

Passo 3: Mover o arquivo para seu destino final

Após validar o arquivo, mova-o com move_uploaded_file(). Essa função recebe dois argumentos: o caminho temporário ($_FILES['userfile']['tmp_name']) e o caminho de destino. Usar essa função em vez de copy() ou rename() é importante — ela verifica se o arquivo foi realmente enviado via HTTP, bloqueando um atacante de enganar o script para mover um arquivo arbitrário do servidor.

Gere o nome final do arquivo você mesmo, em vez de confiar no nome original. Isso evita ataques de travessia de diretório (como um nome ../../config.php) e a sobrescrita de arquivos existentes:

$targetDir = "uploads/";

// Build a safe, unique file name; never trust the client's name.
$extension  = $allowed[$mime];
$safeName   = bin2hex(random_bytes(8)) . "." . $extension;
$targetFile = $targetDir . $safeName;

if (move_uploaded_file($file['tmp_name'], $targetFile)) {
  echo "The file was uploaded as " . $safeName;
} else {
  echo "There was an error saving the file.";
}

Para mais detalhes sobre essa função e sua companheira is_uploaded_file(), consulte os capítulos de referência move_uploaded_file() e is_uploaded_file().

Configurações que afetam os uploads

Algumas diretivas do php.ini limitam silenciosamente o que o script pode receber. Se os uploads falharem para arquivos grandes mesmo com o código correto, verifique estas configurações:

  • file_uploads — deve estar On para que os uploads funcionem.
  • upload_max_filesize — o maior arquivo individual que o PHP aceitará (padrão 2M).
  • post_max_size — o maior corpo de POST total; deve ser maior que upload_max_filesize.
  • max_file_uploads — o número máximo de arquivos em uma única requisição.

Conclusão

O upload de arquivos em PHP é uma parte fundamental do desenvolvimento web. Com o array superglobal $_FILES e a função move_uploaded_file(), você pode lidar com uploads em poucas linhas. A parte difícil é fazê-lo com segurança: sempre verifique o código de erro do upload, aplique um limite de tamanho, detecte o tipo MIME real com finfo em vez de confiar em $_FILES[...]['type'] e gere seu próprio nome de arquivo para que o cliente nunca controle onde o arquivo será armazenado. Para processar o arquivo salvo posteriormente, consulte manipulação de arquivos PHP e validação de formulários.

Prática

Prática
Quais das afirmações a seguir sobre upload de arquivos em PHP estão corretas?
Quais das afirmações a seguir sobre upload de arquivos em PHP estão corretas?
Was this page helpful?