112 lines
2.9 KiB
PHP
112 lines
2.9 KiB
PHP
<?php
|
|
/*
|
|
* usersettings.php
|
|
*
|
|
* Tiny SQLite-backed key/value store for per-user UI preferences.
|
|
*/
|
|
|
|
class UserSettingsStoreException extends Exception
|
|
{
|
|
}
|
|
|
|
class UserSettingsStore
|
|
{
|
|
private $db;
|
|
|
|
public function __construct($dbFile)
|
|
{
|
|
$dir = dirname($dbFile);
|
|
|
|
if (!is_dir($dir)) {
|
|
if (!mkdir($dir, 0700, true)) {
|
|
throw new UserSettingsStoreException('Could not create database directory: ' . $dir);
|
|
}
|
|
}
|
|
|
|
$this->db = new PDO('sqlite:' . $dbFile);
|
|
$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|
$this->db->exec('PRAGMA journal_mode = WAL');
|
|
$this->db->exec('PRAGMA busy_timeout = 5000');
|
|
|
|
$this->init();
|
|
}
|
|
|
|
private function init()
|
|
{
|
|
$this->db->exec(
|
|
'CREATE TABLE IF NOT EXISTS user_settings (
|
|
user_id INTEGER NOT NULL,
|
|
setting_key TEXT NOT NULL,
|
|
setting_value TEXT NOT NULL,
|
|
created_at INTEGER NOT NULL,
|
|
updated_at INTEGER NOT NULL,
|
|
PRIMARY KEY(user_id, setting_key)
|
|
)'
|
|
);
|
|
}
|
|
|
|
public function get($userId, $key, $default = null)
|
|
{
|
|
$stmt = $this->db->prepare(
|
|
'SELECT setting_value
|
|
FROM user_settings
|
|
WHERE user_id = :user_id
|
|
AND setting_key = :setting_key'
|
|
);
|
|
$stmt->execute(array(
|
|
':user_id' => $this->safeUserId($userId),
|
|
':setting_key' => $this->safeKey($key),
|
|
));
|
|
|
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
return $row ? (string)$row['setting_value'] : $default;
|
|
}
|
|
|
|
public function set($userId, $key, $value)
|
|
{
|
|
$now = time();
|
|
|
|
$stmt = $this->db->prepare(
|
|
'INSERT INTO user_settings
|
|
(user_id, setting_key, setting_value, created_at, updated_at)
|
|
VALUES
|
|
(:user_id, :setting_key, :setting_value, :created_at, :updated_at)
|
|
ON CONFLICT(user_id, setting_key)
|
|
DO UPDATE SET
|
|
setting_value = excluded.setting_value,
|
|
updated_at = excluded.updated_at'
|
|
);
|
|
|
|
$stmt->execute(array(
|
|
':user_id' => $this->safeUserId($userId),
|
|
':setting_key' => $this->safeKey($key),
|
|
':setting_value' => (string)$value,
|
|
':created_at' => $now,
|
|
':updated_at' => $now,
|
|
));
|
|
}
|
|
|
|
private function safeUserId($userId)
|
|
{
|
|
$userId = (int)$userId;
|
|
|
|
if ($userId <= 0) {
|
|
throw new UserSettingsStoreException('Invalid user id.');
|
|
}
|
|
|
|
return $userId;
|
|
}
|
|
|
|
private function safeKey($key)
|
|
{
|
|
$key = trim((string)$key);
|
|
|
|
if (!preg_match('/^[a-z0-9_.-]{1,80}$/', $key)) {
|
|
throw new UserSettingsStoreException('Invalid setting key.');
|
|
}
|
|
|
|
return $key;
|
|
}
|
|
}
|