Programowanie w języku PHP

Sesje w PHP

  • 2006-08-01 18:09
  • 9 komentarzy
  • 9183 odsłony
  • Oceń ten tekst jako pierwszy

Czym są sesje?


Co mamy na myśli, mówiąc o sesjach? Nieformalnie, sesja w przypadku przeglądania WWW to czas, w którym dana osoba, siedząc przed jednym komputerem, przegląda określoną liczbę stron, następnie kończy ten proces. Jeżeli prowadzisz witrynę WWW, którą przykładowy użytkownik właśnie przegląda, sesja biegnie od czasu załadowania pierwszej strony, aż do ostatniej. Na przykład witryna hotelu na Karaibach może korzystać z sesji na czas przeglądania pięciu stron, ale użytkownik naprawdę rozpoczął sesję w portalu zajmującym się podróżami, a zakończył ją w czasie rezerwacji miejsca w hotelu konkurencji.

Co stanowi problem?


Dlaczego więc idea sesji jest na tyle skomplikowana? Jest tak dlatego, że protokól HTTP jest bezstanowy. Powoduje to, że twój serwer WWW na mniej pamięci długoterminowej niż twój kod. W rezultacie serwer WWW odpowiada na poszczególne żądania, jakie otrzymuje i nie ma sposobu na ich połączenie, nawet jeżeli żądania te są zapisywane. Jeżeli siądę przed swoim komputerem w Chicago a ty przy swoim, i oboje załadujemy kolejno pierwszą i drugą stronę z witryny hotelu na Karaibach, protokół HTTP nie zaoferuje żadnej pomocy przy rozpoznaniu, że tych dwoje ludzi oglądało dwie kolejne strony. Od strony serwera były to cztery żądania załadowania stron z dodatkowymi danymi związanymi z każdym wywołaniem. Nie tylko taka informacja nie identyfikuje cię (za pomocą nazwiska, adresu e-mail, numeru telefonu lub innego identyfikatora), ale również nie oferuje nic, co może zidetyfikować żądania kolejnych stron jako pochodzące od jednej osoby.

Dlaczego się tym zajmujemy?


Jeżeli twoja witryna jest przeznaczona tylko do dostarczania rozmaitych stron różnym użytkownikom, to w zasadzie nie musisz wiedzieć, kiedy sesja się rozpoczyna, a kiedy kończy. Jednak istnieje wiele sytuacji, kiedy chcemy to wiedzieć.
  • Chcemy dostosowywać się do doświadczenia użytkowników, które zależy od tego, jakie strony (lub ile) już widzieli.
  • Chcemy wyświetlać reklamy, ale nie chcemy wyświetlać jednej reklamy więcej niż raz w czasie sesji.
  • Chcemy zbierać informacje o podejmowanych przez użytkownika działaniach (tak jak w grach przygodowych realizuje się pamiętanie punktów lub w witrynach handlu elektronicznego - wózki na zakupy).
  • Interesuje nas sposób, w jaki ludzie korzystają z witryny - czy przechodzą do wewnętrznych stron korzystając z zakładek, czy przechodzą całą drogę od strony głównej.
Dla wszystkich zastosowań powinniśmy skorelować żądania załadowania stron z kolejnymi częściami sesji; dla niektórych zastosowań wygodnie byłoby zapamiętywać niektóre dane w połączeniu z sesją. Sesje PHP rozwiązują oba te problemy.

Alternatywy sesji:


Zanim zajmiemy się podejściem PHP do sesji, wymieńmy kilka alternatywnych sposobów rozwiązania problemu. Jak się później przekonamy, podejście PHP stanowi kombinację kilku z tych technik:

1. Adres IP


Serwery WWW znają albo nazwę, albo adres IP komputera, z którego przyszło żądanie załadowania strony. W większości konfiguracji PHP są one dostępne w zmiennych, odpowiednio $REMOTE_HOST i $REMOTE_ADDR. Wydaje się, że identyfikacja komputera jest jednoznaczna z użytkownikiem, co najmniej w krótkim czasie. Jeżeli w krótkim okresie dostaniesz dwa żądania z tego samego adresu IP, kod może stwierdzić, że zostały one wysłane przez tę samą osobę, która przeszła z jednej strony witryny na drugą.

