Upload De Arquivos Com PHP

Vocabulário: arquivos = ficheiros

Upload de arquivos. Não há muito a ser dito a não ser o que você precisa saber. Então vou parar de juntar frases e partir para os códigos.

Upload De Arquivos

Formulário Para Upload

Código básico HTML que permite ao usuário enviar uma imagem.


    <form action="upload-arquivo.php" method="post" enctype="multipart/form-data">
        <fieldset>
            <p><label for="Enviar arquivo">Enviar arquivo:</label></p>
            <input type="file" name="arquivo" class="width233" />
            <input type="submit" name="enviar" value="Enviar" />
        </fieldset>
    </form>

O elemento HTML utilizado para selecionar os arquivos a serem enviados é o file. Ele já vem com um botão embutido que oferece esta opção. Note que o name dele é “arquivo”.

Quando o formulário for enviar imagens, é necessário adicionar o atributo enctype. No nosso formulário ele tem o valor multipart/form-data para indicar que vamos enviar arquivos binários.

Tenha muita atenção na hora de programar para não esquecer do atributo enctype. Muitos fazem o script todo certo, mas esquecem dessa parte e perdem preciosos minutos. Se o arquivo não vai para o servidor e você não recebe mensagem de erro no navegador, são grandes as chances de você ter esquecido do enctype.

Código PHP

As informações enviadas pelo elemento file são armazenadas na array $_FILES[] do PHP. Supondo que enviamos uma imagem, veremos quais informações são fornecidas sobre ela.


<?php

$arquivo = $_FILES[‘arquivo’];
print_r($arquivo)

// Array
Array (
[name] => imagem.jpg
[type] => image/jpeg
[tmp_name] => C:\WINDOWS\Temp\php208.tmp
[error] => 0
[size] => 19189 )

?>

Na primeira linha a array $_FILES[] recebe as informações do campo nomeado “arquivo” do formulário. Em seguida para ver os dados contidos na array utilizamos o print_r.

O nome dos índices ajuda bastante a entender que informações eles guardam. São elas:

  • name – nome do arquivo;
  • type – tipo do arquivo;
  • tmp_name – local temporário do arquivo no computador do usuário;
  • error – se houve algum erro;
  • size – tamanho em bytes.

Nesse script eu resolvi criar uma variável para conter as informações do arquivo enviado. A idéia é tornar a digitação mais rápida e o código menor. Veja a diferença para acessar o índice name:


<?php

$_FILES[‘name’][‘arquivo’];
$arquivo[‘name’];

?>

Não existem certo ou errado, apenas jeitos diferentes de se atingir o mesmo objetivo. Os índices continuam os mesmos.

Restringindo O Tipo De Arquivo

O formulário que estamos criando é para o upload de imagens e vamos tratar o arquivo recebido como sendo uma. Mas e se o usuário envia um arquivo .pdf ou .exe? Como não estamos esperando isso, o código vai retornar um erro.

O índice type contém a declaração do tipo de arquivo que foi enviado, conhecido como mime-type. Através dele sabemos se foi enviado uma imagem, uma página web ou um arquivo de texto. A validação dos arquivos utilizando o type é mais indicada do que apenas checar qual a extensão do arquivo, pois esta pode ser trocada pelo usuário.

Uma imagem com extensão jpg, pode apresentar os seguintes mime-types:

  • image/jpeg
  • image/pjpeg
  • image/jpeg
  • image/pjpeg
  • image/jpeg
  • image/pjpeg

Validar todos esses mime-types demora um tanto. Por isso vamos validar os mais comuns para imagens .jpg.


<?php
$arquivo = $_FILES['arquivo'];
if ($arquivo['type'] == "image/jpeg" || $arquivo['type']== "image/pjpeg")
{
  echo "Arquivo aceito.";  
} else{
  echo "Arquivo inválido. É permitido somente imagem com extensão .jpg.";
}

?>

