Como posso enviar arquivos de forma assíncrona?

2914

Gostaria de fazer upload de um arquivo de forma assíncrona com o jQuery.

$(document).ready(function () {
    $("#uploadbutton").click(function () {
        var filename = $("#file").val();

        $.ajax({
            type: "POST",
            url: "addFile.do",
            enctype: 'multipart/form-data',
            data: {
                file: filename
            },
            success: function () {
                alert("Data Uploaded: ");
            }
        });
    });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<span>File</span>
<input type="file" id="file" name="file" size="10"/>
<input id="uploadbutton" type="button" value="Upload"/>

Em vez de o arquivo ser carregado, estou obtendo apenas o nome do arquivo. O que posso fazer para corrigir esse problema?

Sergio del Amo
fonte
Existem vários plugins prontos para fazer upload de arquivos para o jQuery. Fazer esse tipo de upload de hacks não é uma experiência agradável; portanto, as pessoas gostam de usar soluções prontas. Aqui estão alguns: - Uploader de arquivos JQuery - Plugin de upload de vários arquivos - Mini upload de arquivos múltiplos - Upload de arquivos jQuery Você pode procurar mais projetos no NPM (usando "jquery-plugin" como palavra-chave) ou no Github.
agosto
72
você está recebendo apenas o nome do arquivo, porque o seu var filename está recebendo o valor de $ ( '# arquivo'), não o arquivo que se encontra na entrada
Jimmy
21
Aqui está uma boa: http://blueimp.github.io/jQuery-File-Upload/ - Upload em HTML5 ajax - Fallback gracioso para iframes para navegadores não suportados - Upload assíncrono em vários arquivos Nós o usamos e funciona muito bem. ( Documentação aqui )
Ashish Panery
3
Verifique também o seguinte: stackoverflow.com/questions/6974684/... , aqui ele explica como alcançá-lo via jQuery
Chococroc
2
@ Jimmy Como ele conseguiu o arquivo que está na entrada?
alex

Respostas:

2519

Com o HTML5, você pode fazer upload de arquivos com Ajax e jQuery. Além disso, você pode fazer validações de arquivos (nome, tamanho e tipo MIME) ou manipular o evento progress com a tag de progresso HTML5 (ou uma div). Recentemente, tive que fazer um upload de arquivos, mas não queria usar Flash, Iframes ou plugins e, depois de algumas pesquisas, encontrei a solução.

O HTML:

<form enctype="multipart/form-data">
    <input name="file" type="file" />
    <input type="button" value="Upload" />
</form>
<progress></progress>

Primeiro, você pode fazer alguma validação, se quiser. Por exemplo, no .on('change')evento do arquivo:

$(':file').on('change', function () {
  var file = this.files[0];

  if (file.size > 1024) {
    alert('max upload size is 1k');
  }

  // Also see .name, .type
});

Agora, $.ajax()envie com o clique do botão:

$(':button').on('click', function () {
  $.ajax({
    // Your server script to process the upload
    url: 'upload.php',
    type: 'POST',

    // Form data
    data: new FormData($('form')[0]),

    // Tell jQuery not to process data or worry about content-type
    // You *must* include these options!
    cache: false,
    contentType: false,
    processData: false,

    // Custom XMLHttpRequest
    xhr: function () {
      var myXhr = $.ajaxSettings.xhr();
      if (myXhr.upload) {
        // For handling the progress of the upload
        myXhr.upload.addEventListener('progress', function (e) {
          if (e.lengthComputable) {
            $('progress').attr({
              value: e.loaded,
              max: e.total,
            });
          }
        }, false);
      }
      return myXhr;
    }
  });
});

Como você pode ver, com o upload de arquivos HTML5 (e algumas pesquisas), não só se torna possível, mas super fácil. Experimente com o Google Chrome, pois alguns dos componentes HTML5 dos exemplos não estão disponíveis em todos os navegadores.

olanod
fonte
14
Posso então usar $ _FILES no upload.php?
Alessandro Cosentino
71
Isso deve funcionar no Internet Explorer, mas apenas a versão 10. ( caniuse.com/xhr2 )
Tyler
18
Oi, eu aprecio o PHP é a sua linguagem de escolha ... mas estou me perguntando se você sabe se isso também funciona no asp.net MVC? Sou desenvolvedor .NET e tentei utilizar seu exemplo simples para fazer upload de arquivos AJAX, mas no lado do servidor não recebo o arquivo que publiquei via AJAX. Estou usando o Chrome mais recente.
Shumii
25
É FormData quem faz toda a mágica aqui. Verifique esses documentos - ele cobre todas as suas dúvidas sobre vários arquivos e campos.
encarnado
4
Só para alguém não passar horas ... isso name="file"é muito importante na <input>tag do arquivo se você usar os dados em PHP (e provavelmente em outros lugares). Criei um formulário dinamicamente usando javascript, para não precisar do atributo name, mas descobri da maneira mais difícil que você absolutamente precisa para recuperar o servidor de dados.
Kivak Wolf
273

Atualização de 2019: ainda depende dos navegadores usados ​​por seus dados demográficos.

Uma coisa importante a entender com a "nova" fileAPI HTML5 é que ela não era suportada até o IE 10 . Se o mercado específico que você deseja atingir tem uma propensão acima da média em relação às versões mais antigas do Windows, talvez você não tenha acesso a ele.

A partir de 2017, cerca de 5% dos navegadores são do IE 6, 7, 8 ou 9. Se você ingressar em uma grande corporação (por exemplo, esta é uma ferramenta B2B ou algo que você está entregando para treinamento), esse número pode disparar. . Em 2016, lidei com uma empresa que usa o IE8 em mais de 60% de suas máquinas.

É 2019 a partir desta edição, quase 11 anos após a minha resposta inicial. O IE9 e inferiores estão globalmente em torno da marca de 1%, mas ainda existem grupos de maior uso.

A solução importante disso, seja qual for o recurso, é verificar o navegador que seus usuários usam . Caso contrário, você aprenderá uma lição rápida e dolorosa sobre por que "funciona para mim" não é bom o suficiente para ser entregue a um cliente. caniuse é uma ferramenta útil, mas observe de onde eles tiram os dados demográficos. Eles podem não se alinhar com o seu. Isso nunca é mais verdadeiro que os ambientes corporativos.

Minha resposta de 2008 segue.


No entanto, existem métodos não JS viáveis ​​para upload de arquivos. Você pode criar um iframe na página (que você esconde com CSS) e depois direcionar seu formulário para postar nesse iframe. A página principal não precisa ser movida.

É uma postagem "real", portanto não é totalmente interativa. Se você precisar de status, precisará de algo do lado do servidor para processar isso. Isso varia enormemente, dependendo do seu servidor. O ASP.NET possui mecanismos melhores. O PHP plain falha, mas você pode usar as modificações Perl ou Apache para contornar isso.

Se você precisar de vários uploads de arquivos, é melhor fazer cada arquivo um de cada vez (para superar os limites máximos de upload de arquivos). Poste o primeiro formulário no iframe, monitore seu progresso usando o descrito acima e, quando terminar, poste o segundo formulário no iframe e assim por diante.

Ou use uma solução Java / Flash. Eles são muito mais flexíveis no que podem fazer com suas postagens ...

Oli
fonte
142
Para o registro agora é possível fazer o upload de arquivos AJAX puros se o navegador suporta a API File - developer.mozilla.org/en/using_files_from_web_applications
meleyal
A solução iframe é bastante simples e fácil de trabalhar
Matthew Lock
essa é uma resposta bastante antiga, mas foi um pouco enganadora. O IE suportava o XHR originalmente desde o IE7 e o ActiveX desde o IE5. w3schools.com/ajax/ajax_xmlhttprequest_create.asp . A maneira prática de fazer isso era direcionar componentes para flash (ondas de choque) ou implantar um controle Flash / ActiveX (Silverlight). Se você pode originar uma solicitação e manipular a resposta via javascript, é ajax .. embora, tendo dito isso, ajax seja sinônimo de xhr, mas ele próprio não descreve o mecanismo / componentes de sublinhado que entrega / troca a carga útil.
Brett Caswell
4
@BrettCaswell Eu não estava dizendo que o AJAX / XHR não era possível, apenas que não era possível publicar um arquivo com eles em versões antigas - mas eternas - do IE. Isso foi e permanece completamente verdadeiro.
Oli
Não é assim, é uma opinião de UX - talvez valha a pena.
Nimjox 09/02/19
112

Eu recomendo usar o plug-in Fine Uploader para esse fim. Seu JavaScriptcódigo seria:

$(document).ready(function() {
  $("#uploadbutton").jsupload({
    action: "addFile.do",
    onComplete: function(response){
      alert( "server response: " + response);
    }
  });
});
Shiladitya
fonte
Ele usa JSON - portanto, para a versão antiga do PHP, não será possível.
Lorenzo Manucci
Parece muito mais limpo do que o Ajax File Upload, onde preciso incluir um grande pedaço de código apenas para usar essa coisa.
ripper234
URL mais recente para a versão 2 é agora valums-file-uploader.github.com/file-uploader
Simon Leste
35
"Este plugin é de código aberto sob GNU GPL 2 ou posterior e GNU LGPL 2 ou posterior." Portanto, desde que você não distribua a cópia ou uma versão modificada, não será necessário abrir seu projeto.
Trantor Liu
Estou esquecendo de algo? Parece que essa biblioteca não usa mais o jquery; portanto, não suporta a sintaxe da resposta?
James McCormack
102

Nota: Esta resposta está desatualizada, agora é possível fazer upload de arquivos usando o XHR.


Você não pode carregar arquivos usando XMLHttpRequest (Ajax). Você pode simular o efeito usando um iframe ou Flash. O excelente plugin jQuery Form, que publica seus arquivos em um iframe para obter o efeito.

Mattias
fonte
1
Sim, você pode POSTAR para um iframe e capturar o arquivo lá. Eu tenho uma experiência muito limitada com isso, então não posso realmente comentar sobre isso.
Mattias
15
Pequena observação: nas versões mais recentes do chrome e do firefox é possível, stackoverflow.com/questions/4856917/…
Alleo
Não suportado no IE9 e menos
Radmation
96

Finalizando para futuros leitores.

Upload de arquivo assíncrono

Com HTML5

Você pode fazer upload de arquivos com jQuery usando o $.ajax()método se FormData e a API de arquivos forem suportadas (ambos os recursos HTML5).

Você também pode enviar arquivos sem o FormData, mas a API do arquivo deve estar presente para processar os arquivos de forma que possam ser enviados com XMLHttpRequest (Ajax).

$.ajax({
  url: 'file/destination.html', 
  type: 'POST',
  data: new FormData($('#formWithFiles')[0]), // The form with the file inputs.
  processData: false,
  contentType: false                    // Using FormData, no need to process data.
}).done(function(){
  console.log("Success: Files sent!");
}).fail(function(){
  console.log("An error occurred, the files couldn't be sent!");
});

Para obter um exemplo rápido e puro de JavaScript ( sem jQuery ), consulte " Enviando arquivos usando um objeto FormData ".

Cair pra trás

Quando o HTML5 não é suportado (sem API de arquivos ), a única outra solução JavaScript pura (sem Flash ou qualquer outro plug-in de navegador) é a técnica iframe oculta , que permite emular uma solicitação assíncrona sem usar o objeto XMLHttpRequest .

Consiste em definir um iframe como destino do formulário com as entradas do arquivo. Quando o usuário envia uma solicitação, é feito o upload dos arquivos, mas a resposta é exibida dentro do iframe, em vez de renderizar novamente a página principal. Ocultar o iframe torna todo o processo transparente para o usuário e emula uma solicitação assíncrona.

Se feito corretamente, deve funcionar virtualmente em qualquer navegador, mas possui algumas advertências sobre como obter a resposta do iframe.

Nesse caso, você pode preferir usar um plug-in wrapper como o Bifröst, que usa a técnica iframe, mas também fornece um transporte jQuery Ajax que permite enviar arquivos com o $.ajax()método a seguir:

$.ajax({
  url: 'file/destination.html', 
  type: 'POST',
  // Set the transport to use (iframe means to use Bifröst)
  // and the expected data type (json in this case).
  dataType: 'iframe json',                                
  fileInputs: $('input[type="file"]'),  // The file inputs containing the files to send.
  data: { msg: 'Some extra data you might need.'}
}).done(function(){
  console.log("Success: Files sent!");
}).fail(function(){
  console.log("An error occurred, the files couldn't be sent!");
});

Plugins

O Bifröst é apenas um pequeno invólucro que adiciona suporte de fallback ao método ajax do jQuery, mas muitos dos plug-ins mencionados, como o jQuery Form Plugin ou o jQuery File Upload, incluem toda a pilha do HTML5 a diferentes fallbacks e alguns recursos úteis para facilitar o processo. Dependendo de suas necessidades e requisitos, convém considerar uma implementação simples ou um desses plug-ins.

404
fonte
3
Uma coisa a observar, com base na documentação: você também deve enviar contentType: false. Quando não enviei isso com o chrome, o tipo de conteúdo do formulário foi invalidado pelo jQuery.
ash
Boa resposta. Algumas sugestões para aprimoramento: Remova as partes do código não relacionadas à resposta, por exemplo, os retornos de chamada .done()e .fail(). Além disso, um exemplo sem o uso de FormDatae uma lista de prós / contras seria incrível.
Zero3
Eu obtive este erro:TypeError: Argument 1 of FormData.constructor does not implement interface HTMLFormElement.
candlejack 25/12/16
85

Esse plug-in jQuery de upload de arquivo AJAX carrega o arquivo de alguma forma e transmite a resposta a um retorno de chamada, nada mais.

  • Não depende de HTML específico, apenas dê uma <input type="file">
  • Não requer que seu servidor responda de nenhuma maneira específica
  • Não importa quantos arquivos você usa ou onde eles estão na página

- Use tão pouco quanto -

$('#one-specific-file').ajaxfileupload({
  'action': '/upload.php'
});

- ou tanto quanto -

$('input[type="file"]').ajaxfileupload({
  'action': '/upload.php',
  'params': {
    'extra': 'info'
  },
  'onComplete': function(response) {
    console.log('custom handler for file:');
    alert(JSON.stringify(response));
  },
  'onStart': function() {
    if(weWantedTo) return false; // cancels upload
  },
  'onCancel': function() {
    console.log('no file selected');
  }
});
Jordan Feldstein
fonte
1
@ user840250 jQuery 1.9.1?
23413 Jordan Feldstein
62

Eu tenho usado o script abaixo para fazer upload de imagens que, por acaso, funcionam bem.

HTML

<input id="file" type="file" name="file"/>
<div id="response"></div>

Javascript

jQuery('document').ready(function(){
    var input = document.getElementById("file");
    var formdata = false;
    if (window.FormData) {
        formdata = new FormData();
    }
    input.addEventListener("change", function (evt) {
        var i = 0, len = this.files.length, img, reader, file;

        for ( ; i < len; i++ ) {
            file = this.files[i];

            if (!!file.type.match(/image.*/)) {
                if ( window.FileReader ) {
                    reader = new FileReader();
                    reader.onloadend = function (e) {
                        //showUploadedItem(e.target.result, file.fileName);
                    };
                    reader.readAsDataURL(file);
                }

                if (formdata) {
                    formdata.append("image", file);
                    formdata.append("extra",'extra-data');
                }

                if (formdata) {
                    jQuery('div#response').html('<br /><img src="ajax-loader.gif"/>');

                    jQuery.ajax({
                        url: "upload.php",
                        type: "POST",
                        data: formdata,
                        processData: false,
                        contentType: false,
                        success: function (res) {
                         jQuery('div#response').html("Successfully uploaded");
                        }
                    });
                }
            }
            else
            {
                alert('Not a vaild image!');
            }
        }

    }, false);
});

Explicação

Eu uso o response divpara mostrar a animação do upload e a resposta após o término do upload.

A melhor parte é que você pode enviar dados extras, como IDs, etc. com o arquivo ao usar esse script. Eu mencionei isso extra-datacomo no script.

No nível PHP, isso funcionará como o upload normal de arquivos. dados extras podem ser recuperados como $_POSTdados.

Aqui você não está usando um plugin e outras coisas. Você pode alterar o código como desejar. Você não está codificando cegamente aqui. Essa é a funcionalidade principal de qualquer upload de arquivo jQuery. Na verdade Javascript.

Techie
fonte
5
-1 para usar jQuery e não usar seu mecanismo de seleção e manipuladores de eventos. addEventListenernão é entre navegadores.
Mark
3
Porque seria inútil adicionar uma resposta separada, baseada principalmente nessa, com apenas algumas alterações. Em vez disso, esta resposta deve ser corrigida.
Mark
2
@RainFromHeaven, por favor, você pode editar a resposta? Não sei como fazê-lo da maneira entre navegadores.
Thiago Negri
2
Ainda não funciona no IE 9 e inferior. Muitos usuários ainda usam essas versões do IE.
28414 Pierre
1
Alguém pode explicar como isso pode ser feito para funcionar no asp.net? Eu uso o webmethod? Se sim, como seria?
SamuraiJack 23/05
49

Você pode fazer isso em JavaScript vanilla com bastante facilidade. Aqui está um trecho do meu projeto atual:

var xhr = new XMLHttpRequest();
xhr.upload.onprogress = function(e) {
    var percent = (e.position/ e.totalSize);
    // Render a pretty progress bar
};
xhr.onreadystatechange = function(e) {
    if(this.readyState === 4) {
        // Handle file upload complete
    }
};
xhr.open('POST', '/upload', true);
xhr.setRequestHeader('X-FileName',file.name); // Pass the filename along
xhr.send(file);
mpen
fonte
3
@ Gary: Desculpe, eu deveria ter postado isso também. Eu estava apenas usando a nova funcionalidade de arrastar e soltar no HTML5; Você pode encontrar um exemplo aqui: html5demos.com/file-api#view-source - basta clicar em "ver código-fonte". Essencialmente, dentro do ondropevento você pode fazervar file = e.dataTransfer.files[0]
MPEN
Talvez a pergunta tenha sido editada desde então, mas algumas pessoas em uma discussão que eu abri acham que uma resposta JS baunilha está fora do tópico se o OP solicitar uma solução jQuery (desde que exista uma) e essas respostas pertencerem a uma pergunta separada.
Andy
4
@ Andy Bem, eu discordo, e parece que outros 34 também. Se você pode usar o jQuery, certamente pode usar JavaScript. De qualquer forma, este é um site da comunidade - não é apenas o OP que estou tentando ajudar aqui. Todos são livres para escolher / usar a resposta que mais gostam. Algumas pessoas simplesmente se interessam pelo jQuery porque acham que será muito mais fácil / menos linhas de código, quando realmente não precisam da sobrecarga de uma biblioteca extra.
MPEN
47

Você pode fazer o upload simplesmente com o jQuery .ajax().

HTML:

<form id="upload-form">
    <div>
        <label for="file">File:</label>
        <input type="file" id="file" name="file" />
        <progress class="progress" value="0" max="100"></progress>
    </div>
    <hr />
    <input type="submit" value="Submit" />
</form>

CSS

.progress { display: none; }

Javascript:

$(document).ready(function(ev) {
    $("#upload-form").on('submit', (function(ev) {
        ev.preventDefault();
        $.ajax({
            xhr: function() {
                var progress = $('.progress'),
                    xhr = $.ajaxSettings.xhr();

                progress.show();

                xhr.upload.onprogress = function(ev) {
                    if (ev.lengthComputable) {
                        var percentComplete = parseInt((ev.loaded / ev.total) * 100);
                        progress.val(percentComplete);
                        if (percentComplete === 100) {
                            progress.hide().val(0);
                        }
                    }
                };

                return xhr;
            },
            url: 'upload.php',
            type: 'POST',
            data: new FormData(this),
            contentType: false,
            cache: false,
            processData: false,
            success: function(data, status, xhr) {
                // ...
            },
            error: function(xhr, status, error) {
                // ...
            }
       });
    }));
});
Zayn Ali
fonte
1
@RaydenBlack apenas jQuery.
Zayn Ali
como obter o progresso do upload?
Ali Sherafat
44

A maneira mais simples e robusta de fazer isso no passado é simplesmente direcionar uma tag oculta do iFrame com seu formulário - ela será enviada no iframe sem recarregar a página.

Ou seja, se você não quiser usar um plug-in, JavaScript ou qualquer outra forma de "mágica" que não seja HTML. Claro que você pode combinar isso com JavaScript ou o que você tem ...

<form target="iframe" action="" method="post" enctype="multipart/form-data">
    <input name="file" type="file" />
    <input type="button" value="Upload" />
</form>

<iframe name="iframe" id="iframe" style="display:none" ></iframe>

Você também pode ler o conteúdo do iframe onLoadpara erros do servidor ou respostas bem-sucedidas e, em seguida, enviá-lo para o usuário.

Chrome, iFrames e onLoad

Você só precisa continuar lendo se estiver interessado em como configurar um bloqueador de interface do usuário ao fazer upload / download

Atualmente, o Chrome não aciona o evento onLoad para o iframe quando usado para transferir arquivos. Firefox, IE e Edge disparam o evento onload para transferências de arquivos.

A única solução que encontrei para o Chrome foi usar um cookie.

Para fazer isso basicamente quando o upload / download é iniciado:

  • [Lado do cliente] Inicie um intervalo para procurar a existência de um cookie
  • [Lado do servidor] Faça o que precisar com os dados do arquivo
  • [Lado do servidor] Defina o cookie para o intervalo do lado do cliente
  • O intervalo [do lado do cliente] vê o cookie e o usa como o evento onLoad. Por exemplo, você pode iniciar um bloqueador de interface do usuário e, em seguida, ao carregar (ou quando o cookie é criado), você remove o bloqueador de interface do usuário.

Usar um cookie para isso é feio, mas funciona.

Eu criei um plugin jQuery para lidar com esse problema do Chrome ao fazer o download, você pode encontrar aqui

https://github.com/ArtisticPhoenix/jQuery-Plugins/blob/master/iDownloader.js

O mesmo princípio básico também se aplica ao upload.

Para usar o downloader (inclua o JS, obviamente)

 $('body').iDownloader({
     "onComplete" : function(){
          $('#uiBlocker').css('display', 'none'); //hide ui blocker on complete
     }
 });

 $('somebuttion').click( function(){
      $('#uiBlocker').css('display', 'block'); //block the UI
      $('body').iDownloader('download', 'htttp://example.com/location/of/download');
 });

E no lado do servidor, pouco antes de transferir os dados do arquivo, crie o cookie

 setcookie('iDownloader', true, time() + 30, "/");

O plug-in verá o cookie e acionará o onCompleteretorno de chamada.

ArtisticPhoenix
fonte
3
Eu amo isso. Se alguém pudesse mencionar os possíveis problemas com esta solução brilhante. Realmente não entendo por que as pessoas escrevem e usam essas bibliotecas e plugins desajeitados quando existe a solução.
Yevgeniy Afanasyev
1
Bem, acho que o motivo seria mostrar algumas informações de progresso durante o upload.
Prakhar Mishra
32

Uma solução que encontrei foi ter como <form>alvo um iFrame oculto. O iFrame pode executar o JS para exibir ao usuário que está completo (no carregamento da página).

Darryl Hein
fonte
1
Estou interessado nesta resposta. Você tem uma demonstração à qual pode vincular?
Lfender6445
32

Eu escrevi isso em um ambiente Rails . É apenas cerca de cinco linhas de JavaScript, se você usar o plugin leve do jQuery-form.

O desafio está em fazer o upload do AJAX funcionar, pois o padrão remote_form_fornão entende o envio de formulários com várias partes. Ele não enviará os dados do arquivo que o Rails procura com a solicitação AJAX.

É aí que o plugin jQuery-form entra em ação.

Aqui está o código Rails para isso:

<% remote_form_for(:image_form, 
                   :url => { :controller => "blogs", :action => :create_asset }, 
                   :html => { :method => :post, 
                              :id => 'uploadForm', :multipart => true }) 
                                                                        do |f| %>
 Upload a file: <%= f.file_field :uploaded_data %>
<% end %>

Aqui está o JavaScript associado:

$('#uploadForm input').change(function(){
 $(this).parent().ajaxSubmit({
  beforeSubmit: function(a,f,o) {
   o.dataType = 'json';
  },
  complete: function(XMLHttpRequest, textStatus) {
   // XMLHttpRequest.responseText will contain the URL of the uploaded image.
   // Put it in an image element you create, or do with it what you will.
   // For example, if you have an image elemtn with id "my_image", then
   //  $('#my_image').attr('src', XMLHttpRequest.responseText);
   // Will set that image tag to display the uploaded image.
  },
 });
});

E aqui está a ação do controlador Rails, bastante baunilha:

 @image = Image.new(params[:image_form])
 @image.save
 render :text => @image.public_filename

Eu tenho usado isso nas últimas semanas com o Bloggity, e funcionou como um campeão.

wbharding
fonte
31

Simple Ajax Uploader é outra opção:

https://github.com/LPology/Simple-Ajax-Uploader

  • Cross-browser - funciona no IE7 +, Firefox, Chrome, Safari, Opera
  • Suporta vários uploads simultâneos - mesmo em navegadores não HTML5
  • Sem flash ou CSS externo - apenas um arquivo Javascript de 5 KB
  • Suporte interno opcional para barras de progresso totalmente em vários navegadores (usando a extensão APC do PHP)
  • Flexível e altamente personalizável - use qualquer elemento como botão de upload, crie seus próprios indicadores de progresso
  • Não são necessários formulários, basta fornecer um elemento que servirá como botão de upload
  • Licença MIT - livre para uso em projeto comercial

Exemplo de uso:

var uploader = new ss.SimpleUpload({
    button: $('#uploadBtn'), // upload button
    url: '/uploadhandler', // URL of server-side upload handler
    name: 'userfile', // parameter name of the uploaded file
    onSubmit: function() {
        this.setProgressBar( $('#progressBar') ); // designate elem as our progress bar
    },
    onComplete: function(file, response) {
        // do whatever after upload is finished
    }
});
user1091949
fonte
2
Este parece ser o mais promissor até agora, você me teve IE7+! Experimentando agora. Obrigado
Pierre
25

O jQuery Uploadify é outro bom plugin que eu usei antes para fazer upload de arquivos. O código JavaScript é tão simples quanto o seguinte: code. No entanto, a nova versão não funciona no Internet Explorer.

$('#file_upload').uploadify({
    'swf': '/public/js/uploadify.swf',
    'uploader': '/Upload.ashx?formGuid=' + $('#formGuid').val(),
    'cancelImg': '/public/images/uploadify-cancel.png',
    'multi': true,
    'onQueueComplete': function (queueData) {
        // ...
    },
    'onUploadStart': function (file) {
        // ...
    }
});

Pesquisei bastante e cheguei a outra solução para carregar arquivos sem nenhum plug-in e somente com ajax. A solução é a seguinte:

$(document).ready(function () {
    $('#btn_Upload').live('click', AjaxFileUpload);
});

function AjaxFileUpload() {
    var fileInput = document.getElementById("#Uploader");
    var file = fileInput.files[0];
    var fd = new FormData();
    fd.append("files", file);
    var xhr = new XMLHttpRequest();
    xhr.open("POST", 'Uploader.ashx');
    xhr.onreadystatechange = function () {
        if (xhr.readyState == 4) {
             alert('success');
        }
        else if (uploadResult == 'success')
            alert('error');
    };
    xhr.send(fd);
}
farnoush resa
fonte
2
O Uploadify está morto há anos. Não há mais suporte ou manutenção.
precisa saber é o seguinte
24

Aqui está apenas outra solução de como fazer upload de arquivo ( sem nenhum plug-in )

Usando Javascripts simples e AJAX (com barra de progresso)

Parte HTML

<form id="upload_form" enctype="multipart/form-data" method="post">
    <input type="file" name="file1" id="file1"><br>
    <input type="button" value="Upload File" onclick="uploadFile()">
    <progress id="progressBar" value="0" max="100" style="width:300px;"></progress>
    <h3 id="status"></h3>
    <p id="loaded_n_total"></p>
</form>

Parte JS

function _(el){
    return document.getElementById(el);
}
function uploadFile(){
    var file = _("file1").files[0];
    // alert(file.name+" | "+file.size+" | "+file.type);
    var formdata = new FormData();
    formdata.append("file1", file);
    var ajax = new XMLHttpRequest();
    ajax.upload.addEventListener("progress", progressHandler, false);
    ajax.addEventListener("load", completeHandler, false);
    ajax.addEventListener("error", errorHandler, false);
    ajax.addEventListener("abort", abortHandler, false);
    ajax.open("POST", "file_upload_parser.php");
    ajax.send(formdata);
}
function progressHandler(event){
    _("loaded_n_total").innerHTML = "Uploaded "+event.loaded+" bytes of "+event.total;
    var percent = (event.loaded / event.total) * 100;
    _("progressBar").value = Math.round(percent);
    _("status").innerHTML = Math.round(percent)+"% uploaded... please wait";
}
function completeHandler(event){
    _("status").innerHTML = event.target.responseText;
    _("progressBar").value = 0;
}
function errorHandler(event){
    _("status").innerHTML = "Upload Failed";
}
function abortHandler(event){
    _("status").innerHTML = "Upload Aborted";
}

Parte do PHP

<?php
$fileName = $_FILES["file1"]["name"]; // The file name
$fileTmpLoc = $_FILES["file1"]["tmp_name"]; // File in the PHP tmp folder
$fileType = $_FILES["file1"]["type"]; // The type of file it is
$fileSize = $_FILES["file1"]["size"]; // File size in bytes
$fileErrorMsg = $_FILES["file1"]["error"]; // 0 for false... and 1 for true
if (!$fileTmpLoc) { // if file not chosen
    echo "ERROR: Please browse for a file before clicking the upload button.";
    exit();
}
if(move_uploaded_file($fileTmpLoc, "test_uploads/$fileName")){ // assuming the directory name 'test_uploads'
    echo "$fileName upload is complete";
} else {
    echo "move_uploaded_file function failed";
}
?>

Aqui está o aplicativo EXEMPLO

Siddhartha Chowdhury
fonte
19
var formData=new FormData();
formData.append("fieldname","value");
formData.append("image",$('[name="filename"]')[0].files[0]);

$.ajax({
    url:"page.php",
    data:formData,
    type: 'POST',
    dataType:"JSON",
    cache: false,
    contentType: false,
    processData: false,
    success:function(data){ }
});

Você pode usar os dados do formulário para postar todos os seus valores, incluindo imagens.

Vivek Aasaithambi
fonte
6
Nota: cache: falseé redundante em uma POSTsolicitação, pois POST nunca faz cache.
Gone Coding
@Vivek Aasaithambi, obtive este erro:TypeError: Argument 1 of FormData.constructor does not implement interface HTMLFormElement.
candlejack
15

Para fazer upload de arquivo de forma assíncrona com o Jquery, use as etapas abaixo:

etapa 1 No seu projeto, abra o Nuget manager e adicione o pacote (jquery fileupload (você só precisa escrevê-lo na caixa de pesquisa, ele será instalado e instalado)). URL: https://github.com/blueimp/jQuery-File- Envio

etapa 2 Adicione os scripts abaixo nos arquivos HTML, que já foram adicionados ao projeto executando o pacote acima:

jquery.ui.widget.js

jquery.iframe-transport.js

jquery.fileupload.js

Etapa 3 Escreva o controle de upload de arquivo conforme o código abaixo:

<input id="upload" name="upload" type="file" />

etapa 4 escreva um método js como uploadFile como abaixo:

 function uploadFile(element) {

            $(element).fileupload({

                dataType: 'json',
                url: '../DocumentUpload/upload',
                autoUpload: true,
                add: function (e, data) {           
                  // write code for implementing, while selecting a file. 
                  // data represents the file data. 
                  //below code triggers the action in mvc controller
                  data.formData =
                                    {
                                     files: data.files[0]
                                    };
                  data.submit();
                },
                done: function (e, data) {          
                   // after file uploaded
                },
                progress: function (e, data) {

                   // progress
                },
                fail: function (e, data) {

                   //fail operation
                },
                stop: function () {

                  code for cancel operation
                }
            });

        };

Etapa 5 No upload do arquivo do elemento de chamada de função pronto para iniciar o processo conforme abaixo:

$(document).ready(function()
{
    uploadFile($('#upload'));

});

Etapa 6 Escreva o controlador MVC e a ação conforme abaixo:

public class DocumentUploadController : Controller
    {       

        [System.Web.Mvc.HttpPost]
        public JsonResult upload(ICollection<HttpPostedFileBase> files)
        {
            bool result = false;

            if (files != null || files.Count > 0)
            {
                try
                {
                    foreach (HttpPostedFileBase file in files)
                    {
                        if (file.ContentLength == 0)
                            throw new Exception("Zero length file!");                       
                        else 
                            //code for saving a file

                    }
                }
                catch (Exception)
                {
                    result = false;
                }
            }


            return new JsonResult()
                {
                    Data=result
                };


        }

    }
acinzentado
fonte
14

Uma abordagem moderna sem o Jquery é usar o objeto FileList de onde você retorna <input type="file">quando o usuário seleciona um (s) arquivo (s) e depois usar Buscar para publicar o FileList envolvido em um objeto FormData .

// The input DOM element // <input type="file">
const inputElement = document.querySelector('input[type=file]');

// Listen for a file submit from user
inputElement.addEventListener('change', () => {
    const data = new FormData();
    data.append('file', inputElement.files[0]);
    data.append('imageName', 'flower');

    // You can then post it to your server.
    // Fetch can accept an object of type FormData on its  body
    fetch('/uploadImage', {
        method: 'POST',
        body: data
    });
});
Alister
fonte
Aparentemente, não há suporte para o IE
Marco Demaio 16/01/19
11

Você pode ver uma solução resolvida com uma demonstração funcional aqui, que permite visualizar e enviar arquivos de formulário para o servidor. Para o seu caso, você precisa usar o Ajax para facilitar o upload do arquivo no servidor:

<from action="" id="formContent" method="post" enctype="multipart/form-data">
    <span>File</span>
    <input type="file" id="file" name="file" size="10"/>
    <input id="uploadbutton" type="button" value="Upload"/>
</form>

Os dados enviados são dados de formulário. No jQuery, use uma função de envio de formulário em vez de clicar em um botão para enviar o arquivo de formulário, como mostrado abaixo.

$(document).ready(function () {
   $("#formContent").submit(function(e){

     e.preventDefault();
     var formdata = new FormData(this);

 $.ajax({
     url: "ajax_upload_image.php",
     type: "POST",
     data: formdata,
     mimeTypes:"multipart/form-data",
     contentType: false,
     cache: false,
     processData: false,
     success: function(){

     alert("successfully submitted");

     });
   });
});

Ver mais detalhes

Daniel Nyamasyo
fonte
11

Exemplo: se você usa o jQuery, pode facilitar o upload de um arquivo. Este é um plugin jQuery pequeno e forte, http://jquery.malsup.com/form/ .

Exemplo

var $bar   = $('.ProgressBar');
$('.Form').ajaxForm({
  dataType: 'json',

  beforeSend: function(xhr) {
    var percentVal = '0%';
    $bar.width(percentVal);
  },

  uploadProgress: function(event, position, total, percentComplete) {
    var percentVal = percentComplete + '%';
    $bar.width(percentVal)
  },

  success: function(response) {
    // Response
  }
});

Espero que seja útil

MEAbid
fonte
10

Você pode usar

$(function() {
    $("#file_upload_1").uploadify({
        height        : 30,
        swf           : '/uploadify/uploadify.swf',
        uploader      : '/uploadify/uploadify.php',
        width         : 120
    });
});

Demo

Amit
fonte
9

Converta o arquivo em base64 usando o readAsDataURL () ou o codificador base64 do HTML5 . Violino aqui

var reader = new FileReader();

        reader.onload = function(readerEvt) {
            var binaryString = readerEvt.target.result;
            document.getElementById("base64textarea").value = btoa(binaryString);
        };

        reader.readAsBinaryString(file);

Então, para recuperar:

window.open("data:application/octet-stream;base64," + base64);
tnt-rox
fonte
9

Você pode passar parâmetros adicionais junto com o nome do arquivo ao fazer upload assíncrono usando XMLHttpRequest (sem dependência de flash e iframe). Anexe o valor do parâmetro adicional ao FormData e envie a solicitação de upload.


var formData = new FormData();
formData.append('parameter1', 'value1');
formData.append('parameter2', 'value2'); 
formData.append('file', $('input[type=file]')[0].files[0]);

$.ajax({
    url: 'post back url',
    data: formData,
// other attributes of AJAX
});

Além disso, o upload do arquivo de interface do usuário do Syncfusion JavaScript fornece solução para esse cenário simplesmente usando o argumento de evento. você pode encontrar documentação aqui e mais detalhes sobre esse controle aqui, digite a descrição do link aqui

Karthik Ravichandran
fonte
8

Procure Gerenciando o processo de upload de um arquivo, de forma assíncrona aqui: https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications

Amostra do link

<?php
if (isset($_FILES['myFile'])) {
    // Example:
    move_uploaded_file($_FILES['myFile']['tmp_name'], "uploads/" . $_FILES['myFile']['name']);
    exit;
}
?><!DOCTYPE html>
<html>
<head>
    <title>dnd binary upload</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <script type="text/javascript">
        function sendFile(file) {
            var uri = "/index.php";
            var xhr = new XMLHttpRequest();
            var fd = new FormData();

            xhr.open("POST", uri, true);
            xhr.onreadystatechange = function() {
                if (xhr.readyState == 4 && xhr.status == 200) {
                    // Handle response.
                    alert(xhr.responseText); // handle response.
                }
            };
            fd.append('myFile', file);
            // Initiate a multipart/form-data upload
            xhr.send(fd);
        }

        window.onload = function() {
            var dropzone = document.getElementById("dropzone");
            dropzone.ondragover = dropzone.ondragenter = function(event) {
                event.stopPropagation();
                event.preventDefault();
            }

            dropzone.ondrop = function(event) {
                event.stopPropagation();
                event.preventDefault();

                var filesArray = event.dataTransfer.files;
                for (var i=0; i<filesArray.length; i++) {
                    sendFile(filesArray[i]);
                }
            }
        }
    </script>
</head>
<body>
    <div>
        <div id="dropzone" style="margin:30px; width:500px; height:300px; border:1px dotted grey;">Drag & drop your file here...</div>
    </div>
</body>
</html>
Allende
fonte
7

Esta é a minha solução.

<form enctype="multipart/form-data">    

    <div class="form-group">
        <label class="control-label col-md-2" for="apta_Description">Description</label>
        <div class="col-md-10">
            <input class="form-control text-box single-line" id="apta_Description" name="apta_Description" type="text" value="">
        </div>
    </div>

    <input name="file" type="file" />
    <input type="button" value="Upload" />
</form>

e os js

<script>

    $(':button').click(function () {
        var formData = new FormData($('form')[0]);
        $.ajax({
            url: '@Url.Action("Save", "Home")',  
            type: 'POST',                
            success: completeHandler,
            data: formData,
            cache: false,
            contentType: false,
            processData: false
        });
    });    

    function completeHandler() {
        alert(":)");
    }    
</script>

Controlador

[HttpPost]
public ActionResult Save(string apta_Description, HttpPostedFileBase file)
{
    [...]
}
Erick Langford Xenes
fonte
2
Você parece ter misturado algum tipo de estrutura em sua resposta. Você deve, no mínimo, mencionar para qual estrutura sua resposta é utilizável. Melhor ainda, remova todo o material da estrutura e apresente apenas uma resposta à pergunta colocada.
Zero3
2
então existe realmente uma estrutura mvc chamada "mvc"? e usa sintaxe csharpish? Isso é cruel.
nonchip
6

Usando HTML5 e JavaScript , o upload assíncrono é bastante fácil, eu crio a lógica de upload junto com seu html. Isso não funciona totalmente porque precisa da API, mas demonstre como funciona, se você tiver o endpoint chamado a /uploadpartir da raiz do seu site, este código deve funcionar para você:

const asyncFileUpload = () => {
  const fileInput = document.getElementById("file");
  const file = fileInput.files[0];
  const uri = "/upload";
  const xhr = new XMLHttpRequest();
  xhr.upload.onprogress = e => {
    const percentage = e.loaded / e.total;
    console.log(percentage);
  };
  xhr.onreadystatechange = e => {
    if (xhr.readyState === 4 && xhr.status === 200) {
      console.log("file uploaded");
    }
  };
  xhr.open("POST", uri, true);
  xhr.setRequestHeader("X-FileName", file.name);
  xhr.send(file);
}
<form>
  <span>File</span>
  <input type="file" id="file" name="file" size="10" />
  <input onclick="asyncFileUpload()" id="upload" type="button" value="Upload" />
</form>

Também algumas informações adicionais sobre XMLHttpReques:

O objeto XMLHttpRequest

Todos os navegadores modernos suportam o objeto XMLHttpRequest. O objeto XMLHttpRequest pode ser usado para trocar dados com um servidor da Web nos bastidores. Isso significa que é possível atualizar partes de uma página da web, sem recarregar a página inteira.


Crie um objeto XMLHttpRequest

Todos os navegadores modernos (Chrome, Firefox, IE7 +, Edge, Safari, Opera) possuem um objeto XMLHttpRequest interno.

Sintaxe para criar um objeto XMLHttpRequest:

variável = new XMLHttpRequest ();


Acesso entre domínios

Por motivos de segurança, os navegadores modernos não permitem acesso entre domínios.

Isso significa que a página da web e o arquivo XML que ele tenta carregar devem estar localizados no mesmo servidor.

Os exemplos no W3Schools todos os arquivos XML abertos localizados no domínio W3Schools.

Se você deseja usar o exemplo acima em uma de suas próprias páginas da web, os arquivos XML carregados devem estar localizados em seu próprio servidor.

Para mais detalhes, você pode continuar lendo aqui ...

Alireza
fonte
5

Você pode usar a API de busca mais recente por JavaScript. Como isso:

function uploadButtonCLicked(){
    var input = document.querySelector('input[type="file"]')

    fetch('/url', {
      method: 'POST',
      body: input.files[0]
    }).then(res => res.json())   // you can do something with response
      .catch(error => console.error('Error:', error))
      .then(response => console.log('Success:', response));
}                               

Vantagem: a API de busca é suportada nativamente por todos os navegadores modernos, para que você não precise importar nada. Além disso, observe que fetch () retorna uma promessa que é manipulada usando .then(..code to handle response..)assincronamente.

Barba Negra
fonte
4

Você pode fazer o upload de arquivos múltiplos assíncronos usando JavaScript ou jQuery e outros sem usar nenhum plug-in. Você também pode mostrar o progresso em tempo real do upload do arquivo no controle de progresso. Encontrei 2 links interessantes -

  1. Recurso de upload de arquivos múltiplos baseado em formulários da Web do ASP.NET com barra de progresso
  2. Upload de arquivos múltiplos baseado em ASP.NET MVC, feito em jQuery

A linguagem do lado do servidor é C #, mas você pode fazer algumas modificações para fazê-la funcionar com outra linguagem, como PHP.

Upload de arquivo ASP.NET Core MVC:

No modo de exibição, crie o controle de upload de arquivo em html:

<form method="post" asp-action="Add" enctype="multipart/form-data">
    <input type="file" multiple name="mediaUpload" />
    <button type="submit">Submit</button>
</form>

Agora crie o método de ação no seu controlador:

[HttpPost]
public async Task<IActionResult> Add(IFormFile[] mediaUpload)
{
    //looping through all the files
    foreach (IFormFile file in mediaUpload)
    {
        //saving the files
        string path = Path.Combine(hostingEnvironment.WebRootPath, "some-folder-path"); 
        using (var stream = new FileStream(path, FileMode.Create))
        {
            await file.CopyToAsync(stream);
        }
    }
}

A variável hostingEnvironment é do tipo IHostingEnvironment que pode ser injetada no controlador usando injeção de dependência, como:

private IHostingEnvironment hostingEnvironment;
public MediaController(IHostingEnvironment environment)
{
    hostingEnvironment = environment;
}
Joe Clinton
fonte
Você poderia incluir a essência da solução em sua resposta, pois, caso contrário, poderá se tornar inútil se o site vinculado mudar ou ficar offline.
Dima Kozhevin
4

Para PHP, procure https://developer.hyvor.com/php/image-upload-ajax-php-mysql

HTML

<html>
<head>
    <title>Image Upload with AJAX, PHP and MYSQL</title>
</head>
<body>
<form onsubmit="submitForm(event);">
    <input type="file" name="image" id="image-selecter" accept="image/*">
    <input type="submit" name="submit" value="Upload Image">
</form>
<div id="uploading-text" style="display:none;">Uploading...</div>
<img id="preview">
</body>
</html>

JAVASCRIPT

var previewImage = document.getElementById("preview"),  
    uploadingText = document.getElementById("uploading-text");

function submitForm(event) {
    // prevent default form submission
    event.preventDefault();
    uploadImage();
}

function uploadImage() {
    var imageSelecter = document.getElementById("image-selecter"),
        file = imageSelecter.files[0];
    if (!file) 
        return alert("Please select a file");
    // clear the previous image
    previewImage.removeAttribute("src");
    // show uploading text
    uploadingText.style.display = "block";
    // create form data and append the file
    var formData = new FormData();
    formData.append("image", file);
    // do the ajax part
    var ajax = new XMLHttpRequest();
    ajax.onreadystatechange = function() {
        if (this.readyState === 4 && this.status === 200) {
            var json = JSON.parse(this.responseText);
            if (!json || json.status !== true) 
                return uploadError(json.error);

            showImage(json.url);
        }
    }
    ajax.open("POST", "upload.php", true);
    ajax.send(formData); // send the form data
}

PHP

<?php
$host = 'localhost';
$user = 'user';
$password = 'password';
$database = 'database';
$mysqli = new mysqli($host, $user, $password, $database);


 try {
    if (empty($_FILES['image'])) {
        throw new Exception('Image file is missing');
    }
    $image = $_FILES['image'];
    // check INI error
    if ($image['error'] !== 0) {
        if ($image['error'] === 1) 
            throw new Exception('Max upload size exceeded');

        throw new Exception('Image uploading error: INI Error');
    }
    // check if the file exists
    if (!file_exists($image['tmp_name']))
        throw new Exception('Image file is missing in the server');
    $maxFileSize = 2 * 10e6; // in bytes
    if ($image['size'] > $maxFileSize)
        throw new Exception('Max size limit exceeded'); 
    // check if uploaded file is an image
    $imageData = getimagesize($image['tmp_name']);
    if (!$imageData) 
        throw new Exception('Invalid image');
    $mimeType = $imageData['mime'];
    // validate mime type
    $allowedMimeTypes = ['image/jpeg', 'image/png', 'image/gif'];
    if (!in_array($mimeType, $allowedMimeTypes)) 
        throw new Exception('Only JPEG, PNG and GIFs are allowed');

    // nice! it's a valid image
    // get file extension (ex: jpg, png) not (.jpg)
    $fileExtention = strtolower(pathinfo($image['name'] ,PATHINFO_EXTENSION));
    // create random name for your image
    $fileName = round(microtime(true)) . mt_rand() . '.' . $fileExtention; // anyfilename.jpg
    // Create the path starting from DOCUMENT ROOT of your website
    $path = '/examples/image-upload/images/' . $fileName;
    // file path in the computer - where to save it 
    $destination = $_SERVER['DOCUMENT_ROOT'] . $path;

    if (!move_uploaded_file($image['tmp_name'], $destination))
        throw new Exception('Error in moving the uploaded file');

    // create the url
    $protocol = stripos($_SERVER['SERVER_PROTOCOL'],'https') === true ? 'https://' : 'http://';
    $domain = $protocol . $_SERVER['SERVER_NAME'];
    $url = $domain . $path;
    $stmt = $mysqli -> prepare('INSERT INTO image_uploads (url) VALUES (?)');
    if (
        $stmt &&
        $stmt -> bind_param('s', $url) &&
        $stmt -> execute()
    ) {
        exit(
            json_encode(
                array(
                    'status' => true,
                    'url' => $url
                )
            )
        );
    } else 
        throw new Exception('Error in saving into the database');

} catch (Exception $e) {
    exit(json_encode(
        array (
            'status' => false,
            'error' => $e -> getMessage()
        )
    ));
}
Supun Kavinda
fonte
4

Você também pode usar algo como https://uppy.io .

Ele faz o upload de arquivos sem navegar para fora da página e oferece alguns bônus, como arrastar e soltar, retomando os envios em caso de falhas do navegador / redes inadequadas e importando do Instagram, por exemplo. É de código aberto e não depende do jQuery / React / Angular / Vue, mas pode ser usado com ele. Isenção de responsabilidade: como criador, sou tendencioso;)

kvz
fonte
O link acima está morto. Aqui está o github: github.com/transloadit/uppy
Chris Charles
uppy.io as páginas CloudFlare + GitHub são suportadas e preparadas para mim? Ainda útil ter o link repo direta muito embora :)
KVZ