cacheFilePath = $cacheFilePath; } public function get(string $key): ?string { $settings = $this->all(); $value = $settings[$key] ?? null; if ($value === null) { return null; } $value = trim((string) $value); return $value !== '' ? $value : null; } public function all(): array { if ($this->settings !== null) { return $this->settings; } $file = $this->filePath(); if (!is_file($file)) { $this->settings = []; return $this->settings; } $loaded = include $file; $this->settings = is_array($loaded) ? $loaded : []; return $this->settings; } public function update(array $values): bool { $current = $this->all(); foreach ($values as $key => $value) { $settingKey = trim((string) $key); if ($settingKey === '') { continue; } $current[$settingKey] = $value === null ? null : (string) $value; } return $this->write($current); } public function write(array $settings): bool { $file = $this->filePath(); $dir = dirname($file); if (!is_dir($dir) && !@mkdir($dir, 0775, true) && !is_dir($dir)) { return false; } // Write to a temp file first, then rename — rename is atomic on most filesystems, // so readers never see a half-written file. LOCK_EX prevents concurrent write corruption. $tmp = tempnam($dir, 'settings_'); if ($tmp === false) { return false; } // PHP include returns an array — loaded by OPcache on subsequent requests, much faster than DB. $payload = "exportValue($settings) . ";\n"; $written = @file_put_contents($tmp, $payload, LOCK_EX); if ($written === false) { @unlink($tmp); return false; } if (!@rename($tmp, $file)) { @unlink($tmp); return false; } $this->settings = $settings; return true; } public function filePath(): string { if (is_string($this->cacheFilePath) && $this->cacheFilePath !== '') { return $this->cacheFilePath; } return dirname(__DIR__, 3) . '/config/settings.php'; } private function exportValue(mixed $value, int $depth = 0): string { if (!is_array($value)) { return var_export($value, true); } if ($value === []) { return '[]'; } $indent = str_repeat(' ', $depth); $childIndent = str_repeat(' ', $depth + 1); $lines = []; foreach ($value as $key => $item) { $lines[] = $childIndent . var_export($key, true) . ' => ' . $this->exportValue($item, $depth + 1) . ','; } return "[\n" . implode("\n", $lines) . "\n" . $indent . ']'; } }