HTML5 fájlfeltöltés az XMLHttpRequest segítségével

UPDATED! – Frissítve, grafikus progress bar

Nem új a téma, hiszem az XMLHttpRequest (XHR) nem számít új technikának, mégis úgy gondoltam nézzük meg, miként lehet a HTML5-el házasítani. Az XMLHttpRequest nem más, mint egy API, ami böngészőkön belül elérhető olyan interpreteres nyelvben, mint például a JavaScript. Arra használható, hogy HTTP vagy HTTPS protokollon keresztül direkt küldjünk kéréseket a webszervernek, aztán annak a válaszát közvetlenül visszakapjuk például a kérő szkriptben. A visszakapott adatot közvetlenül használhatjuk arra, hogy a böngészőben az aktív weboldal tartalmát módosítsuk, az oldal újratöltése nélkül. Az XMLHttpRequestnek nagyon fontos szerepe van az Ajax webfejlesztési technikákban.

A példában egy egyszerű fájlfeltöltést mutatok be nektek, amelyben használjuk a HTML5 lehetőségeit és a szerver oldalon egy kis php scriptet is. Amit megvalósítunk:

  • fájl feltöltése (egy későbbi cikkben megmutatom a többszörös fájlfeltöltést is)
  • fájlnév, méret és típus kiírása
  • progress bar
  • fájlméret limitálás
  • event kezelés

Nézzük elsőként a HTML5 progress event működését, milyen adatokat szolgáltat a számunkra:

  1. total – Teljes átvitt adatmennyiség
  2. loaded -Eddig feltöltött adatmennyiség
  3. lengthComputable – Ha a fenti két adat elérhető, akkor számítható az értéke. (ez kell nekünk a progress bar-hoz)



A html rész:

<body>
 <form id="form" enctype="multipart/form-data" method="post" action="Upload.php">
 <div class="row">
 <label for="fileToUpload">Válassz egy fájlt a feltöltéshez (Max: 2Mb)</label><br />
 <input type="file" name="fileToUpload" id="fileToUpload" onchange="fileSelected();"/>
 </div>
 <div id="fileName"></div>
 <div id="fileSize"></div>
 <div id="fileType"></div>
 <div class="row">
 <input type="button" onclick="uploadFile()" value="Feltölt" />
 </div>
 <div id="progressNumber"></div>
 </form>
</body>

A kód minimalista, sok újdonságot nem tartalmaz. Létrehozunk egy form-ot, aminek az enctype-ja multipart/form-data és a metódusa post. Készítünk egy beviteli mezőt a fájlkiválasztásához, ahol meghívjuk a fileSelected() függvényünket. Elkészítjük a fájlnév, méret és típus diveket, ahova majd az adatokat kiírjuk. Végül készítünk egy gombot a feltöltésnek és legalulra pedig betesszük az aktuális feltöltés százalékértékének helyet adó div-et.

Ez eddig nem vészes, de nézzük a javascript részt:

<script type="text/javascript">
 var mbMaxFilesize=2097152;

 function fileSelected() {
 /* A fájl kiválasztása után, megnézzük a nevét, kiszámítjuk a méretét és kiírjuk a típusát */
 var file = document.getElementById('fileToUpload').files[0];
 if (file) {
 var fileSize = 0;
 if (file.size > 1024 * 1024)
 fileSize = (Math.round(file.size * 100 / (1024 * 1024)) / 100).toString() + 'MB';
 else
 fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + 'KB';

 document.getElementById('fileName').innerHTML = 'Név: ' + file.name;
 document.getElementById('fileSize').innerHTML = 'Méret: ' + fileSize;
 document.getElementById('fileType').innerHTML = 'Típus: ' + file.type;
 }
 /* Megvizsgáljuk, hogy nem haladja-e meg a limitünket, az aktuálisan kiválasztott fájl mérete */
 if (file.size > mbMaxFilesize) {
 alert("Túl nagy a fájl, válassz kisebbet Max:2 Mb");
 xhr.addEventListener("abort", uploadCanceled, false);
 return false;
 }
 }

