tutorials.de Buch-Aktion 05/2012
  • Echter Ajax Datei Upload

    Hallo und Willkommen zu meinem Tutorial. Behandelt wird heute das Thema Upload mit Ajax.

    Vorrausgesetzt wird, dass man die Grundlagen von Javascript beherrscht und geübt in PHP ist bzw. bereit ist, sich das Nötige zu suchen, um ein vernünftiges Upload Script zu erstellen.

    Das ganze ist relativ einfach aufgebaut, man muss also kein Profi sein.
    Ich werde nicht auf jede einzelne Zeile eingehen!

    Ich möchte darauf hinweisen das das PHP Upload Script sich, so wie es hier vorgestellt wird, nicht für den öffentlichen Gebrauch eignet da es nur das Wichtigste enthält und man ohne Prüfung der Datei eine große Sicherheitslücke erzeugt.


    1. Vorbereitung: Das HTML Dokument


    Kurz und knapp:
    HTML-Code:
    <html>
    <head>
        <script src="upload.js"></script>
    </head>
    <body>
    
        <input type="file" name="fileElem[]" id="fileElem" multiple="true"
    	    accept="image/*" onchange="handleFiles(this.files)">
    
        <div id="auswahl"></div>
    	
        <input type="button" onclick="sendFiles();" value="Hochladen">
    
    </body>
    </html>
    "upload.js" wird unsere JS Datei mit den nötigen Funktionen.
    Im Body Bereich erstellen wir ein File Input Feld. Durch multiple="true" erlauben
    wir das auswählen mehrerer Dateien und mit accept="image/*" sagen wir
    das wir nur Bilddateien haben wollen.
    Die bei onchange angegebene Funktion handleFiles() verarbeitet die ausgewählten
    Dateien.

    Im DIV Element mit der ID "auswahl" zeigen wir dem Nutzer die Bilder
    an die er ausgewählt hat bevor wir sie auf den Server laden.

    Der Button darunter nutzen wir um den Upload zu starten.

    Tipp:

    Mit document.getElementById('fileElem').click(); kann man einen "Klick" auf das Input Feld tätigen. So kann man das meiner Meinung nach schreckliche Dateiauswahl Feld per CSS
    unsichtbar machen und trotzdem benutzen. Ich bevorzuge da schöne Bilder



    2. upload.js : Unsere Funktionen


    Wir werden 3 Funktionen schreiben:

    handleFiles
    sendFiles
    FileUpload


    2.1 handleFiles()

    Gut, fangen wir an mit handleFiles.
    Was soll handleFiles denn nun tun?

    handleFiles verarbeitet unsere ausgewählten Dateien.
    Die Liste mit der Auswahl wird durchgegangen und für jedes
    ausgewählte Bild wird ein IMG Element erstellt.
    Dem IMG Element weisen wir die Klasse "obj" zu.
    Dadurch können wir später die erzeugten Bilder einfach und unkompliziert
    wiederfinden und für den Upload benutzen.

    Mit dem FileReader Object erzeugen wir eine Vorschau des Bildes.
    Danach hängen wir das erzeugte IMG Element an unser DIV Element an.

    Das ganze läuft Clientseitig ab so können wir dem User die ausgewählten Bilder
    nochmal zeigen bevor wir sie Hochladen.



    Der Code sollte nicht all zu schwer zu verstehen sein.

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    
    function handleFiles(files) {
     
            var i = 0;
            var auswahl_div = document.getElementById('auswahl');
     
            var imageType = /image.*/;
     
            var fileList = files;
     
            for(i = 0; i < fileList.length; i++)
            {
                    var img = document.createElement("img");    
                    img.height = 110;
                    img.file = fileList[i];
                    img.name = 'pic_'+ i;
                    img.classList.add("obj");
     
     
                    var reader = new FileReader();
                    reader.onload = (function(aImg) { return function(e) { aImg.src = e.target.result; }; })(img);
                    reader.readAsDataURL(fileList[i]);
     
                    auswahl_div.appendChild(img);    
            }
    }

    Tipp:

    In dem wir dem erzeugten IMG Element einen Wert für height zuweisen können
    wir das Bild für die Vorschau skalieren




    2.2 sendFiles()

    Mit dieser Funktion suchen wir unsere erzeugten Bilder und erzeugen eine
    neue Instanz unserer FileUpload Funktion und starten somit den Upload.

    Um das Tutorial übersichtlich zu halten ist es nur das nötigste.
    Es gibt aber ein Problem.

    Kurze Geschichte: Einige Browser haben ein gesetztes Limit für Verbindungen zu einem Server. Ende.

    In unserem Fall bedeutet das: man kann nicht 100 Bilder gleichzeitig hochladen wenn
    man das Limit im Browser nicht eigenhändig erhöht.

    Klar kann man das machen aber kann man das auch von seinen Usern erwarten?
    Hier sollte ein Zähler eingebaut werden. Nur wenn nicht grad X uploads laufen einen neuen starten. Dies kann man mit einer Globalen Variable, ein, zwei Abfragen und setTimeout realisieren.

    Eine gute Zahl an gleichzeitigen Uploads ist 3.
    In Firefox und Chrome funktioniert es mit dieser Anzahl tadellos.


    Nun zur Funktion sendFiles:

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
     
    function sendFiles(){
      var i = 0;
      var imgs = document.querySelectorAll(".obj");
      
      for(i = 0; i < imgs.length; i++)
       {
     
     
        new FileUpload(imgs[i], imgs[i].file);
     
      }
     
    }


    Der Funktion FileUpload übergeben wir 2 Parameter. Der erste zeigt auf
    das IMG Element, der zweite auf die Datei ( siehe handleFiles -> img.file = fileList[i] )

    Tipp:
    Mit document.querySelectorAll(".obj") finden wir alle unsere erzeugten Bilder.



    2.3 FileUpload()

    Jetzt kommen wir zum Upload.
    Zuerst erzeugen wir ein neues XMLHttpRequest Objekt.
    Dann fügen wir Event Listener Funktionen hinzu.
    "progress" gibt uns in Prozent den Stand des Uploads durch einfache Mathematik.
    Man könnte in dieser Funktion die Prozentzahl in ein HTML Element schreiben lassen.
    So kann man den Upload verfolgen.

    Da diese Funktion uns nie genau 100 ausspuckt fügen wir noch eine Funktion
    hinzu die aufgerufen wird wenn der Upload abgeschlossen ist ("load").
    Dort setzen wir die Variable prozent auf 100.

    Wir benutzen in diesem Tutorial das FormData Objekt.
    Diesem können wir Werte anhängen um sie anschliessend kurz und knapp
    per Ajax zu senden.

    Man kann sich das wie ein per Script erstelltes HTML Formular vorstellen.
    Durch .append(ID_NAME , WERT) fügt man einen neuen Wert hinzu.

    Im PHP Script kann man dann die Daten verarbeiten wie als wenn
    man ein HTML Formular abschickt.

    Wir senden unsere Daten an unser Upload Script "upload.php" und zwar per POST.
    Bevor wir die Daten senden überschreiben wir noch den Mime Type mit
    text/plain; charset=x-user-defined-binary.

    Anschliessend senden wir mit xhr.send unser FormData Objekt 'fd'.


    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    
    function FileUpload(img, file) {
     
      
     
      var xhr = new XMLHttpRequest();
      this.xhr = xhr;
      
     
      var prozent;
     
      this.xhr.upload.addEventListener("progress", function(e) {
            if (e.lengthComputable) {
             
       prozent = Math.round((e.loaded * 100) / e.total);
              
            }
          }, false);
      
      xhr.upload.addEventListener("load", function(e){
            prozent  = 100;
     
          }, false);
      
     
     
        var fd = new FormData;
        fd.append("File", file);
     
     
        xhr.open("POST", "upload.php", true);
        xhr.overrideMimeType('text/plain; charset=x-user-defined-binary');
     
        xhr.send(fd);
     
       
     
    }


    Das war dann auch mit unserem Javascript Teil. Wir sind schon fast fertig. Fehlt nur noch
    das PHP Script.


    3. Das PHP Script


    Jetzt kommen wir zum letzten Teil.
    Ein ganz einfaches PHP Script um die vorherige Arbeit zu testen.

    In der Funktion FileUpload haben wir an unser FormData Objekt
    einen Wert angehangen, genauer gesagt unser Bild.
    Als ID für diesen Wert haben wir 'File' gewählt.
    So können wir im PHP Script mit $_FILES['File'] auf unser Bild zugreifen.

    Es wird geprüft ob es sich bei der gewählten Datei um ein Bild handelt.
    Erlaubt sind gif, png und jpg.
    Der Name des Bildes wird in $original_name gesichert.
    Danach wird ein eindeutiger Name für das Bild erzeugt und
    die passende Endung angehangen.
    Unter diesem Namen wird es auf dem Server gespeichert

    In $dir gibt man das Ziel Verzeichnis des Bildes auf dem Server an.

    Da es hier um den Upload mit Ajax und nicht um die Verarbeitung
    der Daten mit PHP geht , werde ich das Script nicht weiter erklären.

    Ich möchte kurz nochmal auf meinen Hinweis am Anfang hinweisen.

    PHP-Code:
    <?php


    $tempname 
    $_FILES['File']['tmp_name']; 
    $name $_FILES['File']['name']; 
    $type $_FILES['File']['type']; 


    if(
    $type != "image/gif" && $type != "image/jpeg" && $type !="image/png") { 
        
    $content .= "Nur gif, png und jpeg Dateien dürfen hochgeladen werden.<br>";
        
    $err=1




    $original_name $name;


    $imgtype =getimagesize($tempname);


    switch(
    $imgtype[2]){

    case 
    "1":
        
    $endung "gif";
        
    $uniqid uniqid();
        
    $name $uniqid.".gif";
        break;

    case 
    "2":
        
        
    $endung "jpg";
        
    $uniqid uniqid();
        
    $name $uniqid.".jpg";
        break;

    case 
    "3":
        
    $endung "png";
        
    $uniqid uniqid();
        
    $name $uniqid.".png";
        break;




    if(empty(
    $err)) { 

    $dir "uploads/";  // Das Verzeichnis in welches die Bilder gespeichert werden sollen
    $ziel $dir.$name;


    move_uploaded_file  $tempname  $ziel );

    $content .= "Upload erfolgreich";

    }

    echo 
    $content;
    ?>

    Und das wars. Ich hoffe es war verständlich.

    Ich habe eine Testseite angelegt in der man das System mal ausprobieren kann : http://t-bone.lima-city.de

    Erlaubt sind 7 Bilder gleichzeitig. Der Uploadstatus wird angezeigt und nach
    dem Upload werden einem Links angezeigt die aber nicht funktionieren

    Schreib mir wenn du ein Problem hast mit dem Script.
    Ich versuche zu helfen

    Viel Spaß und Erfolg

    euer Hookah
    Aras_Foto bedankt sich. 


    Kommentare 9 Kommentare
    1. Avatar von Tribal
      Tribal -
      Hallo Hookah,

      leider funktioniert die Demo nicht bei mir (Win7 64x, FF 3.6.15) Er zeigt die Seite an, aber wenn man auf Bilder auswählen klickt passiert nichts. Mit IE 8 funktioniert es tadellos. Hast Du eine Idee woran es liegen könnte?

      mfg
      Tribal
    1. Avatar von Tribal
      Tribal -
      Muss mich korrigieren: Bei IE zeigt er zwar die Dateiliste an, aber er lädt nichts hoch...
    1. Avatar von SE
      SE -
      im gegensatz zum FF der alle fehler schluckt und es passiert nichts meldet der IE brav die fehler *ist auch der grund warum ich IE user bin und den FF verachte*

      DEINE SEITE IST KAPUTT !

      ruf sie einfach mal mittem IE auf und kugg dir die fehler an ... es liegen fehler im script vor ... bitte um korrektur

      *ps : SÄMTLICHE AJAX-komponenten sind funktionsunfähig*
    1. Avatar von Entwicklerpages
      Entwicklerpages -
      Die Fehlermeldungen im IE liegen daran, das der IE mit dem XMLHttpRequest so nicht klar kommt.
      Der IE benötigt ein ActiveX Objekt. Man könnte den Script so verbessern:
      Code :
      1
      2
      3
      4
      5
      6
      7
      8
      
      if (XMLHttpRequest())
      {
           //Nicht IE
           xhr = new XMLHttpRequest();
      } else {
           // IE
          xhr = new ActiveXObject("Microsoft.XMLHTTP");
      }
    1. Avatar von paddy89
      paddy89 -
      bekomme ich beim ausführen die Meldung das das FormData Objekt nicht definiert ist. Kann mir da einer helfen?
    1. Avatar von JSCoder
      JSCoder -
      Ihr seid ja Experten. O_O
      Das Problem sind nicht Fehler im Skript sondern der IE. FormData ist eine JavaScript-Erweiterung die es dort einfach noch nicht gibt. Hier nachzulesen: http://alfonsoml.blogspot.com/2010/0...available.html
      Auch der FileReader existiert dort nicht. Vermutlich erst ab Version 10: https://developer.mozilla.org/en/DOM/FileReader (ganz unten)

      Der "Tipp" von Entwicklerpages ist auch unsinnig. Dieses Handling mit ActiveXObject war damals bei IE6 notwendig. Seit IE7 kann dort auch XMLHttpRequest verwendet werden. Heute muss wirklich niemand mehr IE6 supporten. Macht Google auch nicht mehr.

      Trotzdem danke für den Code!

      Gruß
    1. Avatar von sheel
      sheel -
      Zitat Zitat von JSCoder Beitrag anzeigen
      Ihr seid ja Experten. O_O
      Jetzt noch mehr ^^

      Keiner hier behauptet, die eigene Lösung wäre die Beste;
      dazulernen kann man immer.

      Also Danke für die Hinweise!

      PS:
      Zitat Zitat von JSCoder Beitrag anzeigen
      IE6 supporten. Macht Google auch nicht mehr.
      Da muss ich widersprechen.
      Die IE6-Version ist zwar nicht identisch mit der Normalen,
      aber gerade deswegen: Es gibt eine eigene IE6-Version...
    1. Avatar von JSCoder
      JSCoder -
      Versteh mich bitte nicht falsch, mit Experten meinte ich eigentlich nur SE und Entwicklerpages, da diese recht unnütze Kommentare erstellt haben. Der bereitgestellte Beispielcode ist absolut in Ordnung. Gut, er funktioniert nicht im IE und Opera. Wenn man eine cross-browser Lösung haben möchte muss man wohl immernoch auf die IFrame-Methode zurückgreifen oder sich einer JavaScript-Bibliothek (Dojo, jQuery,...) bedienen. Aber diese verwenden beim IE auch blos die IFrame-Methode.

      Zum IE6: Ich verstehe wirklich nicht warum man diesen noch unterstützen sollte.
      Wie gesagt macht dies Google auch nicht mehr: http://www.golem.de/1001/72765.html
      Und selbst Microsoft rät davon ab: http://www.golem.de/1103/81923.html

      Gruß
    1. Avatar von voteron
      voteron -
      Ajax File Uploads und Multi-Uploads gehen nun auch ganz ohne Plugin oder Iframe Hack - nämlich mit HTML und XHR2 und dadurch mit gaaanz wenigen Zeilen Code.

      Hab gestern einen Artikel inkl. Code-Snippet gefunden: http://www.solife.cc/blog/ajax-file-...data-xhr2.html

      Wer keinen Support für IE < 10 braucht, für den wird das sicher nützlich sein

      Liebe Grüße,
      voteron
    Kommentare Kommentar schreiben

    Klicke hier, um dich anzumelden

    Wie heißt die Bundeskanzlerin der BRD mit Nachnamen? Angela...