Zoltan Hosszu

Ajax-szerű fájlfeltöltés PHP-val

Posted on May 12, 2009 by Zoltan - 8 Comments

Ma elég huzamos ideig törtem a fejem és bújtam a fórumokat mire sikerült találnom egy olyan megoldást, amivel fel tudok tölteni egy fájlt anélkül, hogy frissülne az oldal. Hogy ez miért is kellett? A Kajdócsi Építész Stúdió adminisztrációs felületén dolgoztam és – bár később szántam-bántam, de – azt találtam ki, hogy amikor egy bizonyos bejegyzést – esetünkben munkát – szerkeszt az ember, lehessen “on-the-go” fájlokat feltölteni. Nem akarjuk ugyanis egy külön elküldött form miatt az összes módosítást elveszteni, ugye?

Szóval nekiálltam, hogy akkor megtanulom a jQuery Ajax metódusait, de szerencsére ráakadtam egy nagyon hasznos kis kerülőre. Ezt fogom most megosztani veletek.

Az első és legfontosabb dolog, hogy megértsük a <form> működését. A form – magyarul űrlap – egy olyan HTML tag, amivel egyszerű kitölthető mezőket tolhatunk a felhasználó arcába, ezzel rákényszerítve, hogy regisztrációkor megadja nekünk a haja színét és a kedvenc parfümének illatát. Ezek közé a mezők közé tartozik a fájl mező is. Az űrlap működése nagyon egyszerű, beillesztésekor megadjuk, hogy milyen módon (method), és hova (action) küldje az információkat, amiket a mezőkben megadtak a felhasználók.

A milyen módon rész POST vagy GET lehet, attól függően, hogy mennyire titkosan akarjuk küldeni az infokat. Elég másként lehet feldolgozni az adatokat, a GET ugyanis a címsorban küldi az adatokat (pl regisztracio.php?felhasznalo=jozsi&jelszo=123456), míg a POST titkosan küldi tovább, de ezért ha használni akarunk egy-két adatot további oldalakhoz, akkor azokat tovább kell vinni valahogy (PHP-nál nagyjából úgy mint ahogy a GET metódus teszi).

Az űrlap hova része a feldolgozó fájl (esetünkben egy PHP lesz), ami kezeli a megkapott adatokat és tárolja vagy továbbküldi.

A formokban betöltött fájlokkal az a baki összesen, hogy azokat PHP-ban nem $_POST és nem is $_GET, hanem $_FILES előtaggal kell feldolgoznunk, hogy jussunk valahova. Ahhoz, hogy megkapjuk a kiválasztott fájlokat, az űrlapnak meg kell adnunk még egy attribútumot, ez pedig az enctype. Az enctype igazából az elküldött adatok titkosításának módja (nem ugyanaz mint a POST/GET), a fájlok feltöltéséhez szükséges értéke pedig enctype=”multipart/form-data”.

Nézzük is akkor hogy mire lesz szükségünk. Lesz egy form, ahol kiválasztjuk a fájlt; lesz egy PHP ami feldolgozza a fájlt; és egy JavaScript ami a vizualizációért felelős. Az űrlap nem lesz túl bonyolult, lássuk csak:

  <form action="upload.php" method="post" enctype="multipart/form-data" target="upload_target" >
    Fájl: <input name="myfile" type="file" />
    <input type="submit" name="submitBtn" value="Upload" />
  </form>

Igazából néhány extra mezőre szükségünk lesz, hogy a JS is jól működjön:

<body>
  <p id="f1_upload_process">Feltöltés folyamatban...</p>
  <p id="result"></p>
  <form action="upload.php" method="post" enctype="multipart/form-data" target="upload_target" onsubmit="startUpload();" >
    Fájl: <input name="myfile" type="file" />
    <input type="submit" name="submitBtn" value="Feltöltés" />
  </form>
  <iframe id="upload_target" name="upload_target" src="#" style="width:0px; height:0px; border:0px;"></iframe>
</body>

Mint látjátok bekerült két <p> bekezdés és egy <iframe> belső frame, de ez utóbbi el van rejtve (width: 0px, height: 0px;). A keretre azért van szükségünk, mert ha megnézitek, az űrlapunk megkapta target attribútumnak az <iframe> nevét; magyarán oda fog betöltődni az action=”upload.php”. Ezzel le is lőttem a legnagyobb poént, amivel a fájlfeltöltés AJAX-szerűvé válik.  Egy finom kis CSS-t ráhúzunk az oldalra:

#f1_upload_process{
  z-index: 100;
  position: absolute;
  visibility: hidden;
}

Ezzel biztosítottuk, hogy a #f1_upload_process egyelőre láthatatlan legyen, mert majd a JavaScript teszi láthatóvá, a fájlfeltöltés elindításakor. Sok szó esett már a JavaScript részről, nézzük is meg, hogy mit tud. Egyelőre csak a startUpload() függvényt hívtuk meg az űrlap elküldésével. Ez a függvény igazából csak annyit tesz, hogy a már említett #f1_upload_process részt megmutatja nekünk és engedélyezi a form elküldését:

function startUpload(){
  document.getElementById('f1_upload_process').style.visibility = 'visible';
  return true;
}

A hangsúly nem is ezen a függvényen van, hanem a stopUpload()-on, ami a feltöltés eredményét fogja nekünk kiírni. Ezt a függvényt a PHP fájlból fogjuk meghívni majd.

