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:
total– Teljes átvitt adatmennyiségloaded-Eddig feltöltött adatmennyiséglengthComputable– 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.
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:
http://www.w3.org/TR/XMLHttpRequest/ http://www.w3.org/TR/FileAPI/ http://www.matlus.com/html5-file-upload-with-progress/

