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…

25 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 ^^ ….

Laissez un commentaire :