tadarank afiliados

12 março, 2007

Upload Assíncrono (iframe como AJAX) - 1 função simples

Olá povo, conforme prometido, tô postando aqui uma função pra você fazer upload bem parecido com ajax (não é ajax!!). Função simples e fácil de usar.
Ela faz um upload assíncrono, ou seja, não recarrega a página toda (assim como o AJAX).
Quem usa alguns serviços do google como o GMail ou o GooglePages já conhece este recurso muito bem.

Editado 14/01/09: Já há uma nova versão disponível.
Veja em valeus.net/micox/micoxUpload2.htm (ainda não está muito bem testada).

Upload usando apenas AJAX não é viável no ambiente da Internet pois, por motivos de segurança, os navegadores por padrão não dão acesso ao sistema de arquivos para o JavaScript (se quiser descobrir como ativar esta característica não padrão, leia aqui, mas acredito não ser muito útil ajax upload dessa forma).

Esta minha função utiliza técnicas que envolvem iframes, mas não vou dar explicações aqui não. Explicações sobre como desenvolvi a função serão dadas em um novo post. Este post aqui é só para o código.

Ah, sim, no próximo post mostrarei também uma função um pouco mais customizável já pra quem entende melhor de JavaScript.

Testado no Firefox 2.0, Internet Explorer 6.0 e Opera 9.1. Pelamordedeus, quem puder testar em outros navegadores aí e quiser citar a experiência, faça este favor à humanidade e cite a experiência nos comentários. Obrigado.

1) Coloque o código abaixo em um arquivo chamado micoxUpload.js

/* funçõezinhas padrão pra facilitar */
function $m(quem){
 //apelido só pra não ficar repetindo o document.getElementById
 return document.getElementById(quem)
}
function remove(quem){
 quem.parentNode.removeChild(quem);
}
function addEvent(obj, evType, fn){
 //o velho do elcio.com.br/crossbrowser
    if (obj.addEventListener)
        obj.addEventListener(evType, fn, true)
    if (obj.attachEvent)
        obj.attachEvent("on"+evType, fn)
}
function removeEvent( obj, type, fn ) {
  if ( obj.detachEvent ) {
    obj.detachEvent( 'on'+type, fn );
  } else {
    obj.removeEventListener( type, fn, false ); }
} 
/* a que faz o serviço pesado */
function micoxUpload(form,url_action,id_elemento_retorno,html_exibe_carregando,html_erro_http){
/******
* micoxUpload - Submete um form para um iframe oculto e pega o resultado. Consequentemente pode
*               ser usado pra fazer upload de arquivos de forma assíncrona.
* Use a vontade mas coloque meu nome nos créditos. Licença Creative Commons.
* Versão: 1.0 - 03/03/2007 - Testado no FF2.0 IE6.0 e OP9.1
* Autor: Micox - Náiron JCG - elmicox.blogspot.com - micoxjcg@yahoo.com.br
* Parametros:
* form - o form a ser submetido ou seu ID
* url_action - url pra onde deve ser submetido o form
* id_elemento_retorno - id do elemento que irá receber a informação de retorno
* html_exibe_carregando - Texto (ou imagem) que será exibido enquanto se carrega o upload
* html_erro_http - texto (ou imagem) que será exibido se der erro HTTP.
*******/

 //testando se passou o ID ou o objeto mesmo
 form = typeof(form)=="string"?$m(form):form;
 
 var erro="";
 if(form==null || typeof(form)=="undefined"){ erro += "O form passado no 1o parâmetro não existe na página.\n";}
 else if(form.nodeName!="FORM"){ erro += "O form passado no 1o parâmetro da função não é um form.\n";}
 if($m(id_elemento_retorno)==null){ erro += "O elemento passado no 3o parâmetro não existe na página.\n";}
 if(erro.length>0) {
  alert("Erro ao chamar a função micoxUpload:\n" + erro);
  return;
 }

 //criando o iframe
 var iframe = document.createElement("iframe");
 iframe.setAttribute("id","micox-temp");
 iframe.setAttribute("name","micox-temp");
 iframe.setAttribute("width","0");
 iframe.setAttribute("height","0");
 iframe.setAttribute("border","0");
 iframe.setAttribute("style","width: 0; height: 0; border: none;");
 /* Não usei display:none pra esconder o iframe
    pois tem uma lenda que diz que o NS6 ignora
    iframes que tenham o display:none */
 
 //adicionando ao documento
 form.parentNode.appendChild(iframe);
 window.frames['micox-temp'].name="micox-temp"; //ie sucks
 
 //adicionando o evento ao carregar
/**** antigo que não funcionava no chrome
 var carregou = function() { 
   removeEvent( $m('micox-temp'),"load", carregou);
   var cross = "javascript: ";
   cross += "window.parent.$m('" + id_elemento_retorno + "').innerHTML = document.body.innerHTML; void(0); ";
   
   $m(id_elemento_retorno).innerHTML = html_erro_http;
   $m('micox-temp').src = cross;
   //deleta o iframe
   setTimeout(function(){ remove($m('micox-temp'))}, 250);
  }
*********/
//funfando no chrome graças ao Jhone turra
var iframeId = document.getElementById('micox-temp');
var carregou = function() {
window.document.getElementById( id_element ).innerHTML = iframeId.contentDocument.body.innerHTML;
}
 addEvent( $m('micox-temp'),"load", carregou)
 
 //setando propriedades do form
 form.setAttribute("target","micox-temp");
 form.setAttribute("action",url_action);
 form.setAttribute("method","post");
 form.setAttribute("enctype","multipart/form-data");
 form.setAttribute("encoding","multipart/form-data");
 //submetendo
 form.submit();
 
 //se for pra exibir alguma imagem ou texto enquanto carrega
 if(html_exibe_carregando.length > 0){
  $m(id_elemento_retorno ).innerHTML = html_exibe_carregando;
 }
 
}