Niestety adres IP twojej przeglądarki nie musi pasować do komputera, z którego korzysta użytkownik. Zarówno AOL, jak i inni dostawcy internetu często stosują serwery proxy, które działają jako pośrednicy. Jeżeli przeglądarka zażąda załadowania URL, wysyła on to żądanie do docelowego serwera i zwraca stronę użytkownikowi. Taka konfiguracja powoduje, że wielu użytkowników może jednocześnie przeglądać twoją witrynę pozornie z jednego adresu IP. Adresy IP nie są więc wystarczająco jednoznaczne, aby stanowiś podstawę do śledzenia sesji.

2. Ukryte zmienne


Każde wywołanie HTTP jest obsługiwane niezależnie, ale za każdym razem gdy użytkownik przejdzie do innej strony witryny, jest zwykle realizowane przez łącze lub przetworzenie formularza. Jeżeli pierwsza strona, którą użytkownik odwiedza, może wygenerować identyfikator tej wizyty, a następne przejścia ze strony do strony mogą go przenosić.

Poniższy przykładowy fragment kodu można zamieścić na początku strony:

if(!isset($session_id)) 
   $session_id = generate_session_id(); // hipotetyczna funkcja

Ten fragment kodu kontroluje, czy zmienna $session_id została wcześniej zainicjowana. Jeżeli tak, zakładamy, że została przekazana do bieżącej strony i jesteśmy w środku sesji. Jeżeli nie, oznacza to, że jesteśmy na pierszej stronie nowej sesji i wywołujemy hipotetyczną funkcję, nazwaną generate_session_id(), w celu utworzenia identyfikatora danej sesji.

Założyliśmy, że po włączeniu poprzedniego kodu identyfikator sesji został stworzony i teraz wystarczy przekazać go do innych połączonych stron. Każde łącze powinno zawierać $session_id jako argument GET:

<a href="next.php?session_id=$session_id">Następna strona</a> 

Każdy formularz powinien zawierać ukryty argument POST:

<form action="next.php" method="post"> 
 
// tu ciało formularza 
 
<input type="hidden" name="session_id" value="$session_id"> 
</form>

Ta technika jest prostym sposobem odróżniania sesji (dopóki możesz generować identyfikatory). Jeśli mamy identyfikatory sesji, możemy zastosować wiele sposobów dołączania danych do każdej sesji. Jednym z nich jest użycie identyfikatora sesji jako klucza tabeli bazy danych. Jednak to wyjście jest kłopotliwe - musisz upewnić się, że każde łącze i obsługa formularza prawidłowo przenoszą opisane informacje. Jeżeli przesyłasz informacje jako argument GET, maszyna śledzenia sesji będzie widoczna w pasku adresu przeglądarki - argument może zostać łatwo zmieniony lub przechwycony przez użytkownika.

3. Cookies


Innym sposobem śledzenia sesji jest użycie takiego samego identyfikatora sesji, jak opisaliśmy przed chwilą, ale do jego przekazywania pomiędzy stronami stosuje się cookie.

Cookie jest szczególnego rodzaju plikiem, umieszczonym w komputerze z przeglądarką, który może być zapisywany i odczytywany przez serwery WWW. Zamiast sprawdzać zmienną przekazaną za pomocą metody POST lub GET (i przypisywać nową, jeżeli nie została odnaleziona), skrypt może sprawdzić, czy w komputerze klienta istnieje już poprzednio utworzone cookie i zapisać do niego nowy identyfikator, jeżeli nie został odnaleziony. Motoda ta posiada pewne zalety w porównaniu do ukrytych zmiennych: mechanizm ten działa w sposób niewidoczny (nie posiada zazwyczaj w przeglądarce śladów aktywności), a kod, który sprawdza i ustawia cookie może być scentralizowany (zamaiast występować w każdym łączu).

Jakie są wady? Niektóre stare przeglądarki w ogóle nie obsługują cookies, a nowe pozwalają użytkownikowi na zablokowanie możliwości osadzania cookies na dysku przez serwery WWW. Mimo, że cookie dostarczają dobre rozwiązanie problemu, nie możemy zakładać, że zawsze będą dostępne.

Jak działają sesje w PHP?


Dobrze działające sesje zajmują się dwiema rzeczami: śledzeniem sesji (to znaczy wykrywaniem, kiedy dwa osobne wywołania skryptów są częścią tej samej sesji, a kiedy nie) oraz zapamiętywaniem danych związanych z sesją. Musimy mieć pierwszą możliwość, żemy wogóle myśleć o drugiej.

