Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Problem z sesją w PHP - Nie mogę się odnieść do id użytkownika
Forum PHP.pl > Forum > PHP
Baku12345
Witam
Działanie mojego skryptu ma być proste, ma polegać na tym, że po zalogowaniu się danego użytkownika wyświetli mu się lista kursów ze statusami do których ma dostęp a do których nie.

Mam w bazie między innymi takie tabele jak:
- users (id, name, login, password) - tabela przechowuje dane użytkownika
- courses (id, lp, name, url, category_id) - tabela przechowuje kursy, linki do nich i id kategorii do jakiej należy dany kurs
- access_courses (id, id_user, id_course, status) - tabela przechowuje informacje który użytkownik ma dostęp do którego kursu i wyświetla odpowiedni status

To mi działa w połączeniu z kodem, który sobie napisałem, ale problem jest w linii 75. Dokładnie w zapytaniu
  1. SELECT * FROM courses c, access_courses ac WHERE ac.id_user = $_SESSION['id'] && ac.id_course = c.id ORDER BY lp ASC

Jeżeli to wstawię to jest problem, natomiast jeżeli wstawię na sztywno id użytkownika np. tak
  1. SELECT * FROM courses c, access_courses ac WHERE ac.id_user = 1 && ac.id_course = c.id ORDER BY lp ASC

to wszystko jest idealnie. Jednak tak jak wspomniałem będzie więcej użytkowników i id chcę pobierać z sesji.

Poniżej umieszczam swój fragment kodu. Proszę o przeanalizowanie go i podpowiedź jak to naprawić.


  1. <?php
  2. .
  3. . // tu nieistotny fragment kodu
  4. .
  5. if (isset($_POST['login']) && isset($_POST['password']))
  6. {
  7. if (!empty($_POST['login']) && !empty($_POST['password']))
  8. {
  9. $login = addslashes(strip_tags($_POST['login']));
  10. $password = addslashes(strip_tags(md5($_POST['password'])));
  11.  
  12. $stmt = $pdo->prepare("SELECT * FROM users where login = '".$login."' && password = '".$password."';");
  13. $stmt->execute();
  14.  
  15. if ($row = $stmt->fetchAll(PDO::FETCH_ASSOC))
  16. {
  17. $_SESSION['id'] = $row['id'];
  18. $_SESSION['online'] = 1;
  19. $_SESSION['time'] = time();
  20. $_SESSION['user'] = $login;
  21. $_SESSION['ip'] = $_SERVER['REMOTE_ADDR'];
  22. }
  23. else
  24. {
  25. $logon = new cTemplate;
  26.  
  27. $logon->assign['msg'] = "podałeś błędny login lub hasło!<br>spróbuj ponownie";
  28. $page->assign['container'] = $logon->parse("templates/logon.html");
  29. $page->assign['title'] = "Logowanie";
  30. $main->assign['page'] = $page->parse("templates/page.html");
  31. echo $main->parse("templates/index.html");
  32. }
  33. }
  34. else
  35. {
  36. $logon = new cTemplate;
  37.  
  38. $logon->assign['msg'] = "nie wprowadziłeś wszystkich danych<br>spróbuj ponownie";
  39. $page->assign['container'] = $logon->parse("templates/logon.html");
  40. $page->assign['title'] = "Logowanie";
  41. $main->assign['page'] = $page->parse("templates/page.html");
  42. echo $main->parse("templates/index.html");
  43. }
  44. }
  45.  
  46. if (isset($_SESSION['online']) && isset($_SESSION['time']) && $_SESSION['user'] && ($_SESSION['online']===1))
  47. {
  48. if (time()-$_SESSION['time'] < 900)
  49. {
  50. $_SESSION['time'] = time();
  51.  
  52. if (!isset($_GET['action']))
  53. {
  54. $_GET['action'] = "";
  55. }
  56.  
  57. .
  58. . // tu nieistotny fragment kodu
  59. .
  60.  
  61. switch ($_GET['action'])
  62. {
  63. default:
  64. if (isset($_GET['cat_id']))
  65. {
  66. $cat_id = $_GET['cat_id'];
  67.  
  68. $stmt = $pdo->prepare("SELECT * FROM courses c, access_courses ac WHERE ac.id_user = 1 && ac.id_course = c.id && c.category_id = $cat_id ORDER BY lp ASC");
  69. $stmt->execute();
  70. }
  71. else
  72. {
  73. $stmt = $pdo->prepare("SELECT * FROM courses c, access_courses ac WHERE ac.id_user = $_SESSION['id'] && ac.id_course = c.id ORDER BY lp ASC");
  74. $stmt->execute();
  75. }
  76.  
  77. .
  78. . // tu fragment wyświetlający listę kursów dostępnych dla danego użytkownika
  79. .
  80. }
  81.  
  82. $page->assign['container'] = $panel->parse("templates/panel.html");
  83. }
  84. else
  85. {
  86. $logon = new cTemplate;
  87.  
  88. $logon->assign['msg'] = "przekroczono czas bezczynności<br>zaloguj się ponownie";
  89. $page->assign['container'] = $logon->parse("templates/logon.html");
  90. $page->assign['title'] = "Logowanie";
  91. }
  92. }
  93. else
  94. {
  95. $logon = new cTemplate;
  96.  
  97. $logon->assign['msg'] = "<br>podaj login i hasło<br>";
  98. $page->assign['container'] = $logon->parse("templates/logon.html");
  99. $page->assign['title'] = "Witaj na portalu";
  100. }
  101.  
  102. $main->assign['page'] = $page->parse("templates/page.html");
  103.  
  104. echo $main->parse("templates/index.html");
  105. ?>


