PHP a persistence.
Persistencí zde míním zachování stavu zobrazované stránky bez ohledu na skutečnost, že procházíme
historií browseru, opustíme stránku a procházíme jinými stránkami, ovšem při návratu je nám opět
zobrazena tak, jak jsme ji opustili.
Tato vlastnost může být někdy nežádoucí, ovšem při programování uživatelského rozhraní je důležitá.
Pokud uživateli potřebujeme vnutit určitý postup, příkladem mohou být různí průvodci objednávkou
zboží, přihlašováním a podobně, kde potřebujeme znát přesný stav uživatelova rozhraní, je tato vlastnost
více nežli žádoucí.
Takovéto persistence je dosaženo ovlivňováním vzhledu stránky pomocí proměnných, do kterých ukládáme
hodnoty, které je potřeba si zapamatovat. U bezstavového protokolu, jakým protokol HTTP je, je to
bezesporu rozšířením jeho funkcionality. U PHP, ale i ostatních jazyků podporujících programování
webových stránek, se k tomu používá indexace každého spojení klienta se serverem. Každé takové sezení
(session) dostane webovým serverem přiděleno jedinečné označení - index, a tak může být i rozpoznatelné
od sezení jiného. Uvedený index nám potom umožní ukložení potřebných proměnných spolu s jejich hodnotami,
třeba do databáze, nebo do souboru, uloženého na disku příslušného serveru.
Pod tímto textem nalezneme textová pole, která nám umožní změnit hodnotu, která je v nich zobrazována.
Horní pole umožňuje měnit hodnotu vloženou do persistentní proměnné, dolní potom je použito klasicky.
Data jsou na server přenesena metodou GET, tj. spolu s hlavičkou HTTP protokolu, jako parametry v URL.
Pokud do obou polí vložíme nějakou hodnotu a potom stiskneme tlačítko 'Ulož' zůstane vložená hodnota
viditelná v obou polích. Pokud si vynutíme opětovné překreslení stránky, zůstanou data opět beze změny.
Pokud ovšem stránku znovu načteme, řekněme klepnutím na levou nabídku 'Php a persistence', zůstane dolní
políčko prázdné, ovšem v horním je stále stejná hodnota. V horním políčku bude vložená hodnota uchována
až do chvíle, nežli vyprší doba platnosti sezení, nastavená na webovém serveru, nebo pokud zavřeme okno
s instancí browseru, tedy nejenom záložku.
Prohlédněme si dobře zdrojový kód stránky. Uvidíme, že název horního textového pole je poněkud podivný.
Ponechme však textový editor s načteným zdrojovým kódem otevřený a vynuťme si překreslení stránky. Opět
si nechte zobrazit zdrojový kód stránky a povšimněte si názvu horního textového pole. Porovnáním
obsahů obou instancí textového editoru zjistíme, že jméno tohoto prvku je změněno. Přitom ovšem hodnota
v textovém poli je stále stejná.
K čemu je dobré měnit názvy proměnných? Ale kvůli hackerům a různým zvědavcům, kteří se nám pokoušejí
"nabourat" web, nebo databázi. Pokud si totiž tuto stránku uloží, něco změní a potom ji podstrčí jako
kurentní webovému serveru, nezmění vůbec nic. Každý nový dotaz na server má za následek vrácení stránky
s jinak pojmenovanými proměnnými. Tím je zmenšena možnost manipulace v případě odchytávání proměnných.
Persistentní uložení proměnných na straně serveru nám umožní i poznamenat si čas, kdy byla data uživateli
odeslána. Potom můžeme kontrolovat, kdy se nám vrátí uživatelova odpověď, a pokud vzniklý rozdíl bude
větší, nežli jsme povolili, můžeme uživatelem odeslaná data odmítnout, a zaslat mu stránku s teď již jinými
názvy proměnných a žádostí o nové uložení.
Celý postup dosažení persistence potřebných hodnot lze vysledovat v následujícím zdrojovém kódu části
této stránky. Pro zjednošení operací s persistentními proměnými jsem si navrhl jednoduchou třídu.
Vidíme, že celý postup sestává ze 4 kroků.
- vytvoříme instanci třídy, to se provede pouze jednou, stejne jako její definice.
- do naší proměnné ($a) vložíme hodnotu, kterou chceme mít persistentní.
- zrušíme veškeré persistentní proměnné.
- pomocí metody put() uložíme údaje o proměnné spolu s její hodnotou do pole $_SESSION a tak ji zajistíme persistenci. Návratovou hodnotou metody put() je index, čili jméno této proměnné ve formuláři.
Pořadí zde popsaných kroků je potřeba dodržet. Až do použití metody destroy() pracujeme se "starými" proměnnými,
po metodě destroy() nastavujeme proměnné nové. Je to z důvodu práce se stále se měnícími názvy proměnných,
odesílaných uživateli do formuláře!
<?php
$_SESSION["perCounter"] = 0;
class Persist {
var $counter = 0;
function Persist() {
global $_SESSION;
$this->counter = $_SESSION["perCounter"] + 1;
$_SESSION["perCounter"] = $this->counter;
}
function GETS($gets) {
global $_SESSION;
if (is_array($gets)) {
foreach ($gets as $idx => $val) {
if (isset($_SESSION["perIdx"][$idx])) {
$vn = split("=",$_SESSION["perIdx"][$idx]);
$_SESSION[trim($vn[0])] = substr(strstr($_SESSION["perIdx"][$idx],"="),1);
}
}
}
}
function POSTS($gets) {
global $_SESSION;
if (is_array($gets)) {
foreach ($gets as $idx => $val) {
if (isset($_SESSION["perIdx"][$idx])) {
$vn = split("=",$_SESSION["perIdx"][$idx]);
$vn = trim($vn[0]);
$_SESSION[$vn] = $this->check($vn, $val);
}
}
}
}
function getIndex() {
global $_SESSION;
$arrLength = count($_SESSION["perIdx"]);
$timeIndex = substr(microtime(),5,4);
return "i".MD5("$arrLength{$this->counter}$timeIndex");
}
function putVar($varName, $varValue) {
global $_SESSION;
$idx = $this->getIndex();
$_SESSION["perIdx"][$idx] = "$varName=$varValue";
return $idx;
}
function setVar($varName,$varVal) {
global $_SESSION, $$varName;
$_SESSION[$varName] = $$varName = $varVal;
}
function getVar($varName) {
global $_SESSION;
if (is_array($_SESSION)) {
if (isset($_SESSION[$varName])) {
return $_SESSION[$varName];
}
}
return "";
}
function getVars() {
global $_SESSION;
if (is_array($_SESSION)) {
foreach ($_SESSION as $key => $val) {
global $$key; $$key = $val;
}
}
}
function destroy() {
global $_SESSION;
$_SESSION["perIdx"] = array();
}
function unsetVars($varNames) {
global $_SESSION;
if (is_string($varNames)) {
$varNames = array($varNames);
}
if (is_array($varNames)) {
foreach ($varNames as $key => $varName) {
global $$varName; unset($_SESSION[$varName],$$varName);
}
}
}
function check($varName, $varVal) {
$fileName = "$varName.php";
if (file_exists($fileName)) {
require($fileName);
}
return $varVal;
}
}
// 1. krok
$per = new Persist();
// 2. krok
$per->POSTS($_GET);
/*
if (count($_GET) > 0) {
header("Location: cz_persistencePhp.php");
}
*/
// 3. krok
$per->destroy();
// 4. krok
$idx = $per->putVar("a",$a);
if (isset($_GET["b"])) {
$b = $_GET["b"];
}
?>
<center>
<form method="GET" action="../cz/cz_persistencePhp.php" target="body">
<input type="text" name="<?php echo $idx; ?>" value="<?php echo $a; ?>">
<input type="submit" name="uloz" value="ULOŽ">
</form>
</center>
Povšimněte si ještě, že jsem ponechal zakomentovány řádky, které umožňují odstranění proměnných, přidaných
k URL, viz úvaha "Nechtěný insert". Je to úmyslně, neboť tato metoda se nedá použít bez skutečné persistence
proměnných, ať už s pomocí databáze, či session souboru na disku. Přišli bychom tak o pozorování chování
proměnné bez persistence.
© 2007 Djordje Zurovac, všechna práva vyhrazena.