cookiePrefix(); $this->sessionCookieName = $prefix . 'session'; $this->clientCookieName = $prefix . 'client'; } public function start(): void { if (PHP_SAPI === 'cli') { return; } if (session_status() !== PHP_SESSION_NONE) { return; } session_name($this->sessionCookieName); $secure = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https'); session_set_cookie_params([ 'lifetime' => 0, 'path' => '/', 'domain' => $this->config->cookieDomain(), 'secure' => $secure, 'httponly' => true, 'samesite' => 'Lax', ]); session_start(); } public function ensureClientId(int $lifetimeSeconds = 31536000): string { if (PHP_SAPI === 'cli') { return 'cli'; } $id = $_COOKIE[$this->clientCookieName] ?? null; if (!is_string($id) || !preg_match('/^[a-f0-9]{64}$/', $id)) { $id = bin2hex(random_bytes(32)); $secure = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https'); setcookie($this->clientCookieName, $id, [ 'expires' => time() + $lifetimeSeconds, 'path' => '/', 'domain' => $this->config->cookieDomain(), 'secure' => $secure, 'httponly' => false, // accessible to JS if needed 'samesite' => 'Lax', ]); $_COOKIE[$this->clientCookieName] = $id; } return $id; } }