public function check() : bool
{
if (!isset($_SESSION[$this->sessionIndex])) {
// We don't even have a session array initialized
$_SESSION[$this->sessionIndex] = [];
return false;
}
if (!isset($_POST[self::FORM_TOKEN]) || !\is_string($_POST[self::FORM_TOKEN])) {
return false;
}
if (\strpos($_POST[self::FORM_TOKEN], ':') === false) {
return false;
}
// Let's pull the POST data
list($index, $token) = \explode(':', $_POST[self::FORM_TOKEN]);
if (empty($index) || empty($token)) {
return false;
}
if (!isset($_SESSION[$this->sessionIndex][$index])) {
// CSRF Token not found
return false;
}
// Grab the value stored at $index
$stored = $_SESSION[$this->sessionIndex][$index];
// We don't need this anymore
unset($_SESSION[$this->sessionIndex][$index]);
// Which form action="" is this token locked to?
$lockTo = $_SERVER['REQUEST_URI'];
if (\preg_match('#/$#', $lockTo)) {
// Trailing slashes are to be ignored
$lockTo = substr($lockTo, 0, strlen($lockTo) - 1);
}
if (!empty($stored['lockto'])) {
if (!\hash_equals($lockTo, $stored['lockto'])) {
// Form target did not match the request this token is locked to!
return false;
}
}
// This is the expected token value
if ($this->hmacIP === false) {
// We just stored it wholesale
$expected = $stored['token'];
} else {
// We mixed in the client IP address to generate the output
$expected = Base64UrlSafe::encode(CryptoUtil::raw_keyed_hash($_SERVER['REMOTE_ADDR'] ?? '127.0.0.1', Base64UrlSafe::decode($stored['token'])));
}
return \hash_equals($token, $expected);
}