Wydaje mi się że problem może być z tym że sesja nie jest globalna, ale może się mylę. Proszę o pomoc.
Z góry bardzo dziękuję.
viking
Twój kod w tym miejscu:
  1. $stmt = $pdo->prepare("SELECT * FROM users where login = '".$login."' && password = '".$password."';");

Jest totalnie beznadziejny. Czytałeś dokumentację? Twoje zapytanie nie jest bezpieczne i mija się z celem takie używanie prepare. Usuwanie znaków z hasła też specjalnie mądre nie jest. Ach, i jeszcze md5. Poważnie? Czasy PHP4 już dawno minęły. Teraz się używa http://php.net/manual/en/function.password-hash.php

Co zwraca $_SESSION['id'] przed tym zapytaniem?
Baku12345
Dzięki za sugestię dotyczącą tego logowania, poczytam. Co do tego co zwraca session['id'], to zakomentowałem wszystko co znajduje się w default i wstawiłem tylko linijkę

  1. $panel->assign['content'] = "$_SESSION['id']";


Po uruchomieniu skryptu wystąpił komunikat błędu
  1. Parse error: syntax error, unexpected '' (T_ENCAPSED_AND_WHITESPACE), expecting identifier (T_STRING) or variable (T_VARIABLE) or number (T_NUM_STRING) in C:\Xampp\htdocs\www\test\index.php on line 87


Kiedy wstawię linijkę bez cudzysłowia

  1. $panel->assign['content'] = $_SESSION['id'];


to strona ładuje się prawidłowo, ale w zmiennej sesji nie wyświetla się nic, tak jakby nie przyszła.
viking
var_dump($_SESSION['id']);
kpt_lucek
Głupie pytanie...

A dajesz:
Baku12345
Tak session_start daję smile.gif

Skróciłem jeszcze bardziej swój kod i lekko przerobiłem, co by jeszcze bardziej zawęzić problem i żeby każdy mógł go przetestować. Teraz wygląda on tak

Skrócona wersja mojego kodu

  1. <?php
  2.  
  3. $pdo = new PDO('mysql:host=localhost; port=3306; dbname=test', 'root', '');
  4.  
  5. $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  6. $pdo->exec("SET NAMES 'utf8'");
  7.  
  8. if (isset($_POST['login']) && isset($_POST['password']))
  9. {
  10. if (!empty($_POST['login']) && !empty($_POST['password']))
  11. {
  12. $login = addslashes(strip_tags($_POST['login']));
  13. $password = addslashes(strip_tags(md5($_POST['password'])));
  14.  
  15. $stmt = $pdo->prepare("SELECT * FROM users where login = '".$login."' && password = '".$password."';");
  16. $stmt->execute();
  17.  
  18. if ($row = $stmt->fetchAll(PDO::FETCH_ASSOC))
  19. {
  20. $_SESSION['id'] = $row['id'];
  21. $_SESSION['online'] = 1;
  22. $_SESSION['time'] = time();
  23. $_SESSION['user'] = $login;
  24. }
  25. else
  26. {
  27. echo "Podałeś błędny login lub hasło";
  28. }
  29. }
  30. else
  31. {
  32. echo "Nie wprowadzłeś wszystkich danych";
  33. }
  34. }
  35.  
  36. if (isset($_SESSION['id']) && isset($_SESSION['online']) && isset($_SESSION['time']) && $_SESSION['user'] && ($_SESSION['online']===1))
  37. {
  38. if (time()-$_SESSION['time'] < 900)
  39. {
  40. $_SESSION['time'] = time();
  41.  
  42. if (!isset($_GET['action']))
  43. {
  44. $_GET['action'] = "";
  45. }
  46.  
  47. switch ($_GET['action'])
  48. {
  49. default:
  50. var_dump($_SESSION['id']);
  51. break;
  52. }
  53. }
  54. else
  55. {
  56. echo "Przekroczono czas bezczynności";
  57. }
  58. }
  59. else
  60. {
  61. echo "<h1>Panel Użytkownika</h1>
  62. <form method='post' action=''>
  63. <div>
  64. <input type='text' name='login' placeholder='Twój login' value=''>
  65. </div>
  66. <div>
  67. <input type='password' name='password' placeholder='Twoje hasło' value=''>
  68. </div>
  69. <button type='submit'>Zaloguj się</button>
  70. </form>";
  71. }
  72. ?>



