W PHP 4 i wyższych oddano do naszych rąk mechanizm tzw. sesji. W tym artykule chciałbym przybliżyć czytelnikowi to zagadnienie. Ukazać jak proste i równocześnie wygodne jest korzystanie z tego rozwiązania.

Żeby Was jednak nie zanudzić suchym wykładem, działanie mechanizmu sesji przedstawię na przykładzie skryptu autoryzacji użytkowników, który po drobnych przeróbkach będziecie mogli użyć na własnej stronie.

Dlaczego HTTP jest „be”…

HTTP jest tak zwanym protokołem bezstanowym. Oznacza to, iż nie posiada wbudowanego mechanizmu przekazywania stanu pomiędzy poszczególnymi transakcjami. Mowiąc prościej, jeśli otworzysz jakąś stronę WWW i po kliknięciu na link przejdziesz do następnej, to oba wywołania nie będą w żaden sposób ze sobą powiązane, nie będzie można bezpośrednio ustalić czy zostały wykonane przez tego samego użytkownika. Pozostają tylko metody okrężne. Najczęściej aby dokonać takiej operacji wykorzystuje się ciasteczka (cookies). Ta metoda nie jest jednak idealna, jako że niektóre przeglądarki nie obsługują cookies, a inne pozwalają na wyłączenie ich obsługi. Można także doklejać dane do URL (np.: http://serwer.pl/index.php?zmienna=wartosc). Ten sposób jest dobrze znany wszystkim „pehapowcom”, jednak i on ma swoje wady. Do przekazania kilku zmiennych nadaje się bardzo dobrze, ale co w sytuacji gdy chcemy przesłać dużą tablicę? W dodatku to co znajduje się w adresie URL jest widoczne dla użytkownika i może być przez niego bez problemu zmodyfikowane. Poza tym zwyczajnie zaśmieca pasek adresu. Ktoś może powiedzieć: „Czemu nie użyć formularza?”. To jest jakiś sposób, ale niezbyt wygodny jeżeli chcemy, by każdy link na stronie przekazywał określone informacje. O śledzeniu IP wspominam tylko dla pełni obrazu, bo zapewne większość z Was wie jak niepewna jest ta metoda. W tej sytuacji z pomocą przychodzą nam sesje.

Sesja? Z czym to się je?

Ktoś mi kiedyś powiedział, że nie stosuje sesji, bo to „tylko takie ulepszone cookies”. Owszem, sesje mogą wykorzystywać mechanizm ciasteczek, jednak działają na trochę innej zasadzie. Cała tajemnica sesji polega na tym, że przekazywany jest tylko identyfikator sesji, a dane siedzą sobie spokojnie na serwerze. Do przekazania identyfikatora używane są właśnie ciasteczka, a w przypadku gdy nie są one obsługiwane przez przeglądarkę, identyfikator sesji doklejany jest do adresu URL. Jeśli skompilujemy PHP z parametrem –enable-trans-sid identyfikator doklejany jest do linków automatycznie. W przeciwnym wypadku musimy czynić to ręcznie za pomocą stałej SID:

<A href="dokument.php?<?=SID?>">link</A> 

Sesję rozpoczynamy i wznawiamy poleceniem session_start(). Należy pamiętać, że na każdej stronie, w której chcemy mieć dostęp do zmiennych sesji musimy użyć tej funkcji, chyba że w pliku php.ini ustawiliśmy wartość zmiennej session.auto_start na 1. Zmienne sesji zapamiętujemy używając funkcji session_register(), jeśli nie rozpoczęliśmy wcześniej sesji to użycie tej funkcji spowoduje niejawne wywołanie session_start(). Zmienną sesji kasujemy za pomocą session_unregister(). Zakończenie sesji i usunięcie jej wszystkich zmiennych następuje po wywołaniu funkcji session_destroy(). Podejrzewam, że nieźle namieszałem Wam w głowach, dlatego aby lepiej zrozumieć jak działają sesje, napiszemy skrypt autoryzacji użytkowników.

Logowanie

Na początek napiszemy stronę login.php, na której użytkownik będzie proszony o podanie loginu i hasła.

<HTML> 
<HEAD> 
  <TITLE>Logowanie</TITLE> 
</HEAD> 
<BODY> 
  <B>Podaj login i hasło</B> 
  <FORM method="POST" action="<?php echo $PHP_SELF?>"> 
    Login: <INPUT type="text" name="login"><BR> 
    Hasło: <INPUT type="password" name="pass"><BR> 
    <INPUT type="submit" value="Zaloguj się"> 
  </FORM> 
</BODY> 
</HTML> 

Na razie to praktycznie czysty HTML. Warto tylko zwrócić uwagę na zmienną $PHP_SELF, która wskazuje na właśnie wykonywany skrypt. Po wpisaniu loginu i hasła formularz zostaje wysłany do skryptu login.php. Aby sprawdzić poprawność tych danych, przed początkowym znacznikiem wstawiamy kolejne linie kodu.

<?php 
if (isset($login) && isset($pass)){ 
  if ($login == "lockoom" && $pass == "test"){ 
    session_start(); 
    session_register("login"); 
    header("Location: secret.php?" . SID); 
    exit(); 
  } 
} 
?> 

Sprawdzamy czy podano prawidłowy login i hasło. Mogą być one zapisane np. w bazie danych lub pliku. Ja po prostu porównuje je z ustalonymi wartościami. Jeśli nie podano hasła i/lub loginu, bądź też są one błędne, wyświetlony zostaje formularz. W przeciwnym przypadku rozpoczynamy sesję i rejestrujemy zmienną $login. Zwrócicie uwagę, że session_register przyjmuje jako parametr łańcuch tekstowy, który jest nazwą zmiennej bez znaku $. Następnie przekierowujemy użytkownika do chronionej strony secret.php, nie zapominając o dopisaniu na wszelki wypadek identyfikatora sesji (przypominam, że nie jest to konieczne jeśli skompilowaliśmy PHP z opcją –enable-trans-sid). Musimy jeszcze wymusić zakończenie skryptu przy pomocy exit(). Możemy już właściwie przejść do dokumentu secret.php, ale dla wygody użytkownika dodamy do naszego skryptu jakiś komunikat, który będzie się pojawiał w przypadku wpisania nieprawidłowych danych (kod poniżej – linie 8-11 oraz 18-20).

login.php – pełny kod:

<?php 
if (isset($login) && isset($pass)){ 
  if ($login == "lockoom" && $pass == "test"){ 
    session_start(); 
    session_register("login"); 
    header("Location: secret.php?" . SID); 
    exit(); 
  } else 
    $error = "<B>Błędny login lub hasło!</B><BR>"; 
} else 
  $error = false; 
?> 
<HTML> 
<HEAD> 
  <TITLE>Logowanie</TITLE> 
</HEAD> 
<BODY> 
<?php 
  echo $error ? $error : ""; 
?> 
  <B>Podaj login i&nbsp;hasło</B> 
  <FORM method="POST" action="<?php echo $PHP_SELF?>"> 
    Login: <INPUT type="text" name="login"><BR> 
    Hasło: <INPUT type="password" name="pass"><BR> 
    <INPUT type="submit" value="Zaloguj się"> 
  </FORM> 
</BODY> 
</HTML> 

Chronione hasłem

Użytkownik podał poprawne hasło i został przekierowny do strony secret.php. Oczywiście, aby plik ten był rzeczywiście niedostępny dla niepowołanych osób nie wystarczy go nazwać „secret”. W końcu wystarczy, że „chakier” pozna jego nazwę i już może się do niego dostać. Jednak my przecież znamy sesje…

<?php 
session_start(); 
if (!isset($_SESSION["login"])){ 
  header("Location: login.php"); 
  exit(); 
} 
?> 
<HTML> 
<HEAD> 
  <TITLE>Tajne/poufne</TITLE> 
</HEAD> 
<BODY> 
<?php 
echo "Witaj " . $_SESSION["login"]; 
?> 
  <BR><B>Ściśle tajne dane.</B> 
</BODY> 
</HTML> 

Tym razem funkcja session_start() w większości przypadków będzie wznawiała sesję rozpoczętą podczas logowania. Te pozostałe przypadki będą próbami nieautoryzowanego dostępu do strony. Próby takie będą skazane na niepowodzenie ponieważ nie będą zawierały ustawionej zmiennej $login, a więc niezalogowany internauta zostanie przekierowny do skryptu uwierzytelniającego. Zapewne zauważyliście użytą przeze mnie w linii 3 i 14 tablicę $_SESSION (dla wersji PHP starszych niż 4.1.0 jej nazwa to $HTTP_SESSION_VARS) i zastanawiacie się co to za twór. Jest to tablica asocjacyjna przechowująca wszystkie zmienne sesji. Tu podkreślam, zawsze stosujcie tę tablicę jeśli chcecie mieć pewność, że zmienna jest rzeczywiście zmienną sesji. Dlaczego o tym piszę? Jeśli PHP ma włączoną w ustawieniach opcję register_globals to do zmiennych sesji można się dostać się bezpośrednio przez ich nazwę. W naszym przypadku skrypt wyglądałby następująco:

<?php 
session_start(); 
if (!isset($login)){ 
  header("Location: login.php"); 
  exit(); 
} 
?> 
<HTML> 
<HEAD> 
  <TITLE>Tajne/poufne</TITLE> 
</HEAD> 
<BODY> 
<?php 
echo "Witaj " . $_SESSION["login"]; 
?> 
  <BR><B>Ściśle tajne dane.</B> 
</BODY> 
</HTML> 

Krócej? Tak. Lepiej? Nie, a to dlatego, że teraz nie mamy żadnej gwarancji, iż zmienna jest faktycznie zmienną sesji, a nie np.: została przesłana w adresie URL (secret.php?login=sprytny_chakier). Dlatego powtórzę: zawsze używajcie tablicy $_SESSION (lub ew. funkcji session_is_registered()) jeśli chcecie mieć pewność, że macie do czynienia ze zmienną sesji.

OK. Mamy już skrypt logowania i chronione hasłem dane. Do kompletu brakuje nam już tylko skryptu wylogowującego. Dodamy tylko do secret.php jedną linijkę z linkiem do skryptu

<?php 
session_start(); 
if (!isset($_SESSION["login"])){ 
  header("Location: login.php"); 
 exit(); 
} 
?> 
<HTML> 
<HEAD> 
  <TITLE>Tajne/poufne</TITLE> 
</HEAD> 
<BODY> 
<?php 
  echo "Witaj " . $_SESSION["login"]; 
  echo " < A href='logout.php?" . SID . "'>"; 
  echo "[Wyloguj]</ A>"; 
?> 
  <BR><B>Ściśle tajne dane.</B> 
</BODY> 
</HTML> 

User logged out

Tutaj nie ma już wiele roboty. Musimy tylko wznowić sesję, a następnie ją zniszczyć. Bułka z masłem.

logout.php – pełny kod

<?php 
session_start(); 
?> 
<HTML> 
<HEAD> 
  <TITLE>Wylogowanie</TITLE> 
</HEAD> 
<BODY> 
<?php 
  echo "Użytkownik " . $_SESSION["login"]; 
  echo " został wylogowany."; 
  session_destroy(); 
?> 
</BODY> 
</HTML> 

…i żyli długo i szczęśliwie.

To już koniec. Oczywiście ten artykuł nie jest wyczerpującym źródłem wiedzy na temat sesji w PHP. Miał on na celu tylko pokazać, iż w sumie jest to dość prosty w użyciu, a niezwykle użyteczny mechanizm. Uprzedzam, że nie uważam się za specjalistę w dziedzinie PHP, dlatego jeśli sądzicie, że można byłoby coś zrobić lepiej, albo że wręcz gadam głupoty, to pewnie macie racje (albo i nie ). Wszelkie uwagi będą mile widziane. Mam nadzieję, że uznacie ten artykuł za przydatny.

Pozdrawiam,
Marek LOCKOOM Pawłowski

Skasowane dane to nie zawsze tragedia - ściągnij program i odzyskaj dane