Fájlfeltöltés
Most, hogy a szerveren található fájlokkal és könyvtárakkal kényünk-kedvünk szerint tudunk szórakozni, ideje megnézni, hogyan tudunk fájlokat fogadni a weboldalunk felhasználójától. Ezekkel a fájlokkal a feltöltése után természetesen mindegyik műveletet elvégezhetjük, amit az előző két leckében tanultunk.
Fájlfeltöltő űrlap
A fájlfeltöltő űrlapelem, amit az Űrlapok 1. leckében már láthattunk, az alábbi:
<input type="file" name="azonosito" />
Az elem egy szöveges mező vagy szöveg, mellette egy gombbal, a gombra kattintva megnyílik az operációs rendszer által szolgáltatott tallózó ablak, amiben a látogató kiválaszthatja, melyik fájlt akarja feltölteni. Kiválasztás után a fájl teljes elérési útja beíródik a mezőbe, és ez lesz a value attribútum értéke.
A value attribútumot biztonsági okokból mi nem tudjuk előre megadni (mivel így fájlokat lopkodhatnánk a felhasználó gépéről). A name attribútum az eddigiekhez hasonlóan a feldolgozó kódban azonosítja a fájlt.
Egy űrlapelemmel csak egy fájl tölthető fel, tehát ha többet akarunk a felhasználóval feltöltetni, több űrlapelemet kell kiraknunk, különböző name attribútumokkal. Ahhoz, hogy a fájlfeltöltés működjön, a fájlfeltöltő elemet egy ilyen form-ba kell rakni:
<form method="post" action="upload.php" enctype="multipart/form-data"> <input type="file" name="kep" /> <input type="file" name="leiras" /> <input type="submit" name="submit" value="Feltöltés" /> </form>
Csak post metódussal lehet fájlt feltölteni, így a method attribútum értéke csak "post" lehet (nem lehet "get")! Ezenkívül meg kell adnunk az enctype paramétert is. Ez határozza meg az űrlapelemek által küldött adatok kódolását. Alapesetben minden karakterláncot az urlencode() függvénnyel megegyező módon kódol, a file mező tartalmát is, és a fájlfeltöltés nem fog működni. Az értékéül "multipart/form-data"-t kell megadnunk, akkor a fájl mező tartalmát nem fogja kódolni, csak a többit. Ha elfelejtjük megadni ezt az attribútumot, akkor valószínűleg szép hosszú perceket tölthetünk el hibakereséssel, ugyanis nem kapunk semmilyen hibaüzenetet, csak azt fogjuk valahol észrevenni, hogy hiába próbáltunk feltölteni fájlt, mégsem töltődött fel semmi.
Feltöltött fájl ellenőrzése és áthelyezése
A felhasználó bármilyen fájlt kiválaszthat a gépéről, és a fájl feltöltése az űrlap elküldésével történik meg. Amikor elküldjük az űrlapot, minden fájl mezőbe betallózott fájl a szerver egy ideiglenes fájlokat tároló könyvtárába kerül valamilyen generált névvel. A feldolgozó oldalon a $_POST tömb mellett egy $_FILES asszociatív tömb is létrejön, ami a feltöltött fájlok adatait tárolja.
Ez egy kétdimenziós tömb. A $_FILES tömb kulcsai a fájlfeltöltő mezők name paraméterei lesznek, az értékek pedig maguk is tömbök, amik a fájlok néhány adatát tárolják. A fenti űrlap esetében elküldés után egy ehhez hasonló $_FILES tömb lesz a feldolgozó oldalon:
Array(
[kep] => Array(
[name] => szép kép.jpg
[type] => image/jpeg
[tmp_name] => /tmp/phpcLpXz8
[error] => 0
[size] => 2703078
)
[leiras] => Array(
[name] => okosságok.pdf
[type] => application/pdf
[tmp_name] => /tmp/phpt6MUsc
[error] => 0
[size] => 100575
)
)
A $_FILES tömbben egy fájlhoz 5 adat tartozik, amik a következők:
name: a fájl eredeti neve (a felhasználó gépén ezzel a névvel rendelkezett)
type: a fájl típusa (ez az érték néha üres, így nem mindig használható a fájltípus vizsgálatához)
tmp_name: a fájl jelenlegi elérési útja a szerveren
error: hibakód (ha a feltöltés közben hiba történt, akkor egy 0-tól különböző érték szerepel benne)
size: a feltöltött fájl mérete bájtban.
A $_FILES["..."]["tmp_name"] (a ... helyén a feltöltő mező name attribútumának értéke szerepel) egy teljes elérési út, így az előző két leckében tanult műveleteket el tudjuk végezni vele.
A fájlfeltöltés szokásos menete a feldolgozó oldalon, hogy ellenőrizzük a fájlt a $_FILES tömb segítségével, majd ha megfelelő, áthelyezzük egy saját könyvtárba. A "tmp_name" egy ideiglenes hely, ezért át kell helyeznünk, mivel onnan bármikor törlődhet a fájl.
Az előző leckéhez képest annyi az újdonság, hogy a feltöltött fájl áthelyezésére nem a rename(), hanem a move_uploaded_file() függvényt kell használni. A nevüket leszámítva a két függvény működése teljesen megegyezik. Példa:
move_uploaded_file($_FILES["kep"]["tmp_name"], "kepek/upload/".$_FILES["kep"]["name"]);
Ez a sor a feltöltött fájlt az ideiglenes helyről áthalyezi a kepek/upload könyvtárba, és a fájl neve meg fog egyezni az eredeti nevével (ahogy a felhasználó számítógépén volt tárolva). Arra ügyelni kell, hogy a move_uploaded_file() képességei nagyjából a rename() függvénnyel egyeznek meg, így könyvtárat nem tud létrehozni, tehát ha nem vagyunk biztosak a létezésében, ellenőrizzük a helyet az is_dir()-rel, szükség esetén hozzuk létre az előző leckében tanult módszerekkel.
Ha a célfájl már létezik, akkor itt biztosan felül lesz írva, ha ezt nem akarjuk, akkor ezt is ellenőrizni kell, és más névvel kell feltölteni az új fájlt.
Mivel a fájl eredeti nevében ékezetes betűk és speciális karakterek is előfordulhatnak, vagy nekünk kell nevet adni a fájlnak, vagy írnunk kell egy függvényt, ami ezeket kiszedi a fájlnévből.
Ezt a függvényt "normális kinézetűre" megírni nem annyira egyszerű feladat. Segíthet például az str_replace() függvény (ld. Űrlapok 3. lecke). A függvény egy karakterlánc (3. paraméter) belsejében egy adott részláncot (1. paraméter), annak minden előfordulási helyén lecserél egy másikra (2. paraméter).
Az 1. és 2. paraméterben megadhatunk tömböt is. Ekkor a tömbök minden elemére lefut a függvény az alábbi módon:
$szoveg = "A disznó és a marha hülye állat. Főleg a disznó!";
$search = array("disznó", "marha", "hülye");
$replace = array("sertés", "borjú", "buta");
$szoveg = str_replace($search, $replace, $szoveg);
Ennek az eredménye az lesz, hogy a $szoveg karakterláncban lévő szavakat lecseréli valamivel szebbekre, ez kerül bele:
A sertés és a borjú buta állat. Főleg a sertés!
Vagyis a fenti str_replace() az alábbi hárommal egyenértékű:
$szoveg = str_replace("disznó", "sertés", $szoveg);
$szoveg = str_replace("marha", "borjú", $szoveg);
$szoveg = str_replace("hülye", "buta", $szoveg);
Ennek ismeretében megírhatjuk a függvényt például így:
function removeaccent($str){
$search = array("á", "é", "í", "ó", "ö", "ő", "ú", "ü", "ű", " ");
$replace = array("a", "e", "i", "o", "o", "o", "u", "u", "u", "_");
return str_replace($search, $replace, $str);
}
Ez se éppen egy szép megoldás, ráadásul az írásjelek közül csak a szóközt cseréli le, de példának megteszi. A "normális kinézetű" alatt azt értettem, hogy a függvényben nincs például egy hatalmas switch szerkezet.
Nézzünk a fájlfeltöltés feldolgozására egy teljes példát! A következő program ellenőrzi, hogy lett-e feltöltve fájl, majd a fájl kiterjesztése alapján, hogy a feltöltött fájl kép-e, és hogy a mérete nem haladja meg az 1 MB-ot, majd ha ezek teljesülnek, áthelyezi a végleges helyére.
Az űrlap:
<form method="post" action="upload.php" enctype="multipart/form-data"> <input type="file" name="kep" /> <input type="submit" name="submit" value="Feltöltés" /> </form>
A feldolgozó kód (upload.php):
$types = array("jpg", "jpeg", "gif", "png"); // engedélyezett kiterjesztések
$maxsize = 1048576; // maximális méret (1 MB)
$target = "kepek/upload"; // végleges hely
// feltöltés ellenőrzése
if ($_FILES["kep"]["name"] == ""){
print "Nem töltöttél fel képet!";
}
else{
$upload = true;
$name = removeaccent($_FILES["kep"]["name"]);
// kiterjesztés ellenőrzése
$ext = strtolower(array_pop(explode(".", $name)));
if (!in_array($ext, $types)){
print "Csak kép tölthető fel!";
$upload = false;
}
// méret ellenőrzése
if ($_FILES["kep"]["size"] > $maxsize){
print "Túl nagy a fájl mérete!";
$upload = false;
}
// áthelyezés
if ($upload){
move_uploaded_file($_FILES["kep"]["tmp_name"], $target."/".$name);
}
}
A program lényege, hogy ha a feltöltött fájl átment az ellenőrzéseken, akkor az $upload változó értéke true, így lefuttatjuk a move_uploaded_file() függvényt.
A kiterjesztés ellenőrzése technikai szempontból nem túl egyszerű, ott három olyan beépített függvényt is használtam, ami eddig nem volt a tanfolyamon. Ugyebár azt kell megvizsgálni, hogy a fájl kiterjesztése benne van-e az általunk megadott tömbben.
Egy fájl kiterjesztését úgy kapjuk a nevéből, hogy a . (pont) karakter mentén szétdaraboljuk, és a kapott tömb utolsó elemét vesszük. A kiterjesztés előfordulhat nagybetűs alakban is (pl. "JPG"), így a kapott kiterjesztést előbb kisbetűssé alakítjuk, majd utána vizsgájluk, hogy benne van-e a tömbben.
A fájlnévből a kisbetűssé alakított kiterjesztést a 12. sor állítja elő. Először a 10-es sorban leszedjük az ékezeteket a névről a fentebb megírt függvény segítségével, de ez a kiterjesztést nem módosítja, abban nem szokott ékezet lenni. Ezután az explode()-dal szétdaraboljuk a pontok mentén, ekkor kapunk egy tömböt.
Az array_pop() függvény a tömb utolsó elemét adja vissza, úgyhogy ezt ráengedjük a kapott tömbre. Ez tehát a fájl kiterjesztése, amit kisbetűssé alakítunk az strtolower() függvénnyel. Ezután a 13. sorban az in_array() függvény vizsgálja meg, hogy benne van-e a kiterjesztés ($ext) a $types tömbben.
Ha nincs benne, kiírjuk a hibaüzenetet. Ezután a méretet ellenőrizzük, ami a $_FILES tömbben van. Az ellenőrzések úgy működnek, hogy ha hibát találnak az eredetileg true értékre beállított $upload változót false-ra állítják, és a feltöltés előtt ezt a változót vizsgáljuk meg. Vagyis a program végigfut (ha van feltöltött fájl) és az összes hibát kiírja, majd a végén a változó értéke alapján dönti el, hogy feltölti-e a fájlt.
A kiterjesztés ellenőrzésénél használt új függvények részletesebben:
array_pop()
A függvény paramétere egy tömb, amiből eltávolítja az utolsó elemet, és visszaadja visszatérési értékként. A fenti példában lényegtelen volt, hogy a tömböt megváltoztatta, csak a visszatérési érték kellett. A tömb utolsó elemét persze így is megkaphatjuk:
$namearray = explode(".", $name);
$ext = $namearray[count($namearray) - 1];
Itt az $ext változóba a (nem feltétlenül kisbetűs) kiterjesztés kerül, mivel a tömb utolsó elemének indexe elemszám - 1.
strtolower()
A függvény paramétere egy karakterlánc, aminek visszaadja a kisbetűssé alakított változatát. A függvény az angol abc nagybetűit alakítja kisbetűkké, a többi karaktert (kisbetűk, ékezetes betűk, írásjelek) változatlanul hagyja. Mivel a kiterjesztésben csak az angol abc betűi lehetnek, így ez a függvény a fenti példában elegendő volt. A függvénynek egyébként az inverze az strtoupper(), ez ugyanúgy működik, csak nagybetűssé alakítja a karakterláncot.
in_array()
A függvénynek két paramétere van. Az első egy tetszőleges típusú változó, a második egy tömb. Ha az első paraméterként adott érték megtalálható a tömbben, true értéket ad vissza, különben false-t. A függvény az első paramétert a tömb értékei, és nem kulcsai között keresi! Arra vigyázni kell, hogy ha a második paraméter nem tömb, warning-ot dob, úgyhogy ha ebben nem vagyunk biztosak, hívás előtt ellenőrizzük a második paramétert az is_array() függvénnyel!
Ha ezt a kódot kipróbáljuk a localhost-on (tehát a wamp-on), akkor gyönyörűen töltögethetjük vele a fájlokat, feltéve ha nem felejtettél ki semmit, és nem próbálsz meg túl nagy fájlt feltölteni. Ugyanis a feltölthető fájl maximális mérete nem lehet akármekkora, ez az érték a wamp könyvtárán belül egy php.ini nevű fájlban van megadva. Ha rákeresünk, sima szövegszerkesztővel megnyithatjuk (amivel a php fájlokat is nyitogatjuk), és itt keressünk rá a "upload_max_filesize" karakterláncra. Én például egy ilyen részt találtam:
; Maximum allowed size for uploaded files. upload_max_filesize = 64M
Ez azt jelenti, hogy legfeljebb 64 MB-os fájlokat tudok feltölteni, függetlenül attól, hogy a $_FILES["..."]["size"] értékét ellenőrzöm-e vagy sem. Nálad lehet hogy nem ez az érték szerepel, ha nem tetszik amit a saját fájlodban látsz, írd át, ments, majd indítsd újra a wamp-ot.
Jogosultságok
És ha sikerült localhost-on működésre bírni, akkor ugyebár vigyorogva toljuk fel a netre a legújabb alkotásunkat, és szépen ki is próbáljuk, aztán ha nincs szerencsénk (ebben az esetben ez a valószínűbb), csak annyit láthatunk, hogy a fájlok még csak véletlenül se töltődnek fel, ráadásul hibaüzenetet sem kapunk. Ezt egy olyan dolog okozza, ami localhost-on nem jelentkezik, mivel it általában az van, hogy a gépen Windows fut, és rendszergazdaként vagyunk bejelentkezve, így nagyjából bármit megtehetünk, ahogy az általunk futtatott PHP kód is. A neten lévő szervereken viszont Linux fut, és nem is rendszergazdai jogosultságokkal fut a programunk, így szigorú feltételekhez van kötve, hogy a PHP kód miket tud csinálni a könyvtárakkal és fájlokkal. Például ha a könyvtárhoz nincs írási joga, akkor a feltöltött képet nem tudja belerakni. Azokra a könyvtárakra és fájlokra, amelyeket a PHP programmal változtatni szeretnénk, írási jogot kell adnunk. Ha az ftp klienssel (az a program, amivel feltöltjük az oldalt, pl. Total Commander, FileZilla, stb.) hozzuk létre a feltöltött fájloknak szolgáló könyvtárat, illetve azokat a könyvtárakat/fájlokat amiket módosítani szeretnénk, akkor minden felhasználónak olvasási és írási jogot kell adnunk. Magától a programtól függ, hogy ezt hogy lehet vele megcsinálni. Tudomásom szerint a Total Commander a legnépszerűbb, ebben úgy kell, hogy kijelölöd a könyvtárat, majd Fájl / Attribútumok módosítása. Ekkor bejön egy ilyen ablak:

