10, 'login_window_seconds' => 900, 'login_lockout_seconds' => 900, 'session_ttl_seconds' => 30 * 24 * 60 * 60, 'temp_session_ttl_seconds' => 10 * 60, ]; } function qdb_settings_keys(): array { return array_keys(qdb_settings_defaults()); } function qdb_ensure_system_setting_table(PDO $pdo): void { if (!qdb_table_exists($pdo, 'system_setting')) { $pdo->exec(" CREATE TABLE system_setting ( settingKey TEXT NOT NULL PRIMARY KEY, settingValue TEXT NOT NULL DEFAULT '' ) "); } } function qdb_settings_get_on_pdo(PDO $pdo): array { qdb_ensure_system_setting_table($pdo); $out = qdb_settings_defaults(); $rows = $pdo->query('SELECT settingKey, settingValue FROM system_setting')->fetchAll(PDO::FETCH_ASSOC); foreach ($rows as $row) { $key = (string)($row['settingKey'] ?? ''); if ($key === '' || !array_key_exists($key, $out)) { continue; } $out[$key] = (int)$row['settingValue']; } return $out; } function qdb_settings_get(): array { require_once __DIR__ . '/../db_init.php'; [$pdo, $tmpDb, $lockFp] = qdb_open(false); try { return qdb_settings_get_on_pdo($pdo); } finally { qdb_discard($tmpDb, $lockFp); } } /** * @param array $partial * @param array|null $base existing settings; defaults used when null * @return array saved settings */ function qdb_settings_validate_and_merge(array $partial, ?array $base = null): array { $merged = $base ?? qdb_settings_defaults(); $limits = [ 'login_max_attempts' => [1, 100], 'login_window_seconds' => [60, 86400], 'login_lockout_seconds' => [60, 86400], 'session_ttl_seconds' => [3600, 365 * 24 * 60 * 60], 'temp_session_ttl_seconds' => [300, 24 * 60 * 60], ]; foreach (qdb_settings_keys() as $key) { if (!array_key_exists($key, $partial)) { continue; } $val = (int)$partial[$key]; [$min, $max] = $limits[$key]; if ($val < $min || $val > $max) { throw new InvalidArgumentException( "$key must be between $min and $max" ); } $merged[$key] = $val; } return $merged; } /** * @param array $settings full merged settings to persist */ function qdb_settings_save_on_pdo(PDO $pdo, array $settings): void { qdb_ensure_system_setting_table($pdo); $stmt = $pdo->prepare( 'INSERT INTO system_setting (settingKey, settingValue) VALUES (:k, :v) ON CONFLICT(settingKey) DO UPDATE SET settingValue = excluded.settingValue' ); foreach (qdb_settings_keys() as $key) { $stmt->execute([':k' => $key, ':v' => (string)(int)($settings[$key] ?? 0)]); } } function qdb_session_ttl_seconds(?array $settings = null, bool $temp = false): int { $settings ??= qdb_settings_get(); return $temp ? (int)$settings['temp_session_ttl_seconds'] : (int)$settings['session_ttl_seconds']; }