2018-05-27 02:20:35 +02:00
|
|
|
<?php
|
2018-10-03 00:34:05 +02:00
|
|
|
define('MSZ_SESSION_DATA_STORE', '_msz_user_session_data');
|
2018-05-27 02:20:35 +02:00
|
|
|
define('MSZ_SESSION_KEY_SIZE', 64);
|
|
|
|
|
|
|
|
function user_session_create(
|
|
|
|
int $userId,
|
|
|
|
string $ipAddress,
|
|
|
|
string $userAgent
|
|
|
|
): string {
|
|
|
|
$sessionKey = user_session_generate_key();
|
|
|
|
|
2018-10-07 01:30:48 +02:00
|
|
|
$createSession = db_prepare('
|
2018-05-27 02:20:35 +02:00
|
|
|
INSERT INTO `msz_sessions`
|
|
|
|
(
|
|
|
|
`user_id`, `session_ip`, `session_country`,
|
2018-10-29 22:18:53 +01:00
|
|
|
`session_user_agent`, `session_key`, `session_created`, `session_expires`
|
2018-05-27 02:20:35 +02:00
|
|
|
)
|
|
|
|
VALUES
|
|
|
|
(
|
|
|
|
:user_id, INET6_ATON(:session_ip), :session_country,
|
2018-10-29 22:18:53 +01:00
|
|
|
:session_user_agent, :session_key, NOW(), NOW() + INTERVAL 1 MONTH
|
2018-05-27 02:20:35 +02:00
|
|
|
)
|
|
|
|
');
|
|
|
|
$createSession->bindValue('user_id', $userId);
|
|
|
|
$createSession->bindValue('session_ip', $ipAddress);
|
2018-09-27 10:32:43 +02:00
|
|
|
$createSession->bindValue('session_country', ip_country_code($ipAddress));
|
2018-10-29 22:18:53 +01:00
|
|
|
$createSession->bindValue('session_user_agent', $userAgent);
|
2018-05-27 02:20:35 +02:00
|
|
|
$createSession->bindValue('session_key', $sessionKey);
|
|
|
|
|
|
|
|
return $createSession->execute() ? $sessionKey : '';
|
|
|
|
}
|
|
|
|
|
2018-10-03 00:34:05 +02:00
|
|
|
function user_session_find($sessionId, bool $byKey = false): array
|
2018-09-28 00:03:43 +02:00
|
|
|
{
|
2018-10-03 00:34:05 +02:00
|
|
|
if (!$byKey && $sessionId < 1) {
|
2018-09-28 00:03:43 +02:00
|
|
|
return [];
|
|
|
|
}
|
|
|
|
|
2018-10-07 01:30:48 +02:00
|
|
|
$findSession = db_prepare(sprintf('
|
2018-09-28 00:03:43 +02:00
|
|
|
SELECT
|
2019-03-31 01:53:46 +01:00
|
|
|
`session_id`, `user_id`,
|
|
|
|
INET6_NTOA(`session_ip`) as `session_ip`,
|
|
|
|
INET6_NTOA(`session_ip_last`) as `session_ip_last`,
|
|
|
|
`session_country`, `session_user_agent`, `session_key`, `session_created`,
|
|
|
|
`session_expires`, `session_active`, `session_expires_bump`
|
2018-09-28 00:03:43 +02:00
|
|
|
FROM `msz_sessions`
|
2018-10-03 00:34:05 +02:00
|
|
|
WHERE `%s` = :session_id
|
|
|
|
', $byKey ? 'session_key' : 'session_id'));
|
2018-09-28 00:03:43 +02:00
|
|
|
$findSession->bindValue('session_id', $sessionId);
|
2019-01-09 20:06:02 +01:00
|
|
|
return db_fetch($findSession);
|
2018-09-28 00:03:43 +02:00
|
|
|
}
|
|
|
|
|
2018-10-03 00:34:05 +02:00
|
|
|
function user_session_delete(int $sessionId): void
|
2018-05-27 02:20:35 +02:00
|
|
|
{
|
2018-10-07 01:30:48 +02:00
|
|
|
$deleteSession = db_prepare('
|
2018-05-27 02:20:35 +02:00
|
|
|
DELETE FROM `msz_sessions`
|
|
|
|
WHERE `session_id` = :session_id
|
|
|
|
');
|
|
|
|
$deleteSession->bindValue('session_id', $sessionId);
|
2018-10-03 00:34:05 +02:00
|
|
|
$deleteSession->execute();
|
2018-05-27 02:20:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function user_session_generate_key(): string
|
|
|
|
{
|
|
|
|
return bin2hex(random_bytes(MSZ_SESSION_KEY_SIZE / 2));
|
|
|
|
}
|
2018-09-28 00:03:43 +02:00
|
|
|
|
|
|
|
function user_session_purge_all(int $userId): void
|
|
|
|
{
|
2018-10-07 01:30:48 +02:00
|
|
|
db_prepare('
|
2018-09-28 00:03:43 +02:00
|
|
|
DELETE FROM `msz_sessions`
|
|
|
|
WHERE `user_id` = :user_id
|
|
|
|
')->execute([
|
|
|
|
'user_id' => $userId,
|
|
|
|
]);
|
|
|
|
}
|
2018-10-03 00:34:05 +02:00
|
|
|
|
2018-10-29 20:12:06 +01:00
|
|
|
function user_session_count($userId = 0): int
|
|
|
|
{
|
|
|
|
$getCount = db_prepare(sprintf('
|
|
|
|
SELECT COUNT(`session_id`)
|
|
|
|
FROM `msz_sessions`
|
|
|
|
WHERE %s
|
|
|
|
', $userId < 1 ? '1' : '`user_id` = :user_id'));
|
|
|
|
|
|
|
|
if ($userId >= 1) {
|
|
|
|
$getCount->bindValue('user_id', $userId);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $getCount->execute() ? (int)$getCount->fetchColumn() : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function user_session_list(int $offset, int $take, int $userId = 0): array
|
|
|
|
{
|
|
|
|
$offset = max(0, $offset);
|
|
|
|
$take = max(1, $take);
|
|
|
|
|
|
|
|
$getSessions = db_prepare(sprintf('
|
|
|
|
SELECT
|
2019-03-31 01:53:46 +01:00
|
|
|
`session_id`, `session_country`, `session_user_agent`, `session_created`,
|
|
|
|
`session_expires`, `session_active`, `session_expires_bump`,
|
|
|
|
INET6_NTOA(`session_ip`) as `session_ip`,
|
|
|
|
INET6_NTOA(`session_ip_last`) as `session_ip_last`
|
2018-10-29 20:12:06 +01:00
|
|
|
FROM `msz_sessions`
|
|
|
|
WHERE %s
|
|
|
|
ORDER BY `session_id` DESC
|
|
|
|
LIMIT :offset, :take
|
|
|
|
', $userId < 1 ? '1' : '`user_id` = :user_id'));
|
|
|
|
|
|
|
|
if ($userId > 0) {
|
|
|
|
$getSessions->bindValue('user_id', $userId);
|
|
|
|
}
|
|
|
|
|
|
|
|
$getSessions->bindValue('offset', $offset);
|
|
|
|
$getSessions->bindValue('take', $take);
|
|
|
|
|
2019-01-09 20:06:02 +01:00
|
|
|
return db_fetch_all($getSessions);
|
2018-10-29 20:12:06 +01:00
|
|
|
}
|
|
|
|
|
2019-03-31 01:53:46 +01:00
|
|
|
function user_session_bump_active(int $sessionId, string $ipAddress = null): void
|
2018-10-29 22:23:53 +01:00
|
|
|
{
|
|
|
|
if ($sessionId < 1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$bump = db_prepare('
|
|
|
|
UPDATE `msz_sessions`
|
2019-03-31 01:53:46 +01:00
|
|
|
SET `session_active` = NOW(),
|
|
|
|
`session_ip_last` = INET6_ATON(:last_ip),
|
|
|
|
`session_expires` = IF(`session_expires_bump`, NOW() + INTERVAL 1 MONTH, `session_expires`)
|
2018-10-29 22:23:53 +01:00
|
|
|
WHERE `session_id` = :session_id
|
|
|
|
');
|
|
|
|
$bump->bindValue('session_id', $sessionId);
|
2019-03-31 01:53:46 +01:00
|
|
|
$bump->bindValue('last_ip', $ipAddress ?? ip_remote_address());
|
2018-10-29 22:23:53 +01:00
|
|
|
$bump->execute();
|
|
|
|
}
|
|
|
|
|
2018-10-03 00:34:05 +02:00
|
|
|
// the functions below this line are imperative
|
|
|
|
|
|
|
|
function user_session_start(int $userId, string $sessionKey): bool
|
|
|
|
{
|
|
|
|
$session = user_session_find($sessionKey, true);
|
|
|
|
|
|
|
|
if (!$session
|
|
|
|
|| $session['user_id'] !== $userId) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-10-29 22:18:53 +01:00
|
|
|
if (time() >= strtotime($session['session_expires'])) {
|
2018-10-03 00:34:05 +02:00
|
|
|
user_session_delete($session['session_id']);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$GLOBALS[MSZ_SESSION_DATA_STORE] = $session;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
function user_session_stop(bool $delete = false): void
|
|
|
|
{
|
|
|
|
if (empty($GLOBALS[MSZ_SESSION_DATA_STORE])) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($delete) {
|
|
|
|
user_session_delete($GLOBALS[MSZ_SESSION_DATA_STORE]['session_id']);
|
|
|
|
}
|
|
|
|
|
|
|
|
$GLOBALS[MSZ_SESSION_DATA_STORE] = [];
|
|
|
|
}
|
|
|
|
|
|
|
|
function user_session_current(?string $variable = null, $default = null)
|
|
|
|
{
|
|
|
|
if (empty($variable)) {
|
|
|
|
return $GLOBALS[MSZ_SESSION_DATA_STORE] ?? [];
|
|
|
|
}
|
|
|
|
|
|
|
|
return $GLOBALS[MSZ_SESSION_DATA_STORE][$variable] ?? $default;
|
|
|
|
}
|
|
|
|
|
|
|
|
function user_session_active(): bool
|
|
|
|
{
|
|
|
|
return !empty($GLOBALS[MSZ_SESSION_DATA_STORE])
|
2018-10-29 22:18:53 +01:00
|
|
|
&& time() < strtotime($GLOBALS[MSZ_SESSION_DATA_STORE]['session_expires']);
|
2018-10-03 00:34:05 +02:00
|
|
|
}
|
2019-02-12 16:26:39 +01:00
|
|
|
|
|
|
|
define('MSZ_SESSION_COOKIE_VERSION', 1);
|
|
|
|
// make sure to match this to the final fixed size of the cookie string
|
|
|
|
// it'll pad older tokens out for backwards compatibility
|
|
|
|
define('MSZ_SESSION_COOKIE_SIZE', 37);
|
|
|
|
|
|
|
|
function user_session_cookie_pack(int $userId, string $sessionToken): ?string
|
|
|
|
{
|
|
|
|
if (strlen($sessionToken) !== MSZ_SESSION_KEY_SIZE) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return pack('CNH64', MSZ_SESSION_COOKIE_VERSION, $userId, $sessionToken);
|
|
|
|
}
|
|
|
|
|
|
|
|
function user_session_cookie_unpack(string $packed): array
|
|
|
|
{
|
|
|
|
$packed = str_pad($packed, MSZ_SESSION_COOKIE_SIZE, "\x00");
|
|
|
|
$unpacked = unpack('Cversion/Nuser/H64token', $packed);
|
|
|
|
|
|
|
|
if ($unpacked['version'] < 1 || $unpacked['version'] > MSZ_SESSION_COOKIE_VERSION) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure this contains all fields with a default for version > 1 exclusive stuff
|
|
|
|
$data = [
|
|
|
|
'user_id' => $unpacked['user'],
|
|
|
|
'session_token' => $unpacked['token'],
|
|
|
|
];
|
|
|
|
|
|
|
|
return $data;
|
|
|
|
}
|