2) Inclua (chame) este arquivo no seu HTML

<script type="text/javascript" src="micoxUpload.js"></script>

3) Os parâmetros na hora de chamar a função são:

  1. form - o form a ser submetido ou o ID de algum form que queira submeter.
  2. url_action - url pra onde deve ser submetido o form. Tem a mesma função do parâmetro "action" de um form.
  3. id_elemento_retorno - id do elemento que irá receber a informação de retorno.
  4. html_exibe_carregando - Texto (ou imagem) que será exibido enquanto se carrega o upload
  5. html_erro_http - Texto (ou imagem) que será exibido se der erro HTTP.

4) Pronto. Agora você várias formas de ativar o upload assíncrono. Vou exemplificar aqui 3 formas dentre as várias possíveis:

4.1) Uso básico. Você chama o upload a partir de um button (ou um input-type-button) em um form qualquer:

<legend>Uso b&aacute;sico</legend>
  <form>
    <input type="file" name="nome_qualquer" />
    <div id="recebe_up_basico" class="recebe">&nbsp;</div>
    <button onClick="micoxUpload(this.form,'upa.php','recebe_up_basico','Carregando...','Erro ao carregar'); return false;" type="button">testa</button>
  </form>
</fieldset>

4.2) Ativando o upload quando o campo file perde o foco (onblur):

<fieldset>
<legend>Uso no blur do input</legend>
  <form>
    <input type="file" name="nome_qualquer" onblur="micoxUpload(this.form,'upa.php','recebe_up_onblur','Carregando...','Erro ao carregar')" />
    <div id="recebe_up_onblur" class="recebe">&nbsp;</div>
  </form>
</fieldset>

4.3) Agora uma forma que deixará seu form/upload acessível mesmo que o javascript esteja desabilitado:

<fieldset>
<legend>Uso não intrusivo</legend>
    <form action="upa.php" target="_blank">
    <input type="file" name="nome_qualquer" onblur="micoxUpload(this.form,'upa.php','recebe_up_3','Carregando...','Erro ao carregar')" />
    <div id="recebe_up_3" class="recebe">&nbsp;</div>
  </form>
</fieldset>

Pronto. Customize aí agora e bora "uploadar". Bugs, erros, comenta ae.
Por favor, DÚVIDAS SOMENTE NO FÓRUM !!

No próximo post, a explicação e uma versão mais customizável pra quem já entende de JavaScript.

Gostou da dica acima? Então clica nos botões de compartilhamento abaixo e me ajude a dica a subir no Google.

