ДЛЯ ВЕРСИИ TL; DR ... ПЕРЕЙДИТЕ ВНИЗ И ПРОЧИТАЙТЕ, ЧТО ВЫДЕЛено жирным шрифтом
Хорошо, у меня была эта проблема какое-то время, я провел много исследований, внес некоторые изменения и до сих пор понятия не имею, что не так с моим кодом. Моя проблема в том, что когда пользователь отправляет регистрационную форму, сеанс всегда возвращается к пустому. Вот как выглядит логика:
1. Пользователь переходит к mysite / register / и получает доступ к register.php через index.php в том же каталоге.
2. index.php обрабатывает все (вызывает классы для логики и тому подобное, но все выполняется через index.php на верхнем уровне)
3. Пользователь отправляет форму входа через ajax-вызов vanilla.js, и в ответ console.infos возвращается.
Теперь, когда вы понимаете логику ... позвольте мне перейти к коду:
Вот index.php:
<?php
// Allowing PHP to be strictly typed and start session
declare(strict_types=1);
session_start();
// Requiring the necessary classes
require_once "../vendor/autoload.php";
require_once "../model/EditSession.php";
require_once "../model/DatabaseConfig.php";
require_once "../model/ServerValidation.php";
require_once "../model/RegisterUser.php";
require_once "../model/Verify.php";
// Creating the new objects
$validatingServer = new ServerValidation();
$sessionToEdit = new EditSession();
$sessionToEdit->create_new_session_id();
// Checks the request protocol
try {
$validatingServer->checkHttps();
} catch (Exception $ex) {
header("Location: /NotSecure.php");
}
// Setting CSRF token for protection
try {
$csrfToken = $sessionToEdit->store_secure_key_in_session("CSRFTOKEN");
} catch (Exception $ex) {
echo "You have a problem setting your session. $ex";
}
// Handling a navigation to the webpage
$validatingServer->navigateToWebsite("register.php", "Register", $csrfToken);
// For when a user submits the form
try {
$validatingServer->checkRequestType("POST");
$validatingServer->checkContentType("application/json");
$registerFormData = json_decode(file_get_contents("php://input"), true);
$csrfTokenFromForm = $registerFormData["csrfToken"];
$csrfTokenFromSession = $sessionToEdit->get_from_session("CSRFTOKEN");
} catch (Exception $ex) {
echo "Bad request data. $ex";
}
//$validatingServer->checkToken($csrfTokenFromForm, $csrfTokenFromSession);
// Call to make original register user object
try {
$register = new RegisterUser($registerFormData["firstName"], $registerFormData["lastName"], $registerFormData["email"], $registerFormData["password"]);
} catch (Exception $ex) {
echo $ex;
}
// Check email and register the user
try {
$register->checkEmail();
$register->register();
} catch (Exception $ex) {
echo $ex;
}
// Sending registration email to the user
try {
$register->sendRegistrationEmail("http://localhost/");
} catch (Exception $ex) {
echo $ex;
}
echo "Successful Register";
Вот фронтенд
<!doctype html>
<html>
<head>
<title><?=$pageTitle;?></title>
</head>
<body>
<main>
<form id = "registerForm">
<input type = "text" id = "firstName" name = "firstName" autocomplete = "given-name" placeholder = "First Name" pattern = "^[A-Za-z.\s_-]+$" autofocus required>
<input type = "text" id = "lastName" name = "lastName" autocomplete = "family-name" placeholder = "Last Name" pattern = "^[A-Za-z.\s_-]+$" required>
<input type = "email" id = "email" name = "email" autocomplete = "email" placeholder = "Email" required>
<input type = "password" id = "password" name = "password" placeholder = "Password" pattern = "^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#\$%\^&\*]).{8,}" required>
<input type = "hidden" id = "csrfToken" value = "<?=$csrfToken;?>">
<button type = "submit" id = "registerSubmit">Submit</button>
</form>
</main>
<script src = "index.js"></script>
</body>
</html>
Вот index.js
const registerForm = document.getElementById("registerForm");
registerForm.addEventListener("submit", function(e) {
e.preventDefault();
const firstName = document.getElementById("firstName").value;
const lastName = document.getElementById("lastName").value;
const email = document.getElementById("email").value;
const password = document.getElementById("password").value;
const csrfToken = document.getElementById("csrfToken").value;
const registerFormData = {
"firstName":firstName,
"lastName":lastName,
"email":email,
"password":password,
"csrfToken":csrfToken
};
const ajax = new XMLHttpRequest();
ajax.open("POST", "index.php");
ajax.setRequestHeader("Content-Type", "application/json");
ajax.withCredentials = true;
ajax.send(JSON.stringify(registerFormData));
ajax.onload = function() {
console.info(this.response);
}
}, false);
Вот EditSession.php
<?php
declare(strict_types=1);
class EditSession {
private $firstPartOfNewId;
private $secondPartOfNewId;
private $thirdPartOfNewId;
private $newSID;
public $secureKey = "";
// Create new session ID
function create_new_session_id() : void {
if (isset($_SESSION)) {
$firstPartOfNewId = str_replace(array(".", ":"), "", $_SERVER["REMOTE_ADDR"]);
$secondPartOfNewId = round(microtime(true) * 1000);
$thirdPartOfNewId = hash("sha512", random_bytes(64));
$newSID = $firstPartOfNewId.$secondPartOfNewId.$thirdPartOfNewId;
session_id($newSID);
} else {
throw new Exception("Session is not set");
}
}
// Store a value in a set session
function store_in_session(string $key,string $value) : void {
if (!isset($_SESSION)) {
throw new Exception("Session is not set.");
}
if (!isset($_SESSION[$key])) {
$_SESSION[$key] = $value;
}
}
// Store a value in a set session
function store_secure_key_in_session(string $key) : string {
if (!isset($_SESSION)) {
throw new Exception("Session is not set.");
}
if (!isset($_SESSION[$key])) {
$secureKey = hash("sha512", random_bytes(64));
$_SESSION[$key] = $secureKey;
return $secureKey;
} else {
return $secureKey;
}
}
// Unsetting variable associated with the $key
function unset_session_variable(string $key) : void {
if (isset($_SESSION)) {
$_SESSION[$key] = "";
unset($_SESSION[$key]);
} else {
throw new Exception("Session with key is not set.");
}
}
// Getting associated key from session
function get_from_session(string $key) : string {
if (isset($_SESSION[$key])) {
return $_SESSION[$key];
} elseif (isset($_SESSION)) {
throw new Exception("Session is set, but the key passed is not set in the session.");
} else {
throw new Exception("Session is not set.");
}
}
}
?>
Вот ServerValidation.php
<?php
declare(strict_types=1);
class ServerValidation {
// Handles navigation to website
function navigateToWebsite(string $page, string $pageTitle, string $csrfToken) : void {
if (empty($_POST) && empty($_GET) && empty(file_get_contents("php://input"))) {
$csrfToken = $csrfToken;
$pageTitle = $pageTitle;
include_once $page;
exit;
}
}
// Checks if the website is served over https or its localhost
function checkHttps() : void {
if ($_SERVER["REQUEST_SCHEME"] !== "https" && $_SERVER["HTTP_HOST"] !== "localhost") {
throw new Exception("Not served over https");
}
}
// Checks if the content type is what it should be
function checkContentType(string $type) : void {
if ($_SERVER["CONTENT_TYPE"] !== $type) {
throw new Exception("Wrong content-type");
}
}
// Checks request method
function checkRequestType(string $type) : void {
if ($_SERVER["REQUEST_METHOD"] !== $type) {
throw new Exception("Wrong request method");
}
}
function checkToken(string $tokenFromFrontend, string $tokenFromSession) : void {
if ($tokenFromSession !== $tokenFromFrontend) {
throw new Exception("Tokens not matching up, there is a problem!!");
}
}
}
Теперь вот что происходит с кодом. Когда пользователь отправляет регистрационную форму с помощью csrfToken, который извлекается из скрытого значения в форме с помощью AJAX, я получаю исключение в моей программе (в частности, из метода checkToken() в классе ServerValidation), в котором говорится, что «токены не совпадают. ". И я подтвердил, почему это так. Если я var_dump $ _SESSION сразу после вызова session_start (), ВСЕГДА будет пустым. Не имеет значения, был ли он уже инициализирован (пользователем, впервые переходящим на страницу), он ВСЕГДА пуст. Итак, следуя логике программы, она вставляет новое значение для CSRFTOKEN, и поэтому, конечно, они не совпадают. Я в полном тупике и неделю работаю над этой проблемой. Вот несколько ответов на вопросы, которые, я знаю, вам зададут:
1. Я использую macbook с XAMPP и php 7.2
.
2. Мои файлы cookie установлены на http_only, но не на secure_only. Все остальные параметры файлов cookie заданы по умолчанию.
3. Мои права доступа к файлам, в которых хранятся данные моего сеанса (/ Applications / XAMPP / xamppfiles / temp /), равны 777 (я просто хотел сделать что-то, что, я знаю, будет работать)
4. Что произойдет, если я не создам новый php session_id? Произойдет тот же результат ... т.е. сеанс будет по-прежнему всегда инициализирован как empty
5. Могу ли я var_dump сеанса в разных точках программы? Конечно ... вот разные моменты и их результаты:
- Сразу после вызова session_start:
- Когда пользователь изначально переходит на страницу: пустой сеанс.
- Когда пользователь отправил регистрационную форму: пустая сессия
- Сразу после того, как $csrfToken = $sessionToEdit->store_secure_key_in_session("CSRFTOKEN"); называется:
- Когда пользователь изначально переходит на страницу: возвращается сеанс с ключом CSRFTOKEN
- Когда пользователь отправил регистрационную форму: возвращается сеанс с ключом CSRFTOKEN (но значение отличается от того, когда пользователь изначально перешел на страницу)
- Сразу после $validatingServer->navigateToWebsite("register.php", "Register", $csrfToken);
- Когда пользователь сначала переходит на страницу: ничего, потому что программа не заходит так далеко, потому что выходит из нее.
- Когда пользователь отправил регистрационную форму: возвращается сеанс с ключом CSRFTOKEN (но значение отличается от того, когда пользователь изначально перешел на страницу, и значение отличается от того, что находится в скрытом поле в регистрационной форме. )
Вот вопрос: Почему значения моего сеанса продолжают инициализироваться пустыми, даже если я нахожусь в том же домене, выполняю всю свою работу в одном файле, правильно ли заданы параметры сеанса и права доступа к файлу установлены правильно?
@CBroe, о каком методе ты говоришь?
Какой вам нравится ...? Теперь уверен, в чем вопрос.
@CBroe ну, что вы имеете в виду, убедитесь, что клиент отправляет правильный идентификатор сеанса?
Да, конечно (а также, что он также правильно принимается внутри серверного скрипта) ... поскольку это основа для правильной работы сеансов, это также должно быть первое, что вы проверяете.
@CBroe, я проверил это, и ответ отрицательный. Вот почему сеанс каждый раз инициализируется как пустой.






Вы проверили, правильно ли клиент отправляет идентификатор сеанса?