path = storage_path('system/users.json'); } public function hasAnyUsers(): bool { return count($this->all()) > 0; } public function all(): array { $data = decode_json_file($this->path, ['users' => []]); return array_values(array_filter($data['users'] ?? [], 'is_array')); } public function find(string $username): ?array { $needle = normalize_username($username); foreach ($this->all() as $user) { if (($user['username'] ?? '') === $needle) { return $user; } } return null; } public function verify(string $username, string $password): ?array { $user = $this->find($username); if ($user === null) { return null; } if (!password_verify($password, (string) ($user['password_hash'] ?? ''))) { return null; } return $user; } public function create(string $username, string $password, bool $isAdmin = false): array { $normalized = normalize_username($username); if ($normalized === '' || $this->find($normalized) !== null) { throw new RuntimeException('Benutzername existiert bereits oder ist ungueltig.'); } $users = $this->all(); $users[] = [ 'username' => $normalized, 'password_hash' => password_hash($password, PASSWORD_DEFAULT), 'is_admin' => $isAdmin, 'created_at' => date(DATE_ATOM), ]; $this->write(['users' => $users]); return $this->find($normalized) ?? []; } public function changePassword(string $username, string $password): void { $normalized = normalize_username($username); $users = $this->all(); foreach ($users as &$user) { if (($user['username'] ?? '') === $normalized) { $user['password_hash'] = password_hash($password, PASSWORD_DEFAULT); $user['updated_at'] = date(DATE_ATOM); } } unset($user); $this->write(['users' => $users]); } private function write(array $payload): void { if (!is_dir(dirname($this->path))) { mkdir(dirname($this->path), 0775, true); } file_put_contents( $this->path, json_encode($payload, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ); } }