upload file en AJAX : méthodes

Posté le Jeudi 12 avril 2007 à 23 h 10, Read it in english with Google

j’ai dĂ©couvert plusieurs mĂ©thodes permettant d’uploader des fichiers en AJAX sans rechargement de page. Chacune d’elles ont leurs avantages et leurs inconvĂ©nients. Comme on peut remarquer des diffĂ©rences entre les procĂ©dures de sĂ©curitĂ© des navigateurs, la majoritĂ© de ses mĂ©thodes sont donc restreintes Ă  certains d’entre eux. Mais on peut remarquer qu’il existe 2 classes vĂ©ritables de navigateur : les bons, compatibles le plus possible W3C : firefox, opera, safari, konqueror… et l’opposĂ©, le mauvais et tristement cĂ©lèbre : IE.

input cloneNode in iframe

compatibilitĂ©: opera + firefox + … – IE

Quand input.onchange, on copie l’Ă©lĂ©ment input dans un formulaire d’une iframe Ă  l’aide de cloneNode et on fait un submit() sur le formulaire. A vous de correctement crĂ©er le document de votre iframe et de cibler l’action du input sur un script server qui renverra les informations nĂ©cessaires pour retrouver par la suite le fichier uploader. Car lorsque votre ficher est fini d’uploader, le document de l’iframe peut appeler les fonctions JS de votre page principale, vous pouvez ainsi transmettre les paramètres de taille, path, nom… du fichier uploadĂ©.

Une petite remarque, votre iframe ne sera pas charger si vous lui attribué les style display:none, utiliser plutôt width:0px et height:0px.

Pourquoi cela ne marche pas sur IE ? lorsque la node input file est clonĂ©, IE Ă©fface l’attribut value qui cible le fichier. Vous vous retrouvez donc avec un input file vide.

submit form with frame target

compatibilité: tous

Creer une page de frame, avec un frameset vide et invisible nommĂ© « fileframe » pour l’exemple et l’autre contenant votre inputfile. Lors d’un inputfile.onchange, copiez les attributs action et target du formulaire contenant votre input file et remplacer les par l’url d’un script server et par le nom de l’autre frame: « fileframe ». Puis lancez form.submit(). Cela va envoyer toutes les donnĂ©es du formulaire vers « fileframe », y compris donc les fichiers. Ensuite, vous vous Ă©changer les donnĂ©es entre les frame pour sauvegarder les donnĂ©es renvoyĂ©es par le script, sans oublier de supprimer les input file dĂ©jĂ  envoyĂ©s pour que cela ne se rĂ©pète pas.
Si vous compter envoyer un nombre non défini de fichier, lorsque le upload commence (inputfile.onchange est lancé), vous pouvez activer la propriété disable sur les input file, ainsi il ne seront pas renvoyé.

C’est la mĂ©thode utilisĂ© par GMail. Elle Ă  l’avantage d’ĂŞtre simple mais limitĂ© par les paramètres de votre serveur : si l’utilisateur dĂ©cide d’envoyer beaucoup de fichier, la limite d’upload du serveur (post_max_size sur php) peut ĂŞtre rapidement atteinte. Dans ce cas vous pouvez mettre en place une boucle qui permettra d’uploader les fichiers un par un dans diffĂ©rentes frame en assignant la propriĂ©tĂ© disable Ă  tout les fichier non concerner. Cependant, les frames ne peuvent ĂŞtre crĂ©Ă© par javascript (apparement) donc ce n’est pas sans limite…
Je cherche encore la mĂ©thode pour savoir si la frame « fileframe » Ă  Ă©tĂ© correctement chargĂ© ou non.

En passant on peut remarquer que GMail ne gère pas extrèmement bien cela. Si vous y ĂŞtes inscrit et que vous avez un moniteur rĂ©seau, selectionnĂ© un fichier assez gros Ă  uploader, attendez le dĂ©part de l’upload automatique de GMail, et changer de fichier durant l’upload. Une fois l’upload terminĂ©, c’est votre premier fichiers qui a Ă©tĂ© uploadĂ© et GMail Ă  supprimer le champ input file contenant le chemin de votre deuxième fichier.

Cette mĂ©thode fonctionne très bien mais n’est pas très sĂ©duisante. Vos frames devant ĂŞtre dĂ©finit Ă  la source, ne comptez pas sur un rĂ©fĂ©rencement de votre page. De plus c’est assez lourd Ă  gĂ©rer.

submit form with iframe target

compatibilitĂ©: IE, firefox … avec conditions sous IE6

