PHP pro pokroΦilΘ - znovu t°φdy a objekty
V tomto Φlßnku o t°φdßch a objektech si ukß₧eme dalÜφ zajφmavΘ mo₧nosti p°i prßci s OOP v PHP. Budeme se zab²vat vyu₧itφm takzvanΘ serializace a magick²ch funkcφ __sleep() a __wakeup() - vytvo°φme instanci t°φdy, ulo₧φme ji do souboru a nakonec cel² objekt p°edßme v session.
Serializace a unserializace
VÜe zajiÜ¥ujφ funkce serialize()
a unserialize()
, kterΘ p°evedou do takzvanΘho byte °et∞zce prom∞nnΘ objektu. Proces tohoto "p°evodu" se naz²vß serializace a opaΦn² postup unserializace. Na vstupu funkce serialize()
je objekt a na v²stupu ji₧ zmi≥ovan² byte °et∞zec, u funkce unserialize()
je tomu naopak.
Pro dalÜφ experimentovßnφ si nadefinujeme pokusnou t°φdu do souboru "trida.php" se kterou budeme dßle pracovat:
/*
Soubor trida.php ve kterΘm je definice pokusnΘ t°φdy
*/
class clsTrida {
//pomocφ konstruktoru nastavφme hodnoty vlastnostφ
function clsTrida($vl1, $vl2) {
$this->vlastnost1=$vl1;
$this->vlastnost1=$vl2;
}
//funkce vypis() vypφÜe hodnoty obou vlastnostφ
function vypis() {
echo "1. vlastnost: ".$this->vlastnost1."<br />";
echo "2. vlastnost: ".$this->vlastnost2."<br />";
}
}
?>
Nejprve si ukß₧eme postup ulo₧enφ objektu do souboru:
/*
Soubor "a.php"
V prvnφm souboru nßÜ objekt zeserializujeme a ulo₧φme ho do souboru "data"
*/
//naincludujeme soubor s pokusnou t°φdou
include ('trida.php');
//vytvo°φme instanci pokusnΘ t°φdy a nastavφme vlastnostφ, kterΘ se zeserializujφ
$objekt = new clsTrida ("Vlastnost 1", "Vlastnost 2");
//zde vytvo°φme byte °et∞zec
$bytestring=serialize($objekt);
//otev°eme soubor a byte °et∞zec do n∞j ulo₧φme
$f = fopen("data", "w"); //vytvo°enφ a otev°enφ souboru pro zßpis
fputs($f, $bytestring); //ulo₧enφ bytestringu do souboru
fclose($f); //zav°enφ souboru
?>
V souboru s unserializacφ se ji₧ nevytvß°φ ₧ßdnß instance, proto₧e unserializovan² objekt je schopen sßm poznat svoji t°φdu. Ta ale ve skriptu definovßna b²t musφ.
/*
Soubor "b.php"
V druhΘm souboru otev°eme soubor "data", kde je serializovan² objekt a unserializujeme ho
*/
//naincludujeme soubor s pokusnou t°φdou
include ("trida.php");
//otev°enφ souboru a p°eΦtenφ jeho obsahu
$bytestring = implode("", @file("data"));
$UnserializovanyObjekt=unserialize($bytestring);
//nechßme si vlastnosti objektu vypsat, abyste vid∞li, ₧e ulo₧enφ do souboru "p°e₧ili"
$UnserializovanyObjekt->Vypis();
?>
P°edßnφ objektu pomocφ session je v podstat∞ stejnΘ jako p°i uklßdßnφ do souboru, jen zde mφsto funkcφ pro ulo₧enφ souboru pou₧ijeme funkce pro p°edßvßnφ session:
/*
Soubor "sesstrida1.php"
*/
session_start(); //nastartovani session
//naincludujeme soubor s pokusnou t°φdou
include ("trida.php");
//vytvo°φme instanci pokusnΘ t°φdy
$objekt = new clsTrida ("Vlastnost 1", "Vlastnost 2");
//zde vytvo°φme byte °et∞zec
$bytestring=serialize($objekt);
//vytvo°enφ session
$_SESSION["serializovanyobjekt"]=$bytestring;
//napφÜeme odkaz na dalÜφ strßnku
echo '<a href="sesstrida2.php">DalÜφ strßnka</a>';
?>
/*
Soubor "sesstrida2.php"
*/
session_start(); //nastartovani session
//naincludujeme soubor s pokusnou t°φdou
include ("trida.php");
//zde unserializujeme byte °et∞zec
$UnserializovanyObjekt=unserialize($_SESSION["serializovanyobjekt"]);
//op∞t si vypφÜeme hodnoty obou vlastnostφ
$UnserializovanyObjekt->vypis();
?>
MagickΘ funkce __sleep() and __wakeup()
P°i (un)serializaci mohou b²t velmi u₧iteΦnΘ "magickΘ" funkce __sleep()
a __wakeup()
, kterΘ se umis¥ujφ do definice t°φdy. Funkce __sleep()
se spustφ na zaΦßtku serializace. M∙₧eme do nφ vlo₧it k≤d nap°φklad pro ukonΦenφ spojenφ s databßzφ. D∙le₧itΘ je, aby funkce __sleep()
vrßtila pole, kterΘ obsahuje prom∞nnΘ objektu, ze kter²ch se vytvo°φ byte °et∞zec. Naproti tomu funkce __wakeup()
se spustφ na zaΦßtku unserializace. Lze ji vyu₧φt nap°φklad pro obnovenφ spojenφ s databßzφ.
V nßsledujφcφm p°φkladu si vytvo°φme t°φdu, kterß si pamatuje datum svΘ serializace a p°i unserializaci tuto hodnotu vypφÜe. Byte °et∞zec v tomto p°φkladu budeme uklßdat do souboru. Funkce get_object_vars()
byla popsßna v p°edchozφm Φlßnku.
/*
Soubor trida.php ve kterΘm je definice pokusnΘ t°φdy
*/
class clsTrida {
//funkce vypis() vypφÜe hodnoty obou vlastnostφ
function vypis() {
echo "1. vlastnost: ".$this->vlastnost1."<br />";
echo "2. vlastnost: ".$this->vlastnost2."<br />";
}
function __sleep() {
//do vlastnosti "datum" ulo₧φme aktußlnφ datum = datum serializace
$this->datum=Date("Y-m-d");
//vytvo°φme pole vlastnostφ objektu. Jestli₧e n∞jakou vlastnost vynechßme, nebude serializovanß.
$vlastnosti = get_object_vars($this);
foreach ($vlastnosti as $klic => $hodnota) {
$pole[] = $klic;
}
//vrßcenφ pole vlastnostφ t°φdy
return $pole;
}
function __wakeup() {
//jestli₧e jsme ulo₧ili datum, tak ho vypφÜeme
if (isset($this->datum)) {
echo "Datum serializace: ".$this->datum."<br />";
}
}
}
?>
V²Üe uveden² p°φklad je pouze jednoduchou ukßzkou magick²ch funkcφ a velkΘ praktickΘ vyu₧itφ asi nemß. V nßsledujφcφm p°φkladu si tedy vytvo°φme t°φdu, kterß vyu₧φvß databßzi. Funkce __sleep()
v tomto p°φpad∞ spojenφ s nφ ukonΦφ a vrßtφ ·daje pot°ebnΘ k p°ihlßÜenφ do databßze, funkce __wakeup()
spojenφ op∞tovn∞ navß₧e. V²hody tohoto postupu jsou z°ejmΘ.
/*
Soubor trida.php ve kterΘm je definice pokusnΘ t°φdy
*/
class clsTrida {
//konstruktor t°φdy
function clsTrida($server,$uzivatel,$heslo,$databaze){
$this->datserver=$server;
$this->datuzivatel=$uzivatel;
$this->datheslo=$heslo;
$this->datjmeno=$databaze;
$this->Pripojeni();
}
//navß₧e spojeni s databßzφ
function Pripojeni() {
MySQL_Connect($this->datserver,$this->datuzivatel,$this->datheslo);
MySQL_Select_DB($this->datjmeno); //vybrßnφ databßze
}
//funkce vypis() vypφÜe obsah tabulky; je zde samoz°ejm∞ pouze pro demonstraci prßce s databßzφ
function Vypis() {
$dotaz=MySQL_Query("SELECT sloupec1, sloupec2 FROM tabulka") or Die(MySQL_Error());
while ($data = MySQL_Fetch_Array($dotaz)){
echo $data[sloupec1]." ".$data[sloupec2];
echo "<br />";
}
}
//ukonΦφme spojenφ s databßzφ a vrßtφme p°ihlaÜovacφ ·daje
function __sleep() {
MySQL_Close();
//vytvo°φme pole vlastnostφ objektu
$vlastnosti = get_object_vars($this);
foreach ($vlastnosti as $klic => $hodnota) {
$pole[] = $klic;
}
//vrßcenφ pole vlastnostφ t°φdy
return $pole;
}
//op∞t navß₧eme spojenφ s databßzφ
function __wakeup() {
$this->Pripojeni();
}
}
?>
/*
Soubor databaze1.php, kde dochßzφ k serializaci
*/
include("trida.php");
$objekt = new clsTrida("Localhost", "MojeJmeno", "TajneHeslo", "PokusnaDAT");
//vypφÜeme obsah tabulky
$objekt->vypis();
$bytestring=serialize($objekt);
//otev°eme soubor a byte °et∞zec do n∞j ulo₧φme
$f = fopen("data", "w"); //vytvo°enφ a otev°enφ souboru pro zßpis
fputs($f, $bytestring); //ulo₧enφ bytestringu do souboru
fclose($f); //zav°enφ souboru
?>
/*
Soubor databaze2.php, kde dochßzφ k unserializaci
*/
//naincludujeme soubor s pokusnou t°φdou
include ("trida.php");
//otev°enφ souboru a p°eΦtenφ jeho obsahu
$bytestring = implode("", @file("data"));
$UnserializovanyObjekt=unserialize($bytestring);
//vypφÜeme obsah tabulky
$UnserializovanyObjekt->Vypis();
?>
JeÜt∞ se musφm zmφnit o jednom bezpeΦnostnφm nedostatku zmφn∞nΘho p°φkladu. Pokud p°edßvßte byte °et∞zec v session, data jsou zde v nezaÜifrovanΘ form∞, tak₧e je m∙₧e p°φpadn² ·toΦnφk velmi jednoduÜe odchytit a pokud znß strukturu byte °et∞zce (kterß nenφ nijak slo₧itß, zkuste si otev°φt soubor, do kterΘho uklßdßte byte °et∞zec, v libovolnΘm textovΘm editoru), nebude problΘm si je p°eΦφst a dostat se tak do naÜφ databßze. Podmφnkou je tedy pou₧itφ nap°φklad zabezpeΦenΘho protokolu SSL.
VÜechny p°φklady z Φlßnku si m∙₧ete stßhnout. A₧ na p°φklad s databßzφ, kde si musφte upravit p°ihlaÜovacφ ·daje, budou fungovat bez problΘm∙.