Na primeira linha nós verificamos se o mime-type do arquivo enviado é jpeg ou pjpeg Se for mostramos uma mensagem de aceito, senão informamos que a imagem não é permitida.

Podemos validar outros tipos de arquivo como .png e .html com o mesmo procedimento. Acess uma lista completa de mime-types.

Limitar Tamanho Do Arquivo Enviado

O limite padrão estipulado pelo PHP para o tamanho dos arquivos que podem ser enviados para o servidor é de 2MB. Você pode alterar este valor nas configurações do PHP, mas vamos trabalhar com este limite de tamanho. Até porque, uma imagem deste tamanho, para utilização online, esta mais do que bom.


<?php
  if ($arquivo['size']>500000)
  {
    exit('Arquivo muito grande. Tamanho máximo permitido 500kb. O arquivo enviado contém '.round($arquivo['size']/1024).'kb');  
  }
?>

Na primeira linha criamos uma condição que diz: “Se o tamanho do arquivo é maior do que 50.000bytes” executar o código abaixo. As verificações de tamanho dos arquivos sempre serão feitas utilizando os valores em bytes.

Sendo o tamanho do arquivo maior do que 500kb retornamos uma mensagem, usando exit, para que o código pare de ser executado, informando o tamanho excessivo do arquivo. Também avisamos qual o tamanho do arquivo atual fazendo um pequeno cálculo que divide o tamanho do arquivo enviado por 1024 e arredonda o valor.

A divisão por 1024 ocorre porque 1kb é formado por 1024 bytes.

Podemos fazer a verificação de tipo de arquivo e tamanho utilizando apenas uma condicional. Mas no final das contas, para poder mostrar mensagens personalizadas, serão necessárias tantas linhas quanto as que utilizamos fazendo as verificações separadamente.

Nome Único

Tudo certo. Agora sabemos que foi enviada realmente uma imagem. Vamos trabalhar agora o nome do arquivo e torná-lo único. E por que isso?

A princípio para evitar conflito com arquivos já existentes no servidor com o mesmo nome. E também porque alguns clientes escrevem o nome dos arquivos com acentuação e isso pode gerar problema mais adiante se o nome das imagens for salvo em um banco de dados.


<?php

  $novonome = md5(mt_rand(1,10000).$arquivo['name']).'.jpg';

?>

Para criar o novo nome da imagem utilizamos a função mt_rand() que sorteia um número randômico entre 1 e 10000 e concatena ele com o nome da imagem. Em seguida empregamos a função md5 que embaralha os caracteres que recebe e por fim concatenamos as letras e números embaralhados com a string ‘.jpg’ para criar o nome do arquivo.

Enviando Para O Servidor


<?php

  $dir = "img/";
  if (!file_exists($dir))
  {
    mkdir($dir, 0755);  
  }
  $caminho = $dir.$novonome;
  move_uploaded_file($arquivo['tmp_name'],$caminho);

?>

A variável $dir recebe o nome da pasta para onde será enviado o arquivo. Pode ser pasta dentro de pasta, apenas cuide para que a string acabe com uma barra.

Se a pasta “img/” não existir, ela é criada com a função mkdir. Informamos o nome da pasta e já especificamos as permissões dela com o 0755, que permite a opção de escrita para a pasta. Esta segunda opção nem sempre é necessária, mas é aconselhável já que alguns servidores têm um rígido controle de permissões de pastas e arquivos.

Concatenamos o nome da pasta com o nome do arquivo para formar o caminho deste no servidor.

E por fim enviamos o arquivo para o servidor com a função move_uploaded_file. Ela aceita dois parâmetros, a localização temporária do arquivo no computador do usuário e o caminho completo para onde será enviada no servidor.

O código completo fica assim:


<?php