Jeżeli PHP śledzi sesje, można również zachować dane przez "rejestrowanie" określonych zmiennych, w celu wskazania, że ich wartości mają być zapamiętane w połączeniu z identyfikatorem sesji.

Uaktywnianie sesji w PHP


Pierwszym krokiem skryptu, korzystającego z sesji, jest poinstruowanie PHP, że sesja może już trwać, więc trzeba ją przechwycić i odczytać wszystkie związane z nią dane. Realizuje się to przez wywołanie bezargumentowej funkcji session_start(). Jeżeli jest ona wywołana w każdym skrypcie, możesz ją pominąć i w zamian za to ustawić w php.ini zmienną session.auto_start na 1 (jest ona zwykle ustawiona na 0). Również każde wywołanie funkcji session_register() spowoduje niejawne wywołanie funkcji session_start().

Wynik działania session_start() zależy od tego, czy PHP odszukał poprzedni identyfikator sesji, przekazany przez argumenty HTTP lub cookie. Jeżeli został znaleziony, poprzednio związane z nim zmienne sesji zostaną odczytane i zamienione na zwykłe zmienne dostęne na stronie. Jeżeli na przykład poprzednia strona w sesji zarejestrowała zmienną $city i przypisała jej wartość 'Chicago', nasz skrypt może z niej skorzytstać, wywołując sesion_start():

session_start(); 
echo("$city"); 

Jeżeli poprzednio nie została zarejestrowana taka zmienna lub zapomnieliśmy wywołać session_start(), zmienna będzie traktowana jak każda niezainicjowana zmienna.

Jeżeli PHP nie znajdzie poprzedniego identyfikatora sesji, wywołanie session_start() utworzy nową sesję. Podstawowym efektem jest utworzenie nowego identyfikatora, który może być używany do rejestrowania zmiennych.

Rejestrowanie zmiennych w sesji


Wywołanie session_start() zajmuje się importowaniem zmiennych z sesji do bieżącego skryptu - teraz wyeksportujemy zmienne, aby były widoczne w kolejnych stronach tej samej sesji. Jest to zrealizowane przez funkcję session_register(). Jak się okazuje, importowanie zmiennych jest "hurtowe" (robimy to jednym wywołaniem funkcji), natomiast eksport jest "detaliczny" (musimy rejestrować kolejno wszystkie zmienne). Należy pamiętać, że to, co zostało zaimportowane, nie jest automatycznie eksportowane, choć tak wskazuje logika.

Załóżmy, że poprzednia strona ustawiła zmienną $city na 'Chicago'. Teraz skorzystajmy z tej zmiennej i przekażmy ją (po zmianie wartości) do kolejnych stron:

session_start(); 
echo("$city"); 
session_register('city'); 
echo("$city"); 
$city = "Dallas"; 

Wywołanie session_start() ustawia zmienną $city na 'Chicago', więc można użyć tej zmiennej w instrukcji echo czy print. Od tego miejsca $city będzie traktowana jak każda inna zmienna na stronie. Wywołanie session_register() umieszcza jednak w mechanizmie sesji informację o tym, że zmienna $city na być ponownie wyeksportowana do zmiennych sesji. Na kolejnych stronach wartość jej powinna być taka sama, jak po zakończeniu tego skryptu. W naszym kodzie wartość jej zmieniła się na 'Dallas', więc następne strony otrzymają taką właśnie wartość zmiennej.

Jeżeli zapomnimy wywołać funkcją session_start(), pierwszy wiersz będzie zawierał puste miejsca tam, gdzie powinna być wartość zmiennej $city. Drugi drukowany wiersz będzie już wyglądał dobrze, ponieważ wywołanie session_register() powoduje niejawne wywołanie session_start(). Jeżeli opuścimy wywołanie session_register(), na tej stronie wszystko będzie w porządku, ale kolejne strony nie otrzymają zmiennej sesji o nazwie $city.

Gdzie są przechowywane dane?


Mechanizm sesji bazuje na identyfikatorze sesji i związanych z nim zmiennych.

Jak już wiemy, identyfikator sesji jest przechowywany w cookie w komputerze z przeglądarką lub jest wbudowany w argumenty GET, POST, przekazywane razem z żądaniem pobrania strony. Nie jest nigdzie zapamiętywany - przekazywany jako część żądania i zwracany do kody HTML, do łączy i formularzy, które mogą wygenerować kolejne żądanie. Przeglądarka i serwer przerzucają się tą krytyczną dla nas informacją jak "gorącym kartoflem". Jeżeli któraś ze stron zgubi identyfikator, nasza sesja się kończy.

