Session v PHP - Builder.cz - Informacni server o programovani

Odběr fotomagazínu

Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!

 

Zadejte Vaši e-mailovou adresu:

Kamarád fotí rád?

Přihlas ho k odběru fotomagazínu!

 

Zadejte e-mailovou adresu kamaráda:



PHP

Session v PHP

php

19. března 2003, 00.00 | Co to vlastně session jsou? Co nám nabízejí a jak nám usnadňují práci? Proč a jak je používat?
Článek se snaží na tyto otázky odpovědět.

{úvod}Jak jistě víte protokol HTTP, který slouží ke komunikaci mezi www serverem a prohlížečem je bezstavový (mezi jednotlivými přechody stránek se neudržuje žádné spojení. Když kliknete na odkaz, pouze se spojí klient se serverem, server pošle stránku a spojení se ukončí). To je dost velká nevýhoda, hlavně pokud píšete větší aplikaci. Zjistíte, že by bylo vhodné znát obsah hodnotu proměnné, kterou uživatel odeslal formulářem asi tak o 3 stránky dříve. Pokud je to jedna dvě proměnné, není problém si ji předávat v odkazech (př: <A href="neco.php?promenna=hodnota&...">) nebo ve formulářích jako pole typu hidden ( <INPUT type=hidden name="promenna" value="hodnota">). Pokud by ale udajů mělo být hodně, skripty by byly dost nepřehledné a místo ladění chyb byste zkoumali, co jste zapomněli kde předat. Proto máme v PHP session.

Co od session můžeme očekávat a co potřebujeme?
1) identifikaci uživatele - abysme mohli nějaké proměnné uchovávat, musíme vědět od koho pocházejí
2) uchovávání obsahu proměnných

Abychom jednotlivé uživatele od sebe rozeznali, potřebujeme nějaký identifikátor prohlížeče (standardně býva v PHP pojmenován PHPSESSID, často se používá i authid). Jeho název můžeme nastavit v php.ini nebo pomocí funkce session_name (o tom více později). Ten musí být předáván s každým požadavkem na server. Skript vygeneruje identifikátor a předá ho uživateli (není vhodné generovat identifikátor hned na úvodní stránce, komplikuje to práci vyhledávačů a často ani neregistrují URL, které předává parametry (metoda GET)). Lepší je generovat ho později, třeba při úspěšném přihlášení uživatele nebo třeba při vložení prvního zboží do nákupního koše. Jsou dvě možnosti předávání:
Cookies - při každém dalším přístupu se v požadavku klienta posílají i cookies (a samozřejmě i ta naše s identifikátorem).
URL parametr - přímo v odkazech (metoda get) a formulářích (post nebo get). Ke každému skriptu volanému odkazem se přidá identifikátor (např. <A href="pokus.php?authid=5465967416161654964664">odkaz</A>) nebo ve formuláři:
<FORM action="pokus.php">
<INPUT type=hidden name="authid" value="5454657469487912314564654">
.
.
.
</FORM>



Oba způsoby mají své výhody a nevýhody. Použití cookie je jednodušší, ale uživatel je může vypnout. Potom přestávají správně fungovat i session. V druhém případě nás uživatel nemůže překvapit, když cookies nepoužívá. Bohužel je to ale trochu náročnější na tvůrce skriptu. Když ve skriptu identifikátor zapomenete, skript by nefungoval správně. Další a hlavní nevýhodou při předávání v URL je možnost zjištění identifikátoru jinou osobou (například pomocí proměnné HTTP_REFERRER, v logu proxy serveru, ...). Pokud by skript spoléhal jen na identifikátor, mohla by jiná osoba se znalostí identifikátoru získat přístup na stránky, z jejichž URL identifikátor získal. Při použití v URL je proto vhodné kombinovat session ještě třeba s kontrolou IP adresy a času.

Možná se ptáte proč session jsou, když stejně musím předávat identifikátor. Mohl bych přece předávat rovnou proměnné. Uvědomte si, že ale stačí předávat jednu proměnnou (v aplikaci bez session by se jich mohlo předávat o dost více). A hlavně: php lze nastavit tak, že se o předávání starat nemusíte a php ho bude předávat automaticky.


Nastavení

