Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Klasa do autoryzacji użytkowników
Forum PHP.pl > Forum > PHP
Jarod
Moje pytanie skierowane jest głównie do osób, które czytały książkę "PHP5 zaawansowane programowanie",
ponieważ problem dotyczy przykładu tam przedstawionego. W rozdziale 15 autor przedstawił klasę do obsługi
własnych sesji a w rozdziale 22 wdraża ją do użytku.

Na stronie 457 przedstawiony jest sposób logowania, który moim zdaniem jest całkowicie bez sensu. Przytoczę tutaj
główny kod:

  1. <?php
  2. (..)
  3. (..)
  4. (..)
  5.  
  6. $session = new WidgetSession (array ('phptype' => "pgsql",
  7.  'hostspec' => "localhost",
  8.  'database' => "artykulandia",
  9.  'username' => "wuser",
  10.  'password' => "foobar"));
  11.  
  12. $session->Impress();
  13. (...)
  14.  
  15. if ($_REQUEST["action" == "login") {
  16.  $session->login($_REQUEST["login_name"].$_REQUEST["login_pass"]);
  17.  if ($session->isLoggedIn()) {
  18.  $smarty->assign_by_ref("user",$session->getUserObject());
  19.  $smarty_>display("main.tpl");
  20.  exit;
  21.  }
  22.  else {
  23.  $smarty->assign('error', "Nieudane logowanie...");
  24.  $smarty_>display("login.tpl");
  25.  exit;
  26.  }
  27. } else {
  28. if ($session->isLoggedIn() == true) {
  29.  $smarty->assign_by_ref("user",$session->getUserObject());
  30.  $smarty_>display("main.tpl");
  31.  exit;
  32. } 
  33. }
  34. ?>


Mniej więcej tak to wygląda. Nie będę podawał kodu klasy bo za dużo pisania. Zresztą nie chodzi mi o sposób
napisania klasy. Wywoływany jest skrypt index.php, który sprawdza czy przesłano parametr action=login.
Jeżeli tak to znaczy, że dokonano próby logowania (wypełniono formularz i go wysłano), metoda sprawdza dane
w bazie - jeżeli się zgadzają ustawia właściwość prywatną klasy logged_in na true. Następnie metoda isLoggedIn()
sprawdza czy wartość właściwości logged_in ma wartość true - jeśli tak uznaje, że użytkownik się zalogował
i ma dostęp do super tajnych danych winksmiley.jpg

Wszyscy wiemy, że protokół HTTP jest bezstanowy. Więc możemy sobie w jednym skrypcie utworzyć 100 obiektów,
ale jak przejdziemy do drugiego skrytpu (czyli zacznie być wykonywany inny skrypt) to te nasze 100 obiektów
poszło się jeb**.

Wiecie do czego zmierzam? Do tego, że stosując metodę autora po oddaniu sterownia do drugiego skryptu będziemy
musieli utworzyć od nowa obiekt, który będzie miał właściwość logged_in=false (bezstanowość protokołu - zgubiliśmy
dane, że użytkownik jest zalogowany) co wymusza przekierowanie na stronę logowania..

Nie odpalałem całego kodu bo nie chce mi się klepać z książki.. Ale uważam, że jeśli dodamy sprawdzanie
w każdym skrypcie czy użytkownik jest zalogowany to ten sposób nie zadziała. A trzeba sprawdzać czy użytkownik
jest zalogowany, że sprytny user zamiast wpisać www.testowa.pl nie wpisał www.testowa.pl/tajnedane.php i w ten
sposób pominął ekran logowania.


Co o tym myślicie? Bo ja czasem czytająć tą książke miałem wrażenie, że autorzy nie wiedzą co piszą albo piszą kod od niechcenia.
dr_bonzo
A reszta kodu?
Przeciez
$session->login(...)
probuje zalogowac usera i zapewne zapisuje w sesji ($_SESSION) wartosc wskazujaca czy user jest zalogowany. I przy wyswietlaniu nastepnej strony, sesja jest inicjowana i ta wartosc jest zachowana i nadal wskazuje czy user jest zalogowany.


Przenosze na php
Jarod
Cytat(dr_bonzo @ 8.10.2006, 07:32:15 ) *
A reszta kodu?


Nie chce mi się stukać wszystkiego. Dlatego podałem strony w książce.

Cytat(dr_bonzo @ 8.10.2006, 07:32:15 ) *
Przeciez
$session->login(...)
probuje zalogowac usera i zapewne zapisuje w sesji ($_SESSION) wartosc wskazujaca czy user jest zalogowany.

Zapisuje sesje w bazie danych.


Cytat(dr_bonzo @ 8.10.2006, 07:32:15 ) *
I przy wyswietlaniu nastepnej strony, sesja jest inicjowana i ta wartosc jest zachowana i nadal wskazuje czy user jest zalogowany.


Na następnej stronie autor powiela kod:
  1. <?php
  2. $session = new WidgetSession (array ('phptype' => "pgsql",
  3.  'hostspec' => "localhost",
  4.  'database' => "artykulandia",
  5.  'username' => "wuser",
  6.  'password' => "foobar"));
  7.  
  8. $session->Impress();
  9. ?>


A metoda Impress() wygląda tak:

  1. <?php
  2. public function Impress() {
  3. if ($this->native_session_id) {
  4. result = pgquery("UPDATE "sesja_uzytkownika" SET ostatnia_reakcja = now() WHERE id=" .$this->native_session_id);
  5. }
  6. }
  7. ?>


I tyle poczynił, żeby sprawdzić sesje, tylko próbuje ją aktualizować. A skoro w nowym skrypcie utworzył nowy obiekt "WidgetSession" to normalne jest że native_session_id będzie miała wartość false, więć metoda Impress() nie zostanie wykonana.

Nie ma weryfikacji użytkownika, tylko update sesjii w bazie..
dr_bonzo
A czy w konstruktorze $native_session_id nie jest jakos inicjowane?
Bez reszty kodu trudno mi powiedziec co sie tam dzieje.
Jarod
Cytat(dr_bonzo @ 8.10.2006, 07:49:35 ) *
A czy w konstruktorze $native_session_id nie jest jakos inicjowane?

No właśnie nie.

Cytat(dr_bonzo @ 8.10.2006, 07:49:35 ) *
Bez reszty kodu trudno mi powiedziec co sie tam dzieje.


Tu wklejam kod klasu UserSession. Na tym kodzie opiera się WidgetSession
  1. <?php
  2. class UserSession {
  3. private $php_session_id;
  4. private $native_session_id;
  5. private $dbhandle;
  6. private $logged_in;
  7. private $user_id;
  8. private $session_timeout = 600; # 10 minutowy maksymalny czas nieaktywności sesji
  9. private $session_lifespan = 3600; # 1 godzinny maksymalny czas trwania sesji.
  10.  
  11. public function __construct() {
  12. # Łączy z bazą danych
  13. $this->dbhandle = pg_connect("host=db dbname=prophp5 user=edek") or die ("Błąd PostgreSQL: --> " . pg_last_error($this->dbhandle));
  14. # Inicjalizuje mechanizm obsługi sesji
  15. array(&$this, '_session_open_method'), 
  16. array(&$this, '_session_close_method'), 
  17. array(&$this, '_session_read_method'), 
  18. array(&$this, '_session_write_method'), 
  19. array(&$this, '_session_destroy_method'), 
  20. array(&$this, '_session_gc_method')
  21. );
  22. # Sprawdza przesłane cookie o ile je przesłano; jeżeli wygląda podejrzanie zosta
    ja z miejsca anulowane  
  23. $strUserAgent = $GLOBALS["HTTP_USER_AGENT"];
  24. if ($_COOKIE["PHPSESSID"]) {
  25.  # Kontrola bezpieczeństwa i ważności
  26.  $this->php_session_id = $_COOKIE["PHPSESSID"];
  27.  $stmt = "SELECT id FROM "sesja_uzytkownika" WHERE identyfikator_sesji_ascii = '" . $this->php_session_id . "' AND ((now() - utworzono) < ' " . $this->session_lifespan . " seconds') AND user_agent='" . $strUserAgent . "' AND ((now() - ostatnia_reakcja) <= '".$this->session_timeout." seconds' OR ostatnia_reakcja IS NULL)";
  28.  $result = pg_query($stmt);
  29.  if (pg_num_rows($result)==0) {
  30.  # Ustawia znacznik niepowodzenia
  31. $failed = 1;
  32.  # Usuwa z bazy danych - w tym samym czasie usuwane są przeterminowane sesje
  33.  $result = pg_query("DELETE FROM "sesja_uzytkownika" WHERE (identyfikator_sesji_ascii = '". $this->php_session_id . "') OR (now() - utworzono) > $maxlifetime)");
  34.  # Usuwa nieprzydatne zmienne sesji
  35.  $result = pg_query("DELETE FROM "zmienna_sesji" WHERE identyfikator_sesji NOT IN (SELECT id FROM "sesja_użytkownika")");
  36.  # Pozbywa się identyfikatora, wymuszając na php nadanie nowego
  37.  unset($_COOKIE["PHPSESSID"]);
  38.  };
  39. };
  40. # Ustawia czas życia cookie
  41. session_set_cookie_params($this->session_lifespan);
  42. # Wywołuje metodę session_start by zainicjować sesję
  43. }
  44.  
  45. public function Impress() {
  46. if ($this->native_session_id) {
  47. $result = pg_query("UPDATE "sesja_uzytkownika" SET ostatnia_reakcja = now() WHERE id = " . $this->native_session_id);
  48. };
  49. }
  50.  
  51. public function IsLoggedIn() {
  52. return($this->logged_in);
  53. }
  54.  
  55. public function GetUserID() {
  56. if ($this->logged_in) {
  57. return($this->user_id);
  58. } else {
  59. return(false);
  60. };
  61. }
  62.  
  63. public function GetUserObject() {
  64. if ($this->logged_in) {
  65. if (class_exists("user")) {
  66. $objUser = new User($this->user_id);
  67. return($objUser);
  68. } else {
  69. return(false);
  70. };
  71. };
  72. }
  73.  
  74. public function GetSessionIdentifier() {
  75. return($this->php_session_id);
  76. }
  77.  
  78. public function Login($strUsername, $strPlainPassword) {
  79.  $strMD5Password = md5($strPlainPassword);
  80.  $stmt = "SELECT id FROM "uzytkownik" WHERE nazwa_uzytkownika = '$strUsername' AND md5_haslo = '$strMD5Password'";
  81.  $result = pg_query($stmt);
  82.  if (pg_num_rows($result)>0) {
  83. $row = pg_fetch_array($result);
  84. $this->user_id = $row["id"];
  85. $this->logged_in = true;
  86. $result = pg_query("UPDATE "sesja_uzytkownika" SET zalogowany = true, identyfikator_uzytkownika = " . $this->user_id . " WHERE id = " . $this->native_session_id);
  87. return(true);
  88.  } else {
  89. return(false);
  90.  };
  91. }
  92.  
  93. public function LogOut() {
  94.  if ($this->logged_in == true) {
  95. $result = pg_query("UPDATE "sesja_uzytkownika" SET zalogowany = false, identyfikator_uzytkownika = 0 WHERE id = " . $this->native_session_id);
  96. $this->logged_in = false;
  97. $this->user_id = 0;
  98. return(true);
  99.  } else {
  100. return(false);
  101.  };
  102. }
  103.  
  104. public function __get($nm) {
  105.  $result = pg_query("SELECT wartosc_zmiennej FROM zmienna_sesji WHERE identyfikator_sesji = " . $this->native_session_id . " AND nazwa_zmiennej = '" . $nm . "'");
  106.  if (pg_num_rows($result)>0) {
  107. $row = pg_fetch_array($result);
  108. return(unserialize($row["wartosc_zmiennej"]));
  109.  } else {
  110. return(false);
  111.  };
  112. }
  113.  
  114.  
  115. public function __set($nm, $val) {
  116.  $strSer = serialize($val);
  117.  $stmt = "INSERT INTO zmienna_sesji(identyfikator_sesji, nazwa_zmiennej, wartosc_zmiennej) VALUES(" . $this->native_session_id . ", '$nm', '$strSer')";
  118.  $result = pg_query($stmt);
  119. }
  120.  
  121.  
  122. private function _session_open_method($save_path, $session_name) {
  123. # Do nothing
  124. return(true);
  125. }
  126.  
  127. private function _session_close_method() {
  128. pg_close($this->dbhandle);
  129. return(true);
  130. }
  131.  
  132. private function _session_read_method($id) {
  133.  # Służy do ustalenia, czy nasza sesja w ogóle istnieje
  134.  $strUserAgent = $GLOBALS["HTTP_USER_AGENT"];
  135.  $this->php_session_id = $id;
  136.  # Na razie ustawia znacznik niepowodzenie na 1
  137.  $failed = 1;
  138.  # Sprawdza czy sesja istnieje w bazie danych
  139.  $result = pg_query("SELECT id, zalogowany, identyfikator_uzytkownika FROM "sesja_uzytkownika" WHERE identyfikator_sesji_ascii = '$id'");
  140.  if (pg_num_rows($result)>0) {
  141. $row = pg_fetch_array($result);
  142. $this->native_session_id = $row["id"];
  143. if ($row["zalogowany"]=="t") {
  144.  $this->logged_in = true;
  145.  $this->user_id = $row["identyfikator_uzytkownika"];
  146. } else {
  147.  $this->logged_in = false;
  148. };
  149.  } else {
  150. $this->logged_in = false;
  151. # Konieczne jest stworzenie wpisu w bazie danych
  152. $result = pg_query("INSERT INTO sesja_uzytkownika(identyfikator_sesji_ascii, zalogowany, identyfikator_uzytkownika, utworzono
    , user_agent) VALUES ('$id','f',0,now(),'$strUserAgent')"
    );
  153. # Teraz pobiera prawdziwy identyfikator
  154. $result = pg_query("SELECT id from "sesja_uzytkownika" WHERE identyfikator_sesji_ascii = '$id'");
  155. $row = pg_fetch_array($result);
  156. $this->native_session_id = $row["id"];
  157.  };
  158.  # Zwraca jedynie ciąg pusty
  159.  return("");
  160. }
  161.  
  162. private function _session_write_method($id, $sess_data) {
  163.  return(true);
  164. }
  165.  
  166. private function _session_destroy_method($id) {
  167.  $result = pg_query("DELETE FROM "sesja_uzytkownika" WHERE identyfikator_sesji_ascii = '$id'");
  168.  return($result);
  169. }
  170.  
  171.  
  172. private function _session_gc_method($maxlifetime) {
  173. return(true);
  174. }
  175.  
  176.  
  177. }
  178. ?>