Domyślnie zawartość zmiennych sesji jest przechowywana w specjalnych plikach na serwerze, po jednym dla każdej sesji (można przechowywać identyfikator sesji jako cookie w komputerze klienta, ale byłoby grubiaństwem przechowywanie wartości zmiennych sesji na jego dysku). Zapamiętanie danych w ten sposób wymaga kodu sesji, realizującego serializację danych. Termin ten oznacza zamianę danych w liniową sekwencję bajtów, którą można zapisywać na dysku i odczytywać z niego w celu odtworzenia danych.

Możliwe jest takie skonfigurowanie PHP, aby program przechowywał zmienne sesji w bazie danych, zamiast w plikach.

Funkcje obsługi sesji


Tabela poniżej zawiera wszystkie, najbardziej istotne funkcje związane z obsługą sesji:

session_start()
Nie wymaga argumentu. Powoduje, że PHP odczytuje identyfikator sesji przekazany do strony (dzięki cookie lub GET, POST); jeżeli nie może go odszukać, tworzy nowy identyfikator sesji. Jeżeli odnaleziony został stary identyfikator sesji, PHP odtwarza przypisania do wszystkich zarejestrowanych zmiennych i udostępnia te wartości jako zwykłe zmienne globalne.

session_register()
Wymaga ciągu jako argumentu i rejestruje zmienną o nazwie określonej przez ciąg - na przykład session_register('username') rejestruje zmienną o nazwie username. Nazwa zmiennej nie powinna zawierać początkowego znaku '$'. Można równieżprzekazać tablicę ciągów, aby za jedym razem zarejestrować wiele zmiennych. Efektem rejestracji jest zapamiętanie przypisań do obiektów (po zakończeniu skryptu zarejestrowane zmienne podlegają serializacji i są przenoszone w sposób, który zapewnia ich odtworzenie w wywołaniu session_start()). Jeżeli nie wywołano wcześniej funkcji session_start(), session_register() niejawnie ją wywołuje.

