Skip to content

Commit 99449d5

Browse files
author
Pascal MARTINEZ
committed
CHANGE: anonymous sessions (sessions created when user download the login page) have now a lifetime of 5 minutes (new MOD_Z4M_USERSESSIONS_ANONYMOUS_SESSION_LIFETIME PHP constant) and are cleaned when have expired.
CHANGE: the value of the new `MOD_Z4M_USERSESSIONS_ANONYMOUS_SESSION_LIFETIME` PHP constant is displayed in the session configuration modal dialog.
1 parent 26166eb commit 99449d5

5 files changed

Lines changed: 110 additions & 22 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# CHANGE LOG: User sessions (z4m_usersessions)
22

3+
## Version 1.4, 2025-08-11
4+
- CHANGE: anonymous sessions (sessions created when user download the login page) have now a lifetime of 5 minutes (new `MOD_Z4M_USERSESSIONS_ANONYMOUS_SESSION_LIFETIME` PHP constant) and are cleaned when have expired.
5+
- CHANGE: the value of the new `MOD_Z4M_USERSESSIONS_ANONYMOUS_SESSION_LIFETIME` PHP constant is displayed in the session configuration modal dialog.
6+
37
## Version 1.3, 2025-06-27
48
- BUG FIXING: E_WARNING - unserialize(): Extra data starting at offset 406 of 1042 bytes - ./engine/modules/z4m_usersessions/mod/UserSessionFile.php(78)
59

mod/UserSessionManager.php

Lines changed: 63 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
* --------------------------------------------------------------------
2020
* ZnetDK 4 Mobile User sessions class
2121
*
22-
* File version: 1.0
23-
* Last update: 06/10/2025
22+
* File version: 1.1
23+
* Last update: 08/13/2025
2424
*/
2525

