Adatbázis használata PHP-ből Adatbázis használata PHP-ből...1 Nyílt forráskódú adatbázisok...1 A mysql függvények...2 A mysqli függvények...4 Bináris adatok adatbázisban való tárolása...8 Adatbázis csatoló osztályok...9 Esettanulmányok...9 Nyílt forráskódú adatbázisok -MySQL, PostgreSQL, Mysqli -hogyan használjuk őket PHP-ből Az erőforrás (resource) egy olyan speciális PHP változó, ami egy külső erőforrásra tartalmaz referenciát vagy azonosítót. Erőforrás pl. egy állomány megnyitása után az állományra mutató szerkezet, az adatbázis kapcsolat, hálózati kapcsolat. Tehát az erőforrásokat speciális függvények hozzák létre és használják. -kapcsolatok általában TCP portokon keresztül: 3306 MySQL, 5432 PostgreSQL A PHP-ből egyszerű esetben az alábbi műveleteket kell elvégezni adatbázis használatakor: 1. az adatbázis kapcsolat megnyitása: eredménye egy erőforrás típusú változó, az adatbázis kapcsolat (connection) 2. a lekérdezés végrehajtása, SQL keresés esetében eredménye egy SQL válasz, amely a lekérdezett eredményt tartalmazza (resultset). 3. Az előbbiből kell ezután kiolvasni az eredmény sorait, ehhez a művelethez több függvény áll rendelkezésünkre. Kiolvasás után az eredmény sorait PHP tömbökbe olvassuk. 4. Ha feldolgoztuk az eredményt fel kell szabadítani a lefoglalt erőforrásokat. Minden egyes fázis után hibaellenőrzést kell végezni, és ha hiba adódik azt megfelelően kezelni kell. Perszisztens (állandó) adatbázis kapcsolatok -a PHP leellenőrizheti, hogy létezik e ugyanolyan tulajdonságú kapcsolat mielőtt újat nyitna, és ha igen, akkor felhasználja azt. Ezzel terhelést lehet levenni az adatbázisról, mivel nem kell újra és újra hitelesíteni a kapcsolatot. Ezt csak akkor használható, ha a PHP modulként fut. Hátránya a sok megnyitott kapcsolat által lefoglalt erőforrás. A maximálisan megnyitható kapcsolatok számát a php.ini illetve az adatbázis konfigurációs állományaiban lehet behatárolni. Függvénycsoportok: MySQL, MySQLi, Postgres, stb: gyakorlatilag minden fontosabb adatbázishoz 1
találunk függvényeket. A mysql függvények Ez a függvénycsoport a bevezetőben említett kétféle erőforrás típust használja, a kapcsolatot és a lekérdezési választ. Fontosabb függvények (részletesen PHP kézikönyv MySQL függvények fejezete): mysql_connect -- Kapcsolatot nyit meg egy MySQL szerverhez mysql_pconnect -- Perszisztens kapcsolatot nyit meg a MySQL szerverhez mysql_select_db -- Kiválaszt egy MySQL adatbázist mysql_create_db -- Létrehoz egy MySQL adatbázist mysql_error -- Az előző MySQL művelet hibaszövegét adja mysql_query -- MySQL kérést küld a szervernek mysql_affected_rows -- Az előző MySQL műveletben érintett sorok számát adja meg mysql_num_fields -- Az eredményben szereplő mezők számát adja mysql_num_rows -- Az eredményben szereplő sorok számát adja vissza. mysql_result -- Eredmény egy sorának lekérdezése mysql_fetch_array -- Kérés egy sorát adja vissza (tetszőleges) tömb formájában mysql_fetch_assoc -- Az eredmény egy sorát asszociatív tömbként adja vissza. mysql_fetch_field -- Eredményhalmaz egy oszlopáról ad információt objektum formájában mysql_fetch_row -- Az eredmény következő sorát adja vissza számmal indexelt tömb formájában Az SQL parancsokban felhasznált PHP változókat át kell futtatni olyan függvényeken amelyek kiszűrik az SQL kontroll karaktereket: mysql_escape_string -- Egy karakerláncban szereplő speciális karakterek értelmezését szünteti meg de nem törődik a karakterkészlettel, elavult mysql_real_escape_string -- Levédi egy stringben a speciális karaktereket egy SQL lekérdezés számára, az átírt karakterek: \x00, \n, \r, \, ', " és \x1a. Használható erre még a következő két függvény is: addslashes(). Az eredmény mezőiről az alábbi függvényekkel lehet információt kérni: mysql_field_flags -- Adott eredmény adott mezejének flagjeit adja vissza. mysql_field_len -- A kérdezett mező hosszát adja vissza mysql_field_name -- Adott mező nevét adja vissza mysql_field_seek -- Az eredménymutatót a kívánt pozícióba mozgatja mysql_field_table -- Visszaadja annak a táblának a nevét, melyben a megadott mező található mysql_field_type -- Az eredmény adott mezejének típusát adja vissza Lezárásra használt függvények: mysql_free_result -- Felszabadítja az eredmény által lefoglalt memóriát mysql_close -- Lezár egy MySQL kapcsolatot 2
Példa: <?php //a szkript a MySql pelda adabazisat hasznalja (World) include ("print_array.php"); $conn = mysql_connect ('localhost','user','passwd') mysql_select_db ('world') die(mysql_error()); /* a használt City tábla: +-------------+----------+------+-----+---------+----------------+ ID int(11) NO PRI NULL auto_increment Name char(35) NO CountryCode char(3) NO District char(20) NO Population int(11) NO 0 +-------------+----------+------+-----+---------+----------------+ */ $rs = mysql_query ("select * from City order by Id limit 0,5") or die(mysql_error()); //egy mezo beolvasasa az eredmeny elso sorabol (0) //a mezo neve Name $f = mysql_result ($rs, 0, 'Name') or die(mysql_error()); print('<br>az első sor Name oszlopa:'. $f); //egy sor beolvasasa asszociativ tombkent $a = mysql_fetch_assoc($rs); print '<br> a második sor tartalma'; print_array($a); //egy sor beolvasasa numerikus es asszociativ indexu tombkent $a = mysql_fetch_array($rs); print '<br> a harmadik sor tartalma - itt mindkét típusú indexre előállítja a tömböt'; print_array($a); //a tobbi sor beolvasasa numerikus indexu tomkbent print '<br>a maradék 2 sor tartalma'; while (list($id, $name, $distr, $pop) = mysql_fetch_row ($rs)) { print '<br>'.$id.' '. $name. ' '. $distr. ' '. $pop; //lezaras mysql_free_result($rs); mysql_close($conn);?> 3
A mysqli függvények -objektum orientált és procedurális változat is (részletesen PHP kézikönyv MySQLi függvények fejezete): A mysqli objektum Fontosabb osztály függvények: query lefuttatja az SQL parancsot close kapcsolatot zár connect megnyitja a kapcsolatot info kiírja az SQL parancs által érintett sorok számát Webtechnológia, előadásvázlat, 2007/08-II. félév A keresések az adatbázis oldalán vagy lokálisan puffereltek, és az alábbi konstansokkal lehet megadni a keresés módját: - MYSQLI_STORE_RESULT (kliens oldalon pufferelt) - MYSQLI_USE_RESULT(adatbázis oldalán pufferelt), implicit érték: MYSQLI_STORE_RESULT rollback rollback parancsot ad ki select_db kiválasztja az adatbázist prepare lekérdezési tervet készít elő, eredménye egy lekérdezési terv objektum. Osztálytulajdonságok: affected_rows hány sor érintett az UPDATE vagy INSERT parancs errno hibakód visszatérítése error a szerver hibaüzenetét adja vissza field_count hány oszlop van a lekérdezés eredményében num_rows hány sor van a lekérdezés eredményében A mysqli_result objektum A lekérdezés eredményét tartalmazza Fontosabb osztály függvények: close lezárja az eredményt data_seek elmozdítja az eredmény mutatóját fetch_array asszociatív és numerikus indexű tömbbe olvassa az eredményt fetch_assoc - asszociatív indexű tömbbe olvassa az eredményt fetch_row - numerikus indexű tömbbe olvassa az eredményt free_result felszabadítja az eredmény által lefoglalt memóriát Osztálytulajdonságok: num_rows hány sor van az eredményben type az eredmény típusát adja vissza MYSQLI_STORE_RESULT (or MYSQLI_USE_RESULT) 4
A mysqli_stmt objektum a lekérdezési tervet tartalmazza Fontosabb osztály függvények: bind_param paramétereket köt a tervhez bind_result változókat köt az eredményhez close lezárja a lekérdezési tervet execute végrehajtja a tervet fetch lekéri a lekérdezési terv eredményét a változókba free_result felszabadítja az eredmény által foglalt memóriát prepare SQL lekérdezést készít elő send_long_data darabokban küld adatokat a lekérdezési tervnek, hogy egy darab ne haladja meg az adatbázis kapcsolat csomagméretét Értékek (osztálytulajdonságok) affected_rows hány sort érint az SQL utasítás (INSERT, UPDATE) num_rows hány sor van az eredményben Egyszerű lekérdezés példa <?php //egyszeru lekerdezes a mysqli_ fuggvenyekkel bemutatasara //feltetelezzuk, hogy ez egy Internetrol jovo valtozo $pricelimit='20'; $pricelimit = mysql_real_escape_string($pricelimit); $q = "SELECT author, title, price FROM books WHERE price < $pricelimit ORDER BY price limit 0,10" ; //a kapcsolat letrehozasa, hiba eseten leallas $conn = new mysqli ('localhost', 'user', 'pass'); //hiba eseten leallas if (!$conn) die ("Nem lehet kapcsolódni az adatbázishoz"); //adatbazis kivalasztas if (! $conn->select_db('lszabo') ) die (mysqli_error($conn)); //a kereses vegrehajtasa if (! ($res=$conn->query($q))) 5
die (mysqli_error($conn)); echo 'Keresés eredménye'; echo '<br>sorok száma: '. $res->num_rows. '<br>'; //a sorok kiolvasasa asszociativ tombbe while ( $a = $res->fetch_assoc()) { echo $a['author']. ' : ', $a['title']. ' Ár:'. $a['price']. ' RON<br>'; //takarítás $res->free(); $conn->close();?> Lekérdezési tervek használata: -előnye, hogy a lekérdezést egyszer elemzi az adatbázis elemzője (parser) és lekérdezés tervezője (planner) -ha többször kell ismételni ugyanazt az SQL-t akkor nagyon előnyös -mire használható: INSERT, REPLACE, UPDATE, DELETE, CREATE TABLE, SELECT (az úgynevezett adatkezelő DML - parancsokhoz) -használatánál az alábbi menetet kell követni (zárójelben a megfelelő függvénynevek): 1. előkészítés (prepare) 2. paraméterek hozzárendelése a tervhez (bind_param) 3 az SQL lefuttattatása (execute) 4 változók hozzárendelése az eredményhez (bind_result) 5 eredmény beolvasása (fetch) Példa: <?php $conn = new mysqli ('localhost', 'user', 'pass'); if (!$conn) die ("Nem lehet kapcsolódni az adatbázishoz"); if (! $conn->select_db('lszabo') ) die (mysqli_error($conn)); //1. a terv elokeszitese 6
//a kérdőjelek helyén vannak a paraméterek $stmt = $conn->prepare ( 'SELECT author, title FROM books where price <? and weight >?' ); //2. a valtozok hozzarendelese a tervhez $stmt->bind_param('dd',$price,$weight); //itt adunk erteket a valtozoknak a a lekerdezeshez $price=15.; //RON $weight=300.; //g //3. a lekerdezes vegrehajtasa if (!$stmt->execute()) die ("Sikertelen query."); //4. az eredmeny hozzarendelese valtozokhoz $stmt->bind_result($author, $title); echo "Nagy súlyú (>$weight g) és olcsó könyvek (< $price RON) <br>"; //5. az eredmeny beolvasasa a valtozokba while($stmt->fetch()) { echo "<br>". $author. " : ". $title; //a lekerdezest ismetelhetjuk //ismetles, uj bemeneti valtozok $price=15.; //RON $weight=400.; //g if (!$stmt->execute()) die ("Sikertelen query."); echo "<br><br>nagyobb súlyú (>$weight g) és olcsó könyvek (< $price RON) <br>"; // a masodik kereses beolvasasa while($stmt->fetch()) { echo "<br>". $author. " : ". $title; //ismetles $price=15.; //RON $weight=450.; //g if (!$stmt->execute()) die ("Sikertelen query."); echo "<br><br>nagyon nagy súlyú (>$weight g) és olcsó könyvek (< $price RON) <br>"; while($stmt->fetch()) { echo "<br>". $author. " : ". $title; 7
$conn->close();?> Bináris adatok adatbázisban való tárolása -képek vagy mérési adatok -a bináris adatokat az adatbázisok gyakorlatilag sztringként kezelik (text típusként is deklarálhatóak) -méretek amiket tárolni lehet pl. a MySQL-nél: -a TEXT típusokban szöveget, a BLOB típusokban bináris adatot tárol MySQL típus TINYBLOB vagy TINYTEXT MEDIMBLOB vagy MEDIUMTEXT Méret 0.. 256 byte 0.. 65535 byte (65k) BLOB vagy TEXT 0.. 16.777.215 byte (17 M) LONGTEXT vagy LONGBLOG 0.. 4.294.967.295 (4 GB) -hasonló típusok más adatbázisoknál is megtalálhatóak, a méreteket ellenőrizni kell Az adatbázisba írás: -mysql függvények esetében rendes INSERT, SELECT és UPDATE utasításokkal ahol a bináris mezőt értékét úgy kell megadni mint egy sztringet -ezért beíráskor ha $data a mező értéke az: $data = addslashes ($data); függvényt kell használni. A mysqli függvények esetében lehetséges a bináris adatok részletekben való átvitele lekérdezési terv és a mysqli_send_long_data () függvény használatával. A PHP és MySQL közti átviteli kapcsolat csomagmérete általában korlátozva van, ezért ez utóbbi megoldás minden szempontból előnyös. A MySQL implicit átviteli csomagmérete 1 MB, a konfigurációs változó neve max_allowed_packet. Ezt a konfigurációs állományban (my.cnf) a következő sorral lehet módosítani: [mysqld] max_allowed_packet=16m 8
Két példát adunk, az első az egyszerű mysql interfésszel, a második a mysqli -vel ír be bináris adatot. A példa állományok a honlapon a példák között: blob_simple.php (mysql) és blob.php (mysqli és send_long_data() ). Adatbázis csatoló osztályok példák: mysql függvényekre: Db, MyDb mysqli függvényekre: Dbi, MyDbi -a különböző programozási interfészek általában tartalmaznak ilyen osztályt -ezek legtöbb esetben az általános, adatbázistól független csatolást is megoldják Esettanulmányok 1. Azok az esetek amikor egy adatbázis tábla egyetlen sora ábrázol egy alkalmazásban használt objektumot (aktív rekord). Példa: felhasználó kezelése. Példa osztály: User, állomány: user.php -létrehozás, insert/update/select függvények -szesszióba való mentés 2. Azok az esetek amikor az alkalmazás egy adatbázis táblában ábrázolt objektumokat járja végig. Példa osztály: Browser, állomány browser.php -lapozás megoldása -böngészést segítő függvények -szesszióba való mentés Függetleníteni kell az alkalmazások három rétegét: -az objektumaink adatbázisban való ábrázolását -a feldolgozást vagy alkalmazáslogikát -a megjelenítést A Browser osztály az adatbázis elérést a Db osztályra bízza, a megjelenítéshez pedig külön megjelenítő osztályt lehet írni (az osztály tostring() és to_html() metódusai csak a tesztekhez szükséges megjelenítésre jók). 9