Itt minden olvasás, írás és futtatás checkbox kipipálásával érhetjük el, hogy az adott könyvtárban a PHP-vel bármilyen műveletet el tudjunk végezni.
Amennyiben a PHP-vel hozunk létre egy könyvtárat az mkdir() függvénnyel, vagy egy fájlt a fopen()-nel, a jogokkal nem kell foglalkoznunk, mivel egy állomány alapból úgy jön létre, hogy a létrehozónak (tulajdonos) minden jogot megad.
Ezek után, ha a localhost-on működő kódot feltöltöd a netre és ott megadsz minden jogosultságot a megfelelő könyvtárakra (csak azokra, amiket a PHP kód piszkálni akar), a fájlfeltöltésnek működnie kell. Feltéve persze, ha a fájlfeltöltés engedélyezve van a szerveren. Sajnos van néhány ócskább ingyen tárhely, ahol nincs.
Képek kezelése
A fájlfeltöltő mezővel az esetek nagy részében képet kérünk a felhasználótól. Ezt a képet rendszerint azért kérjük, hogy aztán valahol a weboldalon meg is jelenítsük. Például egy fórum esetén a felhasználó feltölthet egy avatart, ami mondjuk minden hozzászólásánál megjelenik. A fenti eszközök segítségével csak a fájl bájtban vett méretét tudjuk korlátozni, itt viszont szükség lehet a szélesség illetve magasság korlátozására. Például ha nagyon elvetemült, akkor feltölt egy 1000x5 pixeles képet amivel alaposan szétnyomja a weboldalunkat. Nézzük meg, hogyan tudjuk egy kép méreteit lekérdezni!
getimagesize()
A függvény egy kép elérési útját várja paraméterként és visszaad egy tömböt, amiben a képről találhatók információk. A tömbnek 7 eleme van, ebből számunkra csak a 0 és 1 indexű elemek lényegesek, a 0-s a kép szélessége, az 1-es a magassága pixelben. A függvény jpg, gif és png képeket egyaránt támogat, de ezenkívül sokféle más formátumot is. Fájlfeltöltés előtt tehát végrehajthatunk egy ilyen ellenőrzést, miután megbizonyosodtunk arról, hogy a fájl egy kép:
$maxwidth = 200;
$maxheight = 150;
$data = getimagesize($_FILES["kep"]["tmp_name"]);
if ($data[0] > $maxwidth || $data[1] > $maxheight){
print "Túl nagy a kép mérete!";
$upload = false;
}
Így legfeljebb 200x150 pixeles képet tudnak feltölteni. Sokszor azonban nem elég egy felső korlát, előfordul, hogy egy konkrét méretű képet kell megjelenítenünk. Ekkor nem az a legjobb módszer, ha kiírjuk a felhasználónak hogy pl. pontosan 220x170 pixeles képet tölts fel, különben elhúzhatsz innen, mert lehet fogalma sincs hogyan kell átméretezni, és inkább az utóbbi opciót választja (főleg ha ilyen udvariasan közöljük vele a helyzetet).
Az se a legjobb ötlet, ha az <img src="..." width="220" height="170" /> formában adjuk meg a html-ben a képet, mert ilyenkor a képet nyújtja a böngésző, vagyis torzulni fog a kép, ha nem ilyen képarányú volt eredetileg.
Az átméretezést azonban mi magunk is meg tudjuk csinálni torzítás nélkül is, egy rakás képkezelő függvény áll rendelkezésünkre a PHP-ben. Most csak az átméretezéssel fogunk foglalkozni, mert ez a leggyakrabban előforduló probléma. Először megnézünk egy példát az átméretezésre, utána pedig a benne használt függvényeket vizsgáljuk meg közelebbről.
Az PHP képkezelő függvényei nem tartoznak a PHP szűkebb értelemben vett beépített függvényei közé, ami azt jelenti, hogy vagy elérhetőek, vagy nem. Az nem nagyon fordulhat elő, hogy például egy strlen() függvényhívásra egy nagy fatal error-t kapjunk, azzal a szöveggel, hogy nincs ilyen függvény, a képkezelő függvényeknél viszont ez megtörténhet. Ezek az úgynevezett GD programkönyvtár függvényei, ami a PHP egy kiterjesztése, és ha ez a programkönyvtár be van kapcsolva, akkor tudjuk használni ezeket.
A wamp újabb verzióiban ez alapból be van kapcsolva, a neten pedig a tárhelyszolgáltatótól függ a dolog. Annyit azért el lehet mondani, hogy ez a GD könyvtár manapság elég alapvető dolognak számít, így ha nincs bekapcsolva és nem is lehet a tárhelyszolgáltató adminfelületén bekapcsolni, akkor az egy gagyi szolgáltató (sajnos ingyenes szolgáltatók közt sok a gagyi). Egyébként a getimagesize() nem tartozik a GD könyvtár függvényei közé, így az mindig elérhető.
Ha be van kapcsolva a GD, akkor az alábbi módon tudunk átméretezni egy JPG képet (méghozzá 220x170 pixelesre):
// fájl elérési útja $filename = $_FILES["kep"]["tmp_name"]; // eredeti kép méretei $data = getimagesize($filename); // új kép méretei $w = 220; $h = 170; // egy 220x170 pixeles üres kép létrehozása $newimage = imagecreatetruecolor($w, $h); // eredeti kép beolvasása $oldimage = imagecreatefromjpeg($filename); // eredeti kép rámásolása az újra, átméretezve imagecopyresampled($newimage, $oldimage, 0, 0, 0, 0, $w, $h, $data[0], $data[1]); // kép mentése imagejpeg($newimage, "images/upload/kep.jpg", 100);
A GD könyvtár függvényeinek használatához a képet a megfelelő függvényekkel be kell olvasnunk, majd elvégezhetjük a kívánt műveletet vele, végül elmentjük a változtatott képet. Hasonlóan készíthetünk egy képet külső kép használata nélkül, vagyis a függvényekkel létrehozunk egy üres képet, rajzolunk rá valamit, majd elmenthetjük.
imagecreatefromjpeg(), imagecreatefromgif(), imagecreatefrompng()
Ezekkel a függvényekkel tudunk egy képet beolvasni. Paraméterként a kép elérési útját kell megadnunk (ami egy karakterlánc), visszatérési értékük pedig egy resource (erőforrás, ld. Alapok 14. lecke) típusú változó, amit a képkezelő függvényeknek kell majd paraméterként átadnunk (hasonló a helyzet, mint a fopen() függvény esetében). Aszerint, hogy a kép jpg, gif vagy png típusú, a megfelelő függvényt kell használnunk a beolvasáshoz. Értelemszerűen, ha a kép például png típusú, akkor így kell beolvasni:
$image = imagecreatefrompng("images/kep.png");
A képkezelő függvényeknek az $image változót kell majd átadnunk, ez azonosítja a beolvasott képet.
imagecreatetruecolor()
Ezzel a függvénnyel egy új, üres képet hozhatunk létre, amire azután a GD könyvtár függvényeivel rajzolhatunk. Paraméterként meg kell adni a kép szélességét és magasságát pixelben, majd visszaadja a resource-t. Példa:
$image = imagecreatetruecolor(200, 150);
Az $image változó itt egy 200x150 pixeles fekete képet tartalmaz, amire ráengedhetjük minden művészi képességünket a manipuláló függvények segítségével.
imagejpeg(), imagegif(), imagepng()
Ezekkel a függvényekkel tudjuk az alkotásunkat elmenteni. Első paraméterként azt a resource-t kell nekik átadnunk, amit még a beolvasás során kaptunk, vagy amit az előző függvénnyel hoztunk létre, a második paraméter pedig a kép elérési útja, ahova menteni szeretnénk. Az elérési útban a kép nevét is meg kell adni, kiterjesztéssel együtt. Nyilván érdemes olyan kiterjesztést adni, amilyen formátumban mentjük. A formátumot a függvény neve határozza meg. Ha az eredeti kép jpg formátumú volt, attól még menthetjük gif vagy png formátumban is ezekkel a függvényekkel, ahogy akarjuk. Így egy kép átkonvertálására is használhatóak, pl.:
$image = imagecreatefromjpeg("images/kep.jpg");
imagepng($image, "images/kep.png");
@unlink("images/kep.jpg");
Ebben a példában az images/kep.jpg képet átkonvertáltuk png formátumúra, és ennek megfelelően .png kiterjesztéssel mentettük el, majd az eredeti jpg képet töröltük.
imagecopyresampled()
Jó sok függvény létezik, amivel a képet tudjuk manipulálni, most csak egyet nézünk meg, amivel az átméretezést el tudjuk végezni. Erre használható például a fenti példában is látható imagecopyresampled() függvény. A függvénynek jó sok, pontosan 10 paramétere van, melyek közül az első az a resource (vagyis kép), amire rá akarjuk helyezni az átméretezett képet (cél), a második pedig az átméretezendő kép (forrás). A többi paraméter arra szolgál, hogy a cél- és forrásképen megadjuk egy téglalap alakú terület koordinátáit, majd a függvény a forrásképről kimásolja ezt a részt és rárakja a célképre. A forráskép nem fog módosulni, mivel a függvény csak kimásolja a kijelölt területet. Az alábbi ábrán látható, hogy hogyan működik a függvény:

A bal oldalon a felső a forráskép, az alsó a célkép. Minkettőben a téglalapot a bal felső sarok x és y koordinátája valamint szélessége és magassága határozza meg, ez összesen 4 adat. Mivel két téglalap van, így jön ki a maradék 8 paraméter a függvényben. A paraméterek sorrendje a következő:
imagecopyresampled(cél, forrás, dst_x, dst_y, src_x, src_y, dst_w, dst_h, src_w, src_h)
Általános esetben tehát erre használható a függvény. A forrásképen kijelölt téglalap alakú területet rárakja a célképen kijelölt területre, a kimásolt képet szükség esetén akkora méretűre nyújtja, hogy illeszkedjen a célképen kijelölt téglalapba.
Egy feltöltött kép átméretezését legtöbbször úgy szokás elvégezni, hogy a képből a lehető legkevesebb rész hiányozzon. Tegyük fel, hogy fekvő képről van szó (vagyis a szélessége nagyobb mint a magassága). Ekkor az átméretezést úgy érdemes elvégezni, hogy az imagecreatetruecolor() függvénnyel létrehozunk egy olyan méretű képet, amekkorára át szeretnénk méretezni a forrásképet, majd ezen a célképen a kijelölt téglalap a teljes képet fogja beteríteni. Ha azt akarjuk, hogy a kép ne torzuljon, akkor egy célképpel megegyező méretarányú téglalapot kell kijelölni a forrásképen úgy, hogy az a lehető legnagyobb területet beterítse, valahogy így:

Ha a bal oldali forrásképet kell a jobb oldalon lévő képpel egyező nagyságúra átméretezni, azt az ábrán látható elven érdemes csinálni. Így a kép meg lesz vágva, de a mérete pont megfelelő lesz, anélkül, hogy torzulna. Állókép esetén nyilván ugyanígy lehet eljárni, csak akkor nem a két oldala, hanem a teteje és az alja lesz levágva. Ilyet pusztán HTML-lel nem lehet megcsinálni, nézzük PHP segítségével hogyan megy!
Tegyük fel, hogy a forráskép méretei $srcimage_w (szélesség) és $srcimage_h (magasság). A kép legyen fekvő. Ezt $dstimage_w x $dstimage_h nagyságúra szeretnénk vágni a fenti módszerrel úgy, hogy ne torzuljon, és a jobb- és baloldalából kivágott rész egyenlő széles legyen (vagyis a közepe legyen látható a célképen). Először hozzuk létre az üres célképet:
$dstimage = imagecreatetruecolor($dstimage_w, $dstimage_h);
A fenti képet tekinthetjük példának, annyi a dolgunk, hogy meghatározzuk a piros téglalap bal felső csúcsának koordinátáit, valamint a szélességét és magasságát. Ehhez beolvassuk az eredeti képet és adatait:
$data = getimagesize("kep.jpg");
$srcimage_w = $data[0];
$srcimage_h = $data[1];
$srcimage = imagecreatefromjpeg("kep.jpg");
A forrásképen lévő téglalap koordinátáit a feljebb lévő képeknél látható módon jelöljük az $scr_x és $src_y változókkal, a méretei $src_w és $src_h. A koordinátát a képkezelő függvények úgy értelmezik, hogy a kép bal felső sarka az origó (x=0;y=0) koordinátájú pont, az x-tengely a kép tetején fekszik és jobbra mutat, az y pedig a bal szélén, és lefelé mutat. Azért lefelé, mert így a kép minden koordinátája pozitív szám lesz.
A csigás kép alapján látható, hogy
$src_y = 0
Az is azonnal látszik, hogy
$src_h = $srcimage_h
vagyis a téglalap magassága megegyezik a forráskép magasságával. Ahhoz, hogy a kép ne torzuljon, a téglalap méretei között fenn kell állnia az alábbi összefüggésnek:
$src_w / $src_h = $dstimage_w / $dstimage_h
vagyis a téglalap méretaránya megegyezik a célkép méretarányával. Ebből az ismeretlen $src_w kifejezve:
$src_w = ($dstimage_w / $dstimage_h) * $src_h
Nincs még vége a matekórának, kell az x koordináta is! Ha a kép közepét akarjuk kivágni, ahogy a képen is látható, akkor az $src_x-re az alábbi összefüggésnek kell teljesülnie:
$src_x + $src_w + $src_x = $srcimage_w
Ez úgy jön ki, hogy a forráskép tetején (aminek hossza a forráskép szélessége) ott fekszik két oldalon az x koordináta hossza, köztük pedig a téglalap szélessége. Ebből az x koordináta:
$src_x = ($srcimage_w - $src_w) / 2
A célképen fekvő téglalap pedig a célkép körvonalával egyezik, tehát a fenti képeken bevezetett jelöléssel:
$dst_x = 0, $dst_y = 0, $dst_w = $dstimage_w, $dst_h = $dstimage_h
Ha állóképről van szó, akkor is ugyanezt a gondolatmenetet lehet végigvinni. Arról még gondoskodni kell, hogy a koordináták és méretek csak egész számok lehetnek (mivel ezek pixelben megadott értékek). Ahol a számítás során osztás szerepel, ott kerekíteni kell a kapott számot. Ezt a legegyszerűbben a round() függvénnyel tudjuk megtenni.
round()
A függvény egy lebegőpontos számot vár paraméterként és azt egész számmá kerekíti, ezt adja vissza visszatérési értékként. Az 5-öst felfelé kerekíti, tehát pl. 3.5 esetén 4 a visszatérési értéke.
Na megvan minden adat, összedobhatjuk a manipuláló függvény paraméterlistáját! Összerakva tehát a tejes program:
$data = getimagesize("kep.jpg");
$srcimage_w = $data[0];
$srcimage_h = $data[1];
$srcimage = imagecreatefromjpeg("kep.jpg");
$dstimage = imagecreatetruecolor($dstimage_w, $dstimage_h);
$src_y = 0;
$src_h = $srcimage_h;
$src_w = round(($dstimage_w / $dstimage_h) * $src_h);
$src_x = round(($srcimage_w - $src_w) / 2);
$dst_x = 0;
$dst_y = 0;
$dst_w = $dstimage_w;
$dst_h = $dstimage_h;
imagecopyresampled($dstimage, $srcimage,
$dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
imagejpeg($dstimage, "thumbnail.jpg");
Ha megszültünk egy ilyen programot, akkor általában azt érdemes csinálni, hogy alaposan leteszteljük, majd berakjuk egy függvénybe, hogy később bárhol felhasználhassuk ha szükség van rá, ne kelljen állandóan végigjárni ezt a gondolatmenetet. És persze nem árt kiegészíteni az állóképek kezelésével, de ezt már rátok bízom.
Az <img> teg width és height attribútumaival való beállítgatást akkor lehet használni, ha nem bánjuk hogy torzul a kép, vagy csak az egyik attribútum beállításával is megfelelő eredményt érünk el (ugyanis ekkor a böngésző a másikat úgy állítja be, hogy a kép méretaránya megmaradjon). Azonban ilyenkor is általában jobb módszer a PHP képkezelő függvényeinek használata. Sokszor ugyanis az eredetileg feltöltött kép sokkal nagyobb, mint amit meg akarunk jeleníteni. Ilyen esetben hiába állítjuk be a kis méretet, a kép betöltődésére ugyanannyit kell várni, mintha az eredeti méretben szeretnénk megjeleníteni. Sokkal gyorsabban töltődik be az oldal, ha a feltöltés után a PHP-vel lekicsinyített és elmentett képet jelenítjük meg.
Házi feladat
1.) Egy fájlfeltöltő mezővel kérjünk egy txt fájlt a felhasználótól, majd a feldolgozó oldalon jelenítsük meg a fájl tartalmát!
A fájlfeltöltő űrlap kódja:
<form method="post" action="upload.php" enctype="multipart/form-data"> <input type="file" name="txtfile" /> <input type="submit" name="submit" value="Feltöltés" /> </form>
A feldolgozó oldal az upload.php, ennek az a dolga, hogy ellenőrizze a fájl kiterjesztését, és ha az txt, akkor olvassa be a tartalmát, és írja ki.
// feltöltés ellenőrzése
if ($_FILES["txtfile"]["name"] == ""){
print "Nem töltöttél fel semmit!";
}
else{
$upload = true;
$name = $_FILES["txtfile"]["name"]; // fájlnév
$filepath = $_FILES["txtfile"]["tmp_name"]; // fájl elérési útja
// kiterjesztés ellenőrzése
$ext = strtolower(array_pop(explode(".", $name)));
if ($ext != "txt"){
print "Csak txt fájl tölthető fel!";
$upload = false;
}
// fájl tartalmának kiírása
if ($upload){
$file = fopen($filepath, "r");
print fread($file, filesize($filepath));
fclose($file);
}
}
Ebben az esetben nem szkséges a move_uploaded_file() függvénnyel áthelyezni a fájlt, mivel a $_FILES["txtfile"]["tmp_name"] is egy fájl elérési útja, így elvégezhetünk vele bármilyen fájlműveletet. Amennyiben el szeretnénk menteni a fájlt, akkor szükséges csak áthelyezni.
Ha úgy szeretnénk kiírni a fájl tartalmát a weboldalra, ahogy benne látható, az újsor-karaktereket <br /> tegekre kell cserélni:
...
// fájl tartalmának kiírása
if ($upload){
$file = fopen($filepath, "r");
$content = fread($file, filesize($filepath));
fclose($file);
}
print str_replace("\n", "<br />", $content);
...
Itt is kiírhatnánk közvetlenül a beolvasott tartalmat, ha az str_replace() függvénybe raknánk az fread() hívását, de így talán könnyebben olvasható a program.
2.) Írj egy olyan függvényt, ami a paramétereként megadott képre vízjelet rak! Például ha a kép a bal oldali sétáló narancs, a vízjel meg a jobb oldali kép:
akkor az eredmény például kinézhet így:

Próbáld meg úgy csinálni, hogy a vízjelet az itt látható módon a jobb alsó sarokba helyezze a függvény!
Persze egy vízjel általában nem így szokott kinézni, hanem inkább egy áttetsző felirat, amit ha rárakunk a képre, látszik az általa eltakart rész is. Ha egy ilyen png-vel megcsináljuk ugyanezt, sajnos nagyjából azonos eredményt kapunk, vagyis egy egyszínű hátterű felirat lesz rajta, ami nem lesz átlátszó. Ennek az az oka, hogy ez a GD könyvtár egy régi időkből visszamaradt gyűjtemény, amit kiegészítgettek ugyan a modernebb követelményeknek megfelelően (pl. átlátszóság kezelése), de ennek nem az lett az eredménye, hogy a függvények alapértelmezetten kezelik ezt, hanem nekünk kell segédfüggvényekkel foltozgatni a programunkat. Emiatt az átlátszóság helyes kezelése is eléggé nehézkes, a modernebb függvénykönyvtárak viszont nincsenek annyira elterjedve, a GD az, ami a legvalószínűbb hogy a rendelkezésünkre áll egy tárhelyen.
Az alapelv az, hogy mindkét képet beolvassuk, és a narancs képe lesz a célkép. A feladat, hogy a célképre rárakjuk a vízjelet változatlan méretben. Mivel a méretek itt nem változnak, az üres képet létrehozó függvényre nincs szükségünk.
$datasrc = getimagesize("vizjel.png");
$datadst = getimagesize("narancs.png");
$srcimage_w = $datasrc[0];
$srcimage_h = $datasrc[1];
$dstimage_w = $datadst[0];
$dstimage_h = $datadst[1];
$srcimage = imagecreatefrompng("vizjel.png");
$dstimage = imagecreatefrompng("narancs.png");
$src_x = 0;
$src_y = 0;
$src_w = $srcimage_w;
$src_h = $srcimage_h;
$dst_x = $dstimage_w - $srcimage_w;
$dst_y = $dstimage_h - $srcimage_h;
$dst_w = $srcimage_w;
$dst_h = $srcimage_h;
imagecopyresampled($dstimage, $srcimage,
$dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
imagepng($dstimage, "kep.png");
A paramétereket a függvény működését bemutató kép alapján lehet könnyen meghatározni. Az $src_* változók (9.-12. sorok) a forráskép (vízjel) egészét lefedő téglalapot határozzák meg, A $dst_* (13.-16. sorok) pedig a célkép jobb alsó sarkában lévő, a vízjellel megegyező nagyságú téglalapot.