function uploadFile() {
 /* Maga az XMLHttpRequest indítása. A fájl kiválasztása esetén itt indítjuk meg a küldést, illetve az eventeket/figyelésüket
 majd meghívjuk az upload.php szerver oldali fájlunkat */
 var fd = new FormData();
 fd.append("fileToUpload", document.getElementById('fileToUpload').files[0]);
 var xhr = new XMLHttpRequest();
 xhr.upload.addEventListener("progress", uploadProgress, false);
 xhr.addEventListener("load", uploadComplete, false);
 xhr.addEventListener("error", uploadFailed, false);
 xhr.addEventListener("abort", uploadCanceled, false);
 xhr.open("POST", "upload.php");
 xhr.send(fd);
 }
 function uploadProgress(evt) {
 /* A fájlművelet aktuális százalékértékének kiszámítása */
 if (evt.lengthComputable) {
 var percentComplete = Math.round(evt.loaded * 100 / evt.total);
 document.getElementById('progressNumber').innerHTML = percentComplete.toString() + '%';
 }
 else {
 document.getElementById('progressNumber').innerHTML = 'nem kiszámithato';
 }
 }
 function uploadComplete(evt) {
 /* A szerver oldali válasz esetén indul */
 document.getElementById('progressNumber').innerHTML = '100' + '%';
 alert(evt.target.responseText);
 }
 function uploadFailed(evt) {
 /* Hiba esetén jelezzen vissza */
 alert("Hiba, a feltöltés sikertelen");
 }
 function uploadCanceled(evt) {
 /* Megszakítás esetén is jelezzen */
 alert("A feltöltést a böngészö megszakitotta");
 }
 </script>

Huu, ez brutális, de csak elsőre. Figyeljétek a szépen elnevezett függvény és változóneveket. Kétszeri olvasás után már értelmezhető azoknak is akik most ismerkednek a módszerrel. Elolvastad kétszer, de még mindig nem egyértelmű? Nézzük függvényenként:

function fileSelected()

Itt használjuk a HTML5 file api képességeit. Konkrétan a filelist objektumban rejlő lehetőségeket. A bele kerülő fájlok méretéről, típusáról és nevéről tartalmaz információkat, amelyeket könnyedén kinyerhetünk (document.getElementById(‘fileName’).innerHTML = ‘Név: ‘ + file.name;). A filesize rész arra szolgál, hogy a fájl méretét, az általunk ismert méretmegadási módba konvertálja át, hiszen alapesetben bájtokban tárolja. Itt megnézzük, hogy a fájl mérete nem haladja e meg a 2 megabyte-ot, amit beállítottam limitnek.

function uploadFile()

Az XMLHttpRequest magja ide kerül, itt történik meg a csoda, majd a postolás a szerver oldali feldolgozó egység felé. Hogy milyen csoda? A form-data csoda.

var fd = new FormData();

fd.append(“fileToUpload”, document.getElementById(‘fileToUpload’).files[0]);

Végre nem kell manuálisan átadnunk a feldolgozó egység felé az adatokat, hanem képes a formunkból kinyerni azokat. A form-data értéke lehet egy szám, egy string vagy akár egy fájl is, mint esetünkben. Utána következnek a szabvány eseményfigyelés indítások valamint a post metódus indítása. Számunkra ez a rész lesz még érdekes.

xhr.upload.addEventListener(“progress”, uploadProgress, false);

Itt hívjuk meg az uploadprogress eventünket, ami a feltöltés aktuális százalékát fogja kiírni. Bővebben az xmlhttprequest-ről itt találsz leírást. Valamint a feltöltés részt itt találod.


function uploadProgress(evt)

Itt íratjuk ki az aktuális százalék értéket, ahol a feltöltésünk jár. Ha megnézitek használjuk a már említett lengthComputable-t.

