Skip to content
This repository has been archived by the owner on Nov 8, 2020. It is now read-only.

Commit

Permalink
Separated sessions from cookie
Browse files Browse the repository at this point in the history
  • Loading branch information
klapuch committed May 8, 2017
1 parent afd4a83 commit 4ce04da
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 77 deletions.
55 changes: 55 additions & 0 deletions Core/CookieExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php
declare(strict_types = 1);
namespace Klapuch\Internal;

final class CookieExtension implements Extension {
private const PROPRIETARIES = ['SameSite'];
private $settings;

public function __construct(array $settings) {
$this->settings = $settings;
}

public function improve(): void {
header(static::raw($this->settings));
}

/**
* The raw cookie header
* @param array $settings
* @return string
*/
private static function raw(array $settings): string {
$cookie = current(preg_grep('~^Set-Cookie: ~', headers_list()));
if ($cookie === false)
return '';
$matches = array_intersect_ukey(
array_flip(self::PROPRIETARIES),
$settings,
'strcasecmp'
);
$headers = array_combine(
array_flip($matches),
array_intersect_ukey($settings, $matches, 'strcasecmp')
);
return rtrim(
trim(
sprintf(
'%s; %s',
$cookie,
implode(
';',
array_map(
function(string $field, string $value): string {
return sprintf('%s=%s', $field, $value);
},
array_keys($headers),
$headers
)
)
)
),
';'
);
}
}
48 changes: 1 addition & 47 deletions Core/SessionExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
final class SessionExtension implements Extension {
private const TIMER = '_timer',
DEFAULT_BREAK = 20;
private const PROPRIETARIES = ['SameSite'];
private $settings;
private $break;

Expand All @@ -16,59 +15,14 @@ public function __construct(array $settings, int $break = self::DEFAULT_BREAK) {

public function improve(): void {
if (session_status() === PHP_SESSION_NONE)
session_start($this->native($this->settings));
session_start($this->settings);
if ($this->elapsed($this->break))
session_regenerate_id(true);
header(static::raw($this->settings));
$_SESSION[self::TIMER] = time();
}

private function elapsed(int $break): bool {
return isset($_SESSION[self::TIMER])
&& (time() - $_SESSION[self::TIMER]) > $break;
}

/**
* Just the native and supported php setting
* @param array $settings
* @return array
*/
private function native(array $settings): array {
return array_diff_ukey(
$settings,
array_flip(self::PROPRIETARIES),
'strcasecmp'
);
}

/**
* The raw cookie header
* @param array $settings
* @return string
*/
private static function raw(array $settings): string {
$matches = array_intersect_ukey(
array_flip(self::PROPRIETARIES),
$settings,
'strcasecmp'
);
$headers = array_combine(
array_flip($matches),
array_intersect_ukey($settings, $matches, 'strcasecmp')
);
return sprintf(
'%s; %s',
current(preg_grep('~^Set-Cookie: ~', headers_list())),
implode(
';',
array_map(
function(string $field, string $value): string {
return sprintf('%s=%s', $field, $value);
},
array_keys($headers),
$headers
)
)
);
}
}
58 changes: 58 additions & 0 deletions Tests/Unit/CookieExtension.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php
declare(strict_types = 1);
/**
* @testCase
* @phpVersion > 7.1
*/
namespace Klapuch\Internal\Unit;

use Klapuch\Internal;
use Tester;
use Tester\Assert;

require __DIR__ . '/../bootstrap.php';

final class CookieExtension extends Tester\TestCase {
public function testNoPassedSettingWithoutAffection() {
$header = 'Set-Cookie: PHPSESSID=xyz; path=/';
header($header);
$extension = new Internal\CookieExtension([]);
$extension->improve();
Assert::same($header, headers_list()[1]);
}

public function testUnknownPassedSettingWithoutAffection() {
$header = 'Set-Cookie: PHPSESSID=xyz; path=/';
header($header);
$extension = new Internal\CookieExtension(['foo' => 'bar']);
$extension->improve();
Assert::same($header, headers_list()[1]);
}

public function testSettingSameSiteFlagToEnd() {
$header = 'Set-Cookie: PHPSESSID=xyz; path=/';
header($header);
$extension = new Internal\CookieExtension(['SameSite' => 'strict']);
$extension->improve();
$cookie = headers_list()[1];
Assert::same(sprintf('%s; SameSite=strict', $header), $cookie);
}

public function testKeepingCases() {
$header = 'Set-Cookie: PHPSESSID=xyz; path=/';
header($header);
$extension = new Internal\CookieExtension(['SaMeSiTE' => 'strict']);
$extension->improve();
$cookie = headers_list()[1];
Assert::same(sprintf('%s; SameSite=strict', $header), $cookie);
}

public function testNoHeaderToImprove() {
$extension = new Internal\CookieExtension(['SameSite' => 'strict']);
$extension->improve();
Assert::count(1, headers_list());
}
}


(new CookieExtension())->run();
32 changes: 2 additions & 30 deletions Tests/Unit/SessionExtension.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -44,43 +44,15 @@ final class SessionExtension extends Tester\TestCase {
public function testNoPassedSetting() {
$extension = new Internal\SessionExtension([]);
$extension->improve();
Assert::match('~^Set-Cookie: PHPSESSID=\S+; path=/;$~', headers_list()[4]);
Assert::match('~^Set-Cookie: PHPSESSID=\S+; path=/$~', headers_list()[1]);
}

public function testPassingSetting() {
$extension = new Internal\SessionExtension(['cookie_httponly' => true]);
$extension->improve();
Assert::contains('HttpOnly', headers_list()[4]);
Assert::contains('HttpOnly', headers_list()[1]);
Assert::true(session_get_cookie_params()['httponly']);
}

public function testSettingSameSite() {
$extension = new Internal\SessionExtension(['SameSite' => 'strict']);
$extension->improve();
$cookie = headers_list()[4];
Assert::match(
'~^Set-Cookie: PHPSESSID=\S+; path=/; SameSite=strict$~',
$cookie
);
}

public function testSettingSameSiteAsCaseInsensitive() {
$extension = new Internal\SessionExtension(['sAmESiTe' => 'strict']);
$extension->improve();
$cookie = headers_list()[4];
Assert::contains('Set-Cookie: ', $cookie);
Assert::contains('; SameSite=strict', $cookie);
}

public function testProprietarSettingAfterRegeneration() {
$extension = new Internal\SessionExtension(['SameSite' => 'strict'], 1);
$extension->improve();
$_SESSION['_timer'] = time() - 2;
$extension->improve();
$cookie = headers_list()[4];
Assert::contains('Set-Cookie: ', $cookie);
Assert::contains('; SameSite=strict', $cookie);
}
}


Expand Down

0 comments on commit 4ce04da

Please sign in to comment.