Do panelu nie da się zalogować, ponieważ nie przychodzi id. Wartość id to null. Widać to kiedy w linii 39 zamiast
  1. isset($_SESSION['id'])

wstawimy
  1. !isset($_SESSION['id'])

Wtedy się zalogujemy a var_dump zwróci NULL. W czym problem?
kpt_lucek
Zrób print_r/var_dump z $row = $stmt->fetchAll(PDO::FETCH_ASSOC)
Baku12345
Wprowadziłem chwilowo taki kod pomiędzy default a break

  1. default:
  2. var_dump($_SESSION['id']);
  3. var_dump($_SESSION['online']);
  4. var_dump($_SESSION['time']);
  5. var_dump($_SESSION['user']);
  6. echo "<br>----------------------------------<br>";
  7. print_r ($row = $stmt->fetchAll(PDO::FETCH_ASSOC));
  8. break;


Wynik w przeglądarce taki
  1. Notice: Undefined index: id in C:\Xampp\htdocs\www\test\index.php on line 21
  2. NULL int(1) int(1474426757) string(7) "Testowy"
  3. ----------------------------------
  4. Array ( )


PS: Oczywiście, żeby w ogóle zobaczyć jakiekolwiek wyniki pomiędzy default a break to musiałem na chwilę zmienić
  1. isset($_SESSION['id'])
na
  1. !isset($_SESSION['id'])
bo to z nim mam cały czas problem.
Star
W jakim celu dajesz tutaj średnik? Nie mam na myśli tego na końcu tylko tego przed ostatnim cudzyslowiem - >

  1.  
  2. prepare("SELECT * FROM users where login = '".$login."' && password = '".$password."';");


Może to jest przyczyną błędu
viking
To teraz jeszcze var_dump($row).
fetchAll zwraca tablicę a nie pojedynczy rekord.
daro0
No rozpacz sad.gif

  1. <?php
  2. $now = time();
  3. $session_key = 'auth_user';
  4.  
  5. if ($_SERVER['REQUEST_METHOD'] == 'POST')
  6. {
  7. $host = 'localhost';
  8. $dbname = 'mojabaza';
  9. $user = 'root';
  10. $passwd = 'root';
  11.  
  12. $dsn = 'mysql:host='. $host . '; dbname=' . $dbname;
  13. $pdo = new PDO($dsn, $user, $passwd);
  14.  
  15. //akurat taka sól jest użyta w celu hashowania hasła w mojej testowej bazie
  16. $salt = 'gj5PxmUt8CAbcnS2';
  17. $login = $_POST['login'];
  18. //test na PHP 5.4 (tam nie ma password_hash :-) )
  19. $password = hash_hmac('sha256', $_POST['password'], $salt);
  20.  
  21. //akurat takie pola mam w bazie czyli username i password jako SHA-256
  22. $stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username AND password = :password");
  23. $stmt->execute(array(':username' => $login, ':password' => $password));
  24.  
  25. if ($row = $stmt->fetch(PDO::FETCH_ASSOC))
  26. {
  27. $session_data = array(
  28. 'time' => $now,
  29. 'user' => $row
  30. );
  31.  
  32. $_SESSION[$session_key] = $session_data;
  33. }
  34. else
  35. {
  36. echo "Blad logowania";
  37. }
  38. }
  39.  
  40. $max_idle_time = 30;
  41. // czy nie wystarczy tylko sprawdzanie po tym questionmark.gifquestionmark.gifquestionmark.gif
  42. if (isset($_SESSION[$session_key]) && !empty($_SESSION[$session_key]))
  43. {
  44. if ($now - $_SESSION[$session_key]['time'] < $max_idle_time)
  45. {
  46. $_SESSION[$session_key]['time'] = $now;
  47. echo "Jestes zalogowany";
  48. }
  49. else
  50. {
  51. echo "Przekroczono czas bezczynnosci";
  52. }
  53. }
  54. else
  55. {
  56. echo '<h1>Panel Uzytkownika</h1>
  57. <form method="post" action="">
  58. <div>
  59. <input type="text" name="login" placeholder="Twoj login" value="">
  60. </div>
  61. <div>
  62. <input type="password" name="password" placeholder="Twoje haslo" value="">
  63. </div>
  64. <button type="submit">Zaloguj sie</button>
  65. </form>';
  66. }
  67. ?>


