Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: własna obsługa sesji
Forum PHP.pl > Forum > PHP > Object-oriented programming
Apo
Witam
Ostanio pisałem własną obsługe sesji opartą na bazie mysql. Oto kod:

  1. <?php
  2. /**
  3. *@author Apo
  4. *@package Obsluga sesji
  5. */
  6.  
  7. require_once('db.php');
  8.  
  9. db::connect('localhost', 'root', '', 'session');
  10.  
  11. $session = new session();
  12.  
  13. // przykład
  14.  
  15. $session->imie = 'Alfred';
  16.  
  17. try
  18. {
  19. echo $session->imie;
  20. } catch(SessionException $e)
  21. {
  22. echo $e->getMessage();
  23. }
  24.  
  25.  // klasa
  26.  
  27. final class session {
  28.  
  29. // unikalny numer identyfikacyjny uzytkownika
  30. private $id = null;
  31.  
  32. // nazwa tabeli w bazie danych gdzie beda trzymane sesje
  33. private $table = '`session`';
  34.  
  35. // ilosc czasu (w sekundach) przez jaką ma być wazna sesja
  36. private $limit = 3600;
  37.  
  38. // tablica z danymi
  39. private $sessionTable = array();
  40.  
  41.  /**
  42.  * Konstruktor sprawdza czy dany uzytkownik ma juz utworzoną sesje, jesli nie je
    st ona tworzona
  43.  *
  44.  */
  45. public function __construct()
  46. {
  47. $this->id = $this->hash();
  48.  
  49. if(!$this->getSessionRows())
  50. $this->createSession();
  51. }
  52.  
  53.  /**
  54.   * Tworzy unikalny numer identyfikacyjny dla kazdego uzytwownika
  55.   *
  56.   * return String
  57.   */
  58. private function hash()
  59. {
  60. return md5($_SERVER['REMOTE_ADDR'] . addslashes($_SERVER['HTTP_USER_AGENT']));
  61. }
  62.  
  63.  /**
  64.   * Sprawdza czy uzytkownik ma utworzona sesje na podstawie ilosci rekordow w bazi
    e
  65.   *
  66.   * return Boolean
  67.   */
  68. private function getSessionRows()
  69. {
  70. db::query('SELECT `czas`, `dane` FROM '.$this->table.'
  71.  WHERE `id`=''.$this->id.'' AND `czas`>'.(time()-$this->limit));
  72.  
  73. if(db::num_rows() == 1)
  74. {
  75. $dane = '';
  76. while($array = db::fetch_row())
  77. $dane = $array;
  78.  
  79. $this->sessionTable = unserialize($dane['dane']);
  80. return true;
  81. }
  82. else
  83. return false;
  84. }
  85.  
  86.  /**
  87.   * Tworzy sesje dla uzytkownika
  88.   *
  89.   * return query
  90.   */
  91. private function createSession()
  92. {
  93. db::query('DELETE FROM '.$this->table.' WHERE id=''.$this->id.''');
  94. return db::query('INSERT INTO '.$this->table.'(`id`, `czas`) VALUES(''.$this->id.'', ''.time().'')');
  95. }
  96.  
  97.  /**
  98.   * Przychwytuje przypisywanie wartosci do niezdefiniowanych skladowych i dodaje d
    o tablicy ktora zostanie zapisana
  99.   *
  100.   */
  101. public function __set($name, $value)
  102. {
  103. return $this->sessionTable[$name] = $value;
  104. }
  105.  
  106.  /**
  107.   * Przychwytuje niezdefiniowane metody i wywoluje odpowiedni klucz z tablicy
  108.   *
  109.   * return String, Int
  110.   */
  111. public function __get($name)
  112. {
  113. if(array_key_exists($name, $this->sessionTable))
  114. return $this->sessionTable[$name];
  115. throw new SessionException('Nie zdefiniowano klucza: '.$name);
  116. }
  117.  
  118.  /**
  119.   * Niszczy sesje dla danego uzytkownika
  120.   *
  121.   */
  122. public function destroy()
  123. {
  124. return db::query('DELETE FROM '.$this->table.' WHERE `id`=''.$this->id.''');
  125. }
  126.  
  127.  /**
  128.   * Zapisuje zserializowane dane do bazy
  129.   *
  130.   */
  131. public function __destruct()
  132. {
  133. db::query('UPDATE '.$this->table.' SET `czas`='.time().', dane=''.serialize($this->sessionTable).'' WHERE `id`=''.$this->id.''');
  134. }
  135. }
  136.  
  137. class SessionException extends Exception {}
  138.  
  139. /* TABELA
  140.  
  141. CREATE TABLE `session` (
  142.   `id` varchar(32) default NULL,
  143.   `czas` int(11) default NULL,
  144.   `dane` longtext,
  145.   UNIQUE KEY `id` (`id`)
  146. ) TYPE=MyISAM;
  147.  
  148.  
  149. */
  150. ?>


No i chciałem się zapytać co sądzicie o takim rozwiązaniu. Muszę jeszcze popracować nad zmniejszeniem ilości zapytań, bo w aktualnej chwili wynoszą średnio one 3.

Pozdrawiam
Ociu
A nie pożna poprostu użyć session_set_save_handler ?
Sprawdzony sposób smile.gif
Kinool
  1. <?php
  2. md5($_SERVER['REMOTE_ADDR'] . addslashes($_SERVER['HTTP_USER_AGENT']));
  3. ?>


a co jesli ktos ma siec przy uzyciu NAT i na kilku kompach jest ta sama przegladarka?? smile.gif
Apo
Cytat(Kinool @ 19.06.2006, 16:38 ) *
  1. <?php
  2. md5($_SERVER['REMOTE_ADDR'] . addslashes($_SERVER['HTTP_USER_AGENT']));
  3. ?>


a co jesli ktos ma siec przy uzyciu NAT i na kilku kompach jest ta sama przegladarka?? smile.gif


no wlasnie też sie chciałem zapytać co tu jeszcze można dodać ;p
Ludvik
Jakiś czas temu było wyjaśniane na forum, że nie zrobisz tego bezpiecznie bez ciastek. Po prostu nie da się, bo wszystkie te informacje można nie przemęczając się nadpisać. Ciastka są najbezpieczniejszym sposobem na przenoszenie sesji między żądaniami.
Ociu
Myśle, że SID można wygenerować poprzez time() + ip + przeglądarka ew. + host.
Ludvik
Jeżeli dodasz time(), to po sekundzie nie odzyskasz tego identyfikatora... Poza tym, za dużo kombinowania - wystarczy dodać liczbę losową z dużego przedziału i sprawdzać, czy nie występują kolizje. Identyfikator sesji przenosić ciastkami. Opieranie się na User-Agent, adresie IP i hoście jest dużym błędem w zabezpieczeniach i nikt nie wdraża takich rozwiązań do swoich systemów...
bigZbig
Ja sie zastanawiam po co ludzie pisza swoje wlasne klasy do obslugi sesji skoro zaimplementowany w php mechanizm jest dobry. Nalezy jedynie zwrocic uwagę na to aby zmienic domyslny katalog dla plikow sesji.
Ociu
Ludvik: nikt przecież nie zabronił Ci przechowac SID'a w ciastku.
Ludvik
Czytając kod, który napisał Apo, można odczytać jego intencje. Poza tym mam w głowie poprzedni temat. Dla mnie oczywiste jest użycie ciastek smile.gif
Apo
No ok to chyba bede zapisywał ID w cookies, ale czy jest jakaś możliwość zrobienie takiej rzeczy (jak jest domyślne w php) ze jeśli jest wyłączone cookie to ID zostanie doklejaony do $_GET ?
NuLL
blink.gif php samemu dokleja identyfikator sesji.
Apo
Cytat(NuLL @ 20.06.2006, 19:38 ) *
blink.gif php samemu dokleja identyfikator sesji.

No ale my tu mówimy o mojej obsłudze sesji której kod jest na samej górze ;p
NuLL
Moze wylacz ciastka sobie w browserze i sprawdz co sie dzieje OK ? winksmiley.jpg
elnino.pl
A co myślicie o następującym rozwiązaniu:

  1. <?php
  2.  
  3. class elSess
  4. {
  5. public $sess_dir = '/tmp/';
  6. public $sess_time = 360;
  7.  
  8. private $key;
  9. private $iv;
  10.  
  11. function elSess()
  12. {
  13. if (!is_writable($this -> sess_dir))
  14. throw new exception('elSess: sess_dir is not writable');
  15. $this -> key = md5($_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT']);
  16. $this -> iv = md5($this -> key);
  17. }
  18.  
  19. function elKoduj($string)
  20. {
  21. return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $this -> key, $string, MCRYPT_MODE_CFB, $this -> iv));
  22. }
  23.  
  24. function elDekoduj($string)
  25. {
  26. return mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $this -> key, base64_decode($string), MCRYPT_MODE_CFB, $this -> iv);
  27. }
  28.  
  29. function _open($session_savepath, $session_name)
  30. {
  31. return true;
  32. }
  33.  
  34. function _close()
  35. {
  36. return true;
  37. }
  38.  
  39. function _read($session_id)
  40. {
  41. if(!file_exists($this -> sess_dir . $session_id))
  42. return '';
  43. $sess_data = $this -> elDekoduj(@file_get_contents($this -> sess_dir . $session_id)) . '';
  44. return($sess_data);
  45. }
  46.  
  47. function _write($session_id, $session_value)
  48. {
  49. return (@file_put_contents($this -> sess_dir . $session_id, $this -> elKoduj($session_value)) && @chmod($this -> sess_dir . $session_id, 0700));
  50. }
  51.  
  52. function _destroy($session_id)
  53. {
  54. return @unlink($this -> sess_dir . $session_id);
  55. }
  56.  
  57. function _gc($session_lifetime)
  58. {
  59. if ($handle = @opendir($this -> sess_dir)) 
  60. {
  61.  while (false !== ($file = readdir($handle)))
  62.  if(@is_file($this -> sess_dir . $file) && @filemtime($this -> sess_dir . $file) < time() - $this -> sess_time)
  63.  @unlink($this -> sess_dir . $file);
  64. @closedir($handle);
  65. return true; 
  66. }
  67. else
  68. return false;
  69. }
  70. };
  71.  
  72. $sess = new elSess;
  73. session_set_save_handler (array(&$sess, '_open'), array(&$sess, '_close'), array(&$sess, '_read'), array(&$sess, '_write'), array(&$sess, '_destroy'), array(&$sess, '_gc'));
  74.  
  75. ?>
