diff --git a/src/PhpSessionPersistence.php b/src/PhpSessionPersistence.php index 3657182..42652b7 100644 --- a/src/PhpSessionPersistence.php +++ b/src/PhpSessionPersistence.php @@ -31,6 +31,9 @@ use function sprintf; use function time; +use const FILTER_VALIDATE_BOOLEAN; +use const FILTER_NULL_ON_FAILURE; + /** * Session persistence using ext-session. * @@ -119,12 +122,7 @@ public function persistSession(SessionInterface $session, ResponseInterface $res return $response; } - $sessionCookie = SetCookie::create(session_name()) - ->withValue($id) - ->withPath(ini_get('session.cookie_path')) - ->withDomain(ini_get('session.cookie_domain')) - ->withSecure(ini_get('session.cookie_secure')) - ->withHttpOnly(ini_get('session.cookie_httponly')); + $sessionCookie = $this->createSessionCookie(session_name(), $id); if ($cookieLifetime = $this->getCookieLifetime($session)) { $sessionCookie = $sessionCookie->withExpires(time() + $cookieLifetime); @@ -182,6 +180,34 @@ private function generateSessionId() : string return bin2hex(random_bytes(16)); } + /** + * Build a SetCookie parsing boolean ini settings + * + * @param string $name The session name as the cookie name + * @param string $id The session id as the cookie value + * @return SetCookie + */ + private function createSessionCookie(string $name, string $id) : SetCookie + { + $secure = filter_var( + ini_get('session.cookie_secure'), + FILTER_VALIDATE_BOOLEAN, + FILTER_NULL_ON_FAILURE + ); + $httpOnly = filter_var( + ini_get('session.cookie_httponly'), + FILTER_VALIDATE_BOOLEAN, + FILTER_NULL_ON_FAILURE + ); + + return SetCookie::create($name) + ->withValue($id) + ->withPath(ini_get('session.cookie_path')) + ->withDomain(ini_get('session.cookie_domain')) + ->withSecure($secure) + ->withHttpOnly($httpOnly); + } + /** * Generate cache http headers for this instance's session cache_limiter and * cache_expire values diff --git a/test/PhpSessionPersistenceTest.php b/test/PhpSessionPersistenceTest.php index d299641..cd8b84e 100644 --- a/test/PhpSessionPersistenceTest.php +++ b/test/PhpSessionPersistenceTest.php @@ -735,4 +735,52 @@ public function testOnlyOneSessionFileIsCreatedIfNoSessionCookiePresentINFirstRe $this->restoreOriginalSessionIniSettings($ini); } + + /** + * @dataProvider cookieSettingsProvider + */ + public function testThatSetCookieCorrectlyInterpretsIniSettings( + $secureIni, + $httpOnlyIni, + $expectedSecure, + $expectedHttpOnly + ) { + $ini = $this->applyCustomSessionOptions([ + 'cookie_secure' => $secureIni, + 'cookie_httponly' => $httpOnlyIni, + ]); + + $persistence = new PhpSessionPersistence(); + + $createSessionCookie = new ReflectionMethod($persistence, 'createSessionCookie'); + $createSessionCookie->setAccessible(true); + + $setCookie = $createSessionCookie->invokeArgs( + $persistence, + ['SETCOOKIESESSIONID', 'set-cookie-test-value'] + ); + + $this->assertSame($expectedSecure, $setCookie->getSecure()); + $this->assertSame($expectedHttpOnly, $setCookie->getHttpOnly()); + + $this->restoreOriginalSessionIniSettings($ini); + } + + public function cookieSettingsProvider() + { + // obvious input/results data are left (commented out) for reference + return [ + //[false, false, false, false], + //[0, 0, false, false], + //['0', '0', false, false], + //['', '', false, false], + ['off', 'off', false, false], + ['Off', 'Off', false, false], + //[true, true, true, true], + //[1, 1, true, true], + //['1', '1', true, true], + //['on', 'on', true, true], + //['On', 'On', true, true], + ]; + } }