Turgon
Otóż tutaj klasa pobiera native_session_id z bazy jako id porządkowe normalne, a nie id sesji. Po za tym ta klasa to już po prostu UserSession.
Nigdy tej klasy nie używałem, tylko na jej podstawie zbudowałem to co chciałem tzn. SessionHandler dla mojego Frameworka...
dr_bonzo
OT:
Ale nakombinowali, masa zapytan do bazy po kazda zmienna sesyjna. Po co to ustawianie ciastek? Po kiego grzyba jest $failed
Ehh

W konstruktorze masz session_start() potem jest odczytywana sesja za pomoca _session_read_method($id) i tutaj jest ustawiane $native_session_id
Jarod
Dlatego napisałem, że czasem odnosze wrażenie, że goście nie wiedzą co piszą..

Chłopaki pytanie do Was. Czy możecie udostępnić swojego frameworka? Chcę sobie zbudować coś swojego, czyli klasy, które w każdym projekcie powtarzają mi się a nie mam za bardzo na czym się wzorować. Nie chcę też przeglądać jakiś dużych projektów bo gubie się w ilości kodu.. Zależy mi tylko na oglądnięciu..
dr_bonzo
Pouzywaj jakichs gotowych frameworkow: Zenda, Symfony, Cake czy inne. Po co od razu wzorowac sie (powstanie kolejny ZF-clone tongue.gif) i przepisywac, uzywaj gotowcow dopoki ci odpowiadaja/dzialaja.
Turgon
J4r0d: Muszę powiedzieć, że tłumacze są beznadziejni. Piszą takie bzdury. Źle tłumaczą etc. W orginalne podobno lepsza.
dr_bonzo: No tak wygodniej gotowce jednak niektórzy jak ja muszą swoje cuś napisać, ja tylko to piszę ze względu na to, że Zend nie jest gotowy.
Jarod
Cytat(dr_bonzo @ 8.10.2006, 09:16:40 ) *
Pouzywaj jakichs gotowych frameworkow: Zenda, Symfony, Cake czy inne. Po co od razu wzorowac sie (powstanie kolejny ZF-clone tongue.gif) i przepisywac, uzywaj gotowcow dopoki ci odpowiadaja/dzialaja.


