Upload de arquivos com jquery e barra de progresso

Fala galera, tudo bem? No post de hoje veremos uma forma bem legal de colocar um simpático formulário de upload de arquivos com barra de progresso utilizando AJAX(JQuery).

Para acompanhar o post, recomendo a leitura desse post, que é onde abordo uma função php para fazer o upload de arquivos de forma segura e simples. É essa função que utilizarei no exemplo de hoje.Para começar, baixe o JQuery e o plugin JQuery.Form. Feito isso, nossa estrutura de diretórios e arquivos deverá ficar da seguinte maneira:

  • index.php (Página onde vai o formulário)
  • jquery.js (Plugin javascript)
  • jquery.form.js (Plugin Jquery para trabalhar com formulários)
  • upload.js (Define as regras da requisição assincrona)
  • enviar_arquivo.php (Realiza o upload do arquivo)
  • funcao_upload.php (Função para auziliar o download)
  • uploads (Diretório onde os arquivos serão salvos)

Ressalto que no nosso exemplo trabalharemos apenas com upload de imagens. Mas fique à vontade para trabalhar com o upload de qualquer tipo de arquivo.

Arquivo index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html>
    <head>
        <title>www.rafaelwendel.com - Upload de arquivos com barra de progresso</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <script src="jquery.js" type="text/javascript"></script>
        <script src="jquery.form.js" type="text/javascript"></script>
        <script src="upload.js" type="text/javascript"></script>
    </head>
    <body>
        <h1><a href="http://www.rafaelwendel.com" target="blank" rel="noopener">www.rafaelwendel.com</a> - Upload de arquivos com barra de progresso</h1>
        <form name="formUpload" id="formUpload" method="post">
            <label>Selecione o arquivo: <input type="file" name="arquivo" id="arquivo" size="45" /></label>
            <br />
            <progress value="0" max="100"></progress><span id="porcentagem">0%</span>
            <br />
            <input type="button" id="btnEnviar" value="Enviar Arquivo" />
        </form>
        <div id="resposta">
 
        </div>
    </body>
</html>

No cabeçalho faço a inclusão dos 3 arquivos javascripts que serão utilizados. No corpo, insiro um formulário de nome/id “formUpload” e dentro desse formulário o campo do tipo “file” chamado “arquivo”.

Na linha 15 é onde vai a barra de progresso que inicialmente tem o valor de 0% e que será preenchida automaticamente quando o upload estiver sendo executado.

Depois vem o botão “btnEnviar” que será o responsável para submeter o formulário.

A div “resposta” será o local onde exibiremos as mensagens retornadas pelas requisições AJAX.

Agora vamos à implementação do arquivo upload.js . É nesse arquivo que definiremos as regras para a requisição assíncrona para upload do arquivo.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$(document).ready(function(){
    $('#btnEnviar').click(function(){
        $('#formUpload').ajaxForm({
            uploadProgress: function(event, position, total, percentComplete) {
                $('progress').attr('value',percentComplete);
                $('#porcentagem').html(percentComplete+'%');
            },        
            success: function(data) {
                $('progress').attr('value','100');
                $('#porcentagem').html('100%');                
                if(data.sucesso == true){
                    $('#resposta').html('<img src="'+ data.msg +'" />');
                }
                else{
                    $('#resposta').html(data.msg);
                }                
            },
            error : function(){
                $('#resposta').html('Erro ao enviar requisição!!!');
            },
            dataType: 'json',
            url: 'enviar_arquivo.php',
            resetForm: true
        }).submit();
    })
})

Definimos a ação no botão “btnEnviar”. Quando ele for clicado o “formUpload” é submetido via requisição AJAX. É aí que definimos as regras através dos parâmetros descritos à seguir:

  • uploadProgess :responsável por gerenciar o progresso do upload (barra de progresso)
  • sucess : o que fazer em caso de sucesso (Se tudo der certo ele exibe na div “resposta” a imagem que foi enviada)
  • error : o que fazer em caso de erro (Exibe na div “resposta” uma mensagem de erro)
  • dataType : o tipo de dado que será uilizado na transmissão de informações (note que utilizamos o JSON em nosso exemplo)
  • url : a arquivo server-side que será executado (No caso: enviar_arquivo.php)
  • resetForm : resetar o formulário ao término da execução