function uploadComplete(evt)

A feltöltése végeztével kapjuk vissza a szerver oldalról a jelzést, hogy minden rendben. Én itt elkövettem egy csalást, mert itt átállítom a progress %-ot 100-ra, hiszen ha a feltöltés hiba nélkül végzett, akkor a teljes fájl feltöltésre került.

function uploadFailed(evt) és a function uploadCanceled(evt)

Hiba esetén jelez vissza a számunkra, hogy valami nincs rendben.

Ezzel meg is van a komplett kódunk, ami nálam így néz ki:

<!DOCTYPE html>
<html>
<head>
 <title>Fájl feltöltés az XMLHttpRequest segítségével</title>

<script type="text/javascript">
 var mbMaxFilesize=2097152;

 function fileSelected() {
 /* A fajl kiválasztása után, megnézzük a nevét, kiszámítjuk a méretét és kiírjuk a típusát */
 var file = document.getElementById('fileToUpload').files[0];
 if (file) {
 var fileSize = 0;
 if (file.size > 1024 * 1024)
 fileSize = (Math.round(file.size * 100 / (1024 * 1024)) / 100).toString() + 'MB';
 else
 fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + 'KB';

 document.getElementById('fileName').innerHTML = 'Név: ' + file.name;
 document.getElementById('fileSize').innerHTML = 'Méret: ' + fileSize;
 document.getElementById('fileType').innerHTML = 'Típus: ' + file.type;
 }
 /* Megvizsgáljuk, hogy nem haladja-e meg a limitünket, az aktuálisan kiválasztott fájl mérete */
 if (file.size > mbMaxFilesize) {
 alert("Túl nagy a fájl, válassz kisebbet Max:2 Mb");
 xhr.addEventListener("abort", uploadCanceled, false);
 return false;
 }
 }

function uploadFile() {
 /* Maga az XMLHttpRequest indítása. A fajl kivalasztasa esetén itt indítjuk meg a küldést, illetve az eventeket/figyelésüket
 majd meghívjuk az upload.php szerver oldali fájlunkat */
 var fd = new FormData();
 fd.append("fileToUpload", document.getElementById('fileToUpload').files[0]);
 var xhr = new XMLHttpRequest();
 xhr.upload.addEventListener("progress", uploadProgress, false);
 xhr.addEventListener("load", uploadComplete, false);
 xhr.addEventListener("error", uploadFailed, false);
 xhr.addEventListener("abort", uploadCanceled, false);
 xhr.open("POST", "upload.php");
 xhr.send(fd);
 }
 function uploadProgress(evt) {
 /* A fájlművelet aktuális százalékértékének kiszámítása */
 if (evt.lengthComputable) {
 var percentComplete = Math.round(evt.loaded * 100 / evt.total);
 document.getElementById('progressNumber').innerHTML = percentComplete.toString() + '%';
 }
 else {
 document.getElementById('progressNumber').innerHTML = 'nem kiszámithato';
 }
 }
 function uploadComplete(evt) {
 /* A szerver oldali válasz esetén indul */
 document.getElementById('progressNumber').innerHTML = '100' + '%';
 alert(evt.target.responseText);
 }
 function uploadFailed(evt) {
 /* Hiba esetén jelezzen vissza */
 alert("Hiba, a feltöltés sikertelen");
 }
 function uploadCanceled(evt) {
 /* Megszakítás esetén is jelezzen */
 alert("A feltöltést a böngészö megszakitotta");
 }
 </script>
</head>

<body>
 <form id="form" enctype="multipart/form-data" method="post" action="Upload.php">
 <div class="row">
 <label for="fileToUpload">Válassz egy fájlt a feltöltéshez (Max: 2Mb)</label><br />
 <input type="file" name="fileToUpload" id="fileToUpload" onchange="fileSelected();"/>
 </div>
 <div id="fileName"></div>
 <div id="fileSize"></div>
 <div id="fileType"></div>
 <div class="row">
 <input type="button" onclick="uploadFile()" value="Feltölt" />
 </div>
 <div id="progressNumber"></div>
 </form>