Vengeance
bigZbig: a moze po to by sprawdzic, ilu ludzi jest aktywnych na stronie.
a moze po to ilu zalogowanych. A moze po to by efektywnie sledzic sciezki przejsc uzytkownika, wyswietlic jego aktualna pozycje, zrobic statystyki uzywanych przegladarek zarazem i milion innych rzeczy....

trzymasz dane w bazie, nie musisz ich usuwać (do przedawnienia sesji służy pole w tabeli int(10) trzymajace timestamp).

Korzyści jest wiele.
bigZbig
@Vengeance - zgadzam się, że chcąc czegoś więcej ponad podstawową użyteczność sesji trzeba napisać coś swojego, ale większość ludzi piszących klasy do obsługi sesji implementuje jedynie ich podstawową funkcjonalność, a w takim wypadku jest to sztuka dla sztuki.
Vengeance
Ano... ale to już ich problem a nie mój winksmiley.jpg Pytałeś do czego... to napisałem do czego ja używam własnych sesji. Tzn tylko własnego handlera podpinanego pod ten z php oczywiscie. Nie wyobrazam sobie robic SessionCostam::register('lol', 'blabla'); zamiast standardowego $_SESSION[]
bigZbig
Teoretycznnie rzecz biorac to moznaby zamiennie uzywac tablicy $_SESSION i metod statycznych przykladowej klasy MySession. Nie sprawdzalem, ale takie cos mogloby zadzialac.

  1. <?php
  2. class MySession {
  3. static private $_aSession = &$_SESSION;
  4.  
  5. static public function register($sVariable, $mValue) 
  6. {
  7. self::$_aSession[$sVariable] = $mValue;
  8. }
  9.  
  10. static public function registry($sVariable)
  11. {
  12. return self::$_aSession[$sVariable];
  13. }
  14. }
  15.  
  16. ?>
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.