MĂ©thode:
C’est la mĂŞme chose que la mĂ©thode prĂ©cĂ©dente, sauf qu’au lieu de cibler une frame vous pouvez cibler une iframe avec la propriĂ©tĂ© target de votre form. Vous pouvez ainsi crĂ©er plusieurs iframes pour chaque input file et vous dĂ©sactivez ceux qui ne doivent pas ĂŞtre charger avec la propriĂ©tĂ© disabled.
C’est très pratique, cependant, si vous crĂ©ez vous iframe dynamiquement (avec du code javascript et les fonctions DOM), cela ne marchera pas sur IE 6. Il faut impĂ©rativement crĂ©er l’iframe dans un conteneur en remplissant la propriĂ©tĂ© innerHTML de celui-ci. ne pas utiliser document.createElement(‘iframe’).

A part cela tout marche bien c’est la mĂ©thode que j’ai adoptĂ© :)

Flash FileReference uploading

compatibilité: tout navigateur possédant le plug-in Flash 8 ou supérieur.

MĂ©thode:
La class ActionScript FileReference ou FileReferenceList permet d’envoyer des fichiers Ă  un serveurs. Vous pouvez crĂ©er un object flash invisible dans la page et communiquer avec lui Ă  l’aide de javascript. Par exemple lorsque l’utilisateur click sur un button de votre page, celui-ci va appler la mĂ©thode FileReference.browse() via une fonction exportĂ© de votre Flash vers javascript. Ensuite l’object Flash peut Ă  son tour appeler des fonctions javascript de votre page, ce qui peut vous permettre, grace aux mĂ©thodes avancĂ©es de la class, de suivre l’avancement d’upload de votre fichier directement dans votre page. La class, c’est le cas de le dire ;)
Consulter la page de macromedia concernant la communication flash-javascript.

iframe simple

compatibilité: tous

MĂ©thode : une iframe au dimension bien calculĂ©es dans laquelle se trouve un formulaire dont l’url cible vers un script server et contenant un input file avec un inputfile.onchange= »this.form.submit(); ». Comme dans les mĂ©thodes prĂ©cĂ©dente, vous accĂ©dez Ă  votre page principale pour inclure les donnĂ©es renvoyĂ©es par le script server.

InconvĂ©niant : pas très pro :) de plus une selection dans l’iframe peut dĂ©caler le contenu se qui est très laid.

ActiveX

compatibilité: IE restreint

MĂ©thode :
Un objet ActiveX qui va permettre d’aller chercher le contenu fichier ciblĂ© par le path de votre input file. Vous pourrez ensuite envoyĂ© ça grace Ă  un XMLHttpRequest. Un avertissement de sĂ©curitĂ© indique au client que le script tente d’accĂ©der Ă  du contenu local, ceci est donc plus destiner Ă  l’intranet. L’avantage Ă©tant que vous pouvez sĂ©parer les contenus mĂŞme de votre fichier en diffĂ©rente partie afin de ne pas dĂ©passer les limites du serveur.
un exemple en ASP

Mise Ă  jour 13.04.2007 : ajout de la mĂ©thode « submit form with iframe target » que j’aurais du trouver bien avant…

encore Ă  suivre…

