diff --git a/.gitattributes b/.gitattributes
index c540470..b67c7ca 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,10 +1,10 @@
* text=auto eol=lf
-/tests export-ignore
-.editorconfig export-ignore
-.gitattributes export-ignore
-.gitignore export-ignore
-.php_cs export-ignore
-.travis.yml export-ignore
-phpcs.xml.dist export-ignore
-phpunit.xml.dist export-ignore
+/tests export-ignore
+.editorconfig export-ignore
+.gitattributes export-ignore
+.gitignore export-ignore
+.php-cs-fixer.php export-ignore
+phpcs.xml.dist export-ignore
+phpunit.xml.dist export-ignore
+.phpstan.neon export-ignore
diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml
index 494d950..5d14a59 100644
--- a/.github/workflows/main.yaml
+++ b/.github/workflows/main.yaml
@@ -1,10 +1,10 @@
name: "testing"
on:
- push:
- branches: [ master ]
- pull_request:
- branches: [ master ]
+ push:
+ branches: [ master ]
+ pull_request:
+ branches: [ master ]
jobs:
qa:
@@ -13,19 +13,19 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@v4
- name: Validate composer.json and composer.lock
run: composer validate
- name: Cache Composer packages
id: composer-cache
- uses: actions/cache@v2
+ uses: actions/cache@v4
with:
- path: vendor
- key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
- restore-keys: |
- ${{ runner.os }}-php-
+ path: vendor
+ key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
+ restore-keys: |
+ ${{ runner.os }}-php-
- name: Install dependencies
if: steps.composer-cache.outputs.cache-hit != 'true'
@@ -40,19 +40,19 @@ jobs:
strategy:
matrix:
- php:
- - 7.2
- - 7.3
- - 7.4
- composer-args: [ "" ]
- include:
- - php: 8.0
- composer-args: --ignore-platform-reqs
- fail-fast: false
+ php:
+ - 7.2
+ - 7.3
+ - 7.4
+ - 8.0
+ - 8.1
+ - 8.2
+ - 8.3
+ - 8.4
steps:
- name: Checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@v4
- name: Install PHP
uses: shivammathur/setup-php@v2
@@ -60,43 +60,14 @@ jobs:
php-version: ${{ matrix.php }}
- name: Cache PHP dependencies
- uses: actions/cache@v2
+ uses: actions/cache@v4
with:
path: vendor
key: ${{ runner.os }}-php-${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}
restore-keys: ${{ runner.os }}-php-${{ matrix.php }}-composer-
- name: Install dependencies
- run: composer install --prefer-dist --no-progress ${{ matrix.composer-args }}
+ run: composer install --prefer-dist --no-progress
- name: Tests
run: composer test
-
- - name: Tests coverage
- run: composer coverage
-
- static-analysis:
- name: Static Analysis
- runs-on: ubuntu-latest
-
- steps:
- - name: Checkout
- uses: actions/checkout@v2
-
- - name: Install PHP
- uses: shivammathur/setup-php@v2
- with:
- php-version: 7.4
-
- - name: Cache PHP dependencies
- uses: actions/cache@v2
- with:
- path: vendor
- key: ${{ runner.os }}-php-${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}
- restore-keys: ${{ runner.os }}-php-${{ matrix.php }}-composer-
-
- - name: Install dependencies
- run: composer install --prefer-dist --no-progress
-
- - name: Static Analysis
- run: composer run-script phpstan -- --level=5 src/ tests/
diff --git a/.gitignore b/.gitignore
index 364d1a4..5ae8693 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,5 @@ vendor
composer.lock
coverage
*.cache
+.idea
+kit
diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php
new file mode 100644
index 0000000..90b12a3
--- /dev/null
+++ b/.php-cs-fixer.php
@@ -0,0 +1,10 @@
+setFinder(
+ PhpCsFixer\Finder::create()
+ ->files()
+ ->name('*.php')
+ ->in(__DIR__.'/src')
+ ->in(__DIR__.'/tests')
+ );
\ No newline at end of file
diff --git a/.phpstan.neon b/.phpstan.neon
new file mode 100644
index 0000000..7f33c04
--- /dev/null
+++ b/.phpstan.neon
@@ -0,0 +1,5 @@
+parameters:
+ level: 8
+ paths:
+ - src
+ - tests
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 31b7020..9851485 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
+## [3.2.0] - 2025-03-21
+### Added
+- Support for PHP 8.4
+
## [3.1.1] - 2022-03-13
### Fixed
- Get the session name from options if available and not explicity set [#14]
@@ -90,6 +94,7 @@ First version
[#9]: https://github.com/middlewares/php-session/issues/9
[#14]: https://github.com/middlewares/php-session/issues/14
+[3.2.0]: https://github.com/middlewares/php-session/compare/v3.1.1...v3.2.0
[3.1.1]: https://github.com/middlewares/php-session/compare/v3.1.0...v3.1.1
[3.1.0]: https://github.com/middlewares/php-session/compare/v3.0.1...v3.1.0
[3.0.1]: https://github.com/middlewares/php-session/compare/v3.0.0...v3.0.1
diff --git a/LICENSE b/LICENSE
index 017c0cd..374fb13 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2019
+Copyright (c) 2019-2025
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/composer.json b/composer.json
index f350d54..512ebcb 100644
--- a/composer.json
+++ b/composer.json
@@ -17,16 +17,16 @@
},
"require": {
"php": "^7.2 || ^8.0",
- "psr/http-server-middleware": "^1.0"
+ "psr/http-server-middleware": "^1"
},
"require-dev": {
- "middlewares/utils": "^3.0",
- "phpunit/phpunit": "^8|^9",
- "friendsofphp/php-cs-fixer": "^2.0",
- "squizlabs/php_codesniffer": "^3.0",
- "oscarotero/php-cs-fixer-config": "^1.0",
- "phpstan/phpstan": "^0.12",
- "laminas/laminas-diactoros": "^2.3"
+ "middlewares/utils": "^2 || ^3 || ^4",
+ "phpunit/phpunit": "^8 || ^9",
+ "friendsofphp/php-cs-fixer": "^3",
+ "squizlabs/php_codesniffer": "^3",
+ "oscarotero/php-cs-fixer-config": "^2",
+ "phpstan/phpstan": "^1 || ^2",
+ "laminas/laminas-diactoros": "^2 || ^3"
},
"autoload": {
"psr-4": {
@@ -46,4 +46,4 @@
"coverage": "phpunit --coverage-text",
"coverage-html": "phpunit --coverage-html=coverage"
}
-}
+}
\ No newline at end of file
diff --git a/phpcs.xml b/phpcs.xml
new file mode 100644
index 0000000..7814331
--- /dev/null
+++ b/phpcs.xml
@@ -0,0 +1,16 @@
+
+
+ Middlewares coding standard
+
+
+
+
+
+
+
+
+
+
+ src
+ tests
+
diff --git a/phpunit.xml b/phpunit.xml
new file mode 100644
index 0000000..c2d04d2
--- /dev/null
+++ b/phpunit.xml
@@ -0,0 +1,33 @@
+
+
+
+
+ tests
+
+
+
+
+
+ ./src
+
+ ./tests
+ ./vendor
+
+
+
+
diff --git a/src/PhpSession.php b/src/PhpSession.php
index 2f995ca..99636e0 100644
--- a/src/PhpSession.php
+++ b/src/PhpSession.php
@@ -22,7 +22,7 @@ class PhpSession implements MiddlewareInterface
private $id;
/**
- * @var array|null
+ * @var array|null
*/
private $options;
@@ -59,6 +59,7 @@ public function id(string $id): self
/**
* Set the session options.
*
+ * @param array $options
* @throws RuntimeException
*/
public function options(array $options): self
@@ -92,10 +93,10 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
// Session name
$name = $this->name ?? $this->options['name'] ?? session_name();
- session_name($name);
+ session_name((string) $name);
// Session ID
- $id = $this->id ?: self::readSessionCookie($request, $name);
+ $id = $this->id ?: self::readSessionCookie($request, (string) $name);
if (!empty($id)) {
session_id($id);
}
@@ -119,8 +120,8 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
if (session_id() !== $id) {
$response = self::writeSessionCookie(
$response,
- session_name(),
- session_id(),
+ (string) session_name(),
+ (string) session_id(),
time(),
session_get_cookie_params()
);
@@ -132,6 +133,7 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
/**
* Check PHP session settings for compatibility with PSR-7.
*
+ * @param array $options
* @throws RuntimeException
*/
private static function checkSessionSettings(array $options): void
@@ -178,7 +180,7 @@ private static function checkSessionCanStart(): void
/**
* Regenerate the session ID if it's needed.
*/
- private static function runIdRegeneration(int $interval = null, string $key = null): void
+ private static function runIdRegeneration(?int $interval = null, ?string $key = null): void
{
if (empty($interval)) {
return;
@@ -203,11 +205,14 @@ private static function runIdRegeneration(int $interval = null, string $key = nu
private static function readSessionCookie(ServerRequestInterface $request, string $name): string
{
$cookies = $request->getCookieParams();
+
return $cookies[$name] ?? '';
}
/**
* Write a session cookie to the PSR-7 response.
+ *
+ * @param array $params
*/
private static function writeSessionCookie(
ResponseInterface $response,
@@ -220,6 +225,7 @@ private static function writeSessionCookie(
// if omitted, the cookie will expire at end of the session (ie when the browser closes)
if (!empty($params['lifetime'])) {
+ // @phpstan-ignore-next-line
$expires = gmdate('D, d M Y H:i:s T', $now + $params['lifetime']);
$cookie .= "; Expires={$expires}; Max-Age={$params['lifetime']}";
}
diff --git a/tests/PhpSessionTest.php b/tests/PhpSessionTest.php
index 38982fe..d8c4986 100644
--- a/tests/PhpSessionTest.php
+++ b/tests/PhpSessionTest.php
@@ -10,6 +10,7 @@
class PhpSessionTest extends TestCase
{
+ /** @var array */
private $sessionOptions = [
'use_strict_mode' => false,
'use_trans_sid' => false,
@@ -23,18 +24,21 @@ class PhpSessionTest extends TestCase
'cookie_httponly' => true,
];
- private function getCookieHeader(string $sessionName, string $sessionId): string
- {
- return sprintf(
- '%s=%s; expires=%s; path=%s; domain=%s; secure; httponly',
- urlencode($sessionName),
- urlencode($sessionId),
- $this->sessionOptions['cookie_path'],
- $this->sessionOptions['cookie_domain'],
- gmdate('D, d M Y H:i:s T', $this->sessionOptions['cookie_lifetime'])
- );
- }
+ // private function getCookieHeader(string $sessionName, string $sessionId): string
+ // {
+ // return sprintf(
+ // '%s=%s; expires=%s; path=%s; domain=%s; secure; httponly',
+ // urlencode($sessionName),
+ // urlencode($sessionId),
+ // $this->sessionOptions['cookie_path'],
+ // $this->sessionOptions['cookie_domain'],
+ // gmdate('D, d M Y H:i:s T', $this->sessionOptions['cookie_lifetime'])
+ // );
+ // }
+ /**
+ * @return array>
+ */
public function sessionDataProvider(): array
{
return [
@@ -50,7 +54,7 @@ public function sessionDataProvider(): array
];
}
- public function testCheckUseTransSidSettingException()
+ public function testCheckUseTransSidSettingException(): void
{
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('session.use_trans_sid must be false');
@@ -60,7 +64,7 @@ public function testCheckUseTransSidSettingException()
]);
}
- public function testCheckUseCookiesSettingException()
+ public function testCheckUseCookiesSettingException(): void
{
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('session.use_cookies must be false');
@@ -71,7 +75,7 @@ public function testCheckUseCookiesSettingException()
]);
}
- public function testCheckUseOnlyCookiesSettingException()
+ public function testCheckUseOnlyCookiesSettingException(): void
{
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('session.use_only_cookies must be true');
@@ -83,7 +87,7 @@ public function testCheckUseOnlyCookiesSettingException()
]);
}
- public function testCheckCacheLimiterSettingException()
+ public function testCheckCacheLimiterSettingException(): void
{
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('session.cache_limiter must be set to an empty string');
@@ -99,7 +103,7 @@ public function testCheckCacheLimiterSettingException()
/**
* @runInSeparateProcess
*/
- public function testDefaultSettingCheck()
+ public function testDefaultSettingCheck(): void
{
ini_set('session.use_trans_sid', '0');
ini_set('session.use_cookies', '0');
@@ -112,7 +116,7 @@ public function testDefaultSettingCheck()
/**
* @runInSeparateProcess
*/
- public function testWriteSessionCookie()
+ public function testWriteSessionCookie(): void
{
$response = Dispatcher::run(
[
@@ -132,7 +136,7 @@ function () {
* @runInSeparateProcess
* @dataProvider sessionDataProvider
*/
- public function testPhpSession(string $sessionName, string $sessionId, string $value)
+ public function testPhpSession(string $sessionName, string $sessionId, string $value): void
{
$response = Dispatcher::run(
[
@@ -157,14 +161,14 @@ function ($request) use ($value) {
/**
* @runInSeparateProcess
*/
- public function testRegenerateId()
+ public function testRegenerateId(): void
{
$sessionId = session_create_id();
$response = Dispatcher::run(
[
(new PhpSession())
- ->id($sessionId)
+ ->id((string) $sessionId)
->regenerateId(-10)
->options($this->sessionOptions),
@@ -184,14 +188,14 @@ function () use ($sessionId) {
/**
* @runInSeparateProcess
*/
- public function testStrictMode()
+ public function testStrictMode(): void
{
$sessionId = session_create_id();
$response = Dispatcher::run(
[
(new PhpSession())
- ->id($sessionId)
+ ->id((string) $sessionId)
->options(array_merge($this->sessionOptions, [
'use_strict_mode' => true,
])),