Bo wiem, że to co sam napisze będzie moją zasługą i osiągne to co będę chciał.

Cytat(Turgon @ 8.10.2006, 09:35:15 ) *
J4r0d: Muszę powiedzieć, że tłumacze są beznadziejni. Piszą takie bzdury. Źle tłumaczą etc. W orginalne podobno lepsza.

Niestety jak ostatnio wszystkie książki helionu. Następna będzie z mikom..
Ta książka jest dobra jak się każdy rozdział przeczyta kilka razy - tak zrobiłem. Łapiesz o co chodzi tylko jak ją skończysz to nie wiesz jak to zastosować w praktyce. Pozatym czytając ją mógłbym wskazać, które rozdziały pisane lub łumaczone były przez innego autora/tłumacza. Sposób przekazywania myśli i wiedzy jest inny. Może to źle a może lepiej, że nie cała jest zjeb***
thornag
Bardzo dobry artykul autorstwa Zyxa znajduje sie tutaj. Zdecydowanie lepszy sposob zaimplementowania obslugi sesji uzytkownika. Do tego jak zwykle dodam, ze lepiej owa ksiazke czym predzej odstaw na polke i zapomnij ze ja miales. Przyklady przedstawione tam sa bezsensu, zawieraja mase bledow dla przykladu. Ksiazka ma tytul PHP5 Zaawansowane progrmowanie, a autorzy robia np tak
  1. <?php
  2. $fh = fopen(); fwrite(); fclose()
  3. ?>