session_unregister()
Wymaga ciągu jako argumentu i usuwa z listy zarejestrowanych zmiennych zmienną o nazwie przekazanej jako argument. W wyniku tego zmienna ta nie będzie podlegała serializacji i nie będzie przenoszona pomiędzy stronami (nazwa zmiennej nie powinna zawierać początkowego znaku '$'.

session_is_registered()
Sprawdza, czy zmienna o podanej nazwie jest zarejestrowana w bieżącej sesji, zwracając TRUE, jeżeli zmienna jest zarejestrowana, FALSE, jeżeli nie jest.

session_destroy()
Wywołanie tej funkcji usuwa wszystkie zapamiętane dane o sesji (identyfikator sesji nie musi się zmieniać po wywołaniu tej funkcji). Wywołanie tej funkcji nie zmienia wartości żadnych zmiennych w bieżącym sktypcie.

session_name()
Funkcja wywołana bez parametrów zwraca nazwę bieżącej sesji. Jest to zwykle 'PHPSESSID'. Wywołana z jedym argumentem session_name() ustawia nazwę bieżącej sesji na podany ciąg. Nazwa ta jest używana jako klucz do odszukania identyfikatora sesji w cookie lub argumentach GET, POST. Aby odnalezienie sesji się udało, nazwa sesji musi być identyczna jak nazwa sesji, w trakcie której poddano zmienne serializacji. Zauważ, że nie ma powodu do zmiany nazwy sesji, chyba, że chcesz rozróżniać różne typy sesji obsługiwanych jednocześnie przez serwer WWW (np. w przypadku wielu witryn korzystających z sesji). Nazwa sesji jest zmienna na domyślną za każdym uruchomieniem skryptu, więc zmiana nazwy sesji musi zostać wykonana w każdym skrypcie przez wywołaniem innej funkcji obsługi sesji.

session_module_name()
Jeżeli nie zostaną podane żadne argumenty, funkcja zwraca nazwę modułu odpowiedzialnego za obsługę danych sesji. Nazwa ta jest domyślnie ustawiona na 'files', co oznacza, że dane sesji po serializacji są zapisywane do plików w katalogu ustawionym przez funkcję session_save_path(). Jeżeli podany zostanie ciąg jako argument, nazwa modułu jest zmienna na ten ciąg (np. 'user' dla zdefiniowanej przez użytkownika bazy danych sesji; ale nie powinieneś zmieniać tego parametru, jeżeli nie wiesz dokładnie co robisz).

session_save_path()
Zwraca (lub ustawia w przypadku podania argumentu) ścieżkę do katalogu, w którym zapisywane są wartości zmiennych sesji (zwykle jest to /tmp w systemach Unix). Katalog ten musi mieć odpowiednio ustawione uprawniwnia, aby PHP mógł tam zapisywać pliki.

session_id()
Nie ma argumentów. Zwraca ciąg, który jest kluczem, określającym sesje. Jeżeli zostanie przekazany argument, funkcja ta ustawi identyfikator sesji na tę wartość.

session_encode()
Zwraca ciąg z zakodowanym stanem bieżącej sesji, który może zostać zdekodowany przez funkcję session_decode(). Ciąg ten może zostać użyty do zapamiętania sesji w celu odtworzenia jej za jakiś czas (np. zapisanie zakodowanego ciągu w pliku lub w bazie danych).

session_decode()
Pobiera wynik działania funkcji session_encode() i odtwarza stan sesji, zmieniając zmienne sesji na zmienne strony (analogicznie do session_start()).
 

Podsumowanie


Sesje są użyteczne w sytuacjach, gdy chcesz śledzić działania użytkownika w przypadku interakcji trwającej dłużej niż wykonanie jednego skryptu. Jeżeli prezentowana zawartość strony zależy od działań podejmowanych na poprzedniej, kod powinien zapamiętywać i przenosić te informacje w sposób, który umożliwia odróżnienie poszczególnych użytkowników. Ponieważ protokół HTTP jest protokołem bezstanowym, prowadzi to do zastosowania technik zastępczych - zwykle albo ukrytych zmiennych (które są niestety kłopotliwe), albo cookies (niektóre przeglądarki klientów ich nie obsługują).

Implementacja sesji w PHP hermetyzuje te skomplikowane zagadnienia. Identyfikatory sesji są tworzone i rozprowadzone w sposób automatyczny, a mechanizm rejestracji pozwala programiście dołączać dowolne dane PHP do sesji. Poza początkowym dołączeniem się do sesji i zarejestrowaniem zmiennych, które powinny zostać rozpropagowane poza bieżącą stronę, użycie sesji jest dla programisty przejrzyste.



Autor: Bartosz - webcity.pl

9 komentarzy

Brak avatara
Staszek 2014-04-17 16:06

Tak jak niżej, przydałaby się aktualizacja. Teraz nie używamy rejestrowania zmiennych przy pomocy session_register() tylko stosuje się zmienną superglobalną $_SESSION.

Twardy 2006-08-03 14:28

Artykul jest stary i powinien zostać zmieniony. Kto teraz w sesjach nie uzywa tablic predefiniowanych się pytam?

Rene 2007-01-05 12:19

... dokładnie tak jak mówi Twardy..... artykuł przestarzały!

Axceel 2005-01-22 20:50

2 godziny sie pieprzyłęm z tymi sesjami, aż natrafiłęm na tę strone, tak czy siak za pierwszym razem nawet ten kurs nie zadzial, ale w końcu sie udało ... :D

spooky 2004-02-04 11:22

Dobrze, ze wrzuciles ten artykul tutaj, bo webcity.pl od jakiegos czasu chyba przestalo istniec... ;)

Immortal 2003-09-02 11:40

Artykul ten jest dostepny na webcity.pl: http://webcity.pl/artykuly.php/t/3
Jako autor podany jest Tim Converse.

korn 2003-08-09 11:17

Najpierw do Adama:

Nie wiem skad to jest, wiem tylko ze zessalem to z www.webcity.pl (chyba) i wwalilem tutaj zeby ludziochy sie uczyly.




A teraz do LofiXa:

siegac to siegam z wielu stron ale raczej sie nie podpisuje pod cudzymi materialami, chyba ze gdzies zobaczyles taka sytuacje, jesli tak to mi daj cynk bo moze wwalilem to jeszcze jak bylem mlody i glupi :-)

lofix 2003-07-11 13:36

korn siega rowniez po materialy ze stron
ygreg.com i innych :>
nieladnie

Adam Boduch 2003-06-25 16:30

Otrzymalem informacje, ze artykul jest plagiatem z ksiazki PHP 4. Biblia.