2626
namespace z4m_usersessions\mod;
@@ -32,17 +32,74 @@ class UserSessionManager {
3232

3333
/**
3434
* Clean expired user sessions by calling the PHP session_gc() function.
35+
* if MOD_Z4M_USERSESSIONS_ANONYMOUS_SESSION_LIFETIME PHP constant is set,
36+
* anonymous sessions are also cleaned after the lifetime indicated.
3537
* @param boolean $isCurrentSessionDestroyed When set to TRUE, the current
3638
* user session is destroyed (PHP session_destroy() function) after session
3739
* cleaning.
38-
* @return string Message indicating the number of cleaned sessions.
40+
* @return string Message indicating the number of cleaned sessions.
3941
*/
40-
static public function clean($isCurrentSessionDestroyed) {
42+
static public function clean($isCurrentSessionDestroyed, $includeReport = FALSE) {
4143
$count = session_gc();
44+
if ($count === FALSE) {
45+
$report = "Failed to remove sessions by the garbage collector. ";
46+
} else {
47+
$report = "{$count} sessions removed by the garbage collector. ";
48+
}
49+
session_write_close(); // Avoid error "Session file xxx is empty".
50+
try {
51+
$count2 = self::cleanAnonymousSessions();
52+
$report .= "{$count2} anonymous sessions removed. ";
53+
$count += $count2;
54+
} catch (\Exception $ex) {
55+
$report .= 'Error cleaning anonymous sessions: ' . $ex->getMessage() . ' ';
56+
}
4257
if ($isCurrentSessionDestroyed) {
43-
session_destroy();
58+
session_start();
59+
$destroyStatus = session_destroy();
60+
$report .= $destroyStatus ? 'Current session is destroyed. ' : 'Failed to destroy current session.';
61+
}
62+
return \General::getFilledMessage(MOD_Z4M_USERSESSIONS_ACTION_CLEAN_SUCCESS, $count)
63+
. ($includeReport ? ' EXTRA INFOS: ' . $report : '');
64+
}
65+
66+
static protected function cleanAnonymousSessions() {
67+
$now = new \DateTime('now');
68+
$anonymousSessionsLifetime = MOD_Z4M_USERSESSIONS_ANONYMOUS_SESSION_LIFETIME;
69+
if (is_null($anonymousSessionsLifetime)
70+
|| !is_int($anonymousSessionsLifetime) || $anonymousSessionsLifetime < 1) {
71+
return 0;
72+
}
73+
$rows = [];
74+
try {
75+
self::getSessionDataFromFiles($rows, NULL, NULL, TRUE);
76+
} catch (\Exception $ex) {
77+
throw new \Exception('Error getting session data from files: ' . $ex->getMessage());
4478
}
45-
return \General::getFilledMessage(MOD_Z4M_USERSESSIONS_ACTION_CLEAN_SUCCESS, $count);
79+
$sessionFilesToRemove = [];
80+
foreach ($rows as $row) {
81+
if (key_exists('login_name', $row)
82+
|| in_array($row['file_path'], $sessionFilesToRemove)) {
83+
continue;
84+
}
85+
$startDateTime = new \DateTime();
86+
$startDateTime->setTimestamp($row['session_timestamp']);
87+
$endDateTime = Z4MUserSessionFile::calculateSessionEndDateTime($startDateTime, FALSE, TRUE);
88+
if ($now > $endDateTime) {
89+
$sessionFilesToRemove[] = $row['file_path'];
90+
}
91+
}
92+
$count = 0;
93+
foreach ($sessionFilesToRemove as $sessionFilePath) {
94+
try {
95+
$sessionFile = new Z4MUserSessionFile($sessionFilePath);
96+
} catch (\Exception $ex) {
97+
throw new \Exception("Error removing session file '{$sessionFilePath}': " . $ex->getMessage());
98+
}
99+
$sessionFile->remove();
100+
$count++;
101+
}
102+
return $count;
46103
}
47104

48105
/**

mod/Z4MUserSessionFile.php

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
* --------------------------------------------------------------------
2020
* ZnetDK 4 Mobile User sessions module PHP class
2121
*
22-
* File version: 1.1
23-
* Last update: 06/15/2025
22+
* File version: 1.2
23+
* Last update: 08/11/2025
2424
*/
2525

2626
namespace z4m_usersessions\mod;
@@ -67,7 +67,7 @@ public function convertSessionDataToDatalistRows($withFilePath = FALSE) {
6767
$thisAppURI = MOD_Z4M_USERSESSIONS_APPLICATION_URI === NULL
6868
? \General::getAbsoluteURI() : MOD_Z4M_USERSESSIONS_APPLICATION_URI;
6969
foreach ($decodedSessionData as $appKey => $sessionData) {
70-
if (!is_array($sessionData) || ($thisAppURI !== 'ALL'
70+
if (!is_array($sessionData) || ($thisAppURI !== 'ALL'
7171
&& strpos($appKey, $thisAppURI) !== 0)) {
7272
// This is not session data for this App
7373
continue;
@@ -113,9 +113,10 @@ protected function extractInfosFromSessionData($sessionData, $applicationKey) {
113113
$startDateTime = new \DateTime();
114114
$startDateTime->setTimestamp($sessionTimestamp);
115115
$lastTimeAccess = key_exists('last_time_access', $sessionData) ? $sessionData['last_time_access'] : FALSE;
116-
$endDateTime = self::calculateSessionEndDateTime($startDateTime, $lastTimeAccess);
117116
$returnedRow = array_intersect_key($sessionData, array_flip(['login_name', 'ip_address', 'user_name']));
118-
if (!key_exists('user_name', $returnedRow)) {
117+
$isAnonymous = !key_exists('user_name', $returnedRow);
118+
$endDateTime = self::calculateSessionEndDateTime($startDateTime, $lastTimeAccess, $isAnonymous);
119+
if ($isAnonymous) {
119120
$returnedRow['user_name'] = MOD_Z4M_USERSESSIONS_LIST_UNKNOWNUSER_LABEL;
120121
}
121122
$returnedRow['application_key'] = $applicationKey;
@@ -128,15 +129,24 @@ protected function extractInfosFromSessionData($sessionData, $applicationKey) {
128129
}
129130

130131
/**
131-
* Calculates session end time from the session start time and the
132-
* session.gc_maxlifetime. If session is opened in public mode, the last
132+
* Calculates session end time from the session start time and the
133+
* session.gc_maxlifetime. If session is opened in public mode, the last
133134
* access time is used instead of session.gc_maxlifetime.
135+
* For anonymous sessions, the end date time is calculated from the session
136+
* lifetime set via the MOD_Z4M_USERSESSIONS_ANONYMOUS_SESSION_LIFETIME PHP
137+
* constant.
134138
* @param \DateTime $startDateTime Last session modification time
135-
* @param \DateTime|FALSE $lastTimeAccess Last time access
139+
* @param \DateTime|FALSE $lastTimeAccess Last time access
140+
* @param Boolean $isAnonymous If TRUE, this is an anonymous session.
136141
* @return \DateTime Calculated end time.
137142
*/
138-
static protected function calculateSessionEndDateTime(\DateTime $startDateTime, $lastTimeAccess) {
139-
if ($lastTimeAccess === FALSE) { // Private access
143+
static public function calculateSessionEndDateTime(\DateTime $startDateTime, $lastTimeAccess, $isAnonymous) {
144+
$anonymousSessionsLifetime = MOD_Z4M_USERSESSIONS_ANONYMOUS_SESSION_LIFETIME;
145+
if ($isAnonymous && !is_null($anonymousSessionsLifetime)
146+
&& is_int($anonymousSessionsLifetime) && $anonymousSessionsLifetime > 0) {
147+
$endDateTime = clone $startDateTime;
148+
$endDateTime->add(new \DateInterval("PT{$anonymousSessionsLifetime}S"));
149+
} elseif ($lastTimeAccess === FALSE) { // Private access
140150
$endDateTime = clone $startDateTime;
141151
$maxLifeTime = ini_get('session.gc_maxlifetime'); // In seconds
142152
$endDateTime->add(new \DateInterval("PT{$maxLifeTime}S"));

mod/config.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
* --------------------------------------------------------------------
1919
* Parameters of the ZnetDK 4 Mobile User sessions module
2020
*
21-
* File version: 1.3
22-
* Last update: 07/29/2025
21+
* File version: 1.4
22+
* Last update: 08/11/2025
2323
*/
2424

2525

@@ -33,6 +33,18 @@
3333
*/
3434
define('MOD_Z4M_USERSESSIONS_APPLICATION_URI', NULL);
3535

36+
/**
37+
* Lifetime in seconds of an anonymous session.
38+
* An anononymous session is a user session created when user display the login
39+
* page.
40+
* @var int|NULL The anonymous session lifetime in seconds.
41+
* If NULL, the anonymous sessions are not cleaned by the
42+
* UserSessionManager::clean() method.
43+
* If lifetime is set, anonymous session are cleaned after the indicated
44+
* deadline.
45+
*/
46+
define('MOD_Z4M_USERSESSIONS_ANONYMOUS_SESSION_LIFETIME', 300);
47+
3648
/**
3749
* Color scheme applied to the User sessions view.
3850
* @var array|NULL Colors used to display the view. The expected array keys are
@@ -47,9 +59,9 @@
4759
* Module version number
4860
* @return string Version
4961
*/
50-
define('MOD_Z4M_USERSESSIONS_VERSION_NUMBER','1.3');
62+
define('MOD_Z4M_USERSESSIONS_VERSION_NUMBER','1.4');
5163
/**
5264
* Module version date
5365
* @return string Date in W3C format
5466
*/
55-
define('MOD_Z4M_USERSESSIONS_VERSION_DATE','2025-07-29');
67+
define('MOD_Z4M_USERSESSIONS_VERSION_DATE','2025-08-11');

mod/view/fragment/settings_modal.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
* --------------------------------------------------------------------
2020
* ZnetDK 4 Mobile User sessions module view fragment
2121
*
22-
* File version: 1.1
23-
* Last update: 06/15/2025
22+
* File version: 1.2
23+
* Last update: 08/11/2025
2424
*/
2525
?>
2626
<div id="z4m-user-sessions-settings-modal" class="w3-modal">
@@ -80,6 +80,11 @@
8080
<td class="w3-monospace">-</td>
8181
<th class="w3-monospace"><?php echo MOD_Z4M_USERSESSIONS_APPLICATION_URI === NULL ? 'null' : "'" . MOD_Z4M_USERSESSIONS_APPLICATION_URI . "'"; ?></th>
8282
</tr>
83+
<tr>
84+
<td class="param">MOD_Z4M_USERSESSIONS_ANONYMOUS_SESSION_LIFETIME</td>
85+
<td class="w3-monospace">-</td>
86+
<th class="w3-monospace"><?php echo MOD_Z4M_USERSESSIONS_ANONYMOUS_SESSION_LIFETIME === NULL ? 'null' : MOD_Z4M_USERSESSIONS_ANONYMOUS_SESSION_LIFETIME; ?></th>
87+
</tr>
8388
</tbody>
8489
</table>
8590
</div>

0 commit comments

Comments
 (0)