-
-
Notifications
You must be signed in to change notification settings - Fork 60
fix for https://github.com/XOOPS/XoopsCore25/issues/1588 #1589
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
4cbb3fd
fix for https://github.com/XOOPS/XoopsCore25/issues/1588
mambax7 3f7b88f
Remove trans-SID (url SID appending)
mambax7 974edb1
Update htdocs/kernel/session74.php
mambax7 341a106
Update htdocs/kernel/session74.php
mambax7 805311e
Update htdocs/kernel/session74.php
mambax7 9e0780d
Merge branch 'master' into feature/session_for_PHP8.4
mambax7 94746fa
Update htdocs/kernel/session74.php
mambax7 d1feefa
Update htdocs/kernel/session74.php
mambax7 5f811f2
Update htdocs/kernel/session.php
mambax7 b9a2867
Update htdocs/kernel/session80.php
mambax7 470c048
Update htdocs/kernel/session80.php
mambax7 dbb23d9
Update htdocs/kernel/session80.php
mambax7 c62b1fd
Update htdocs/kernel/session80.php
mambax7 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,304 +22,12 @@ | |
| } | ||
|
|
||
| /** | ||
| * Handler for a session | ||
| * @package kernel | ||
| * | ||
| * @author Kazumi Ono <[email protected]> | ||
| * @author Taiwen Jiang <[email protected]> | ||
| * @copyright (c) 2000-2025 XOOPS Project (https://xoops.org) | ||
| * Loader shim: include the correct handler for this PHP version. | ||
| * - PHP < 8.0: PHP 7.4-compatible handler (no union types, no SessionUpdateTimestampHandlerInterface) | ||
| * - PHP >= 8.0: handler using union types and lazy timestamp updates | ||
| */ | ||
| class XoopsSessionHandler implements SessionHandlerInterface | ||
| { | ||
| /** | ||
| * Database connection | ||
| * | ||
| * @var object | ||
| * @access private | ||
| */ | ||
| public $db; | ||
|
|
||
| /** | ||
| * Security checking level | ||
| * | ||
| * Possible value: | ||
| * 0 - no check; | ||
| * 1 - check browser characteristics (HTTP_USER_AGENT/HTTP_ACCEPT_LANGUAGE), to be implemented in the future now; | ||
| * 2 - check browser and IP A.B; | ||
| * 3 - check browser and IP A.B.C, recommended; | ||
| * 4 - check browser and IP A.B.C.D; | ||
| * | ||
| * @var int | ||
| * @access public | ||
| */ | ||
| public $securityLevel = 3; | ||
|
|
||
| protected $bitMasks = [ | ||
| 2 => ['v4' => 16, 'v6' => 64], | ||
| 3 => ['v4' => 24, 'v6' => 56], | ||
| 4 => ['v4' => 32, 'v6' => 128], | ||
| ]; | ||
|
|
||
| /** | ||
| * Enable regenerate_id | ||
| * | ||
| * @var bool | ||
| * @access public | ||
| */ | ||
| public $enableRegenerateId = true; | ||
|
|
||
| /** | ||
| * Constructor | ||
| * | ||
| * @param XoopsDatabase $db reference to the {@link XoopsDatabase} object | ||
| * | ||
| */ | ||
| public function __construct(XoopsDatabase $db) | ||
| { | ||
| global $xoopsConfig; | ||
|
|
||
| $this->db = $db; | ||
| // after php 7.3 we just let php handle the session cookie | ||
| $lifetime = ($xoopsConfig['use_mysession'] && $xoopsConfig['session_name'] != '') | ||
| ? $xoopsConfig['session_expire'] * 60 | ||
| : ini_get('session.cookie_lifetime'); | ||
| $secure = (XOOPS_PROT === 'https://'); | ||
| // --- START: New Domain Validation Logic --- | ||
| $host = parse_url(XOOPS_URL, PHP_URL_HOST); | ||
| if (!is_string($host)) { | ||
| $host = ''; // Fallback in case of invalid XOOPS_URL | ||
| } | ||
| $cookieDomain = XOOPS_COOKIE_DOMAIN; | ||
| if (class_exists('\Xoops\RegDom\RegisteredDomain')) { | ||
| if (!\Xoops\RegDom\RegisteredDomain::domainMatches($host, $cookieDomain)) { | ||
| $cookieDomain = ''; // The corrected, safe domain | ||
| } | ||
| } | ||
| // --- END: New Domain Validation Logic --- | ||
|
|
||
| if (PHP_VERSION_ID >= 70300) { | ||
| $options = [ | ||
| 'lifetime' => $lifetime, | ||
| 'path' => '/', | ||
| 'domain' => $cookieDomain, | ||
| 'secure' => $secure, | ||
| 'httponly' => true, | ||
| 'samesite' => 'Lax', | ||
| ]; | ||
| session_set_cookie_params($options); | ||
| } else { | ||
| session_set_cookie_params($lifetime, '/', $cookieDomain, $secure, true); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Open a session | ||
| * | ||
| * @param string $savePath | ||
| * @param string $sessionName | ||
| * | ||
| * @return bool | ||
| */ | ||
| public function open($savePath, $sessionName): bool | ||
| { | ||
| return true; | ||
| } | ||
|
|
||
| /** | ||
| * Close a session | ||
| * | ||
| * @return bool | ||
| */ | ||
| public function close(): bool | ||
| { | ||
| $this->gc_force(); | ||
| return true; | ||
| } | ||
|
|
||
| /** | ||
| * Read a session from the database | ||
| * | ||
| * @param string $sessionId ID of the session | ||
| * | ||
| * @return string Session data (empty string if no data or failure) | ||
| */ | ||
| public function read($sessionId): string | ||
| { | ||
| $ip = \Xmf\IPAddress::fromRequest(); | ||
| $sql = sprintf( | ||
| 'SELECT sess_data, sess_ip FROM %s WHERE sess_id = %s', | ||
| $this->db->prefix('session'), | ||
| $this->db->quote($sessionId) | ||
| ); | ||
|
|
||
| $result = $this->db->queryF($sql); | ||
| if ($this->db->isResultSet($result)) { | ||
| $row = $this->db->fetchRow($result); | ||
| if (false !== $row) { | ||
| [$sess_data, $sess_ip] = $row; | ||
| if ($this->securityLevel > 1) { | ||
| if (false === $ip->sameSubnet( | ||
| $sess_ip, | ||
| $this->bitMasks[$this->securityLevel]['v4'], | ||
| $this->bitMasks[$this->securityLevel]['v6'] | ||
| )) { | ||
| $sess_data = ''; | ||
| } | ||
| } | ||
| return $sess_data; | ||
| } | ||
| } | ||
| return ''; | ||
| } | ||
|
|
||
| /** | ||
| * Write a session to the database | ||
| * | ||
| * @param string $sessionId | ||
| * @param string $data | ||
| * | ||
| * @return bool | ||
| */ | ||
| public function write($sessionId, $data): bool | ||
| { | ||
| $myReturn = true; | ||
| $remoteAddress = \Xmf\IPAddress::fromRequest()->asReadable(); | ||
| $sessionId = $this->db->quote($sessionId); | ||
|
|
||
| $sql= sprintf('INSERT INTO %s (sess_id, sess_updated, sess_ip, sess_data) | ||
| VALUES (%s, %u, %s, %s) | ||
| ON DUPLICATE KEY UPDATE | ||
| sess_updated = %u, | ||
| sess_data = %s | ||
| ', | ||
| $this->db->prefix('session'), | ||
| $sessionId, | ||
| time(), | ||
| $this->db->quote($remoteAddress), | ||
| $this->db->quote($data), | ||
| time(), | ||
| $this->db->quote($data), | ||
| ); | ||
| $myReturn = $this->db->exec($sql); | ||
| $this->update_cookie(); | ||
| return $myReturn; | ||
| } | ||
|
|
||
| /** | ||
| * Destroy a session | ||
| * | ||
| * @param string $sessionId | ||
| * | ||
| * @return bool | ||
| */ | ||
| public function destroy($sessionId): bool | ||
| { | ||
| $sql = sprintf( | ||
| 'DELETE FROM %s WHERE sess_id = %s', | ||
| $this->db->prefix('session'), | ||
| $this->db->quote($sessionId) | ||
| ); | ||
| if (!$result = $this->db->exec($sql)) { | ||
| return false; | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| /** | ||
| * Garbage Collector | ||
| * | ||
| * @param int $expire Time in seconds until a session expires | ||
| * @return int|bool The number of deleted sessions on success, or false on failure | ||
| */ | ||
| #[\ReturnTypeWillChange] | ||
| public function gc($expire) | ||
| { | ||
| if (empty($expire)) { | ||
| return 0; | ||
| } | ||
|
|
||
| $mintime = time() - (int)$expire; | ||
| $sql = sprintf('DELETE FROM %s WHERE sess_updated < %u', $this->db->prefix('session'), $mintime); | ||
|
|
||
| if ($this->db->exec($sql)) { | ||
| return $this->db->getAffectedRows(); | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| /** | ||
| * Force gc for situations where gc is registered but not executed | ||
| **/ | ||
| public function gc_force() | ||
| { | ||
| if (mt_rand(1, 100) < 11) { | ||
| $expire = @ini_get('session.gc_maxlifetime'); | ||
| $expire = ($expire > 0) ? $expire : 900; | ||
| $this->gc($expire); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Update the current session id with a newly generated one | ||
| * | ||
| * To be refactored | ||
| * | ||
| * @param bool $delete_old_session | ||
| * @return bool | ||
| **/ | ||
| public function regenerate_id($delete_old_session = false) | ||
| { | ||
| if (!$this->enableRegenerateId) { | ||
| $success = true; | ||
| } else { | ||
| $success = session_regenerate_id($delete_old_session); | ||
| } | ||
|
|
||
| // Force updating cookie for session cookie | ||
| if ($success) { | ||
| $this->update_cookie(); | ||
| } | ||
|
|
||
| return $success; | ||
| } | ||
|
|
||
| /** | ||
| * Update cookie status for current session | ||
| * | ||
| * To be refactored | ||
| * FIXME: how about $xoopsConfig['use_ssl'] is enabled? | ||
| * | ||
| * @param string $sess_id session ID | ||
| * @param int $expire Time in seconds until a session expires | ||
| * @return bool | ||
| **/ | ||
| public function update_cookie($sess_id = null, $expire = null) | ||
| { | ||
| if (PHP_VERSION_ID < 70300) { | ||
| global $xoopsConfig; | ||
| $session_name = session_name(); | ||
| $session_expire = null !== $expire | ||
| ? (int)$expire | ||
| : ( | ||
| ($xoopsConfig['use_mysession'] && $xoopsConfig['session_name'] != '') | ||
| ? $xoopsConfig['session_expire'] * 60 | ||
| : ini_get('session.cookie_lifetime') | ||
| ); | ||
| $session_id = empty($sess_id) ? session_id() : $sess_id; | ||
| $cookieDomain = XOOPS_COOKIE_DOMAIN; | ||
| if (2 > substr_count($cookieDomain, '.')) { | ||
| $cookieDomain = '.' . $cookieDomain ; | ||
| } | ||
|
|
||
| xoops_setcookie( | ||
| $session_name, | ||
| $session_id, | ||
| $session_expire ? time() + $session_expire : 0, | ||
| '/', | ||
| $cookieDomain, | ||
| (XOOPS_PROT === 'https://'), | ||
| true, | ||
| ); | ||
| } | ||
| } | ||
| if (PHP_VERSION_ID < 80000) { | ||
| require_once __DIR__ . '/session74.php'; | ||
| } else { | ||
| require_once __DIR__ . '/session80.php'; | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.