Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [MySQL][PHP] Wykrycie timeout sesji
Forum PHP.pl > Forum > Przedszkole
Thompsoon
Witam,

Mam problem.
Potrzebuje wykonać pewne operacje na bazie danych ale dopiero wtedy gdy użytkownik się wyloguje lub zostanie sam wylogowany automatycznie po timeout sesji.
Jeżeli chodzi o tę pierwszą wersje to poradziłem sobie bez problemu.
Niestety nie wiem jak wykryć, że dany użytkownik nie jest już aktywny i że wygasła sesja. Szukałem na różnych forach ale nie znalazłem niczego co pomogłoby mi rozwiązać problem.
Proszę o pomoc, nakierowanie.

Pozdrawiam
Pyton_000
Robisz sesje na BD, okresowo sprawdzasz tabelę sesii pod kątem czasu ostatniej aktywności. Jeśli czas nieaktywności > ustalony czas sesii robisz sobie coś z userem, i wywalasz rekord z BD.
Thompsoon
A nie ma takiej możlwiości żeby zrobić to z automatu, tak żeby nie sprawdzać samemu nieaktywności co jakiś czas ?
Jeżeli nie ma to czy można np. zrobić automat, który działa co jakiś określony czas?
Pyton_000
cron
Thompsoon
To jedyne rozwiązanie? Dopiero zaczynam przygodę z php i nie wiem czy będe w stanie to ugryźć
salfunglandyare
sesja na db - http://php.net/manual/en/function.session-...ave-handler.php
Zmiany w bazie przy usuwaniu rekordu sesji możesz wykonać przy pomocy triggerów before delete lub after delete. Za ich pomocą i sys_exec możesz wykonać nawet zewnętrzny skrypt/program bezpośrednio z mysql biggrin.gif np:
  1. DELIMITER //
  2.  
  3. CREATE TRIGGER po_usunieciu
  4. AFTER DELETE ON `Tabela`
  5. FOR EACH ROW
  6. BEGIN
  7. DECLARE zwrot int(10);
  8. DECLARE polecenie char(200);
  9. SET polecenie=CONCAT('/usr/bin/php /home/XXXX/skrypt.php ',OLD.id);
  10. SET zwrot = sys_exec(polecenie);
  11. END;
  12. //
  13. DELIMITER ;


//Edit: oczywiście zamiast sys_exec możesz wykonać jakiś SQL, informacje o starym rekordzie znajdują się w OLD
rad11
Zrob sobie przy uzytkowniku kolumne ostatni czas aktywnosci (oczywiscie aktywnosc musisz updatowac przy kazdym reloadzie), ustaw czas aktywnosci sesji np na 1 godzine jezeli uzytkownik ostatnia aktywnosc mial godzine temu to automatycznie sesja go wyloguje i bedziesz wiedziec ze jest nieaktywny rowniez w bazie danych.
Thompsoon
Cytat(rad11 @ 13.05.2015, 17:50:40 ) *
Zrob sobie przy uzytkowniku kolumne ostatni czas aktywnosci (oczywiscie aktywnosc musisz updatowac przy kazdym reloadzie), ustaw czas aktywnosci sesji np na 1 godzine jezeli uzytkownik w bazie ostatnia aktywnosc mial godzine temu to automatycznie sesja go wyloguje i bedziesz wiedziec ze jest nieaktywny.


Ten sposób chyba jest najbliższy temu co mam teraz.

Mam dwie kolumny: jedna pokazuje czy użytkownik jest aktywny a druga czas ostatniej aktywności. I to działa.
Tylko jak sprawdzić automatycznie czy użytkownik nie był aktywny przez np. godz i wysłać polecenie o wykonaniu określonych operacji na bazie gdy nie był aktywny?
rad11
Musisz pobrac date ostatniej aktywnosci i porownac ja z aktualna. Jezeli roznica jest wieksza niz godzina tzn ze jest nieaktywny.
Thompsoon
No tak, tylko to musiał bym zrobić nową funkcje i uruchamiać ją manualnie.

Idea jest taka:

1. Loguje się użytkownik
2. Robi jakieś dziwne rzeczy powodujące wpisy w bazie
3. Kończy pracę:
a. wylogowuję się -> odpalam funkcje, która czyści to czego nie potrzebuje - to zrobiłem
b. nie wylogowuje się -> sesja się zamyka po jakimś czasie automatycznie - i tutaj potrzebuje zrobić coś żeby wykrywało zamknięcie sesji i wykonywało funkcje takie jak przy wylogowaniu
rad11
No to Ci tlumacze masz do tego ostatnia aktywnosc. Jezeli bedziesz mial ustawiona sesje na godzine to na tej podstawie sprawdzasz ostatnia aktywnosc. Tylko jezeli nie chcesz tego robic manualnie bo z tego to wynika to musisz albo wykonywac ajaxem jakies operacje co jakis czas albo cronem.
salfunglandyare
Albo mimo wszystko sesja w db i trigger na before/after delete biggrin.gif
rad11
Lepiej aby chlopak zaczal od latwiejszego sposobu wedlug mnie haha.gif ale to juz jego wybor.
Thompsoon
Cytat(salfunglandyare @ 13.05.2015, 18:23:43 ) *
Albo mimo wszystko sesja w db i trigger na before/after delete biggrin.gif


Czy w przypadku tego sposobu osiągnę to co zamierzam bez AJAXa i Crona?
Jeżeli tak to spróbuje się w to zagłębić chociaż na pierwszy rzut oka może być ciężko.

Manualne wykonywanie tej fukcji mnie niestety nie urządza. Operacje te muszą się wykonywać niemal niezwłocznie po zamknięciu sesji.
salfunglandyare
Generalnie tak:
- sesja zapisywana w bazie przez mechanizm PHP, gdy sesja ma timeout, PHP co jakiś czas sam sprawdza i wywołuje metodę usuwania (teoretycznie budując własny handler w tym miejscu też możesz się wpiąć). Uswanie powoduje usunięcie rekordu z bazy
- w bazie danych podczas usuniecia rekordu (lub rekordów) wywoływany jest trigger (before - przed usunieciem, after - po usunieciu),
- trigger może uruchomić SQL lub skrypt.
Problem jest w tym, aby dobrać się do wartości sesji, ale przy odrobinie wysiłku można dobrać się do wszystkich informacji, zawartość to zserializowana $_SESSION
Wszystko z automatu biggrin.gif
Thompsoon
Ok czyli wiem jak to ma działać ale jak się za to zabrać?
Pomoże ktoś? Deklaruje od razu, że jak uda się napisać taki skrypt to wrzucę go do sekcji "gotowe rozwiązania" żeby służył też innym.

Na początku musimy stworzyć bazę danych zapisujących sesje. Czy pola: Id, Timeout wystarczą?
salfunglandyare
http://php.net/manual/en/function.session-...ave-handler.php - tu w pierwszym komentarzu masz w sumie gotowe rozwiązanie na sesję w bazie smile.gif
Thompsoon
Ok. Skopiuje do kodu swojej strony i zobaczę czy działa:)
Żartuje. Dzięki za pomoc.
Pyton_000
Skoro chcesz wykonać operacje po wylogowaniu i zakończeniu sesji to czy nie lepiej czyścić przed zalogowaniem? (O ile dane które są czyszczone nie są powiązane z niczym poza samym uzytkownikiem)
Thompsoon
Ale jeżeli ktoś się już nie zaloguje? Coś tam podłubie, niewyloguje się i zamknie przeglądarke
Chyba, że przed jakimolwiek zalogowaniem miałby sprawdzać czy czasy aktywnosci w bazie a nie w przypadku konkretnego usera.
Rozwiązanie nieidealne ale zawsze coś.