Moze o file_put_contents nie slyszeli. Ja po leturze tej ksiazki dowiedzialem sie jak pisac kod arcvhaiczny i malo optymalny. Polecam "Obiekty, wzorce, narzedzia" o wiele lepsza pozycja.

Wracajac jednak do tematu. Zastanow sie czy w swojej aplikacji oprocz logowania, bedziesz uzywal sesji do przenoszenia jakis waznych danych. Jesli nie po co Ci osobny session handler ? To raz, dwa jak dla mnie mieszanie autoryzacji uzytkownika z handlerem sesji jest bezsensu, lepiej stworzyc dwie osobne klasy ktore moga zyc rozlacznie. Jesli natomiast bardzo chcesz pisac cos swojego, przeczytaj tutoriale usiadz i zrob, pozniej poulepszaj i bedzie good, nie ma sensu przepisywac przykladow uczacych zlych nawykow.
Jarod
Cytat(dr_bonzo @ 8.10.2006, 08:54:06 ) *
W konstruktorze masz session_start() potem jest odczytywana sesja za pomoca _session_read_method($id) i tutaj jest ustawiane $native_session_id


Możesz wskazać miejse, w którym odczytywana jest sesja za pomocą _session_read_method($id) ? Bo ja tego nie widze..
Turgon
Dobra tak to wyjaśnie. Thornag w kod ingerowali tłumacze...
Co skończyło się źle.
Ta książka mnie nauczyła więcej niż masa stron.
Ten art Zyxa, to kolejna zła praktyka. SH dostarcza tylko obsługę sesji !
A nogdy co z tym użytkownikiem. Czy to on etc. smile.gif
thornag
@Turgon, nie twierdze ze nie nauczyla ale przy okazji niezle namieszla, bede juz jej zagorzlym przeciwnikiem i kropka smile.gif oczywiscie zdaje sobie sprawe ze nie altorzy tylko tlumacze, ale i w kodzie udalo mi sie kilka bledow wychwycic ;P

Co do artu Zyxa nie uwazam zeby bylo to zla praktyka, jak dla mnie SessionHandler i nazijmy to UserHandler powinny byc dwoma oddzielnymi komponentami, niech SH handluje sesje a UH korzysta z SH, nie potrzeben mi wtedy w SH metody do sprawdzania zalogowania uzytkownika czy tez logowania go.

Chyba sie troche zagalopowalismy i zeszlismy z tematu, winksmiley.jpg

edit: ehh przetarlem oczeta. w KOD ingerowali tlumacze ? blinksmiley.gif Ze zapytam kiego grzyba ?
Turgon
Thornag właśnie nie wiem.... Chyba, że po polsku było.
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.