$arquivo = $_FILES['arquivo'];
if ($arquivo['type'] == "image/jpeg" || $arquivo['type']== "image/pjpeg")
{
  if ($arquivo['size']>500000)
  {
    exit('Arquivo muito grande. Tamanho máximo permitido 500kb. O arquivo enviado contém '.round($arquivo['size']/1024).'kb');  
  }
  
  $novonome = md5(mt_rand(1,10000).$arquivo['name']).'.jpg';
  $dir = "img/";
  if (!file_exists($dir))
  {
    mkdir($dir, 0755);  
  }
  $caminho = $dir.$novonome;
  move_uploaded_file($arquivo['tmp_name'],$caminho);
  echo '<script type="text/javascript">alert("Arquivo enviado!")</script>';
  echo '<meta http-equiv="refresh" content="1; url=index.html" />';  
} else{
  echo "Arquivo inválido. É permitido somente imagem com extensão .jpg.";
}

?>

Com algumas alterações no código acima, você pode validar e enviar todo tipo de arquivo.

DOWNLOAD: Descarregue o código utilizado neste tutorial para o Upload De Arquivos Com PHP, em formato .zip.

Be Sociable, Share!

30 Comentários

  1. Rodrigo

    Muito obrigado pelo tutorial! Funcionou tudo direitinho e me ajudou bastante!!

  2. Edgar Galluzzo

    Cara, simplesmente perfeito. Tinha visto vários tutos mas nenhum funcionou. Parabéns e muito obrigado!

    Forte abraço

  3. Karlos

    OK!;;; Funcionou legal…Mas quando tentei fazer o uplaod de arquivo .mp3… iz as alterações mas no crome não funciona, porem no internet explorer ocorre tudo blz? Por que será esta incompatibilidade.?

  4. leandro

    parabéns, muito bom…

  5. Jhonatan Pereira

    Recebi a seguinte msg de erro: (http://mmdesigndigital.com.br/boot/imagem.htm)

    PHP Warning: move_uploaded_file(img/c1ef89a8e305df329ca35c6b357ffaeb.jpg) [function.move-uploaded-file]: failed to open stream: Permission denied in E:homemmdesigndi2Webbootupload-arquivo.php on line 35
    PHP Warning: move_uploaded_file() [function.move-uploaded-file]: Unable to move 'C:UsersTEMPUO~1.058AppDataLocalTempphp90C6.tmp' to 'img/c1ef89a8e305df329ca35c6b357ffaeb.jpg' in E:homemmdesigndi2Webbootupload-arquivo.php on line 35

  6. Olá, como faço para resolver o erro na linha 15?

    // Array

    15 – Array (

    [name] => imagem.jpg

    [type] => image/jpeg

    [tmp_name] => C:WINDOWSTempphp208.tmp

    [error] => 0

    [size] => 19189 )

    —————————————————–
    MSG DO SERVER: PHP Parse error: parse error in E:homemmdesigndi2Webbootupload-arquivo.php on line 15

  7. Leandro

    só esqueceu de mencionar algo PRIMORDIAL neste tutorial e esta dando problema para todo mundo. o arquivo HTML é um arquivo à parte e o código PHP é outro. ou seja, o php não fica junto com o html. o código fonte no final do tutorial é o completo, e…existe um erro que se você carregar um arquivo .JPEG (maiúsculo) ele não sabe diferenciar de .jpeg (minúsculo) e ocorre erro informando que não é um arquivo .jpeg válido.

  8. Está ocorrendo este erro:

    PHP Warning:  move_uploaded_file(img/upload/6d32e889ea69e034f554633ca310fa4d.jpg) [function.move-uploaded-file]: failed to open stream: Permission denied in E:homekolbrasilWebv2upload_arquivo.php on line 25
    PHP Warning:  move_uploaded_file() [function.move-uploaded-file]: Unable to move 'C:WINDOWSTempphp5EE.tmp' to 'img/upload/6d32e889ea69e034f554633ca310fa4d.jpg' in E:homekolbrasilWebv2upload_arquivo.php on line 25

    O que ocorre?

  9. Led Lemos

    A respeito da duvida anterior que mandei, consegui resolver…. Apenas mudar a permissao para 755 ==b

    Como faço para o nome da imagem, invés de ser tmp_name, ser o nome da pessoa que enviou o arquivo?

  10. Paulinho

    Parabéns cara, rodei pela net e só achei coisas que me confundisse ainda mais. Muito bem explicado e muito melhor quando se explica cada coisa e como funciona, assim a pessoa aprende ai invés de decorar!!! Parabéns ai novamente! 

  11. Pedro

    ótimo trabalho amigo.

    gostaria de manter o nome do arquivo original, como faço?

    grato

  12. getulio

    cara usei esse script para fazer um sistema de gerenciamento de arquivos. até ai tudo bem, mas agora tenho uma grande problema.

    gravei os dados do upload no mysql.

    gerei o link para download, que chama um formulario que o usuario deve preencher para acionar o download. A ideia eh acionar o download quando o cara pressionar o submit.

    fiz algum mas da uns erros e tals.

  13. kenny rafael

    muitiiissimo obrigado, graças a esse post descobri que faltava o enctype no meu codigo…

  14. Guilherme

    Muito interessante..funcionou corretamente. Mas e se eu precisar fazer o upload de varias imagens, sem uma quantidade definida. Como eu faria?

  15. Luan

    como faço pra ter o link da imagem quando enviada para outra pessoa poder tela ?

  16. e onde a imagem vai parar depois disso

  17. OusadoRafael

    muito bom mesmo esse código, comparado com os outros que já vi, esse da dez a zero, esta bem simples e eficiente.

  18. wander santos

    Beleza……..agora como fazer pra esta imagem ficar no formulario, como se fosse um cadastro de funcionario com opção pra ficar a foto ao lado?

    • Miguel

      Com o código apresentado neste site você vai enviar a imagem pra uma pasta chamada "img", daí é só chamar ela como qualquer outra imagem.

  19. Thiago

    Boa tarde, parabéns. Consigo fazer o upload do arquivo para um servidor de arquivos que não seja meu servidor web?

  20. cassiane

    ali em novo nome vc utiliza a extensão.jpeg no final mas e se por um acaso o arquivo que foi baixado não for jpeg ? como eu colocaria pra ele colocar a terminação certa do arquivo?

  21. FERNANDO

    Olá!

    Estou tentando criar um botão de upload de arquivos que envie documentos do Word, Excel, PDF diretamente do meu site. 
    É para receber orçamentos e cotações. 
    Gostaria de criar numa linguagem simples, HTML de preferência, pois não sei usar PHP. 
    Um Form que faça upload de pelo menos 3 arquivos 
    Preciso que o site envie os documentos diretamente para meu e-mail.
    Não há necessidade de campos nome, assunto, etc!
    Poderia me ajudar? 

  22. Miguel

    Boa tarde,
    No código que você mostra, caso seja anexado um arquivo com mais do que 2 mb, acredito que irá dar problema, pois no formulário html o tamanho máximo padrão já é de 2 mb. Neste caso como o arquivo é maior que 2 mb ele não irá passar nada para o arquivo php, e assim não será feita nenhuma operação. Quando testei ele alegou erro na extensão, e testando mais pude ver que não tinha nada, ou seja, o arquivo estava zerado. Você sabe como posso resolver esse problema???

  23. Ricardo

    Muito bom tutorial.
    No meu caso estou tentando enviar arquivos mp3 e no localhost funciona 100% já no meu servidor diz que o tipo de arquivo está incorreto. 
    Se alguém puder me ajudar agradeço.

    require_once ("../db_con.php");

    // Lista de tipos de arquivos permitidos
    $tiposPermitidos= array('audio/mpeg', 'audio/x-mpeg', 'audio/mp3', 'audio/x-mp3', 'audio/mpeg3', 'audio/x-mpeg3', 'audio/mpg', 'audio/x-mpg', 'audio/x-mpegaudio', 'video/mpeg', 'video/x-mpeg', 'video/mpeg','mp3', 'application/force-download','application/octet-stream' );
    //tiposPermitidos= array('mp3' );
    // Tamanho máximo (em bytes)
    $tamanhoPermitido = 1024 * 995500; // 500 Kb

    $titulo   = $_POST['titulo'];
    $obs  = $_POST['obs'];
    $tempo  = $_POST['tempo'];
    $preletor = $_POST['preletor'];

    $sucesso  = "Arquivo Enviado com sucesso!";

    // O nome original do arquivo no computador do usuário
    $arqName = $_FILES['arquivo']['name'];
    // O tipo mime do arquivo. Um exemplo pode ser "image/gif"
    $arqType = $_FILES['arquivo']['type'];
    // O tamanho, em bytes, do arquivo
    $arqSize = $_FILES['arquivo']['size'];
    // O nome temporário do arquivo, como foi guardado no servidor
    $arqTemp = $_FILES['arquivo']['tmp_name'];
    // O código de erro associado a este upload de arquivo
    $arqError = $_FILES['arquivo']['error'];

    if ($arqError == 0) {
            // Verifica o tipo de arquivo enviado
    if (array_search($arqType, $tiposPermitidos) === false) {
    echo var_dump($arqType);
    echo 'O tipo de arquivo enviado &eacute; inv&aacute;lido!';
    // Verifica o tamanho do arquivo enviado
    } else if ($arqSize > $tamanhoPermitido) {
    echo 'O tamanho do arquivo enviado &eacute; maior que o limite!';
    // Não houveram erros, move o arquivo
    } else {
    $pasta = '../content/mp3/';
    // Pega a extensão do arquivo enviado
    $extensao = strtolower(end(explode('.', $arqName)));
    // Define o novo nome do arquivo usando um UNIX TIMESTAMP
    $nome = time() . '.' . $extensao;
    $prefix = "byCelso";
    $nome = ($prefix.$nome);

    $upload = move_uploaded_file($arqTemp, $pasta . $nome);

    if ($upload == true) {

    $dirSalvar = "content/mp3/";
    $pathArquivo = ($dirSalvar.$nome);
    $obsAjuste = ("—");
    $obsAjuste = ($obsAjuste.$obs);
    $status = 1;
    $data = date('Y-m-d H:i:s'); // Formato DATETIME: 2009-03-12 03:39:57
    $sql = "INSERT INTO mensagem(idmensagem, titulo, idpreletor, data, status, nome_arquivo, path_arquivo, obs, duracao) VALUES (NULL,'".$titulo."', '".$preletor."', '".$data."', '".$status."', '".$nome."','".$pathArquivo."', '".$obsAjuste."', '".$tempo."')";
    //$res = mysqlexecuta($id,$sql);
    $query = mysql_query($sql);

    echo 'Arquivo inserido com sucesso!'."";

    //if ($res == true) {
    //echo 'Arquivo inserido com sucesso!';

    //}

    }
    echo "T&iacute;tulo da Mensagem:"." ".$titulo;?><?
    echo "Nome do Arquivo MP3:"." ".$nome;?><?
    echo $sucesso;
    }
    }else {

            echo 'Ocorreu algum erro com o upload, por favor tente novamente!';

        }
    ?>
    <script>
    function link()
    {
    window.open('index.php', '_top');
    }
    </script>

    <input type='button' value='Para Enviar Outro Arquivo Clique Aqui' onClick='link()'>

  24. lino

    ótimo trabalho amigo. 

    gostaria de manter o nome do arquivo original, como faço? 

    grato

  25. thiago

    posta o link para downlaod

  26. teleo83

    Excelente tutorial. isso mesmo que eu precisava. só gostaria de saber mais um topico. se alguem puder ajudar… estou procurando pelos foruns também.

    Gostaria de junto com a foto com a imagem fosse enviado um email a geolocalizacao do PC que enviou a foto. Será que é possivel?
    obrigado

Participa! Comenta... para FERNANDO