Testowałem to na jednej ze swoich baz na localhoście, Ty musisz dostosować (pola), jak i hasła (sposób hashowania) do swojej.
kpt_lucek
Cytat(viking @ 21.09.2016, 08:05:03 ) *
To teraz jeszcze var_dump($row).
fetchAll zwraca tablicę a nie pojedynczy rekord.

Pisałem o tym wyżej tongue.gif

Autor tematu widać nie do końca złapał o co chodzi smile.gif
Baku12345
Dziękuję Wam wszystkim za odpowiedzi, wcześniej nie miałem czasu odpisać. Udało mi się wreszcie poprawić ten kod, głównie dzięki zmianom wprowadzonym na podstawie skryptu daro0. Nie była to wina średnika na końcu zapytania, jak sugerował Star, choć faktycznie był zbędny smile.gif

Co do tego co zwracał var_dump($row) to zwracał wszystko co trzeba było czyli

  1. Notice: Undefined index: id in C:\Xampp\htdocs\www\test\index.php on line 23
  2.  
  3. Notice: Undefined index: name in C:\Xampp\htdocs\www\test\index.php on line 25
  4. array(1) { [0]=> array(4) { ["id"]=> string(1) "1" ["name"]=> string(12) "Użytkownik1" ["login"]=> string(7) "Testowy" ["password"]=> string(32) "f86bdb19deb2c5ab632734b8d884ce06" } }


no może bez tego notice tego nie trzeba było smile.gif Dlatego się dziwiłem, bo w tablicy id i name było a warunek nie był spełniony co skutkowało tym, że nie można się było zalogować i żeby zobaczyć co wyświetla var_dump to musiałem zmienić
  1. isset($_SESSION['id'])
na
  1. !isset($_SESSION['id'])
i się okazywało, że jednak id przyszło smile.gif

Ogólnie to mógłbym już dać wszystkim pomógł i można by zamknąć temat, ale dalej nie wiem co było przyczyną tych problemów w tamtej wersji mojego uproszczonego kodu. Czy mógłby mi ktoś wyjaśnić?

Stara wersja zawierała
  1. if ($row = $stmt->fetchAll(PDO::FETCH_ASSOC))
  2. {
  3. $_SESSION['id'] = $row['id'];
  4. $_SESSION['time'] = time();
  5. $_SESSION['user'] = $row['name'];
  6. }

oraz
  1. if (isset($_SESSION['id']) && isset($_SESSION['time']) && isset($_SESSION['name']))
  2. {
  3. if (time()-$_SESSION['time'] < 900)
  4. {
  5. $_SESSION['time'] = time();
  6. var_dump($row);
  7. }
  8. }


Nowa wersja zawiera
  1. $sessionauth = "";

oraz
  1.  
  2. if ($row = $stmt->fetch(PDO::FETCH_ASSOC))
  3. {
  4. $x = array('id' => $row['id'], 'time' => time(), 'user' => $row['name']);
  5.  
  6. $_SESSION[$sessionauth] = $x;
  7. }

i to
  1. if (isset($_SESSION[$sessionauth]) && !empty($_SESSION[$sessionauth]))
  2. {
  3. if (time()-$_SESSION[$sessionauth]['time'] < 900)
  4. {
  5. $_SESSION[$sessionauth]['time'] = time();
  6. var_dump($row);
  7. }
  8. else
  9. {
  10. echo "Przekroczono czas bezczynności";
  11. }
  12. }


I to działa. W czym więc był problem??
viking
Chyba czytasz co się do ciebie pisze?

Cytat
array(1) { [0]=> array(4) { ["id"]=> string(1) "1" ["name"]=> string(12) "Użytkownik1" ["login"]=> string(7) "Testowy" ["password"]=> string(32) "f86bdb19deb2c5ab632734b8d884ce06" } }


