This repository has been archived on 2021-07-02. You can view files and clone it, but cannot push or open issues or pull requests.
chie/include/_user.php

253 lines
7.8 KiB
PHP

<?php
include_once '_utils.php';
define('FMF_UF_SCROLLBEYOND', 1);
//define('FMF_UF_NEWSTYLE', 2);
function get_user_id(string $username, string $email): int {
global $pdo;
$checkUser = $pdo->prepare('SELECT `user_id` FROM `fmf_users` WHERE LOWER(`user_login`) = LOWER(:login) OR LOWER(`user_email`) = LOWER(:email)');
$checkUser->bindValue('login', $username);
$checkUser->bindValue('email', $email);
$checkUser->execute();
return (int)$checkUser->fetchColumn();
}
function get_user_for_login(string $nameOrMail): array {
global $pdo;
$getUser = $pdo->prepare('SELECT `user_id`, `user_login`, `user_password`, `user_email_verification` FROM `fmf_users` WHERE LOWER(`user_login`) = LOWER(:login) OR LOWER(`user_email`) = LOWER(:email)');
$getUser->bindValue('login', $nameOrMail);
$getUser->bindValue('email', $nameOrMail);
$user = $getUser->execute() ? $getUser->fetch(PDO::FETCH_ASSOC) : false;
return $user ? $user : [];
}
function user_info(?int $user, bool $fresh = false): array {
global $pdo;
static $cache = [];
if($user < 1)
return [];
if(!$fresh && !empty($cache[$user]))
return $cache[$user];
$getUserInfo = $pdo->prepare('SELECT *, UNIX_TIMESTAMP(`user_created`) AS `user_created`, UNIX_TIMESTAMP(`user_banned`) AS `user_banned`, MD5(LOWER(TRIM(`user_email`))) AS `gravatar_hash` FROM `fmf_users` WHERE `user_id` = :user');
$getUserInfo->bindValue('user', $user);
$userInfo = $getUserInfo->execute() ? $getUserInfo->fetch(PDO::FETCH_ASSOC) : false;
return $cache[$user] = ($userInfo ? $userInfo : []);
}
function user_has_flag(int $user, int $flag, bool $strict = false): bool {
$userInfo = user_info($user);
if(empty($userInfo))
return false;
$flags = ($userInfo['user_flags'] & $flag);
return $strict ? ($flags === $flag) : ($flags > 0);
}
function create_user(string $username, string $email, string $password, string $ipAddr, bool $verified = false): array {
global $pdo;
$verification = $verified ? null : bin2hex(random_bytes(16));
$createUser = $pdo->prepare('INSERT INTO `fmf_users` (`user_login`, `user_password`, `user_email`, `user_email_verification`, `user_ip_created`) VALUES (:login, :password, :email, :verification, INET6_ATON(:ip))');
$createUser->bindValue('login', $username);
$createUser->bindValue('password', password_hash($password, PASSWORD_DEFAULT));
$createUser->bindValue('email', $email);
$createUser->bindValue('verification', $verification);
$createUser->bindValue('ip', $ipAddr);
$createUser->execute();
return [
'user_id' => (int)$pdo->lastInsertId(),
'verification' => $verification,
];
}
function validate_username(string $username): ?string {
if($username !== trim($username))
return 'Your username may not start or end with spaces.';
$usernameLength = strlen($username);
if($usernameLength < 3)
return 'Your username must be longer than 3 characters.';
if($usernameLength > 16)
return 'Your username may not be longer than 16 characters.';
if(!preg_match('#^[A-Za-z0-9-_]+$#u', $username))
return 'Your username may only contains alphanumeric characters, dashes and underscores (A-Z, a-z, 0-9, -, _).';
return null;
}
function validate_email(string $email): ?string {
if(filter_var($email, FILTER_VALIDATE_EMAIL) === false)
return 'Your e-mail address is not correctly formatted.';
$domain = mb_substr(mb_strstr($email, '@'), 1);
if(!checkdnsrr($domain, 'MX') && !checkdnsrr($domain, 'A'))
return 'Your e-mail address domain does not have valid DNS records.';
return null;
}
function validate_password(string $password): ?string {
if(unique_chars($password) < 10)
return 'Your password is too weak.';
return null;
}
function activate_user(string $code): void {
global $pdo;
if(strlen($code) !== 32)
return;
$verify = $pdo->prepare('UPDATE `fmf_users` SET `user_email_verification` = NULL WHERE `user_email_verification` = :code');
$verify->bindValue('code', $code);
$verify->execute();
}
function create_session(int $userId): string {
global $pdo;
if($userId < 1)
return '';
$sessionKey = bin2hex(random_bytes(32));
$createSession = $pdo->prepare('INSERT INTO `fmf_sessions` (`user_id`, `sess_key`) VALUES (:user, :key)');
$createSession->bindValue('user', $userId);
$createSession->bindValue('key', $sessionKey);
$createSession->execute();
return $sessionKey;
}
function purge_old_sessions(): void {
global $pdo;
$pdo->exec('DELETE FROM `fmf_sessions` WHERE `sess_created` + INTERVAL 1 MONTH <= NOW()');
}
function session_activate(?string $key): void {
global $pdo;
if(empty($key) || strlen($key) !== 64)
return;
$verify = $pdo->prepare('SELECT `user_id` FROM `fmf_sessions` WHERE `sess_key` = :key AND `sess_created` + INTERVAL 1 MONTH > NOW()');
$verify->bindValue('key', $key);
$userId = $verify->execute() ? $verify->fetchColumn() : 0;
if($userId < 1)
return;
$GLOBALS['fmf_user_id'] = (int)$userId;
}
function session_active(): bool {
return !empty($GLOBALS['fmf_user_id']) && is_int($GLOBALS['fmf_user_id']) && $GLOBALS['fmf_user_id'] > 0;
}
function logout_token(): string {
$sessionKey = $_COOKIE['fmfauth'] ?? '';
if(strlen($sessionKey) !== 64 || !ctype_xdigit($sessionKey))
return bin2hex(random_bytes(4));
$offset = hexdec($sessionKey[0]) * 2;
$offset = hexdec($sessionKey[$offset]) * 2;
$offset = hexdec($sessionKey[$offset]) * 2;
return substr($sessionKey, $offset, 8);
}
function destroy_session(string $token): void {
global $pdo;
$delete = $pdo->prepare('DELETE FROM `fmf_sessions` WHERE `sess_key` = :key');
$delete->bindValue('key', $token);
$delete->execute();
}
function destroy_user_sessions(int $userId): void {
global $pdo;
$delete = $pdo->prepare('DELETE FROM `fmf_sessions` WHERE `user_id` = :user');
$delete->bindValue('user', $userId);
$delete->execute();
}
function destroy_current_user_sessions(): void {
destroy_user_sessions(current_user_id());
}
function current_user_id(): int {
return session_active() ? $GLOBALS['fmf_user_id'] : 0;
}
function verify_password(string $pass, ?int $user = null): bool {
global $pdo;
$user = $user ?? current_user_id();
if($user < 1)
return false;
$getHash = $pdo->prepare('SELECT `user_password` FROM `fmf_users` WHERE `user_id` = :user');
$getHash->bindValue('user', $user);
$hash = $getHash->execute() ? $getHash->fetchColumn() : '';
if(empty($hash))
return false;
return password_verify($pass, $hash);
}
function user_set_password(int $user, string $password): void {
global $pdo;
if($user < 1)
return;
$password = password_hash($password, PASSWORD_DEFAULT);
$update = $pdo->prepare('UPDATE `fmf_users` SET `user_password` = :pass WHERE `user_id` = :user');
$update->bindValue('pass', $password);
$update->bindValue('user', $user);
$update->execute();
}
function user_set_email(int $user, string $email, bool $verified = false): ?string {
global $pdo;
if($user < 1)
return null;
$verification = $verified ? null : bin2hex(random_bytes(16));
$update = $pdo->prepare('UPDATE `fmf_users` SET `user_email` = LOWER(:mail), `user_email_verification` = :verf WHERE `user_id` = :user');
$update->bindValue('mail', $email);
$update->bindValue('verf', $verification);
$update->bindValue('user', $user);
$update->execute();
return $verification;
}
function user_gravatar(?int $user, int $res = 80): string {
$authorInfo = user_info($user);
return '//www.gravatar.com/avatar/'. ($authorInfo['gravatar_hash'] ?? str_repeat('0', 32)) .'?s='. $res .'&amp;r=g&amp;d=identicon';
}