function stopUpload(success) {
  if (success == 1){
    document.getElementById('result').innerHTML = '<span class="msg">Sikeres volt a fájlfeltöltés!</span>>';
  } else {
    document.getElementById('result').innerHTML = '<span class="emsg">Hiba történt a feltöltés során!</span>';
  }
  document.getElementById('f1_upload_process').style.visibility = 'hidden';
  return true;
}

A függvényt egy success paraméterrel együtt hívhatjuk meg, ami az eredménynek megfelelő üzenetet dob ki a <p id=”result”> bekezdésünkbe. A vizualizációval meg is volnánk, nézzük meg, hogy mi is történik a háttérben. A PHP az űrlapból megkapott fájlt egyszerűen felmásolja a gyökérkönyvtárjába, majd 1 másodperces pihenő után (hogy a nagyon kicsi fájloknál is látszódjon, hogy történik valami :P ) meghívja a stopUpload() JS függvényt.

<?php
  $destination_path = getcwd().DIRECTORY_SEPARATOR;
  $result = 0;
  $target_path = $destination_path . basename( $_FILES['myfile']['name']);
  if(move_uploaded_file($_FILES['myfile']['tmp_name'], $target_path)) {
    $result = 1;
  }
  sleep(1);

  echo('<script language="javascript" type="text/javascript">
    window.top.window.stopUpload(' . $result . ');
  </script> ');

?>

Ezzel tulajdonképpen meg is volnánk. A dolog működik szépen, én is használom, használjátok ti is egészséggel! Ha bármilyen kérdés vagy észrevétel van, jöhet fórumba!

Forrás: ajaxf1.com

Comments

Atesz [cshu: senZ]
January 9, 2010 12:53 am Reply

Hmm nagyon tetszik! Ezt ki fogom próbálni, pont szükségem volt egy ilyen szkripre::))

Anonymus
January 6, 2011 10:49 pm Reply

Nagyon hasznos és jó cikk. Gratulálok. :-)

Gézu
February 10, 2011 10:47 pm Reply

Így minden file típus feltölthető a serverre. Hogyan lehetne azt beállítani, hogy csak zip vagy rar file-oket lehessen feltölteni, semmilyen más típust ne (főleg ne php-t vagy exe-t)?

    Zoltan
    February 10, 2011 10:56 pm Reply

    A php fájlban be kell tenni egy ellenőrzés, hogy csak abban az esetben másolja a fájlt, ha az bizonyos típusú. Ezt teheted többféleképpen is.
    - Ellenőrzöd a fájl kiterjesztését (utolsó pont után lévő betűk ellenőrzése a fájlnévben).
    - Ellenőrzöd a “$_FILES["uploaded_file"]["type"]“-ban megadott MIME típust. Ezt a böngésző küldi a feltöltőnek, tehát nem lehet mondjuk exe fájlt jpg kiterjesztéssel feltölteni, ha jól tudom. Nézz utána ezeknek a típusoknak, mert nem minden van, de ez egyszerű és biztonságos.

Rob
March 21, 2011 10:07 pm Reply

Szia Zoli,

tényleg frankó ez a cucc, de ki szeretném bővíteni egy aprósággal. Hogyan tudnám úgy módosítani, hogy maxfilesize-zal checkolja a méretét? php-ban működik, de ez az ajaxos téma nekem kicsit új…

Köszi a helpet!

    Zoltan
    March 23, 2011 9:52 pm Reply

    A legjobb szerintem az lehet, hogy a PHP fájlba beleraksz egy feltételt, hogy ha a küldött fájl nagyobb mint a maxfilesize, akkor mondjuk resultnak 2-t ír ki, ezt a 2-t pedig a javascriptben lekezeled, és visszaadsz egy hibaüzenetet, hogy nagy a fájl, kb így:

    PHP
    [...]
    $limitsize = 50000; //50000 kilobyte fájlméret
    if ($_FILES['myfile']['size'] > $limitsize) {
    if (move_uploaded_file($_FILES['myfile']['tmp_name'], $target_path)) {
    $result = 1;
    }
    } else $result = 2;
    [...]

    JS:
    [...]
    if (success == 1){
    document.getElementById(‘result’).innerHTML = ‘Sikeres volt a fájlfeltöltés!>’;
    } else if (success == 2) {
    document.getElementById(‘result’).innerHTML = ‘Túl nagy a fájl!‘;
    } else {
    document.getElementById(‘result’).innerHTML = ‘Hiba történt a feltöltés során!‘;
    }
    [...]

    Szerintem ennek így működnie kéne, gyors ránézésre, de ne vedd biztosra. Hajrá :)

b3nk3
February 1, 2012 5:37 pm Reply

Szia Zoli, nekem egy olyan kérdésem van, hogy arra van-e lehetőség, hogy egy inputba bekérek egy nevet, majd ezt a nevet felhasználva a létrehozzon egy mappát( ahol kisbetűsre alakít és az ékezetes karaktereket eldobja)

    Zoltan
    February 1, 2012 10:38 pm Reply

    Persze van rá lehetőség! Annyit kell tenned, hogy a formba beteszel egy input mezőt, amiben bekéred a mappa nevet, majd az upload.php-ban elvégzed ennek az átalakítását (kisbetűsítés, speciális karakterek átalakítása) és ellenőrzését (van-e már ilyen mappa, ha nincs létre kell hozni).

    Mivel a php minden form mezőt megkap POST elemként, ezért nem nehéz lekezelni ezeket a dolgokat.

    A mappanév átalakításra szerintem keress valamilyen egyszerű scriptet, ami ilyenre alkalmas, biztos van belőle neten pár :)

Leave a Reply

Your email address will not be published. Required fields are marked *

Name *:
E-mail address *:
Website:
Message:
You may use these: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>