Masz tutaj tablicę.

  1. $_SESSION['id'] = $row[0]['id'];


Fetch zwraca już pojedynczy rekord stąd jest dobrze. Jeszcze strzelam że zapewne brakuje ci kluczy (np unikalnego na login), oraz mógłbyś dodać LIMIT w zapytaniu.
Baku12345
A no faktycznie głupi błąd, powinienem był pobrać tylko jeden wiersz spełniający warunek czyli wstawić
  1. $_SESSION['id'] = $row[0]['id'];
  2. $_SESSION['user'] = $row[0]['name'];

zamiast
  1. $_SESSION['id'] = $row['id'];
  2. $_SESSION['user'] = $row['name'];


Poza tym błąd miałem w warunku pobierałem
  1. if (isset($_SESSION['id']) && isset($_SESSION['time']) && isset($_SESSION['name']))

zamiast
  1. if (isset($_SESSION['id']) && isset($_SESSION['time']) && isset($_SESSION['user']))


Dzięki wszystkim za podpowiedzi, teraz działają mi już obie wersje skryptu smile.gif

Mam jeszcze tylko jedno ostatnie pytanko odnośnie
Usuwanie znaków z hasła też specjalnie mądre nie jest.

Teraz mój kod w części odpowiadającej za logowanie wygląda tak

  1. if (isset($_POST['login']) && isset($_POST['password']))
  2. {
  3. if (!empty($_POST['login']) && !empty($_POST['password']))
  4. {
  5. $login = addslashes(strip_tags($_POST['login']));
  6. $password = hash_hmac('sha256', $_POST['password'], '2NYbH5qS8J');
  7.  
  8. $stmt = $pdo->prepare("SELECT * FROM users WHERE login = :login && password = :password");
  9. $stmt -> execute(array(':login' => $login, ':password' => $password));
  10.  
  11. if ($row = $stmt->fetch(PDO::FETCH_ASSOC))
  12. {
  13. $_SESSION[$session_data] = array('id' => $row['id'], 'time' => $now, 'user' => $row['name']);
  14. }
  15. else
  16. {
  17. echo "Podałeś błędny login lub hasło";
  18. }
  19. }
  20. else
  21. {
  22. echo "Nie wprowadzłeś wszystkich danych";
  23. }
  24. }


Czy teraz jest już ok, w sensie bezpiecznie? Czy addslashes i strip_tags przy loginie jest uzasadnione czy może pominąć? I podobne pytanie przy haśle czy dodać addslashes? A jeśli tak to w takiej formie
  1. addslashes(hash_hmac('sha256', $_POST['password'], '2NYbH5qS8J'));

czy takiej
  1. hash_hmac('sha256', addslashes($_POST['password']), '2NYbH5qS8J');


Jeszcze raz dzięki za odpowiedzi, to już ostatnie moje pytanie w tym temacie smile.gif
daro0
No to sobie sprawdź co Ci wypluje hash_hmac, bez względu na to jakie hasło wpiszesz i bez względu na to jak je obrabiasz w PHP. W przypadku SHA-256 będzie to coś tego typu:

e9f379a548dc29a242759944decc45702cbbb000f65b163e46ca7ae210161df2

I zawsze będzie miało długość 64 znaków tylko te literki i cyferki będą inne. Będziesz kombinował to się nawet nie zalogujesz, bo to co porównujesz będzie inne. No i w tym przypadku nawet jak gdzieś tam zmienisz sól a masz hasła zapisane na poprzednią, to też już się nie zalogujesz.


Baku12345
To wiem, że zawsze po obrobieniu hasła, zmianie soli czy kodu odpowiedzialnego za hashowanie te znaki się zmienią i zmieniając to muszę potem do bazy wstawić nowe zahashwane hasło. Tutaj bardziej chodziło mi o bezpieczeństwo skryptu, bazy i formularzy, bo viking napisał w drugim poście "Usuwanie znaków z hasła też specjalnie mądre nie jest.", a ja dodałem addslashes i strip_tags żeby uniemożliwić wprowadzenie i wykonanie ewentualnego złośliwego kodu. Kiedyś się uczyłem, żeby tak robić, ale wtedy nie używałem PDO. Z tąd to pytanie czy dodawać to do loginu i hasła czy nie, a jak tak to w jakiej formie tej pierwszej czy drugiej.
daro0
No cóż, z tego co widać to nie takie proste...
http://stackoverflow.com/questions/134099/...t-sql-injection

Może się ktoś do tego odnieść?
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.