W międzyczasie przygotowałem kod. Tzn przerobiłem ten http://php.net/manual/en/function.session-...ave-handler.php

  1.  
  2. class session
  3. {
  4. // session-lifetime
  5. var $lifeTime;
  6. // mysql-handle
  7. var $db_connect;
  8.  
  9. function open($savePath, $sessName)
  10. {
  11. // get session-lifetime
  12. $this->lifeTime = get_cfg_var("session.gc_maxlifetime");
  13. // open database-connection
  14. require "db_connection.php";
  15. // return success
  16. $this->db_connect = $db_connect;
  17.  
  18. return true;
  19. }
  20.  
  21. function close()
  22. {
  23. $this->gc(ini_get('session.gc_maxlifetime'));
  24. // close database-connection
  25. return mysqli_close($this->db_connect);
  26. }
  27.  
  28. function read($sessID)
  29. {
  30. // fetch session-data
  31. $query = "SELECT SessionData AS d FROM Sessions WHERE Id = '$sessID' AND SessionExpires > ".time();
  32.  
  33. $res = mysqli_query($this->db_connect, $query);
  34.  
  35. // return data or an empty string at failure
  36. if($row = mysqli_fetch_assoc($res))
  37. return $row['d'];
  38. return "";
  39. }
  40.  
  41. function write($sessID,$sessData)
  42. {
  43. // new session-expire-time
  44. $newExp = time() + $this->lifeTime;
  45. // is a session with this id in the database?
  46.  
  47. $query = "SELECT * FROM Sessions WHERE Id = '$sessID' ";
  48.  
  49. $res = mysqli_query($this->db_connect, $query);
  50.  
  51. // if yes,
  52. if(mysqli_num_rows($res)) {
  53. // ...update session-data
  54.  
  55. $query = "UPDATE Sessions SET SessionExpires = '$newExp', SessionData = '$sessData' WHERE Id = '$sessID' ";
  56.  
  57. mysqli_query($this->db_connect, $query);
  58.  
  59. // if something happened, return true
  60. if(mysqli_affected_rows($this->db_connect))
  61. return true;
  62. } else {
  63. // if no session-data was found,
  64. // create a new row
  65. $query2 = "INSERT INTO Sessions (Id, SessionExpires, SessionData)
  66. VALUES('$sessID', '$newExp', '$sessData')";
  67.  
  68. mysqli_query($this->db_connect, $query2);
  69.  
  70. // if row was created, return true
  71. if(mysqli_affected_rows($this->db_connect))
  72. return true;
  73. }
  74. // an unknown error occured
  75. return false;
  76. }
  77.  
  78. function destroy($sessID)
  79. {
  80. // delete session-data
  81. $query = "DELETE FROM Sessions WHERE Id = '$sessID' ";
  82.  
  83. mysqli_query($this->db_connect, $query);
  84.  
  85. // if session was deleted, return true,
  86. if(mysql_affected_rows($this->db_connect))
  87. return true;
  88. // ...else return false
  89. return false;
  90. }
  91.  
  92. function gc($sessMaxLifeTime)
  93. {
  94. // delete old sessions
  95. $query = "DELETE FROM Sessions WHERE SessionExpires < ".time();
  96.  
  97. mysqli_query($this->db_connect, $query);
  98.  
  99. // return affected rows
  100. return mysql_affected_rows($this->db_connect);
  101.  
  102. return true;
  103. }
  104.  
  105. }
  106.  
  107. $session = new session();
  108. session_set_save_handler(array(&$session,"open"),
  109. array(&$session,"close"),
  110. array(&$session,"read"),
  111. array(&$session,"write"),
  112. array(&$session,"destroy"),
  113. array(&$session,"gc"));
  114.  
  115.  
  116.  


Ale chyba nie działa tak jakbym chciał.
Zapisuje w polu 'Id' nazwę sesji, aktualizuje 'SessionExpires' w przypadku przeładowania strony ale w momenie gdy np. otworzę stronę na dwóch różnych przeglądarkach to mam tylko jeden wpis w bazie. Tak jakby się zastępował, a przecież gdy nie znajdzie 'Id' sesji to powienien tworzyć nowy.
I widzę też że sesja nie usuwa się z bazy danych.
salfunglandyare
A otwierasz sesję za każdym razem? Może otwierasz ją dopiero w trakcie zalogowania, lub coś podobnego? Raczej mało prawdopodobne jest, aby dwie różne przeglądarki (nie dwa okna) otrzymały ten sam numer sesji
Pyton_000
Co do czyszczenia to jest ustawione prawdopodobieństwo że Garbage Collector się odpali i wywoła czyszczenie.
Co do zapisywania nowej sesii to zrób sobie jakieś debugowanie. Dodaj w write wyświetlanie Session ID. Może masz za małą pojemność pola na SSID
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.