26 réponses à “upload file en AJAX : mĂ©thodes”

  1. bertelle nicolas

    hi,

    excellent article que j’ai testĂ© pour les deux premiers exemples ceux ci ayant correspondus Ă  mes besoins.

    deux remarques :

    pour l’exemple « iframe » => excellent, bats les couilles pour IE zont qu’Ă  se mettre aux normes, les utils ? passer Ă  firefox qu’ils soient admins ou utils finaux lol
    pour l’exemple « typeGMail » => fonctionne nickel mais rĂ©ellement ennuyeux Ă  adapter pour des pages complexes Ă  formulaire multiples et puis bon lol les frameset j’en faisai dĂ©jĂ  en 1998 relol

    au vu du service que m’a rendu cette page il me semblerait normal de vous transmettre les codes sources des exemples que j’ai mis en forme (client side) ;-)

    tenez moi au courant et cann your blog has long life ;-)

  2. deY!

    pour gardĂ© le contenu lors d’un clonage :

    mynode.cloneNode(true)

    Je n’ai pas testĂ© avec un input… mais cela devrait fonctionner sous le mĂŞme principe…

  3. XoraX

    j’ai testĂ©, ça ne marche pa sur IE…
    voir le § « input cloneNode in iframe »

  4. wG

    très interessant!
    Bravo

    wG from Brazil.

  5. Ravery

    J’utilise les iframe comme destination de formulaire depuis pas mal de temps. Avec une petite bibliothèque js de communication iframe/page mère qui va bien Ă  cĂ´tĂ©, « ca le fait » rapidement et efficacement.
    La meilleur solution Ă  mon avis…..

  6. Zakwil

    C’est exactement ce que je cherche. Un upload de fichier un peu classieux, par contre je pite rien Ă  ActionScript (bon j’ai mĂŞme pas flash).

    Est-ce qu’il serai trop demandĂ© de mettre Ă  la disposition un swf qui appelle l’explorateur de fichier?

    Si vous faites ça vous êtes des dieux :)

    Merci

  7. XoraX

    ça existe déjà :)
    http://swfupload.mammon.se/

    mais je doute que ce soit des dieux, ça marche pas sur opera :)

  8. Zakwil

    Ouais il est pas parfait mais bon…

  9. Plouceur

    Cet article fait le tour de la solution iframe implĂ©mentĂ©e Ă  l’aide de Yahoo UI… très intĂ©ressant.

  10. obel

    Alors en effet, c’est trĂ©s intĂ©rressant, mais ça le serait d’autant plus avec quelques codes sources pour ilustrer tout ça. Je trouve le code plus « comprehensible » que des explications.
    Et … (atention conne) pourquoi est ce si difficile pour javascript de faire une fonction qui recupere le $_FILES et le transforme en DOM (tout ça grace Ă  la cĂ©lèbre library David Coperfield :D ).

    En tout cas merci bien, ça m’as beaucoup aidĂ© … mĂŞme si je suis retissant a tout ce qui est frame … (c’est vrai quoi .. c’est pas catholique les frames).

  11. droopy6

    FileReference en Flash ne marche pas en HTTPS sous firefox. on a:
    Error #2038: Erreur d’E/S de fichier.

  12. Yragael

    Puisque le problème est de crĂ©er un clone d’un INPUT de type file existant dans le document pour l’intĂ©grer Ă  une formulaire particulier, je peux vous suggĂ©rer une solution de contournement esthĂ©tique sous IE et Firefox :

    tagINPUT = document.getElementById (id);
    if (navigator.userAgent.substr (0, « Mozilla/5.0″.length) == « Mozilla/5.0″)
    {
    tagClone = tagINPUT.cloneNode (false);
    }
    else
    {
    tagClone = tagINPUT.cloneNode (false);
    tagParent = tagINPUT.parentElement;
    tagParent.replaceChild (tagClone, tagINPUT);
    tagClone = tagINPUT;
    }
    tagClone.style.display = « none »;
    document.forms["tagXMLHttpRequest"].appendChild (tagClone);

  13. ldsmem

    Merci pour cette page très instructive et surtout un grand merci à Yragael pour sa solution.

  14. billitch

    merci pour ces explications ! Yragael ta methode est très Ă©lĂ©gante (qui fait danser le tas de boue qu’est IE)
    de mon cotĂ© je commence Ă  Ă©crire une sĂ©rie de widgets php qui permettront d’utiliser simplement ce genre de fonctionnalitĂ©s

  15. cquemoi

    bon article, le seul problème de toutes ces solutions c’est que les restrictions de sĂ©curitĂ© javascript que l’on trouve dans les portails web par exemple, prohibent la communication entre frame en interdisant l’appel Ă  la mĂ©thode ‘parent’.

  16. Blogouille » Blog Archive » Chargement de fichier (upload) en ajax contient sur le sujet :

    [...] on se contente de merles et quelques expédients sont possibles. La plupart sont listés sur ce blog. Bon courage [...]

    le Dimanche 18 janvier 2009 @ 1 h 33
  17. Martin

    En ce qui concerne la mĂ©thode : « submit form with iframe target », il me semble qu’elle n’est pas compatible avec Firefox 3.5.1 … Quand le dĂ©veloppement web ne sera plus du bricolage ?? :S

    Sinon merci pour cet article intéressant !

  18. Valdelievre

    Salut,

    J’utilise la mĂŞme mĂ©thode de clone dans une iframe, vous pouvez-vous voir le code source ici :
    http://developers.sirika.com/mfu/

    Merci pour ton article !

  19. File upload Ajax : Firefox 3.0 – read file content - La Billetterie contient sur le sujet :

    [...] sert qu’à une chose: insérer un uploader Flash 8 dans la page et le configurer à la volée » http://www.xorax.info/blog/programmation/127-ajax-upload-input-file.html## Ou bien utiliser les interface de firefox 3 pour lire le contenu du fichier à la volée : [...]

    le Mardi 20 juillet 2010 @ 7 h 55
  20. yoz

    Hello,

    intĂ©ressant mais je voudrais Ă©viter une confusion car on m’a posĂ© la question Ă  la suite de la lecture de votre article, l’upload de fichier en AJAX est pour des raison de sĂ©curitĂ© IMPOSSIBLE ! Il faut donc parler d’upload sans recharger la page courante mais pas d’AJAX :)

    Sinon pour faire fonctionner tous ça sous IE pas de pb, il faut juste changer un peu la manière de faire. Au lieu de cloner l’element et bien on charge directement le formulaire dans l’iframe, avec un peu de css l’iframe passera totalement inaperçue, il suffit ensuite de soumettre le formulaire et de supprimer l’iframe une fois le fichier uploadĂ©

    Aller vivement des standard suivit par tous !

  21. brady

    Super article qui m’a Ă©tĂ© très utile, j’ai finalement utilisĂ© la mĂ©thode avec iframes.
    qui marche plutĂ´t bien :)
    merci beaucoup !!

  22. Serru

    Bonjour,
    Ce poste spĂ©cifiquement pour XoraX, que j’ai cru comprendre inconditionnel d’Opera.
    Je suis maintenant fâchĂ© avec Opera: pas de traitement de onUnload ni de onBeforeUnload, considĂ©rĂ© comme non prioritaires. Je ne peux pas (simplement) savoir que le visiteur en a fini avec moi! J’utilise la version Version 11.50, RĂ©vision 1074, Plate-forme Linux, Système x86_64, 2.6.22.19-0.3-default. Je vais jusqu’Ă  tester mes pages avec MSIE6 et en utilisant JQuery, et Ă©vitant les grosses bouses de cette #?@ de MSIE6, tout fini par aller pour tous les fureteurs sauf pour… OpĂ©ra.
    J’aimerais bien revenir de Firefox (ben ouais!). J’ai bien aimĂ© OpĂ©ra au Dragon pas mĂ»r, bien que « seulement » gratuit et donc exposer Ă  la vente. Mais le label « LIBRE » n’est pas une garantie, le pire des exemples pour moi dans ce domaine Ă©tant celui de SĂĽse.
    Cordialement,
    Patrick

  23. XoraX

    Cette article date un peu (il existe maintenant bien d’autres mĂ©thodes notamment en html5).

    Mais effectivement, bien qu’Opera ne soit pas libre, disons que j’admire leurs Ă©quipes de dĂ©veloppement qui ont mis au point beaucoup d’innovations avant les autres, bien qu’ils n’aient pas la force commerciale de certains.
    Je parle notamment de la home diaporama, des thumbs miniatures des onglets, des mots de raccourcies dans la barre d’url (g+kw pour rechercher sur google) et bien d’autres choses que les autres navigateurs ne se sont pas privĂ© de copier sans donner leur source d’inspiration. Aujourd’hui j’utilise Firefox pour des raisons pratique dans mon mĂ©tier, mais il ne couvre pas encore toutes les optimisations d’interface que j’avais dans l’Opera d’il y a 4 ans (pas de personnalisation des raccourcies claviers, gestionnaire de tĂ©lĂ©chargement très lent, pas de gestion des types mime… etc), Opera est Ă©galement bien plus rapide sur bien des niveaux.

    Évidemment son caractère commercial est un frein, mais pour moi beaucoup moins que Chrome (qui n’est pas libre, c’est Chromium qui l’est, et Google a jouĂ© au diable en faisant accepter Chrome de cette manière), ou encore Safari (lamentable fermĂ©). Je vous recommanderais donc Opera en second choix en tant qu’utilisateur simple, Firefox en premier.

  24. Samuel

    Merci beaucoup pour cet article, sa faisait un bout de temps que je cherchais une bonne solution (meme si elle n’existe pas vraiment visiblement…)

  25. tomasoma

    Bon billet, bien rĂ©fĂ©rencĂ©. Pour le rafraichir, une question, quelqu’un a dĂ©jĂ  testĂ© https://github.com/valums/file-uploader ?

    pour l’instant je suis en local avec un mac alors pour les tests sur IE c’est tendu ^^ ….

  26. kepago

    Hello, after reading this amazing post i am also cheerful to
    share my know-how here with friends.

Laissez un commentaire :