initial import
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user