Доброго времени суток. Недавно начал изучать ООП, поэтому пытаюсь написать для себя более-менее рабочий движок. Застрял с написанием ядра. После перезапуска браузера, пользователь вновь не авторизован. Хотя куки и сессии вроде как прописаны правильно. Код основного ядра системы /includes/core.php: Код (PHP): <?php /** * @package SkyBlog CMS * @author MyZik * @link http://skyblogcms.ru */ session_name('sid'); session_start(); /** * Устанавливаем системные настройки */ ini_set("display_errors","1"); // Показ ошибок ini_set("display_startup_errors","1"); ini_set('error_reporting', E_ALL); mb_internal_encoding('UTF-8'); // Кодировка по умолчанию /** * Системные переменные и константы */ define('HOME', dirname(__DIR__)); // Серверный путь к сайту define('URL', 'http://' . $_SERVER['HTTP_HOST']); // URL-путь к сайту define('SkyBlog_VERSION', '1.0.0'); // Версия движка (!НЕ МЕНЯТЬ!) /** * Инициализация PDO, подключение к БД */ $mySQL = parse_ini_file(HOME . '/includes/database.ini'); $db = new PDO('mysql:host=' . $mySQL['host'] .';dbname=' . $mySQL['base'], $mySQL['user'], $mySQL['password'], array( PDO::ATTR_PERSISTENT => true )) or die('Cannot connect to MySQL server :('); $db->query("SET NAMES utf8"); /** * Загружаем классы */ spl_autoload_register(function($name) { $file = dirname(__DIR__) . '/includes/classes/' . $name . '.php'; if(!file_exists($file)) { throw new Exception('Autoload class: File '.$file.' not found'); } require $file; }); $user = new User; $userID = $user->userID; Теперь, код класса User: /includes/classes/User.php Код (PHP): <?php /** * @package SkyBlog CMS * @author MyZik * @link http://skyblogcms.ru */ class User { public $user; public $userID, $login, $password, $email; function __construct() { global $db; if (isset($_SESSION['user_id']) && $db->query("SELECT COUNT(*) FROM `users` WHERE `id` = '" . $_SESSION['user_id'] . "' LIMIT 1")->fetchColumn() == 1) { # Создаем массив с данными пользователя $this->user = $db->query("SELECT * FROM `users` WHERE `id` = '" . $_SESSION['user_id'] . "' LIMIT 1")->fetch(); setcookie('user_id', $user['id'], time() + 60 * 60 * 24 * 365); setcookie('password', md5($user['password']), time() + 60 * 60 * 24 * 365); # Записываем дату последнего посещения $db->query("UPDATE `users` SET `last_time_entry` = '" . time() . "' WHERE `id` = '" . $this->user['id'] . "' LIMIT 1"); $this->userID = $this->user['id']; } } public static function login($login, $password) { global $db; $user = $db->query("SELECT * FROM `users` WHERE `login` = '$login' AND `password` = '" . md5($password) . "' LIMIT 1")->fetch(); // Создаем массив с данными юзера $_SESSION['user_id'] = $user['id']; // Создаем ID в сессиии $db->query("UPDATE `users` SET `last_entry_time` = '" . time() . "' WHERE `id` = '" . $user['id'] . "' LIMIT 1"); // Обновляем дату последнего посещения } public function registerUser($user_login, $user_password, $user_email) { global $db; $this->login = $user_login; $this->password = md5($user_password); $this->email = $user_email; /** * Подготавливаем запрос */ $st = $db->prepare("INSERT INTO `users` (`login`, `password`, `email`, `time`) VALUES (:login, :password, :email, :time)"); /** * Регистрируем пользователя в БД */ $st->execute(array( 'login' => $this->login, 'password' => $this->password, 'email' => $this->email, 'time' => time() )); return true; } } Ну, и простейшая форма авторизации: Код (PHP): <?php /** * @package SkyBlog CMS * @author MyZik * @link http://skyblogcms.ru */ require_once '../includes/core.php'; $title = 'Авторизация'; require_once '../includes/header.php'; if (isset($_POST['auth'])) { if ($db->query("SELECT COUNT(*) FROM `users` WHERE `login` = '" . $_POST['login'] . "' AND `password` = '" . md5($_POST['password']) . "' LIMIT 1")->fetchColumn() == 1) { echo 'Authorized!'; $user->login($_POST['login'], $_POST['password']); } else { echo 'Error'; } } ?> <div class="list-group"> <div class="list-group-item"> <form class="form-horizontal" action="entry.php" method="POST" role="form"> <div class="form-group"> <label for="login" class="col-sm-1 control-label">Логин</label> <div class="col-sm-10"> <input type="text" class="form-control" name="login" placeholder="Login"> </div> </div> <div class="form-group"> <label for="password" class="col-sm-1 control-label">Пароль</label> <div class="col-sm-10"> <input type="password" class="form-control" name="password" placeholder="Password"> </div> </div> <div class="form-group"> <div class="col-sm-offset-1 col-sm-10"> <input type="submit" name="auth" class="btn btn-primary btn-lg btn-block" value="Войти!" /> </div> </div> </form> </div> </div> <?php require_once '../includes/footer.php'; Заранее спасибо за ответ. Выделение цветом синтаксиса работает если сделать [code=php] — модераторъ
Сессионная кука по умолчанию живет до закрытия браузера. И лучше оставить это время как есть, иначе получишь новые проблемы! Хочешь запомнить юзера на бОльший срок — используй для идентификации не сессию, а отдельную куку для которой задавай время какое хочешь. Добавлено спустя 3 минуты 21 секунду: По коду есть замечания: — раз уж ты используешь классы, избавься от global, передавай $db в конструктор класса User и сохраняй в приватном свойстве. — вот это говнокод: Код (PHP): if (isset($_SESSION['user_id']) …) { … setcookie('user_id', $user['id'], time() + 60 * 60 * 24 * 365); setcookie('password', md5($user['password']), time() + 60 * 60 * 24 * 365); сам догадаешся почему?
Хм. Наверное, задаю COOKIE и нигде их не использую? Или, может быть, в куках нельзя хранить пароль? Да и вообще, код весь мне самому не нравится, но ничего с этим поделать не могу. Например, при авторизации и переходу по сайту - ошибка headers already sent by. Если перенести setcookie чуть выше в __construct - тоже самое, только уже раз в 5 минут приблизительно. Уже и не знаю что делать...
Наверное потому говнокод, что ты заносишь в куку то, что тебе уже известно из сессии. Зачем этот дубль? Перепиши с нуля. Помоему здесь не за что держаться.
Хм. Разве при написании не нужно работать и с $_SESSION и с $_COOKIE? Ну, т.е., чтобы данные в них не различались. Попробую переписать заново, да только я не знаю уже, как.
ИЛИ, а не И Добавлено спустя 53 секунды: Идентификатор пользователя или в сессионной переменной или в специальной куке. Нет смысла читать значение из сессии и класть его в куку. Немного теории: viewtopic.php?f=13&t=53234&p=426001#p426001
Понял, спасибо. Попробую что-нибудь состряпать и напишу сюда. Пока никак не получается подружиться с PHPStorm.
В общем, переписал авторизацию на COOKIE. Хранятся ID пользователя + хэш. Авторизация вроде как работает без ошибок, всё хорошо. Но теперь запутался. Дело в том, что не удаляются COOKIE, как бы не пытался. class User Код (PHP): <?php class User { public $user; public $userID, $login, $password, $email; function __construct() { global $db; /** * Проверяем наличие COOKIE пользователя */ if (isset($_COOKIE['id']) && isset($_COOKIE['hash']) && (!empty($_COOKIE['id']) && !empty($_COOKIE['hash']))) { /** * Создаем массив с данными юзера */ $req = $db->query("SELECT * FROM `users` WHERE `id` = '" . intval($_COOKIE['id']) . "' LIMIT 1"); $this->user = $req->fetch(); $this->userID = $this->user['id']; /** * Если COOKIE не верны, обнуляем */ if (($this->user['hash'] !== $_COOKIE['hash']) || ($this->userID !== $_COOKIE['id'])) { setcookie("id", "", time() - 3600 * 24 * 30 * 12, "/"); setcookie("hash", "", time() - 3600 * 24 * 30 * 12, "/"); } } } public function registerUser($user_login, $user_password, $user_email) { global $db; $this->login = $user_login; $this->password = md5($user_password); $this->email = $user_email; /** * Подготавливаем запрос */ $st = $db->prepare("INSERT INTO `users` (`login`, `password`, `email`, `time`) VALUES (:login, :password, :email, :time)"); /** * Регистрируем пользователя в БД */ $st->execute(array( 'login' => $this->login, 'password' => $this->password, 'email' => $this->email, 'time' => time(), 'last_entry_time' => time() )); return true; } public static function login($login, $password) { global $db; $query = $db->query("SELECT * FROM `users` WHERE `login` = '$login' AND `password` = '$password' LIMIT 1"); $user = $query->fetch(); // Generate random string $hash = md5(Core::generateCode(10)); /** * Подготавливаем запрос */ $st = $db->prepare("UPDATE `users` SET `hash` = :hash, WHERE `id` = :id"); /** * Обновляем данные в БД */ $st->execute(array( 'hash' => $hash, 'id' => $user['id'] )); /** * Устанавливаем COOKIE */ setcookie("id", $user['id'], time()+60*60*24*30); setcookie("hash", $hash, time()+60*60*24*30); } } COOKIE удаляю так: Код (PHP): setcookie("id", "", time() - 3600*24*30*12, "/"); setcookie("hash", "", time() - 3600*24*30*12, "/"); В чём проблема?
отлаживайся. phpfaq.ru/debug может быть это место вообще не вызывается или вызывается в неподходящий момент. Добавлено спустя 3 минуты 29 секунд: когда дело доходит до отладки, не надо думать и рассуждать, очевидно что логика тебя уже подвела. просто проверяй всё подряд. Добавлено спустя 1 минуту 53 секунды: убери пожалуйста свои авторские ссылки из кода ))) это смешно.
Нет, ничего не получается. Да и авторизация толком не работает. На страницах выходе / авторизации пользователь есть, на главной странице авторизация сбивается. $_COOKIE и $user - пусты, если проверять var_dump`ом.
Проверял $_COOKIE и $user на всех страницах. Проверял наличие хэша. Хэш в БД не передавался, из-за опечатки, исправил, но в принципе, основная проблема осталась. На главной слетает авторизация, на странице выхода куки и $user не обнуляются.
MyZik, тебе надо проследить всю цепочку вызовов. Например примерно ты знаешь какой класс какая функция должны вызываться. И там самое простое можно написать так: echo "отладка функции testPHP()"; потом смотришь в окно браузера. А по поводу сессий. делай var_dump() на определенных участках кода, которые должны вызваться, и ты увидишь где именно происходит их обнуление.
Да делал уже, всё что можно... Почему-то на страницах, которые находятся в корне - авторизация сбивается. В файлах, которые в папках (например /users/) - авторизация работает. Бред какой-то.
Для опытных товарищей это очевидно, но не для нубов: 1. когда делаешь setcookie('name'…), значение $_COOKIE['name'] не меняется! Новое значение будет прочитано в переменную только при следующем запросе. 2. если ты в процессе жизнедеятельности успел насоздавать кук с разными значениями path, ты будешь получать разные значения одной и той же куки на разных страничках — депрессия гарантирована. разный path появляется если этот параметр не указан явно при вызове setcookie, считается что кука ставится для текущей папки (и вложенных в неё). Перед началом отладки чисти все куки домена!