Nastavit chování můžeme několika způsoby. Vše lze nastavit v php.ini pomocí následujících direktiv:
session.save_handler - určuje, co se použije pro ukládání dat session (soubor, databáze)
session.save_path - adresář pro ukládání souborů session (použije se v případě session.save_handler = files)
session.name - jméno identifikátoru. Stejně se bude jmenovat i cookie, pokud k předávání identifikátoru cookie použijete
session.auto_start - Pokud nastavíme na 1, budou se session spouštět automaticky, jinak je musíme spouštět ručně funkcí session_start().
session.use_cookies - určuje, že se pro předávání identifikátoru použije cookie
session.use_only_cookies - dovoluje k přenosu identifikátoru použít pouze cookie
session.cookie_lifetime - nastavení doby platnosti cookie ve vteřinách. Je možné nastavit 0, cookie pak platí do ukončení prohlížeče
session.cookie_path - cesta uložená v cookie
session.cookie_domain - doména uložená v cookie
session.cookie_secure - dovoluje poslat cookie jen na zabezpečeném spojení (HTTPS)
session.gc_probability - pravděpodobnost, že se garbage collection spustí při každém požadavku. Udává se v procentech. Není dobré nastavovat vysokou hodnotu. Garbage collector je poměrně náročný na výkon. Je lepší aby se spouštěl méně a mazal více dat, než aby se spouštěl při každém požadavku a nemazal nic.
session.gc_maxlifetime - určuje po kolika vteřinách budou nepoužívaná data považovaná za smetí a vyčištěna
session.referer_check - kotrola HTTP Referer
session.entropy_file - cesta k externímu souboru, který se použije jako externí zdroj ke generování identifikátoru
session.entropy_length - určuje kolik bajtů se přečte z externího souboru
session.cache_limiter - nastavení způsobu kešování
session.cache_expire - nastavení expiračního času pro kešování
session.use_trans_sid - nastavuje automatické předávání identifikátoru
url_rewriter.tags - určuje, které html tady budou upraveny (bude do nich přidán identifikátor, pokud je nastaveno session.use_trans_sid)

Vždy ale přístup k php.ini nemáme (např. hosting). Potom můžeme použít funkci ini_set. Funkce změní hodnotu konfigurační volby a vrátí předchozí hodnotu. Při chybě vrátí FALSE.
Př: ini_set('session.name','authid');

Ini_set nám dovolí nastavit téměř vše z nastavení session. Všechny direktivy patří mají příznak PHP_INI_ALL a je možné je nastavovat z uživatelských skriptů. Jedinou vyjímkou je session.use_trans_sid (PHP_INI_SYSTEM, PHP_INI_PERDIR). Lze měnit v php.ini, httpd.conf nebo .htaccess. Podrobnosti jak a co lze nastavit je nad rámec tohoto článku. Podrobnosti naleznete na www.php.net.

Dalším způsobem jak něco nastavit je možné pomocí funkcí přímo k tomu určených, například: session_set_cookie_params, session_cache_limiter.


Funkce

Pro práci se session se nám budou hodit následující funkce:
session_start - nastaví session data
session_register - registrování proměnné do session
session_is_registered - zjišťuje, jestli je proměnná registrovaná v session
session_id - nastaví nebo vrátí session id
session_name - nastaví nebo vrátí session name

Ještě se nám budou hodit fce isset a empty. Nebudu zde vypisovat jak přesně která funkce pracuje, to si jistě najdete na www.php.net v přehledu funkcí.


SID

Pro usnadnění práce při předávání identifikátoru slouží konstanta SID. Dala by se zapsat jako jmeno_identifikatoru=hodnota ( stejného výsledku dosáhnete zápisem echo session_name()."=".session_id(); ).

Př. 1:
header ('Location: http://'.$_SERVER['SERVER_NAME'].'/index2.php?'.SID);


Př. 2:
<A href=index2.php?<? echo SID ?>>



Bezpečnost

Než přejdeme k ukázce skriptu, ještě je třeba zmínit jednu důležitou věc. Už jste určitě slyšeli o superglobálních polích, globálních proměnných, register_globals, ... Z důvodu vyšší bezpečnosti se ve verzi php 4.1.0 objevilo superglobální pole $_SESSION (stejné jako známe například $_GET, $_POST,...).
Ve starších verzích php, ale pole $_SESSION nemáme a proměnné musíme registrovat pomocí funkcí session_register. Při nastavení register_globals = off ale takový způsob registrace nefunguje.

Je bezpečnější používat pole $_SESSION. V opačném případě (session_register a register_globals =on) nemáme totiž jistotu, odkud data pocházejí. Pokud máme například skript, ve kterém je v session proměnné $prihlaseny určeno, zda uživatel může do systému, můžeme narazit:
session_register ("prihlaseny");

if ( $prihlaseny == 1 ) {
// jsem v systemu
}


Pokud ale skript zavolám index.php?prihlaseny=1 dostanu se také do systému. Protože podmínka je splněna. Když ale budu testovat podle následujícího skriptu, už budeme mít jistotu, že v proměnné je skutečně hodnota ze session.


if ($_SESSION['prihlaseny'] == 1) {
// jsem v systemu
}


[-more-]{Praktická ukázka} Praktická ukázka


Jak registrovat proměnné v php starším 4.1.0 (nemáme pole $_SESSION):

if (!session_is_registered("promenna"))   {

    session_register("promenna");
    $promenna = 12345; // ted uz je mozne pracovat s $promenna jako s kazdou jinou promenou
}

session_unregister("promenna"); // odregistrovani


Jak registrovat proměnné při php 4.1.0 a vyšším:
V tomto případě přistupujeme k proměnným session přes superglobální pole $_SESSION. Není potřeba proměnné registrovat, stačí jen hodnoty deklarovat:

if (!isset($_SESSION["promenna"]))   {

    $_SESSION["promenna"] = 12345;

}