</body>
</html>

Most lássuk a php scriptünket, amire még szükség lesz, hogy a feltöltés működjön.

<?php

$target_path = "uploads/";
$target_path = $target_path . basename( $_FILES['fileToUpload']['name']);
$maxsize = 2097152;

if(($_FILES['fileToUpload']['size'] >= $maxsize) || ($_FILES["fileToUpload"]["size"] == 0)) {
 echo "Túl nagy a fájl, válassz kisebbet Max:2 Mb";
 die();
}else{

if(move_uploaded_file($_FILES['fileToUpload']['tmp_name'], $target_path)) {
 echo "A file ". basename( $_FILES['fileToUpload']['name']).
 " sikeresen feltöltve";
 }

}

A HTML5 file upload with XMLHttpRequest példát itt tudjátok kipróbálni.

A két demó fájlt innen le tudjátok tölteni.

UPDATE !

Grafikus progress bar

Többen jeleztétek, hogy grafikusan is jelenítsük meg, hogy hol is tart a feltöltés, ezért egy nagyon egyszerű módszert mutatnék arra, hogyan tudjuk megjeleníteni az aktuális állapotát a feltöltésünknek. A meglévő kódot egészítjük ki. A HTML5 résznél a következő módosításra lesz szükségünk: Létrehozunk egy progress div-et, abba beletesszük a progressNumber-t és készítünk egy progressValue div-et is. Az egyik a grafikus kijelzésnek, a másik a %-os értéknek. A kód nálam így néz ki:


<body>

<form id="form" enctype="multipart/form-data" method="post" action="Upload.php">

<div class="row">

<label for="fileToUpload">Válassz egy fájlt a feltöltéshez (Max: 2Mb)</label><br />

<input type="file" name="fileToUpload" id="fileToUpload" onchange="fileSelected();"/>

</div>

<div id="fileName"></div>

<div id="fileSize"></div>

<div id="fileType"></div>

<div class="row">

<input type="button" onclick="uploadFile()" value="Feltölt" />

</div>

<div id="progress" style="display: block;width: 200px;padding: 1px 5px;margin: 1px 0;border: 1px inset #446;border-radius: 4px;">
 <div id="progressNumber" style="height:5px;background: lime;"></div>
 <div id="progressValue" Style="text-align: center;"></div>
</div>
 </form>

</body>

Ezután lássuk, hogy a függvényeinket hogyan kell módosítanunk:


function uploadProgress(evt) {

/* A fájlművelet aktuális százalékértékének kiszámítása */

if (evt.lengthComputable) {

var percentComplete = Math.round(evt.loaded * 100 / evt.total);
 document.getElementById('progressNumber').style.width = percentComplete + '%'; /*grafikus kijelzésnek*/
 document.getElementById('progressValue').innerHTML = percentComplete.toString() + '%'; /*érték kijelzésének*/
 }

else {

document.getElementById('progressNumber').innerHTML = 'nem kiszámithato';

}

 


function uploadComplete(evt) {

/* A szerver oldali válasz esetén indul */
 document.getElementById('progressNumber').style.width = 100 + '%'; /*grafikus kijelzésnek*/
 document.getElementById('progressValue').innerHTML = '100' + '%'; /*érték kijelzésének*/
 alert(evt.target.responseText);

}

A példát itt tudod megtekinteni.

Forrás:

Creative Commons Licenc
HTML5 fájlfeltöltés az XMLHttpRequest segítségével a Creative Commons Nevezd meg! – Ne add el! – Így add tovább! 2.5 Magyarország Licenc alatt van.
  Permissions beyond the scope of this license may be available at https://html5.ugyesen.com.

You may also like...