64 comentários:

  1. Uhum pelo código Micox, vai me ser muito útil. veleu

    ResponderExcluir
  2. Demais!!
    Vou testar e falo como funcionou.
    Será que era só eu que tava louco por isso?
    Obrigado.

    ResponderExcluir
  3. Cara... valew!!! (apesar de eu não ter entendido algumas partes.. hehe)
    http://forum.ievolution.com.br/index.php?showtopic=9372
    dah 1 olhada lah... ok?

    ResponderExcluir
  4. Opa, vamos testar. Belo trabalho.

    ResponderExcluir
  5. Opa, beleza galera.
    No próximo post a explicação pra que vocês possam adaptar melhor.

    E não se esqueçam de testar em diversos navegadores e me informar aqui, ok?

    ResponderExcluir
  6. Muito bom esse código mas estou com um problema está dando um erro de objeto esperado, provavelmente na linha do input.

    ResponderExcluir
  7. Fala Micox, muito bom. O assunto é atualíssimo.
    Cara, me interessou o seu exemplo 3 - preocupado com acessibilidade, mas... precisaríamos de um botão submit, para ser acessível... não? sem JS e sem submit, resta apenas o [ENTER], que é desconhecido da maioria.
    Que tal algo assim (só tem submit se não houver JS):
    criamos o botão submit com o id "sbmt", normal, visível. Então...

    window.onload = function() {
    $m('sbmt').style.display = 'none';
    }

    Abraço, Cau

    ResponderExcluir
  8. É verdade Cau.
    Eu lembrei só do acessível para o JavaScript e esqueci do outro tipo de acessibilidade. VAleus.

    ResponderExcluir
  9. PARABENS BIXO
    Por favor da pra tu pasar o teu msn pra mim usa o email pra mandar pedroafsouza@gmail.com

    ResponderExcluir
  10. Parabéns pelo código Micox.
    Me vai ser muito util em cadastro de fotos de um sistema de concessionaria que estava parado justamente pq não conceguia um sistema de upload leval e funcional.

    Seguem com seus direitos, nada de remove-los, certo?

    Um grande abraço

    ResponderExcluir
  11. Só uma dúvida: como é que o PHP deve tratar o dado recebido? Eu fiz o seguinte teste: submeti uma imagem jpeg para o script abaixo:

    header("Content-type: image/jpeg");
    echo ($HTTP_RAW_POST_DATA);

    O que ele retornou foi simplesmente a própria URL.

    ResponderExcluir
  12. O PHP vai trabalhar exatamente do mesmo jeito que um upload normal.
    Afinal, é isto mesmo que eu faço: só faço um upload via iframe.

    Eu, por exemplo, uso um script de upload básico normal que se acha aí pela net.

    ResponderExcluir
  13. Simplesmente excelente! Esta era uma solução que eu estava buscando há muito tempo e o autor expôs de forma simplificada. É ótimo saber que existem pessoas que não têm medo de compartilhar o conhecimento. Este tipo de iniciativa é sempre bem vinda.
    Parabéns e Obrigado!

    ResponderExcluir
  14. Esse script é totalmente ÚTIL!
    Perfeito..
    Estou terminando um pequeno sistema para os alunos postarem notas de aula via web, assim que terminar te envio o Código Fonte .. e é claro vou por seus créditos nele.. Acredito em Software Livre!
    Grande abraço.

    ResponderExcluir
  15. Tem como disponibilizar o arquivo upa.php ?? Gostaria de testar..

    Outra pergunta tem como validar por exemplo somente para fazer upload de imagens (jpg e gif) ?

    Renato

    ResponderExcluir
  16. Renato, é um script de upload como outro qualquer, pode ser PHP, ASP ou qualquer linguagem server-side.

    Eu por exemplo, no arquivo upa.php uso este script aqui: http://www.plugmasters.com.br/sys/materias/493/1/Upload-de-Imagens-Com-Seguran%E7a

    ResponderExcluir
  17. Excelente trabalho. Sua dica funionou muito bem para mim.

    ResponderExcluir
  18. usei hoje no meu site, muito bom parabens

    ResponderExcluir
  19. legal, mas não haveria necessidade de um javascript desse tamanho, poderia ser beeeeeeeeeem mais simples...

    ResponderExcluir
  20. É, to sabendo manezei. Mas já tem uma versão 2.0 prontinha aqui na minha máquina só esperando eu blogar. hehe

    É que tô querendo fazer uns exemplos mais reais e mais fáceis de usar.

    Valeus...

    ResponderExcluir
  21. Cara ..... você é um NINJA !!!
    Parabéns ... função utilíssima

    ResponderExcluir
  22. Para ficar ultra completo só faltava o arquivo php :o)

    ResponderExcluir
  23. Bem,

    tentei aceder ao forum, mas sem sucesso. Ja agora aproveito para colocar a minha duvida aqui:

    Utilizando isto (sim, consegui, ate integrando com um plugin de Jquery para upload, fico lindinho...), como consigo saber se o upload terminou?

    ResponderExcluir
  24. Cara, com essa função aí não dá pra saber não. com essa aí você apenas joga o resultado em uma div qualquer.

    Esta semana pretendo postar uma versão nova desse upload aí onde será possível saber. Quem tiver pressa me mande um email que eu mando o código.

    Galera, a função php pra upload, vocês acham no google pesquisando por Upload php. Simples!

    ResponderExcluir
  25. Muito boa a função, fiquei de cara, vc esta de parabens.

    ResponderExcluir
  26. Estou com um problema, testei no IE6 e da a mensagem de erro que é enviada por parametro para sua função.

    Poderia me ajudar?
    Meu email: tiagowanke@gmail.com

    Agradeço desde já.

    ResponderExcluir
  27. Fala Micox blz !?
    Eu percebi que pode se fazer um multiplo upload, porem, como eu poderia fazer uma verificação nos campos antes de enviar os arquivos ?

    email: lfrs_web@yahoo.com.br

    Vlw...

    ps:belissimo codigo ^^

    ResponderExcluir
  28. Ué.
    É só chamar seu código (ou função) que faz a verificação ANTES de chamar minha função. Simples.
    (supondo que você JÁ tenha uma função pra verificação)

    ResponderExcluir
  29. Micox, só dizer uma coisa: Show de bola!! Simples de usar, de entender, direto ao ponto!! Muiito bom mesmo! Matou a pau!

    Abraço!

    ResponderExcluir
  30. obrigado por ajudar os reles mortais!!

    ResponderExcluir
  31. Muito legal micox, me ajudou muito!
    também não tive sucesso com o fórum
    e lendo os posts percebi que você ja possui uma nova função de upload melhor que esta ja postada.
    Gostaria de saber se esta ja esta pronta e queria analisa-la para ver qual se enquadra mais às minha necessidades.
    Se puder me enviar esta outra no meu e-mail agradeço: eric_freitas@hotmail.com
    ------------------
    dúvida sobre a função:
    O resultado retornado na div/span é o retorno do meu PHP?
    ->Pq como vou usar com ajax, preciso do endereço da foto para enviar pro banco...

    Muito Obrigado.
    Att. Eric Rodrigo de Freitas

    ResponderExcluir
  32. Parabéns! Funcionou beleza! Com firefox 3. Valeu!

    ResponderExcluir
  33. ei Micox, parabens pelo topico.

    quase 1 ano e meio depois esse topico me ajudou.

    Parabens pela iniciativa

    ResponderExcluir
  34. Mano blz teu esquema funciona certinho so to com um problema não sei se é falta de entendimento do negocio mais quando eu envio o upload e ele esta dentro de um form para envio de outros campos depois de enviar o up o action do meu form para que muda e fica como o action do upload não sei se fui muito claro mais ai esta meu email ok se puder entrar em contato

    email/msn: a2web@a2web.com.br

    ResponderExcluir
  35. Excelente seu artigo! não tive problemas em implementar na minha aplicação! Parabéns! Nota 1000!!!!

    ResponderExcluir
  36. Este comentário foi removido pelo autor.

    ResponderExcluir
  37. Mto bom msmo, mas naum consegui colocar uma imagem no codigo...
    ex: micoxUpload(this.form,'cad_foto.php','recebe_up_basico',
    'espera.gif','Erro ao carregar'); return false;"...

    ele exibe somente o texto "espera.gif", a imagem está no mesmo diretorio do html.

    ResponderExcluir
  38. Ué Rafa, é só colocar a tag img inteira ué.

    ResponderExcluir
  39. Gostei, to tentando usar, só queria saber onde está a versão 2.0?

    Mesmo assim agradeço

    ResponderExcluir
  40. Olá! Sou Aline Amaral Rigues e vim agradecer a sua contribuição para nós programadores com o código apresentado! Agradeço veemente!
    Um grande abraço!

    ResponderExcluir
  41. Noh cara vlw d+,vou usar elas !
    flwss abrass

    ResponderExcluir
  42. Eh possivel aplicar esse codigo, usando Jquery?!

    ResponderExcluir
  43. Sim, é possível usar com jquery, mas acredito que o jquery tem seus próprios plugins para isso.

    Uma versão mais atualizada também pode ser vista aqui: http://webly.com.br/Micox/micoxUpload2.htm

    ResponderExcluir
  44. Este comentário foi removido pelo autor.

    ResponderExcluir
  45. Show de bola ... teria como me enviar a versao nova no email juniorpcosta@gmail.com ... obrigado....

    ResponderExcluir
  46. Onde tem o script para dowload?

    ResponderExcluir
  47. É uma gambi de primeira, porém resolve o problema.

    O próprio Google usa o "upload em ajax" dessa forma.

    Parabéns o/

    ResponderExcluir
  48. Boa noite, preciso de uma ajuda sua ja mexi re-mexi nesse seu script, voce ja deve ter notado que quando clica para upar o nome do arquivo que ta sendo upado desaparece do box, precisava deixar o nome mostrando ate a finalizacao do up
    albert@volix.com.br

    ResponderExcluir
  49. Oi aqui deu tudo certo, porém ja tentei varios arquivos para encaixar ai no upa.php e com nenhum eu obtive sucesso, será que não poderia incluir ele ai e deixar o tutorial ate mesmo mais completo?
    No meu caso preciso desse php para fazer upload de qualquer tipo de arquivo mesmo.

    ResponderExcluir
  50. Primeiramente, eu gostaria de dar parabens pelo trabalho. Ficou fantástico, funcionou perfeitamente. Segundo, eu gostaria de saber se posso utiliza-lo em minha página comercial? Estou trabalhando em um site com alguns recursos AJAX e este seu código me serviu muito bem. Mas tenho preocupação de utiliza-lo de forma comercial.

    ResponderExcluir
  51. Codigo muito util, nao consegui compreender ele muito bem porem ele esta me ajudando na concepção do meu tcc na parte de cadastro, muito obrigado [creditos foram mantidos]

    ResponderExcluir
  52. Boa tarde.. muito legal esse seu post. mas eu sou cru em programação de javascript e não entendi direito.. estou tentando criar uma mensagem de carregando o arquivo para os meus usuário não acharem q o arquivo não está carregando.. irei colocar sem problemas o seu nome no arquivo. uso linux e sou fã de GLP. se vc puder me ajudar eu agradeço.

    ResponderExcluir
  53. O código não funciona para usuarios do CHROME e SAFARI. O problema está na função remove. Sendo mais específico, não é possivel tranformar o iframe em objeto, retornando NULL. Ambos os browsers não pegam o conteúdo do iframe com o getElementById nem com nenhuma outra função.

    ResponderExcluir
  54. Ummm que saco.
    Valeu o aviso koto.
    Atualmente ando meio sem tempo de corrigir a função mas tá aí o aviso.
    Valeu.

    ResponderExcluir
  55. Fiz uma mudança no código e ele agora também funciona no CHROME e SAFARI.

    Substitui:

    var carregou = function() {
    removeEvent( $m('micox-temp'),"load", carregou);
    var cross = "javascript: ";
    cross += "window.parent.$m('" + id_elemento_retorno + "').innerHTML = document.body.innerHTML; void(0); ";
    $m(id_elemento_retorno).innerHTML = html_erro_http;
    $m('micox-temp').src = cross;
    //deleta o iframe
    setTimeout(function(){ remove($m('micox-temp'))}, 250);
    }


    por:


    var carregou = function() {
    window.document.getElementById( id_elemento_retorno ).innerHTML = 'Arquivo enviado com sucesso';
    }


    Dessa forma ele a mensagem de retorno vai normalmente.

    ResponderExcluir
  56. Opa achei bem legal essa função, mais estou tendo problemas com o chrome e safari elea aparece carregando depois fica em branco, agora com essa alteração ele aparece o 'Arquivo enviado com sucesso'. Detalhe nas duas formas a imagem não é gravada

    ResponderExcluir
  57. Eu Também estava com problema com o CHROME quando fazia upload, a função só ficava carregando ou iria para uma página de erro do CHROME, a partir da dica do koto eu conseguir solucionar, em meu caso substituir por um código do jquery para recarregar.
    exemplo:
    Substituir a função para está:
    var carregou = function() {
    $.get(url_action, { id:'' },
    function(data) {
    $(seu_id_elemento_retorno).html(data);
    return false;
    });
    }

    ResponderExcluir
  58. ta ai a solução

    var iframeId = document.getElementById('micox-temp');
    var carregou = function() {
    window.document.getElementById( id_element ).innerHTML = iframeId.contentDocument.body.innerHTML;
    }

    ResponderExcluir

Resultado! Concursos