unset ($_SESSION["promenna"]); // odregistrovani


Ukázali jsme si dva způsoby práce se session. Oba je možné používat, ale:
Pokud chcete psát bezpečné skripty, u kterých nezáleží na nastavení register_globals, používejte pole $_SESSION. (pro toto je nutné mít ale php verze 4.1.0 nebo vyšší). Musíte si ale vybrat jen jeden způsob. Pokud používáte pole $_SESSION, už nepoužívejte funkce session_register, session_unregister a session_is_registered.

Příklad je záměrně rozdělen do dvou skriptů, aby bylo jasně vidět, že k deklaraci dochází v jiném skriptu. Po spuštění skriptu a 5 kliknutích zjistíte, že se na výstupu objeví řetězec, který jsme deklarovali v prvním skriptu. Ukázky jsou dvě: pro verze php starší než 4.1.0 a pro novější. V příklad je použito nastavení session.use_trans_sid = 0, session.use_cookie=1 a session.auto_start = 0.


Praktická ukázka pro php vyšší 4.1.0 a vyšší:
index.php:
<?php

session_start(); // nastartuji session

if (empty ($_SESSION['s_klik'])) $_SESSION['s_klik'] = 0; // pri prvnim spustneni nastavim pocet kliknuti na 0
if (empty ($_SESSION['s_text'])) $_SESSION['s_text'] = "Už jsi klikl nejméně 5x - tento text byl deklarovan v prvnim skriptu.";

echo "<A href=index2.php>Můžeš dál ...</A>";
echo "<BR><BR>Klik = " . $_SESSION['s_klik'];
?>


index2.php:
<?php

session_start(); // nastartuji session

$_SESSION['s_klik']++;

if ($_SESSION['s_klik'] > 4) {
echo "<BR><B>" . $_SESSION['s_text'] . "</B><BR>";
}

echo "<A href=index2.php>Několikrát klikni</A>";
echo "<BR><BR>Klik = " . $_SESSION['s_klik'];
?>


Praktická ukázka pro php do verze 4.1.0:
index.php:
<?php

/*
prvni cast kodu (podminka if) neni nutna. Je vhodna, pokud si chceme generovat vlastni id a nazev identifikatoru. Jinak nam ho vygeneruje samo php (nazev identifikatoru se pouzije z php.ini)
*/

if(!$authid) {

    $session_id = uniqid(20);       // pokud nemam jeste id, tak si ho vytvorim
    session_id ($session_id);     // urcim, ze identifikatorem bude $authid
    session_name ("authid");       // urcim jmeno identifikatoru

}

session_start();     // nastartuji session

if (!session_is_registered ("s_klik")) session_register("s_klik");     // zaregistrujeme nekolik promennych
if (!session_is_registered ("s_text")) session_register("s_text");    

if (empty ($s_klik)) $s_klik = 0;     // pri prvnim spustneni nastavim pocet kliknuti na 0
if (empty ($s_text)) $s_text = "Už jsi klikl nejméně 5x - tento text byl deklarovan v prvnim skriptu.";

echo "<A href=index2.php?authid=$authid>Můžeš dál ...</A>";
echo "<BR><BR>Klik = $s_klik";
?>


index2.php:
<?php

session_start();     // nastartuji session

$s_klik++;

if ($s_klik > 4) {
    echo "<BR><B>" . $s_text . "</B><BR>";
}

echo "<A href=index2.php?authid=$authid>Několikrát klikni</A>";
echo "<BR><BR>Klik = $s_klik";
?>


Konec práce se session

Pokud už hodnoty ze session nejsou potřeba, můžeme se jich jednoduše zbavit. To provedeme ve dvou krocích - vyprázdnění všech proměnných v session a zrušení vlastní session:

<?

// pri php starší než 4.1.0 :

session_start();
session_unset();
session_destroy();


// pri použití superglobálního pole $_SESSION (PHP 4.0.1 +):

$_SESSION = array();
session_destroy();

?>


Pár rad na závěr

Ještě bych rád upozornil, že hodnoty v session se neudrží donekonečna. Je vhodné kód skriptu ošetřit na tuto možnost.

Pokud na přenos identifikátoru používáme cookie (session.use_cookies = 1 v php.ini), je nutné volat session_start na začátku skriptu ještě před jakýmkoli výstupem. Funkce session_start totiž přidává k hlavičkám cookie a jak jistě víte, hlavičky se posílají jako první.


Spoluautor: Ondrej Ivanič(, )

Tématické zařazení:

 » Rubriky  » PHP  

 » Rubriky  » Web  

Poslat článek

Nyní máte možnost poslat odkaz článku svým přátelům:

Váš e-mail:

(Není povinný)

E-mail adresáta:

Odkaz článku:

Vzkaz:

Kontrola:

Do spodního pole opište z obrázku 5 znaků:

Kód pro ověření

 

 

 

 

Nejčtenější články
Nejlépe hodnocené články

 

Přihlášení k mému účtu

Uživatelské jméno:

Heslo: