Menu
Jest wolny
rejestracja
Dom  /  Nawigatorzy/ Plik php dożywotni. Ciasteczka PHP - twórz, czytaj, usuwaj

Żywotność plików cookie PHP. Ciasteczka PHP - twórz, czytaj, usuwaj

Witaj kochana społeczność.

Przede wszystkim chcę podziękować za bardzo przydatne źródło. Nie raz znalazłem tu wiele ciekawych pomysłów i praktycznych porad.

Celem tego artykułu jest zwrócenie uwagi na pułapki korzystania z sesji w PHP. Oczywiście istnieje dokumentacja PHP i mnóstwo przykładów, a ten artykuł nie ma na celu kompletny przewodnik... Został zaprojektowany, aby ujawnić niektóre niuanse pracy z sesjami i chronić programistów przed niepotrzebną stratą czasu.

Najczęstszym przypadkiem użycia dla sesji jest oczywiście autoryzacja użytkownika. Zacznijmy od najbardziej podstawowego wdrożenia, abyśmy mogli je konsekwentnie rozwijać w miarę pojawiania się nowych wyzwań.

(Aby zaoszczędzić miejsce i czas, ograniczymy się do przykładów tylko przez funkcje pracy z sesjami, zamiast budować tutaj pełnoprawną aplikację testową z piękną hierarchią klas, wyczerpującą obsługą błędów i innymi poprawnymi rzeczami).

Funkcja startSession() (// Jeśli sesja została już uruchomiona, zatrzymaj wykonywanie i zwróć TRUE // (parametr session.auto_start w pliku ustawień php.ini musi być wyłączony - wartość domyślna) if (session_id()) return true; else return session_start ();// Uwaga: przed wersją 5.3.0 funkcja session_start () zwracała TRUE nawet w przypadku błędu. // Jeśli używasz wersji niższej niż 5.3.0, wykonaj dodatkową walidację session_id ( ) // po wywołaniu session_start() funkcji destroySession() (if (session_id()) (// Jeśli jest aktywna sesja, usuń ciasteczka sesyjne, setcookie (session_name(), session_id()), time() - 60 * 60 * 24); // i zniszcz sesję session_unset ( ); session_destroy (;))

Notatka: Zakłada się, że czytelnik ma podstawową wiedzę na temat sesji PHP, więc nie będziemy omawiać, jak działają funkcje session_start() i session_destroy(). Zadania związane z układem formularza logowania i uwierzytelnianiem użytkownika nie są związane z tematem artykułu, dlatego też je pominiemy. Przypomnę tylko, że aby zidentyfikować użytkownika w każdym kolejnym żądaniu, w momencie udanego logowania musimy zapisać identyfikator użytkownika w zmiennej sesyjnej (np. o nazwie userid), która będzie dostępna we wszystkich kolejnych żądania w czasie trwania sesji. Niezbędne jest również zaimplementowanie przetwarzania wyniku naszej funkcji startSession(). Jeśli funkcja zwraca FALSE, wyświetl formularz logowania w przeglądarce. Jeżeli funkcja zwróci TRUE, a zmienna sesji zawierająca identyfikator uprawnionego użytkownika (w naszym przypadku userid) istnieje, wyświetl stronę uprawnionego użytkownika (więcej informacji na temat obsługi błędów można znaleźć w dodatku z 2013-06- 07 w części dotyczącej zmiennych sesji).

Jak dotąd wszystko jest jasne. Pytania zaczynają się, gdy konieczne jest zaimplementowanie kontroli braku aktywności użytkowników (limit czasu sesji), umożliwienie kilku użytkownikom jednoczesnej pracy w jednej przeglądarce, a także ochrona sesji przed nieautoryzowanym użyciem. Zostanie to omówione poniżej.

Kontrolowanie bezczynności użytkowników za pomocą wbudowanych narzędzi PHP

Pierwszym pytaniem, które często pojawia się wśród twórców wszelkiego rodzaju konsol dla użytkowników, jest automatyczne zakończenie sesji w przypadku braku aktywności ze strony użytkownika. Nie może być prostsze, dzięki wbudowanym możliwościom PHP. (Ta opcja nie jest zbyt niezawodna i elastyczna, ale rozważmy ją pod kątem kompletności).

Function startSession() (// limit czasu nieaktywności użytkownika (w sekundach) $ sessionLifetime = 300; if (session_id ()) return true; // ustaw czas życia pliku cookie ini_set ("session.cookie_lifetime", $ sessionLifetime); // jeśli ustawiony jest limit czasu nieaktywności użytkownika, ustaw czas życia sesji na serwerze // Uwaga: W przypadku serwera produkcyjnego zaleca się ustawienie tych parametrów w pliku php.ini if ​​($ sessionLifetime) ini_set ("session.gc_maxlifetime", $ sessionLifetime );if (session_start ( )) (setcookie (session_name (), session_id (), czas () + $ sessionLifetime); zwróć true;) w przeciwnym razie zwróć false;)

Kilka wyjaśnień. Jak wiesz, PHP określa, którą sesję rozpocząć, na podstawie nazwy pliku cookie przekazanego przez przeglądarkę w nagłówku żądania. Z kolei przeglądarka otrzymuje to ciasteczko z serwera, na którym umieszcza je funkcja session_start(). Jeśli plik cookie wygasł w przeglądarce, nie zostanie przesłany w żądaniu, co oznacza, że ​​PHP nie będzie w stanie określić, którą sesję rozpocząć i potraktuje to jako utworzenie nowej sesji. Parametr Ustawienia PHP session.gc_maxlifetime, który jest ustawiony na czas nieaktywności naszego użytkownika, ustawia czas życia sesji PHP i jest monitorowany przez serwer. Kontrola czasu życia sesji działa w następujący sposób (tu rozważamy przykład przechowywania sesji w plikach tymczasowych jako najbardziej powszechną i domyślną wersję w PHP).

W momencie tworzenia nowej sesji tworzony jest plik o nazwie sess_ w katalogu ustawionym jako katalog do przechowywania sesji w parametrze ustawień PHP session.save_path. , gdzie - identyfikator sesji. Ponadto w każdym żądaniu, w momencie uruchomienia istniejącej sesji, PHP aktualizuje czas modyfikacji tego pliku. Tak więc w każdym kolejnym żądaniu PHP, na podstawie różnicy pomiędzy aktualnym czasem a czasem ostatniej modyfikacji pliku sesji, może określić, czy sesja jest aktywna, czy też jej czas życia już upłynął. (Mechanizm usuwania starych plików sesji jest omówiony bardziej szczegółowo w następnej sekcji).

Notatka: Należy tutaj zaznaczyć, że parametr session.gc_maxlifetime wpływa na wszystkie sesje w ramach jednego serwera (dokładniej w ramach jednego głównego Proces PHP). W praktyce oznacza to, że jeśli na serwerze działa kilka witryn, a każda z nich ma swój własny limit czasu bezczynności użytkowników, to ustawienie tego parametru na jednej ze stron spowoduje jego instalację również na innych. To samo dotyczy hostingu współdzielonego. Aby uniknąć takiej sytuacji, dla każdej witryny na jednym serwerze używane są oddzielne katalogi sesji. Ustawienie ścieżki do katalogu sesji odbywa się za pomocą parametru session.save_path w pliku ustawień php.ini lub poprzez wywołanie funkcji ini_set(). Następnie sesje każdego serwisu będą przechowywane w osobnych katalogach, a parametr session.gc_maxlifetime, ustawiony na jednej z witryn, będzie obowiązywał tylko dla jego sesji. Nie będziemy szczegółowo omawiać tego przypadku, zwłaszcza, że ​​mamy na stanie bardziej elastyczną opcję kontrolowania braku aktywności użytkownika.

Kontrolowanie braku aktywności użytkownika za pomocą zmiennych sesji

Wydawałoby się, że poprzednia opcja, przy całej swojej prostocie (tylko kilka dodatkowych linijek kodu), daje wszystko, czego potrzebujemy. Ale co, jeśli nie każde żądanie można uznać za wynik aktywności użytkownika? Na przykład strona ma zegar, który okresowo wysyła żądanie AJAX w celu otrzymywania aktualizacji z serwera. Takie żądanie nie może być traktowane jako aktywność użytkownika, co oznacza, że ​​automatyczne wydłużanie czasu trwania sesji nie jest w tym przypadku poprawne. Wiemy jednak, że PHP automatycznie aktualizuje czas modyfikacji pliku sesji przy każdym wywołaniu funkcji session_start(), co oznacza, że ​​każde żądanie prowadzi do wydłużenia czasu życia sesji, a czas braku aktywności użytkownika nigdy nie wystąpi. Dodatkowo ostatnia uwaga z poprzedniej sekcji dotycząca zawiłości parametru session.gc_maxlifetime może wydawać się zbyt zagmatwana i skomplikowana do zaimplementowania.

Aby rozwiązać ten problem, zrezygnujemy z używania wbudowanych Mechanizmy PHP oraz wprowadzimy kilka nowych zmiennych sesyjnych, które pozwolą nam samodzielnie kontrolować czas bezczynności użytkowników.

Funkcja startSession ($ isUserActivity = true) ($ sessionLifetime = 300; if (session_id ()) return true; // Ustaw czas życia ciasteczek do zamknięcia przeglądarki (będziemy kontrolować wszystko po stronie serwera) ini_set ("session.cookie_lifetime ", 0) ; if (! session_start ()) return false; $ t = time (); if ($ sessionLifetime) (// Jeśli ustawiony jest limit czasu nieaktywności użytkownika, // sprawdź czas, jaki upłynął od ostatniej aktywności użytkownika / / (czas ostatniego żądania, kiedy zmienna sesji lastactivity została zaktualizowana) if (isset ($ _ SESSION ["lastactivity"]) && $ t - $ _ SESSION ["lastactivity"]> = $ sessionLifetime) (// Jeśli czas, który upłynął od ostatniej aktywności użytkownika // więcej limitu czasu nieaktywności, to sesja wygasła i należy zakończyć sesję destroySession (); return false;) else (// jeśli limit czasu jeszcze nie nastąpił, // i jeśli żądanie pojawiło się w wyniku aktywności użytkownika, // zaktualizuj zmienną lastactivity o wartość bieżącego vr emeny, // wydłużając w ten sposób czas sesji o kolejne sekundy sessionLifetime if ($ isUserActivity) $ _SESSION ["lastactivity"] = $ t; )) zwróć prawdę; )

Podsumujmy. W każdym żądaniu sprawdzamy, czy limit czasu został osiągnięty od momentu ostatniej aktywności użytkownika do chwili obecnej, a jeśli zostanie osiągnięty, niszczymy sesję i przerywamy wykonanie funkcji, zwracając FALSE. Jeżeli timeout nie został osiągnięty, a do funkcji zostanie przekazany parametr $ isUserActivity z wartością TRUE, aktualizujemy czas ostatniej aktywności użytkownika. Wystarczy, że w wywołującym skrypcie ustalimy, czy żądanie jest wynikiem aktywności użytkownika, a jeśli nie, wywołamy funkcję startSession z wartością parametru $ isUserActivity równą FALSE.

Aktualizacja z dnia 2013-06-07
Przetwarzanie wyniku funkcji sessionStart ()

W komentarzach zauważyliśmy, że zwrócenie FALSE nie daje pełnego zrozumienia przyczyny błędu i jest to absolutnie prawda. Nie publikowałem tutaj szczegółowej obsługi błędów (objętość artykułu i tak nie jest mała), ponieważ nie odnosi się to bezpośrednio do tematu artykułu. Ale biorąc pod uwagę komentarze, wyjaśnię.

Jak widać, funkcja sessionStart może zwrócić FALSE w dwóch przypadkach. Sesja nie mogła zostać rozpoczęta z powodu niektórych błędy wewnętrzne serwer (na przykład złe ustawienia sesji w php.ini) lub sesja wygasła. W pierwszym przypadku musimy przekierować użytkownika na stronę z błędem, że występują problemy na serwerze i formą kontaktu z pomocą techniczną. W drugim przypadku musimy przenieść użytkownika do formularza logowania i wyświetlić w nim odpowiedni komunikat, że sesja wygasła. Aby to zrobić, musimy wprowadzić kody błędów i zwrócić odpowiedni kod zamiast FALSE, a następnie sprawdzić go w metodzie wywołującej i odpowiednio postępować.

Teraz, nawet jeśli sesja na serwerze nadal istnieje, zostanie zniszczona przy pierwszym dostępie, jeśli upłynął limit czasu nieaktywności użytkownika. A stanie się tak niezależnie od tego, jaki czas życia sesji jest ustawiony w globalnych ustawieniach PHP.

Notatka: Co się stanie, jeśli przeglądarka zostanie zamknięta, a plik cookie nazwy sesji zostanie automatycznie zniszczony? Żądanie do serwera przy następnym otwarciu przeglądarki nie będzie zawierało plików cookie sesji, a serwer nie będzie mógł otworzyć sesji i sprawdzić limitu czasu bezczynności użytkownika. Dla nas jest to równoznaczne z utworzeniem nowej sesji i nie wpływa w żaden sposób na funkcjonalność ani bezpieczeństwo. Ale pojawia się uczciwe pytanie - kto wtedy zniszczy starą sesję, jeśli zniszczyliśmy ją do tej pory po upływie limitu czasu? Czy może teraz zawiesi się w katalogu sesji na zawsze? Do czyszczenia starych sesji PHP ma mechanizm zwany garbage collection. Rozpoczyna się w momencie następnego żądania do serwera i czyści wszystkie stare sesje na podstawie daty Ostatnia zmiana pliki sesji. Ale mechanizm garbage collection nie uruchamia się przy każdym żądaniu do serwera. Częstotliwość (a dokładniej prawdopodobieństwo) uruchamiania jest określona przez dwa parametry ustawień session.gc_probability i session.gc_divisor. Wynikiem dzielenia pierwszego parametru przez drugi jest prawdopodobieństwo uruchomienia mechanizmu garbage collection. W związku z tym, aby mechanizm czyszczenia sesji uruchamiał się przy każdym żądaniu do serwera, parametry te muszą być ustawione na równe wartości, na przykład „1”. Takie podejście zapewnia, że ​​katalog sesji jest czysty, ale oczywiście jest zbyt obciążający dla serwera. Dlatego w systemach produkcyjnych session.gc_divisor jest domyślnie ustawione na 1000, co oznacza, że ​​silnik garbage collection zostanie uruchomiony z prawdopodobieństwem 1/1000. Jeśli poeksperymentujesz z tymi ustawieniami w swoim pliku php.ini, zauważysz, że w powyższym przypadku, gdy przeglądarka zamknie się i wyczyści wszystkie swoje pliki cookie, przez jakiś czas w katalogu sesji są jeszcze stare sesje. Ale to nie powinno cię martwić, ponieważ jak już wspomniano, w żaden sposób nie wpływa to na bezpieczeństwo naszego mechanizmu.

Aktualizacja z dnia 2013-06-07

Zapobieganie zawieszaniu się skryptów z powodu zablokowania pliku sesji

W komentarzach podnieśli kwestię zawieszania się jednocześnie działających skryptów z powodu zablokowania pliku sesji (jako najjaśniejsza opcja - długa sonda).

Na początek zauważam, że problem ten nie zależy bezpośrednio od obciążenia serwera ani liczby użytkowników. Oczywiście im więcej żądań, tym wolniej działają skrypty. Ale to jest zależność pośrednia. Problem pojawia się tylko w ramach jednej sesji, kiedy serwer otrzymuje kilka żądań w imieniu jednego użytkownika (np. jedno z nich to długi sondaż, a pozostałe to zwykłe żądania). Każde żądanie próbuje uzyskać dostęp do tego samego pliku sesji, a jeśli poprzednie żądanie nie odblokowało pliku, następne będzie zawieszone w oczekiwaniu.

Aby ograniczyć do minimum blokowanie plików sesji, zdecydowanie zaleca się zamknięcie sesji przez wywołanie funkcji session_write_close() natychmiast po wykonaniu wszystkich akcji ze zmiennymi sesji. W praktyce oznacza to, że nie należy przechowywać wszystkiego w zmiennych sesji i odwoływać się do nich podczas wykonywania skryptu. A jeśli konieczne jest przechowywanie jakichś danych roboczych w zmiennych sesyjnych, to od razu je odczytaj na początku sesji, zapisz w zmiennych lokalnych do późniejszego wykorzystania i zamknij sesję (czyli zamykając sesję za pomocą funkcji session_write_close, a nie niszcząc za pomocą session_destroy).

W naszym przykładzie oznacza to, że zaraz po otwarciu sesji, sprawdzeniu jej życia i istnienia autoryzowanego użytkownika, musimy odczytać i zapisać wszystkie dodatkowe zmienne sesji niezbędne dla aplikacji (jeśli są), a następnie zamknąć sesję za pomocą session_write_close ( ) wywołaj i kontynuuj wykonywanie skryptu, niezależnie od tego, czy jest to długa ankieta, czy zwykłe żądanie.

Ochrona sesji przed nieautoryzowanym użyciem

Wyobraźmy sobie sytuację. Jeden z Twoich użytkowników przechwytuje trojana, który okrada plik cookie przeglądarki (w którym przechowywana jest nasza sesja) i wysyła go na określony adres e-mail. Atakujący otrzymuje plik cookie i używa go do sfałszowania żądania w imieniu naszego autoryzowanego użytkownika. Serwer pomyślnie akceptuje i przetwarza to żądanie tak, jakby pochodziło od autoryzowanego użytkownika. Jeśli nie zostanie zaimplementowana dodatkowa weryfikacja adresu IP, taki atak doprowadzi do skutecznego włamania się na konto użytkownika ze wszystkimi wynikającymi z tego konsekwencjami.

Dlaczego jest to możliwe? Oczywiście, ponieważ nazwa i identyfikator sesji są zawsze takie same przez cały czas trwania sesji, a jeśli otrzymasz te dane, możesz swobodnie wysyłać żądania w imieniu innego użytkownika (oczywiście w czasie trwania tej sesji). Być może nie jest to najczęstszy rodzaj ataków, ale teoretycznie wszystko wygląda na całkiem wykonalne, zwłaszcza biorąc pod uwagę, że taki trojan nie potrzebuje nawet uprawnień administratora, aby obrabować pliki cookie przeglądarki użytkownika.

Jak bronić się przed tego typu atakami? Ponownie, oczywiście poprzez ograniczenie czasu życia identyfikatora sesji i okresową zmianę identyfikatora w ramach jednej sesji. Możemy również zmienić nazwę sesji, całkowicie usuwając starą i tworząc nową sesję, kopiując do niej wszystkie zmienne sesyjne ze starej. Nie wpływa to jednak na istotę podejścia, dlatego dla uproszczenia ograniczymy się tylko do identyfikatora sesji.

Oczywiste jest, że im krótszy czas życia identyfikatora sesji, tym mniej czasu atakujący będzie musiał uzyskać i wykorzystać pliki cookie do sfałszowania żądania użytkownika. W idealnym przypadku do każdego żądania należy użyć nowego identyfikatora, co zminimalizuje możliwość wykorzystania cudzej sesji. Rozważymy jednak ogólny przypadek, w którym czas regeneracji identyfikatora sesji jest ustalany arbitralnie.

(Pomińmy część kodu, która została już omówiona).

Funkcja startSession ($ isUserActivity = true) (// Okres istnienia identyfikatora sesji $ idLifetime = 60; ... if ($ idLifetime) (// Jeśli ustawiony jest okres istnienia identyfikatora sesji, // sprawdź czas, jaki upłynął od utworzenia sesji lub ostatnia regeneracja // (czas ostatniego żądania, kiedy zmienna sesji starttime została zaktualizowana) if (isset ($ _ SESSION ["starttime"])) (if ($ t - $ _ SESSION ["starttime"]> = $ idLifetime) (// Czas wygaśnięcia identyfikatora sesji // Wygeneruj nowy identyfikator session_regenerate_id (true); $ _SESSION ["starttime"] = $ t;)) else (// Dostajemy tutaj, jeśli sesja została właśnie utworzona // Ustaw czas generowania identyfikatora sesji w bieżącym czasie $ _SESSION ["czas startu"] = $ t;)) return true;)

Czyli tworząc nową sesję (co następuje, gdy użytkownik pomyślnie się zaloguje) ustawiamy zmienną sesji starttime, która przechowuje dla nas czas ostatniego wygenerowania identyfikatora sesji, na wartość równą aktualnemu czasowi serwera. Ponadto w każdym żądaniu sprawdzamy, czy minęło wystarczająco dużo czasu (idLifetime) od ostatniej generacji identyfikatora, a jeśli minął, generujemy nowy. Tak więc, jeśli w określonym czasie życia identyfikatora atakujący, który otrzymał plik cookie autoryzowanego użytkownika, nie zdoła z niego skorzystać, fałszywe żądanie zostanie uznane przez serwer za nieautoryzowane, a atakujący zostanie przeniesiony na stronę logowania.

Notatka: Nowy identyfikator sesji dostaje się do pliku cookie przeglądarki po wywołaniu funkcji session_regenerate_id(), która wysyła nowe cookie, podobnie jak funkcja session_start(), więc nie musimy sami aktualizować plików cookie.

Jeśli chcemy maksymalnie zabezpieczyć nasze sesje, wystarczy ustawić czas życia identyfikatora na jeden lub nawet umieścić funkcję session_regenerate_id() poza nawiasami i usunąć wszystkie sprawdzenia, co doprowadzi do regeneracji identyfikatora w każdym wniosku. (Nie testowałem wpływu takiego podejścia na wydajność i mogę tylko powiedzieć, że funkcja session_regenerate_id (true) zasadniczo wykonuje tylko 4 akcje: generowanie nowego identyfikatora, tworzenie nagłówka z pliku cookie sesji, usuwanie starego i tworzenie nowego pliku sesji).

Dygresja liryczna: Jeśli trojan okaże się na tyle sprytny, że nie będzie wysyłał plików cookie do atakującego, ale sam zorganizuje wysłanie wcześniej przygotowanego fałszywego żądania natychmiast po otrzymaniu pliku cookie, opisana powyżej metoda najprawdopodobniej nie będzie w stanie ochronić przeciwko takiemu atakowi, ponieważ od momentu otrzymania przez trojana pliku cookie do wysłania fałszywego nie będzie praktycznie żadnej różnicy w żądaniu, a istnieje duże prawdopodobieństwo, że identyfikator sesji nie zostanie w tym momencie odtworzony.

Możliwość jednoczesnej pracy w jednej przeglądarce w imieniu kilku użytkowników

Ostatnim zadaniem, które chciałbym rozważyć, jest możliwość jednoczesnej pracy w jednej przeglądarce dla kilku użytkowników. Ta funkcja jest szczególnie przydatna na etapie testów, kiedy trzeba emulować jednoczesną pracę użytkowników i wskazane jest, aby zrobić to w ulubionej przeglądarce, a nie korzystać z całego dostępnego arsenału lub otwierać wielu instancji przeglądarki w trybie „incognito”. " tryb.

W naszych poprzednich przykładach nie ustawiliśmy jawnie nazwy sesji, więc użyliśmy domyślnej nazwy PHP (PHPSESSID). Oznacza to, że wszystkie dotychczas utworzone przez nas sesje wysyłały do ​​przeglądarki pliki cookie o nazwie PHPSESSID. Oczywiście, jeśli nazwa pliku cookie jest zawsze taka sama, to w jednej przeglądarce nie ma możliwości zorganizowania dwóch sesji z to samo imię... Ale jeśli użyjemy innej nazwy sesji dla każdego użytkownika, problem zostanie rozwiązany. Więc zrobimy to.

Funkcja startSession ($ isUserActivity = true, $ prefix = null) (... if (session_id ()) return true; // Jeśli prefiks użytkownika jest przekazany w parametrach, // ustaw unikalną nazwę sesji, która zawiera to prefiks, // w przeciwnym razie ustaw nazwę wspólną dla wszystkich użytkowników (na przykład MÓJPROJEKT) nazwa_sesji ("MÓJPROJEKT" ($prefiks? "_". $prefiks: "")); ini_set ("session.cookie_lifetime", 0) ;if (! session_start ()) zwraca false;...)

Teraz pozostaje tylko upewnić się, że skrypt wywołujący przekazuje unikalny prefiks dla każdego użytkownika do funkcji startSession(). Można to zrobić np. poprzez przekazanie prefiksu w parametrach GET/POST każdego żądania lub poprzez dodatkowe ciasteczko.

Wniosek

Na zakończenie podam pełny kod końcowy naszych funkcji do pracy z sesjami PHP, łącznie ze wszystkimi zadaniami omówionymi powyżej.

Funkcja startSession ($ isUserActivity = true, $ prefix = null) ($ sessionLifetime = 300; $ idLifetime = 60; if (session_id ()) return true; session_name ("MYPROJECT". ($ Prefix? "_"). $ Prefix: "")); ini_set ("session.cookie_lifetime", 0); if (! session_start ()) return false; $ t = time (); if ($ sessionLifetime) (if (isset ($ _ SESSION ["lastactivity" ] ) && $ t - $ _ SESSION ["lastactivity"]> = $ sessionLifetime) (destroySession (); return false;) else (if ($ isUserActivity) $ _SESSION ["lastactivity"] = $ t;)) if ( $ idLifetime ) (if (isset ($ _ SESSION ["starttime"])) (if ($ t - $ _ SESSION ["starttime"]> = $ idLifetime) (session_regenerate_id (true); $ _SESSION ["starttime"] = $ t; )) else ($ _SESSION ["starttime"] = $ t;)) return true;) function destroySession () (if (session_id ()) (session_unset (); setcookie (session_name (), session_id ()) , czas () -60 * 60 * 24); session_destroy ();))

Mam nadzieję, że ten artykuł zaoszczędzi trochę czasu tym, którzy nigdy tak naprawdę nie zagłębili się w mechanizm sesji, a także da wystarczające zrozumienie tego mechanizmu tym, którzy dopiero zaczynają zapoznawać się z PHP.

Nuuu, wymyślmy to.

Najpierw przeczytaj o HTTP na tej samej wiki. Nie musisz wiedzieć dokładnie, ale powinieneś mieć minimalne zrozumienie struktury żądań/odpowiedzi, zrozum, że żądanie i odpowiedź mają nagłówki i treść (może nie być treści, w zależności od typu żądania/ odpowiedź).

Więc to jest to. Ciasteczka. Pliki cookie znajdują się po stronie przeglądarki. Są one przesyłane przez nagłówek HTTP dla każdego żądania do serwera (nawet jeśli szukałeś zdjęć). Są tylko ciasteczka, są tylko ciasteczka http. Pliki cookie można rozróżnić według hosta i ścieżki. Wszystko to daje nam elastyczność i pomaga w bezpieczeństwie. W PHP zawartość $_COOKIE dostarcza nam SAPI. Gdy PHP otrzyma żądanie do przetworzenia, użyte SAPI (php-fpm, cgi, mod_php mają swoje implementacje SAPI) w ten moment pobiera nagłówki i treść żądania, analizuje je i wypełnia wszystkie te superglobalne tablice, takie jak $_SERVER, $_GET, w tym $_COOKIE. Wszystko, co wysłał nam klient (coś, co wysyła żądania to klient, coś, co je przetwarza, to serwer), a przeglądarka wysyła nam tylko te pliki cookie, które są możliwe na podstawie tego, gdzie wysyłane jest żądanie. Ciasteczka są ustawiane przez nagłówek Set-Cookie w odpowiedzi, czyli tutaj musisz przeczytać więcej w zasadzie o HTTP, a nie o PHP. PHP po prostu pozwala ci pracować z tymi rzeczami. Możesz ustawić pliki cookie bezpośrednio, pracując z nagłówkami odpowiedzi za pomocą funkcji nagłówka. Co więcej, jeśli ustawisz czas życia plików cookie na 0, to one, a nie sesja, zostaną zresetowane po zamknięciu przeglądarki, ponieważ zapomni ona wszystkie takie pliki cookie.

Oto ... sesje ... B Sesja PHP zwykle plik. Tylko jakiś plik z losową nazwą. Jeśli, powiedzmy, session.autostart jest określone w php.ini lub wywoływana jest session_start, to tworzony jest plik dla sesji użytkownika (możesz go przenieść do redis lub memcache, swojego magazynu itp., w zależności od potrzeb. Możesz również szyfrować dane, co dzieje się domyślnie ). Ten plik ma identyfikator, tylko losowy ciąg. A jeśli podczas przetwarzania żądania nie zostanie znaleziona sesja z poprzedniego żądania, tworzona jest nowa.

A teraz dochodzimy do najciekawszego - jak PHP wiąże sesję z poprzedniego żądania z bieżącym. A tutaj wszystko jest całkiem proste - ciasteczka. Kiedy sesja jest przypisywana użytkownikowi, automatycznie ustawiany jest plik cookie tylko http (aby źli ludzie nie mogli usunąć naszej sesji z js) plik cookie, w którym zapisany jest identyfikator sesji. W debuggerze przeglądarki możesz sprawdzić, czy masz plik cookie PHPSESSID (nazwę można zmienić w ustawieniach, a ogólnie sesje można łączyć nie tylko za pomocą plików cookie, ale są to już długopisy zabezpieczające) podczas eksperymentowania z sesjami.

Gdy żądanie jest przetwarzane przez SAPI, w obecności session.autostart, przed rozpoczęciem tworzenia nowej sesji nadal sprawdza, czy mamy plik cookie z identyfikatorem sesji, sprawdza, czy go ma, a jeśli tak, uspokaja i nie tworzy nowego. Ponieważ sesja jest powiązana za pomocą plików cookie, możesz ustawić czas życia tego samego pliku cookie (w php.ini), a tym samym dostosować czas życia sesji.

Tutaj ... kiedy używać plików cookie, a kiedy sesje? Wskazane jest, aby zrozumieć, że im więcej danych w plikach cookie (i mają one limit słów), tym więcej danych przesyłamy dla każdego żądania. To znaczy, że nie jest fajnie, gdy aby otrzymać 1 kilobajt danych, musimy przesłać kilka kilobajtów plików cookie w nagłówkach. Ludzie skupieni na optymalizacji przechowują nawet zdjęcia w oddzielnych domenach bez plików cookie, aby zmniejszyć ruch i pakiety (zwykle prosty żądanie HTTP mieści się w rozmiarze jednego pakietu TCP). Jeśli musisz pracować z tymi danymi z JS na dowolnej stronie, na przykład w ustawieniach regionalnych wybranych przez użytkownika, aby zastosować tłumaczenia również w JS, powinieneś użyć plików cookie. Do wszystkiego innego najlepiej oczywiście używać sesji. W każdym razie na początkowych etapach, kiedy coś bardzo skomplikowanego nie będziesz musiał robić.

HTTP to bezstanowy protokół żądań. Oznacza to, że użytkownik wysyła żądanie, serwer odpowiada na to żądanie bez późniejszego zapamiętywania żądania. W celu śledzenia ważna informacja(np. preferencje użytkownika, działania użytkownika itp.) na stronie, gdy: Pomoc PHP tworzone są pliki cookie, no lub pliki cookie. W tym artykule opowiem o tym, jak pracować z plikami cookie, jak je tworzyć, jakie mają parametry i jak je usunąć.

Co to jest plik cookie?

Pliki cookie są bardzo przydatne do przechowywania informacji bezpośrednio w samej przeglądarce użytkownika. To proste plik tekstowy który przechowuje maksymalnie 4kb danych.

Cookies tworzone są za pomocą przeglądarki na żądanie serwera (zgodnie z logiką programu). Po utworzeniu pliku cookie po stronie użytkownika przeglądarka użytkownika przesyła tę informację (z pliku cookie) z powrotem do serwera za pomocą nagłówka HTTP.

Pliki cookie często przechowują loginy, hasła i nie tylko. Na przykład wchodzisz na stronę, wpisujesz swoją nazwę użytkownika i hasło. Witryna automatycznie tworzy dla Ciebie plik cookie z tymi danymi. A przy następnej wizycie na stronie po prostu sprawdza obecność plików cookie i ładuje zapisane w nich dane użytkownika.

// Przykładowa strona indeksowa dla takiej witryny if ($_COOKIE ["login"]) (nagłówek ("lokalizacja: /lk/index.php?login=".$_COOKIE ["login"]);/) / Przelewy bezpośrednio na konto osobiste ) // Dalej jest np. formularz logowania i rejestracji

Dlaczego ciasteczko?

HTTP jest protokołem bezstanowym, więc nie ma możliwości śledzenia wcześniejszych działań użytkownika w witrynie. Pliki cookie są Najlepszym sposobem do przechowywania danych. Wiem wszystko o ciasteczkach pragnień, które łamiesz, a w środku kartka z tym, co może ci się przydarzyć w przyszłości. Jak dla mnie to stąd wyrastają nogi, o imię.

Pliki cookie PHP

Właściwie, skoro już wyjaśniłem, co to jest, dowiedzmy się, jak ustawić pliki cookie w PHP.

Używamy metody SetCookie() w celu ustawienia plików cookie w przeglądarce użytkownika.

Składnia do ustawiania plików cookie w PHP

Setcookie (nazwa, wartość, godzina, ścieżka, domena, bezpieczne);

nazwa — określa nazwę pliku cookie.

val — wartość, którą chcemy przechowywać w pliku cookie. Plik cookie zawsze przechowuje wartość ciągu.

czas (opcjonalnie) — Ustaw czas wygaśnięcia pliku cookie. Jeśli to pole jest puste, pliki cookie zostaną usunięte po zamknięciu przeglądarki.

domena (opcjonalnie) — ustaw domenę, w której plik cookie jest dostępny. Jeśli chcesz ustawić pliki cookie dla wielu subdomen, użyj nazwy domeny głównej z kropką jako prefiksem.

Na przykład:

Niech my.com ma wiele subdomen, takich jak tech.my.com, only.my.com. I chcę, aby plik cookie ustawiony w my.com był dostępny dla wszystkich moich subdomen, a następnie ustawiam domenę na .my.com.

bezpieczne (opcjonalne) — określa, czy plik cookie powinien być przesyłany przez bezpieczne połączenie HTTPS. Wartość domyślna to FAŁSZ. Jeśli ta jest ustawiona na true, oznacza to, że plik cookie zostanie ustanowiony tylko wtedy, gdy istnieje bezpieczne połączenie i logiczne jest, że nie zostanie utworzony podczas HTTP.

Setcookie („login”, „valera123”);

Korzystając z powyższego skryptu, utworzymy plik cookie o nazwie login i wartości valera123.

Uwaga: pliki cookie mogą przechowywać tylko wartości ciągów. Nie mogą przechowywać tablicy. Aby przechowywać tablicę w plikach cookie, musisz najpierw przekonwertować je na ciąg. Na pewno powiem o tym później.

Uwaga: jak zauważyłeś, nie ustawiłem czasu życia naszego pliku cookie. Dlatego zniknie po zamknięciu naszej przeglądarki…

Nasz plik cookie zostanie ustawiony przy użyciu metody SetCookie(). Po wykonaniu skryptu z określoną metodą możesz łatwo sprawdzić plik cookie w panelu programisty w chrome lub w firebugu w firefox.


Nie zdefiniowaliśmy czasu wygaśnięcia pliku cookie. Dajmy to 30 dni. W tym przypadku musimy wspomnieć o czasie. Następnie będzie działać przez 30 dni, dopóki użytkownik go ręcznie nie usunie.

Setcookie („login”, „valera123”, czas () + 3600 * 24 * 30);

3600 - 1 godzina
24 - dzień
30 dni

Jak ustawić pliki cookie dla subdomen

setcookie („login”, „valera123”, czas () + 3600 * 24 * 30, „/”, „. my.com”);

Właściwie ten przykład został już podany.

Jak uzyskać wartość pliku cookie w PHP

$ _COOKIE - Używany do uzyskania wartości pliku cookie. Poniżej znajduje się kod, jak dokładnie można uzyskać wartość ustawionego wcześniej pliku cookie.

$ val = $ _COOKIE ["logowanie"]; echo $ val; // wypisze valera123

Jak usunąć pliki cookie w PHP

Aby usunąć pliki cookie w PHP, ustaw ujemny czas (czas, który upłynął).

Setcookie („login”, „valera123”, czas () - 3600 * 24);

Co się stanie, jeśli ustawimy czas ujemny. W takim przypadku plik cookie wygaśnie automatycznie.

Ważne punkty dotyczące plików cookie

1. Cook może przechowywać maksymalnie 4 KB danych.

2. Może przechowywać tylko ciągi.

3. Dostęp do plików cookie ma tylko przeglądarka, która je ustawia. Ciasteczka ustawione w Przeglądarka Chrome może nie być dostępny w Przeglądarka Mozilli lub jakiś inny.

4. Staraj się unikać przechowywania w plikach cookies poufnych i wysoce wrażliwych danych.

Właściwie to wszystko. Naprawdę mam nadzieję, że spodobała Ci się ta linia, podziel się swoją opinią w komentarzach, a także nie zapomnij o ponownym opublikowaniu.

Okres działania zmiennych PHP $_SESSION, a co za tym idzie aktywność aplikacji webowych zależy od czasu trwania sesji. Przykładowo, jeśli użytkownik jest autoryzowany w systemie, to od tego parametru zależy czas, przez jaki może być bezczynny bez konieczności ponownego wpisywania loginu i hasła.

istnieje różne sposoby ustawienie czasu trwania sesji. Spróbujmy to rozgryźć na przykładzie system operacyjny Linuksa.

Jak sprawdzić czas trwania sesji?

Przed skonfigurowaniem warto się przyjrzeć Stan obecny... Można to zrobić na kilka sposobów:

1. Na serwerze za pomocą polecenia php

php -i | sesja grep

Otrzymujemy listę parametrów związanych z sesjami. Jesteśmy zainteresowani:

  • session.cookie_lifetime => 0 => 0
  • session.gc_maxlifetime => 1440 => 1440

Te wartości są wartościami domyślnymi. cookie_lifetime => 0 wskazuje działanie ciasteczek do zamknięcia przeglądarki, jeśli ustawisz ten parametr na określoną wartość, sesja zostanie przerwana w czasie, gdy sesja jest aktywna, dlatego lepiej pozostawić ją na zero.

2. Korzystanie z funkcji php ini_get

$ maxlifetime = ini_get ("session.gc_maxlifetime");
$ cookielifetime = ini_get ("session.cookie_lifetime");

Echo $ maxżywotność;
echo $ cookielifetime;

systemctl restart apache2 || systemctl zrestartuj httpd

* w wersjach Linuksa bez systemd użyj polecenia restart usługi Apache2 lub usługa httpd restart.

Jeśli używamy FastCGI (PHP-FPM):

Personalizacja za pomocą pliku .htaccess

Plik ten umożliwia webmasterowi zarządzanie niektórymi ustawieniami serwera WWW. Aby go edytować, potrzebujesz dostępu do plików witryny. Metoda nie zadziała, jeśli handler PHP nie jest Apache, ale na przykład NGINX + PHP-FPM. Chociaż jest też sposób (o nim poniżej).

Dodaj następujące elementy do pliku .htaccess:

sesja php_value.gc_maxlifetime 86400
php_value session.cookie_lifetime 0

* jak widać parametry są takie same jak przy konfiguracji przez php.ini.

Jak wspomniano powyżej, ta metoda nie zadziała, jeśli nie zostanie użyty Apache. Konfiguracji możemy jednak dokonać na serwerze (znów musimy mieć odpowiedni dostęp).

Otwórz plik konfiguracyjny serwera WWW, na przykład w php-fpm:

vi /etc/php-fpm.d/www.conf

i edytuj / dodaj:

wartość_php = 86400
wartość_php = 0

Po ponownym uruchomieniu usługi:

systemctl restart php-fpm || usługa restart php-fpm

Ustawianie parametru w kodzie aplikacji

Ta metoda może być przydatna, gdy różne strony portalu muszą mieć inny czas sesja życiowa. W tym celu możesz użyć funkcji PHP ini_set i session_set_cookie_params, na przykład:

Ini_set („session.gc_maxlifetime”, 86400);
ini_set ("session.cookie_lifetime", 0);
session_set_cookie_params (0);

Rozpoczęcie_sesji ();

Funkcje muszą zostać wywołane przed otwarciem sesji (session_start).

Konfigurowanie sesji w aplikacji

Niektóre aplikacje mogą zastąpić te ustawienia. W takim przypadku konieczne jest ustawienie czasu trwania sesji w parametrach programu. Każda aplikacja ma swoje własne ustawienia, które musisz samodzielnie ustalić. Podajmy na przykład założenie sesji w CMS Bitrix.

Iść do Grupy użytkowników- wybierz grupę - Bezpieczeństwo... Znajdź parametr „Czas życia sesji (minuty)” i ustaw czas, na przykład 1440 (24 godziny w minutach).

Jak automatycznie odnawiać sesje

Jeżeli sesja jest wydawana na określony okres i kończy się o określony czas, może to przerwać aktywną sesję użytkownika. O wiele wygodniej jest, jeśli czas trwania sesji zostanie automatycznie przedłużony, jeśli odwiedzający odświeży stronę. Do tego służy parametr cookie_lifetime, który we wszystkich powyższych przykładach ustawiamy na 0.

Jeżeli ustawimy wartość cookie_lifetime na 86400, to po 24 godzinach sesja zostanie zakończona. Nie zawsze jest to wygodne.

Jeśli istnieje potrzeba kontrolowania i przerywania sesji, można skorzystać z funkcji php session_destroy ().

Ścieżka przechowywania pliku sesji

Miejsce przechowywania plików sesji jest ustawiane przez parametr sesja.zapisz_ścieżkę tak samo jest z czasem życia. Domyślnie można użyć ścieżki / var / lib / php / sesje.

to ważny parametr- jeśli serwer WWW nie ma uprawnień do zapisu w tym katalogu, spowoduje to niemożność przechowywania sesji, co spowoduje nieoczekiwane wyniki aplikacji.

Serwer WWW nie utrzymuje stałego połączenia z klientem, a każde żądanie jest traktowane jak nowe, bez żadnego połączenia z poprzednimi.
Oznacza to, że nie możesz ani śledzić żądań tego samego gościa, ani zapisywać dla niego zmiennych między wyświetleniami. poszczególne strony... Sesje zostały wymyślone, aby rozwiązać te dwa problemy.
Właściwie sesje, w skrócie, to mechanizm, który pozwala jednoznacznie zidentyfikować przeglądarkę i tworzy plik dla tej przeglądarki na serwerze, który przechowuje zmienne sesji.

Nie będę szczegółowo opisywał potrzeby takiego mechanizmu. Są to takie podręcznikowe przypadki jak koszyk w e-sklepie, autoryzacja, a także nie do końca trywialne problemy, jak np. zabezpieczenie interaktywnych części serwisu przed spamem.

W zasadzie dość łatwo jest stworzyć własny analog sesji, nie tak funkcjonalny jak wbudowany PHP, ale podobny w istocie. Na ciasteczkach i bazie danych.
Gdy żądamy skryptu, sprawdzamy, czy dotarł plik cookie o określonej nazwie. Jeśli nie ma ciasteczka, ustaw je i wpisz nową linię z danymi użytkownika do bazy danych. Jeśli jest plik cookie, to odczytujemy z bazy danych. Z jeszcze jednym żądaniem usuwamy stare rekordy z bazy, a teraz mamy gotowy mechanizm sesji. To wcale nie jest trudne. Istnieją jednak pewne niuanse, które sprawiają, że lepiej jest korzystać z wbudowanego mechanizmu sesji.

Jeśli włączony jest tylko pierwszy, to na początku sesji (przy każdym połączeniu) sesja_start ()) plik cookie jest instalowany dla klienta. Przeglądarka poprawnie zwraca to ciasteczko przy każdym kolejnym żądaniu, a PHP ma identyfikator sesji. Problemy zaczynają się, jeśli przeglądarka nie zwraca plików cookie. W takim przypadku PHP zawsze rozpocznie nową sesję bez odbierania ciasteczek z identyfikatorem, a mechanizm nie będzie działał.

Jeśli włączony jest tylko drugi, plik cookie nie jest ustawiony. A co się dzieje, to w imię czego w zasadzie tak naprawdę warto skorzystać z wbudowanego mechanizmu sesji. Gdy skrypt wykona swoje zadanie, a strona jest w pełni uformowana, PHP przegląda to wszystko i dołącza identyfikator sesji do każdego łącza i do każdego formularza. Wygląda to mniej więcej tak:
Indeks przemienia się w
Indeks
a do formularzy dodawane jest ukryte pole

A przeglądarka, gdy klikniesz w dowolny link, lub gdy klikniesz przycisk w formularzu, wyśle ​​w żądaniu potrzebną nam zmienną - identyfikator sesji!
Z oczywistych powodów identyfikator jest dodawany tylko do linków względnych.

Teoretycznie w naszych domowych sesjach na ciasteczkach i bazie danych możesz ręcznie przypisać transfer id do wszystkich linków - wtedy nasze własne sesje będą działały niezależnie od ciasteczek. Ale widzisz - przyjemniej jest, gdy ktoś inny to robi? ;-)

Obie opcje są domyślnie włączone w najnowszych wersjach PHP. Jak PHP sobie z tym radzi? Kucharz jest zawsze wystawiany. A linki są automatycznie uzupełniane tylko wtedy, gdy PHP nie znajdzie pliku cookie z identyfikatorem sesji. Kiedy użytkownik odwiedza witrynę po raz pierwszy podczas tej sesji, otrzymuje plik cookie i dodawane są linki. Przy następnym żądaniu, jeśli pliki cookie są obsługiwane, PHP widzi plik cookie i przestaje uzupełniać linki. Jeśli pliki cookie nie działają, PHP kontynuuje prawidłowe dodawanie id do linków, a sesja nie jest tracona.
Użytkownicy, którzy mają działające pliki cookie, zobaczą długi link z identyfikatorem tylko raz.

Fuh. Wraz z zakończeniem przesyłania identyfikatora.
Teraz pozostaje powiązać z nim plik z danymi po stronie serwera.
PHP zrobi to za nas. Wystarczy tylko napisać
start_sesji ();
$ _SESSION ["test"] = "Witaj świecie!" ;

A PHP zapisze zmienną test do pliku powiązanego z tą sesją.
Jest tu bardzo ważny punkt.
Szyk $_SESJA- specjalny.
W rzeczywistości są w nim zmienne, które chcemy udostępnić w różnych skryptach.
Aby umieścić zmienną w sesji wystarczy przypisać ją do elementu tablicy $_SESSION.
Aby uzyskać jego wartość, wystarczy odwołać się do tego samego elementu. Przykład będzie poniżej.

Wywóz śmieci - usuwanie przestarzałych Pliki PHP robi to też sam. A także kodowanie danych i kilka innych niezbędnych rzeczy. Dzięki tej trosce praca z sesjami jest bardzo łatwa.
Oto jesteśmy w rzeczywistości i dochodzimy do przykładu pracy sesji.
Przykład jest bardzo mały:
start_sesji ();

Echo „Zaktualizowałeś tę stronę”... $_SESJA ["licznik"] ++. " pewnego razu. " ;
Echo "
aktualizacja ";
?>

Sprawdzamy, czy mamy w sesji zmienną licznikową, jeśli nie, tworzymy ją z wartością 0, a następnie wypisujemy jej wartość i zwiększamy ją o jeden. Zwiększona wartość zostanie zapisana w sesji, a przy następnym wywołaniu skryptu zmienna będzie miała wartość 1 i tak dalej.
Wszystko jest bardzo proste.

Aby mieć dostęp do zmiennych sesji na dowolnych stronach serwisu, należy napisać TYLKO JEDEN (!) wiersz na samym początku KAŻDEGO pliku, w którym potrzebujemy sesji:
start_sesji ();
A następnie odwołaj się do elementów tablicy $_SESSION. Na przykład sprawdzenie autoryzacji wyglądałoby mniej więcej tak:
start_sesji ();
if ($ _SESSION ["autoryzowany"]<> 1 ) {
nagłówek ("Lokalizacja: /auth.php");
Wyjście;
}

Usuwanie zmiennych z sesji.
Jeśli masz register_globals = off, po prostu napisz
nieustawiona ($ _ SESSION ["zmienna"]);
Jeśli nie wtedy w pobliżu muszę z nią napisać
session_unregister ("zmienna");

Najczęstsze błędy, które pojawiają się w PHP podczas próby pracy z sesjami, to:
Dwoje z nich,
Ostrzeżenie: nie można wysłać pliku cookie sesji - nagłówki już wysłane
Ostrzeżenie: nie można wysłać ogranicznika pamięci podręcznej sesji - nagłówki już wysłane

z tego samego powodu, rozwiązanie jest opisane w tym fakcie
Trzeci,
Ostrzeżenie: otwarcie (/ tmp \ sess_SID, O_RDWR) nie powiodło się: brak takiego pliku lub katalogu (2) w pełnej_ścieżce_skryptu w wierszu numer(wcześniej wyglądała jak Ostrzeżenie: nie udało się zapisać danych sesji (plików). Sprawdź, czy bieżące ustawienie session.save_path jest poprawne (/tmp)),
jeśli przetłumaczony z angielskiego, szczegółowo wyjaśnia problem: ścieżka określona w php.ini do katalogu, w którym zapisywane są pliki sesji, jest niedostępna. Ten błąd jest najłatwiejszy do naprawienia. Po prostu napisz katalog, który istnieje i jest zapisywalny, na przykład
session.save_path = c: \ windows \ temp
I nie zapomnij ponownie uruchomić Apache po tym.

Jak się okazuje, ludzka inteligencja nie ma granic, dlatego muszę wyjaśnić:
trzeci komunikat o błędzie (nie można znaleźć katalogu) będzie prowadzić do dwóch pierwszych, ponieważ komunikat o błędzie jest wysyłany do przeglądarki i nie można używać po nim nagłówków. Dlatego nie spiesz się, aby szukać przedwczesnych wniosków, ale najpierw napisz prawidłową ścieżkę!

Następnym najczęstszym problemem związanym z sesjami jest ciężkie dziedzictwo register_globals. NIE NAdaj zmiennym skryptu takich samych nazw jak indeksy tablicy $_SESSION!
Z register_globals = on, wartości będą się nadpisywać i będziesz zdezorientowany.
A jeśli register_globals = off, pojawi się kolejny błąd: "Twój skrypt prawdopodobnie opiera się na efekcie ubocznym sesji, który istniał do PHP 4.2.3." ... Aby się go pozbyć, należy zawsze zainicjalizować zmienne przed użyciem (lub przynajmniej sprawdzić ich istnienie) i nie podawać nazw globalnych zmiennych, które pasują do indeksów tablicy $_SESSION.

Jeśli to nie działa, ale nie są też wyświetlane żadne komunikaty, dodaj dwie linie na samym początku skryptu, które są odpowiedzialne za wyświetlanie WSZYSTKICH błędów na ekranie - całkiem możliwe, że są błędy, ale po prostu nie widzisz im.
ini_set ("display_errors", 1);
raportowanie_błędów (E_ALL);

lub zobacz błędy w error_log. Ogólnie rzecz biorąc, temat wyświetlania komunikatów o błędach wykracza poza zakres tego artykułu, więc upewnij się, że przynajmniej je widzisz. Więcej informacji na temat rozwiązywania problemów znajdziesz w tej sekcji.

Jeśli jesteś pewien, że nie ma błędów, ale podany przykład i tak nie działa, to możliwe, że PHP nie umożliwia przesyłania id przez url, a ciasteczka z jakiegoś powodu nie działają.
Zobacz, co masz z ciasteczkami.
Generalnie, jeśli Twoje sesje „nie działają”, to najpierw spróbuj ręcznie przenieść identyfikator sesji, czyli zrób link i przypisz mu identyfikator:
start_sesji ();
if (! isset ($ _ SESSION ["licznik"])) $ _SESSION ["licznik"] = 0;
Echo „Zaktualizowałeś tę stronę”... $_SESJA ["licznik"] ++. " pewnego razu.

aktualizacja ";
?>

Robiąc to, upewnij się, że dyrektywa session.use_only_cookies nie jest włączona, co uniemożliwia PHP akceptowanie identyfikatora sesji, jeśli został on przekazany przez adres URL.

Jeśli ten przykład nie działa, problem jest albo banalny literówki(połowa „problemów” z sesjami pochodzi z błędnej nazwy zmiennej) lub też stara wersja PHP: obsługa sesji została wprowadzona w wersji 4.0, a tablica $_SESJA- w 4.1 (wcześniej używany) $ HTTP_SESSION_VARS).
Jeśli to działa, problem tkwi w plikach cookie. Śledź, jaki rodzaj pliku cookie serwer umieszcza w przeglądarce, czy przeglądarka go zwraca. Wyszukiwanie jest bardzo przydatne podczas przeglądania nagłówków HTTP wymiany między przeglądarką a serwerem.
Wyjaśnienie, jak działają pliki cookie, wykracza poza zakres tego i tak już zbyt dużego tekstu, ale przynajmniej upewnij się, że serwer wyśle ​​plik cookie z identyfikatorem, a przeglądarka powróci. I chociaż identyfikatory pokrywają się ze sobą =)
Ustawienie ciasteczka powinno wyglądać jak
Plik cookie zestawu: PHPSESSID = prlgdfbvlg5fbsbshch6hj0cq6;
albo jak
Plik cookie zestawu: PHPSESSID = prlgdfbvlg5fbsbshch6hj0cq6; ścieżka = /
(jeśli żądasz skryptu nie z katalogu głównego)
Odpowiedź serwera powinna wyglądać tak:
Plik cookie: PHPSESSID = prlgdfbvlg5fbsbshch6hj0cq6
lub
Plik cookie: PHPSESSID = prlgdfbvlg5fbsbshch6hj0cq6; b = b
jeśli przeglądarka zwraca inne pliki cookie poza identyfikatorem sesji.

Jeśli przeglądarka nie zwraca plików cookie, sprawdź, czy pliki cookie w ogóle działają.
Upewnij się, że domena, do której uzyskujesz dostęp, ma normalną nazwę (która ma co najmniej jedną kropkę i nie zawiera zabronionych znaków, takich jak podkreślenia) i wyczyść pamięć podręczną przeglądarki — to dwa główne powody, dla których pliki cookie mogą nie działać.

Jeśli przykład z tego miejsca działa, ale twój własny kod nie, to problem oczywiście nie tkwi w sesjach, ale w algorytmie. Poszukaj, gdzie zgubiłeś zmienną, przenieś przykład stąd krok po kroku, debuguj swój skrypt.

Inny problem może się pojawić, jeśli używasz przekierowania nagłówka lub nawigacji JavaScript.
Faktem jest, że PHP automatycznie dołącza identyfikator sesji tylko do linków formularza , ale nie robi tego w przypadku nagłówków, javascript, metatagów.
Dlatego musisz dodać identyfikator ręcznie, na przykład tak:
nagłówek ("Lokalizacja: /script.php?". nazwa_sesji (). "=". session_id ());

Ponadto, bardzo rzadko i nie jest całkowicie jasne, skąd pochodzi problem, problem polega na tym, że ustawienie session.save_handler ma wartość inną niż pliki. Jeśli tak nie jest, popraw to.

Bezpieczeństwo
Bezpieczeństwo sesji to obszerny temat. Dlatego skupię się na kilku głównych punktach.
Najbardziej podręcznikową rzeczą jest nie przekazywać identyfikatora pasek adresu... Jest to napisane nawet w php.ini, ale to ogranicza funkcjonalność sesji. Jeśli zdecydujesz się skorzystać z tej rady, to oprócz session.use_trans_sid = 0 nie zapomnij session.use_only_cookies = 1
Wskazane jest powiązanie sesji z adresem IP: w ten sposób, jeśli identyfikator zostanie skradziony, złoczyńca w większości przypadków nadal nie będzie mógł go użyć.
Zalecane jest użycie dyrektywy session.save_path, za pomocą której można ustawić własny katalog do zapisywania plików sesji. Jest to bezpieczniejsze niż przechowywanie ich w domyślnym udostępnionym katalogu tymczasowym serwera.

Dodatkowe informacje:

  • Oprócz plików cookie mechanizm sesji wysyła również nagłówki, które zabraniają buforowania strony (ten sam ogranicznik pamięci podręcznej). W przypadku html jest to poprawne i konieczne. Ale kiedy próbujesz wysłać plik ze skryptem sprawdzającym autoryzację, Internet Explorer odmawia jego pobrania. To z powodu tego tytułu. Połączenie
    session_cache_limiter ("prywatny");
    musi rozwiązać problem przed rozpoczęciem sesji.
  • Dziwne, ale w tablicy $_SESJA nie możesz używać indeksów liczbowych - $ _SESJA [1], $ _SESJA ["10"]- sesje nie będą działać.
  • Gdzieś pomiędzy 4.2 a 5.0 nie można było ustawić session.use_trans_sid za pomocą ini_set ()... Od wersji 5.0 jest to już możliwe.
  • Przed wersją 4.3.3 plik cookie PHP wysyłał plik cookie tylko wtedy, gdy żądanie nie zawierało identyfikatora na początku sesji. Teraz ciasteczko jest wysyłane przy każdym połączeniu sesja_start ()

    Przykład autoryzacji za pomocą sesji
    Zilustrujmy to wszystko na małym przykładzie:
    stwórzmy plik auth.php:
    if (isset ($ _ POST ["auth_name"]))
    {
    $ sql = "SELECT * FROM użytkowników WHERE nazwa =? S";
    $row = $db -> getRow ($sql, $_POST ["auth_name"]);
    if ($ row && password_verify ($ _POST ["auth_pass"], $ row ["pass"])) (
    $ _SESSION ["identyfikator_użytkownika"] = $ wiersz ["identyfikator"];
    }
    nagłówek („Lokalizacja: http: //”. $ _SERVER [„HTTP_HOST”]. $ _SERVER [„REQUEST_URI”]);
    Wyjście;
    }

    if (isset ($ _ GET ["akcja"]) AND $ _GET ["akcja"] == "wyloguj się") (
    start_sesji ();
    session_destroy ();
    nagłówek („Lokalizacja: http: //”. $ _SERVER [„HTTP_HOST”]. „/”);
    Wyjście;
    }

    if (! isset ($ _ SESSION ["user_id"])) (
    ?>








    Wyjście;
    }

    Teraz wystarczy napisać we wszystkich chronionych skryptach linię
    wymagają "auth.php";
    W tym przykładzie zakłada się, że sesja już się rozpoczęła, a połączenie z bazą danych zostało utworzone przy użyciu Class do bezpiecznej i wygodnej pracy z MySQL. Zakłada również, że hasło zostało zahaszowane przy użyciu zalecanej funkcji password_hash.
    Przykład chronionego pliku:

    start_sesji ();
    dołącz "safemysql.class.php";
    $ db = new safemysql (["db" => "test"]);
    dołącz "auth.php";
    ?>
    sekret

    Wyloguj

    OPS! Bardzo przydatne linki:
    http://www.php.net/manual/ru/ref.session.php - najnowsze i aktualne informacje na temat obsługi sesji w PHP w oficjalnej dokumentacji oraz liczne komentarze użytkowników. Czytanie gorąco polecam.
    http://phpclub.ru/manrus/f/ref.session.html - BARDZO nieaktualne tłumaczenie tego rozdziału na język rosyjski, z dokumentacji przetłumaczonej przez Alexandra Pyramidina.
    http://phpclub.ru/detail/article/sessions
    Artykuł o pretensjonalnym tytule „Prawda o sesjach”. Pozostawia ambiwalentne wrażenie. Na początku autor BARDZO łatwo mówi o mechanizmie sesji, ale metody, które proponuje pod koniec artykułu, są kompletnie niejasne.

    Artykuł podręcznikowy autorstwa Dmitrija Borodina ze strony
    http://php.spb.ru/ NIE jest zdecydowanie zalecane.
    Chłopaki, ona jest strasznie nieaktualna. Nie tylko są w nim nieścisłości merytoryczne, ale sesje w PHP po prostu nie były używane od dawna.
    Ogromne podziękowania dla Dimy za nią, to był pierwszy artykuł o sesjach w języku rosyjskim, sam go studiowałem, ale teraz muszę wysłać ją na zasłużony odpoczynek.
    Również niestety wiele innych artykułów, które są w Internecie i nie były aktualizowane od lat, również są nieaktualne.