Agora só falta o arquivo enviar_arquivo.php que é o responsável por fazer o trabalho em si do upload do arquivo “por baixo dos panos”.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
/* Importa o arquivo onde a função de upload está implementada */
require_once('funcao_upload.php');
 
/* Captura o arquivo selecionado */
$arquivo = $_FILES['arquivo'];
 
/*Define os tipos de arquivos válidos (No nosso caso, só imagens)*/
$tipos = array('jpg', 'png', 'gif', 'psd', 'bmp');
 
/* Chama a função para enviar o arquivo */
$enviar = uploadFile($arquivo, 'uploads/', $tipos);
 
$data['sucesso'] = false;
 
if($enviar['erro']){    
    $data['msg'] = $enviar['erro'];
}
else{
    $data['sucesso'] = true;
 
    /* Caminho do arquivo */
    $data['msg'] = $enviar['caminho'];
}
 
/* Codifica a variável array $data para o formato JSON */
echo json_encode($data);

Ele utiliza a função uploadFile que está implementada no funcao_upload.php. As informações de sucesso ou erro são armazenadas dentro de um array que no final é codificado para o formato JSON para que o javascript seja capaz de recebê-las e utilizá-las.

E ponto final. Teste o seu formulário. Se tudo ocorrer corretamente, após o término do upload a imagem será exibida na tela.

Para fazer o download dos arquivos do post, clique aqui.

Em caso de dúvidas, utilize a caixa de comentários.

Abs

Siga-me no twitter: @rafaelwendel

É formado em Sistemas de Informação, pós-graduado em Sistemas de Banco de Dados e mestre em Educação com foco em Tecnologias Sociocomunitárias. Trabalha como professor de ensino técnico e tecnológico no Instituto Federal de Educação, Ciência e Tecnologia de São Paulo ministrando disciplinas nas áreas de programação, banco de dados, desenvolvimento de projetos e engenharia de software.

Posts relacionados

Comentários

    1. Bom dia Leonardo. O problema ocorre por alguns erros no código PHP.
      Faça as seguintes alterações e tudo vai funcionar corretamente:

      funcao_upload.php
      $nomeOriginal = $nomeOriginal . $infos[$i] . “.”; // Errado, variável $nomeOriginal não existe
      $nomeOriginal = $arquivo[“name”] . $infos[$i] . “.”; // Correto

      enviar_arquivo.php:
      if($enviar[‘erro’]){ // Errado, pode não existir um erro
      $data[‘msg’] = $enviar[‘erro’];
      }

      if(isset($enviar[‘erro’])){ Correto, se existir um erro mostra o erro
      $data[‘msg’] = $enviar[‘erro’];
      }

      Com essas alterações funciona perfeitamente. Um abraço

  1. Rafael testei os arquivos aqui mas sempre reporta o seguinte erro: já dei uma olhada nos arquivos js e php e não consegui encontrar a causa do problema;

    Dei permissão total para a pasta e não adiantou;

    Tem alguma extensão ou modulo do PHP e apache que deva ser liberada em especifico para funcionar as classes?

    1. Olá Rodrigo,

      Nada deve ser habilitado para que o upload funcione sem problemas.

      O erro (“Erro ao enviar requisição” – Linha 19) acontece porque por algum motivo a requisição AJAX não conseguiu ser efetuada.

      Possíveis causas:
      – URL está incorreta.
      – Nao houve um retorno no formato JSON esperado
      – Algum erro na URL que esta sendo executada.

      Dê uma olhada no seu código e vê se tudo está de acordo.

      Abs!

      1. Rafael eu fiz o teste com algumas alterações simples e com o script orginal baixado

        no arquivo original é necessário fazer alguma alteração para que o script funcione???

        Obs.: Testei o script via WAMP

    1. Cícero, basta alterar a linha 12 do código JQuery para:

      12
      
      $('#resposta').html('<a href="'+ data.msg +'" rel="nofollow">Clique aqui para fazer o download</a>');

      Abs!

  2. Rafa, eu tentei de tds as formas. na index.php, no enviar_arquivo.php, no funcao_upload.php.

    Só nao tentei no tal php .ini pq nao sei aonde é isso…
    Não tem como vc nos ensinar da mesma maneira que fez aqui nessa página?
    Fazer um tutorial bem detalhado.
    Não digo entregar os arquivos de mão beijada, apenas mostrar como se faz.
    Estou entrando nesta área agora , e ja cheguei na pagina 60 do google e não consegui achar a maneira correta de se fazer esses arquivos grandes subirem.
    Hoje eu vejo a falta que faz um professor rsrsrsrs

    Desde já meu muito Obrigado.

  3. Aew rafael blz?

    É seguinte estou tendo problemas com o servidor local e o da minha hospedagem.

    No local ocorre tudo bem, mas no da minha hospedagem ocorre o seguinte erro: Erro ao enviar requisição.

    Qual será o motivo?
    Será que a hospedagem nao da surporte a JSON, ou Jquery?

    Abraço e parabens pelo blog.

    1. Olá Jonatas.

      O javascript é rodado do lado cliente e não servidor, logo não pode ser problema de suporte da hospedagem.

      Para tentar descobrir o erro, altere a linha 19 (de acordo com meu exemplo) do arquivo upload.js para:

      19
      
      $('#resposta').html('Erro ao enviar requisição!!!' + data.responseText );

      Isso fará ele “imprimir” a mensagem de erro. Verifique a mensagem e tente pesquisar soluções ou poste ela aqui.

      Abs!

  4. Opa,
    Alguém está com problema no IE9 ? , ele faz o Upload mas sem barra de progresso.
    FF e Chrome vai bem.

    Ps: Parabéns pelo Artigo

    Jaguer

  5. Rafael, estou ficando louco já… rsrs…
    Aqui está dando erro de:
    – Uncaught TypeError: Object [object Object] has no method ‘ajaxForm’.

    Não sei mais onde mexer pra que funcione. Já comparei umas 300 vezes o seu arquivo com o meu e nada…

    Abraços…

  6. Esqueci de postar o meu código…

    $(document).ready(function(){

    $(‘#btnEnviar’).click(function(){
    var arquivo = $(‘#arquivo’).val();
    extensoes_permitidas = new Array(“.zip”, “.rar”, “.pdf”);
    if (!arquivo) {
    $.post(“dlf.php”, {act: “ai”}, function(data) {
    $(“#lightbox-msg, #lightbox-panel-msg”).fadeIn(300);
    $(‘#lightbox-panel-msg’).load(“carq.php?v=”+data);
    });
    $(‘#barrafundo’).hide();
    }else{
    extensao = (arquivo.substring(arquivo.lastIndexOf(“.”))).toLowerCase();
    permitida = false;
    for (var i = 0; i < extensoes_permitidas.length; i++) {
    if (extensoes_permitidas[i] == extensao) {
    permitida = true;
    break;
    }
    }
    if (!permitida) {
    $.post("dlf.php", {act: "ae"}, function(data) {
    $("#lightbox-msg, #lightbox-panel-msg").fadeIn(300);
    $('#lightbox-panel-msg').load("carq.php?v="+data);
    });
    $('#barrafundo').hide();
    }else{

    var barra = $('#barra');
    $('#barrafundo').show();
    $('#formUpload').ajaxForm({
    uploadProgress: function(event, position, total, percentComplete) {
    barra.width(percentComplete*5);
    $('#porcentagem').html(percentComplete+'%');
    },
    success: function(data) {
    barra.width(500);
    $('#porcentagem').html('100%');
    if(data.sucesso == true){
    $.post("dlf.php", {act: "ao"}, function(data) {
    $("#lightbox-msg, #lightbox-panel-msg").fadeIn(300);
    $('#lightbox-panel-msg').load("carq.php?v="+data);
    });
    }else{
    var resp = data.msg;
    $.post("dlf.php", {act: ""+resp+""}, function(data) {
    $("#lightbox-msg, #lightbox-panel-msg").fadeIn(300);
    $('#lightbox-panel-msg').load("carq.php?v="+data);
    });
    $('#barrafundo').hide();
    }
    },
    error : function(){
    var respp = data.msg;
    $.post("dlf.php", {act: ""+respp+""}, function(data) {
    $("#lightbox-msg, #lightbox-panel-msg").fadeIn(300);
    $('#lightbox-panel-msg').load("carq.php?v="+data);
    });
    },
    dataType: 'json',
    url: 'enviararquivo.php',
    resetForm: true
    }).submit();

    }
    }
    });

    });

  7. Muito bom o tutorial, facil de ententer!!!

    Mas estou com um problema: nao esta sendo enviado corretamente o campo file pelo ajax.
    O php me deu a seguinte mensagem: “Notice: Undefined index: arquivo in C:\wamp\www\aptana\UPLOAD\enviar_arquivo.php on line 6″
    Entao adicionei essa linha:
    var_dump($_FILES);
    antes da linha:
    $arquivo = $_FILES[‘arquivo’];
    e deu como resultado:
    array
    empty

    Tentei mudar o enctype do formulario, mas nao mudou nada.
    Coloquei também essa linha:
    var_dump($_POST);
    e deu o resultado:
    array
    ‘arquivo’ => string ” (length=0)

    Alguem sabe como resolver este problema??? xD

  8. Olá Rafael, também utilizo este script para upload de arquivos e estou tendo um problema.
    Ao testar o script localmente tudo funciona perfeitamente, mas ao testar no servidor e tentar enviar um arquivo com algum caracter especial no nome (exemplo: [name’sfile.jpg]) é retornado um erro de requisição (no caso no teste que fiz com seus arquivos, no meu caso retorna SyntaxError: JSON.parse: unexpected character), mas acredito que o erro seja o mesmo.
    Você sabe como validar esse envio de dados para solucionar o problema? Já estou tentando a algum tempo e pelos testes que venho fazendo o problema parece nem chegar no arquivo php, parece estar no próprio script do jQuery.Form. Já fez esse teste?

    Obrigado e fico no aguardo…
    Abraços.

  9. Bom dia Rafael
    Estou com problema onde o arquivo é enviado, mas a barra de progresso não anda, e o retorno do arquivo não carrega, mas se eu clicar sem selecionar arquivo o erro vem, se eu colocar alguma extensão não permitida ele tambem não dar retorno, alguma ideia do que seria?
    e parabens pelo post.

    Geraldo

  10. Boa tarde,
    Parabéns, ótimo código!
    Consigo alterar o caminho do upload do arquivo para outro servidor, que não seja o web e sim um servidor de arquivos.
    Grato

  11. Boa tarde Rafael,
    Na linha 12 do arquivo ‘enviar_arquivo.php’, o segundo parâmetro é o diretório para onde realizamos o upload, eu poderia colocar um servidor da rede neste parâmetro. Por exemplo:
    $enviar = uploadFile($arquivo, ‘\\meuservidor\public\uploads/’, $tipos);

    Explicando melhor, o servidor web para onde realizo os uploads tem pouco espaço em disco, mas tem um servidor de arquivos que seria exatamente para receber estes arquivos.
    Ou se conseguir pensar em alguma outra solução e me dar uma dica.

    A linha 12 do arquivo é essa:
    /* Chama a função para enviar o arquivo */
    $enviar = uploadFile($arquivo, ‘uploads/’, $tipos);

    Valeu!

  12. Rafael, blz…
    Muito bom este seu script….
    Vc poderia me ajudar somente com uma coisa…?
    preciso que seja enviado também uma frase que faz ser digitada em uma caixa de texto…

  13. 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?

  14. Rafael, simplesmente perfeito.
    Estava tentando com o uploadfy e até deu certo, mas pra customizar os erros eu estava apanhando d+, até encontrar seu post com esta outra abordagem… Muito obrigado cara, sou seu fã… forte abraço…

  15. Blz fera..
    Gostaria de tirar uma duvida em relação ao meu código..
    ao enviar a imagem, está enviando duas de cada vez. o que sera?
    no aguardo..
    ate+

  16. Olá amigo parabéns pelo post gostaria de saber se têm como acrescentar vários inputs para enviar mais de 1 anexo e se tiver como além de enviar para a pasta de uploads se têm como enviar tbm para o email de destino ?

  17. Boa tarde, tudo bem, primeiramente gostaria de parabenizá-lo pelo seu trabalho, tem ajudado muitos desenvolvedores iniciantes a não se tornarem script kiddies, ou moleques de script, enfim, eu estou com uma dúvida e não consegui resposta pelos meios convencionais, você sabe se tem algum meio de colocar no meu site um botão de upload que façam os arquivos irem para o 4shared ou algum outro serviço de Cloud Hosting disponível na internet ?°
    Att,

    Luciano dii Souza WD.
    + 55 31 9831-3692

    1. Olá Luciano,

      Isso aí depende se o provedor oferece o serviço. Dando uma rápida pesquisada aqui vejo que o 4shared oferece uma API para que desenvolvedores conectem suas aplicações e utilizem os serviços do site. Porém, para implementar você precisará de conhecimentos pelo menos intermediários em PHP ou outra linguagem.

      Bom, segue link (em inglês) para você dar uma olhada: http://help.4shared.com/index.php/SOAP_API

      Boa sorte.

      Abs!

  18. Boa tarde, Cara muito bom esse tutorial, parabéns e obrigado pelas dicas de ouro!

    Gostaria de saber se tem como adaptar esse script para fazer upload de vários arquivos, tipo quando clicar para procurar o arquivo poder selecionar vários arquivos?

    Obrigado!

  19. Sei que o post é meio antigo mas não custa perguntar… preciso salvar o nome do arquivo “upado” e algumas outras informações sobre o arquivo no banco de dados. Minha dúvida é, onde executo o script myql para inclusão no banco de dados?

  20. Olá, amigo! Parabéns pelo artigo, muito bom!
    Só um dúvida… estou com o mesmo problema de alguns acima, da linha 19 do arquivo ‘upload.js’. Ele apresenta o erro “Erro ao enviar requisição!!!” ao término do upload, porém o arquivo é salvo normalmente na pasta nomeada.
    O que pode estar ocasionando este erro?
    Acrescentei a função para mostrar o erro na tela, e me retornou isso: http://i.snag.gy/iKjNg.jpg
    Agradeço desde já!
    Abraço

    1. Olá Thiago,

      Esse “Notice” na verdade não é necessariamente um erro. Ela apareceu não porque deu algum erro no script mas porque você tentou usar uma variável que não existe (nomeOriginal) e acessar uma posição inexistente no array (erro). Como esse notice é disparado, o AJAX entende que o arquivo .php não foi executado direito. Você pode desabilitar o aparecimento desse tipo de mensagem (os notices). Dê uma olhada em http://forum.imasters.com.br/topic/470546-ocultar-notice-php/

      Ou se preferir pode refatorar o seu código verificando as variáveis e arrays.

      Abs!

  21. falae rafael, bom dia.

    cara, preciso implementar um retorno de pagina, o que seria mais interessante, no jquery ou no php?
    outra duvida, se fosse um upload tipo do instagram, ele começa o upload no retorno da pagina. daria para fazer com este form?

    abraço
    elio

  22. Muito obrigado Rafael, me foi de muita ajuda! Demorei um dia inteiro para descobrir que eu estava usando uma variável $data no meu código, por isso dava erro no Json, mudei o nome para $datax e tudo funcionou perfeitamente!

Deixe um comentário

O seu endereço de e-mail não será publicado.