Skip to content

Commit 0db03c4

Browse files
committed
Improve sesson write failure message for user error handlers
Closes GH-7787 Closes GH-8186
1 parent 6b2187b commit 0db03c4

File tree

4 files changed

+119
-1
lines changed

4 files changed

+119
-1
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,8 @@ PHP NEWS
3535
. add ZipArchive::getStreamName() method
3636
. add ZipArchive::getStreamIndex() method
3737

38+
- Session:
39+
. Fixed bug GH-7787 (Improve session write failure message for user error
40+
handlers). (ilutov)
41+
3842
<<< NOTE: Insert NEWS from last stable release here prior to actual release! >>>

ext/session/php_session.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ typedef struct _php_ps_globals {
176176
} mod_user_names;
177177
int mod_user_implemented;
178178
int mod_user_is_open;
179+
zend_string *mod_user_class_name;
179180
const struct ps_serializer_struct *serializer;
180181
zval http_session_vars;
181182
bool auto_start;

ext/session/session.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,9 @@ static void php_session_save_current_state(int write) /* {{{ */
472472

473473
if (write) {
474474
IF_SESSION_VARS() {
475+
zend_string *handler_class_name = PS(mod_user_class_name);
476+
const char *handler_function_name;
477+
475478
if (PS(mod_data) || PS(mod_user_implemented)) {
476479
zend_string *val;
477480

@@ -483,12 +486,15 @@ static void php_session_save_current_state(int write) /* {{{ */
483486
&& zend_string_equals(val, PS(session_vars))
484487
) {
485488
ret = PS(mod)->s_update_timestamp(&PS(mod_data), PS(id), val, PS(gc_maxlifetime));
489+
handler_function_name = handler_class_name != NULL ? "updateTimestamp" : "update_timestamp";
486490
} else {
487491
ret = PS(mod)->s_write(&PS(mod_data), PS(id), val, PS(gc_maxlifetime));
492+
handler_function_name = "write";
488493
}
489494
zend_string_release_ex(val, 0);
490495
} else {
491496
ret = PS(mod)->s_write(&PS(mod_data), PS(id), ZSTR_EMPTY_ALLOC(), PS(gc_maxlifetime));
497+
handler_function_name = "write";
492498
}
493499
}
494500

@@ -499,9 +505,14 @@ static void php_session_save_current_state(int write) /* {{{ */
499505
"is correct (%s)",
500506
PS(mod)->s_name,
501507
PS(save_path));
508+
} else if (handler_class_name != NULL) {
509+
php_error_docref(NULL, E_WARNING, "Failed to write session data using user "
510+
"defined save handler. (session.save_path: %s, handler: %s::%s)", PS(save_path),
511+
ZSTR_VAL(handler_class_name), handler_function_name);
502512
} else {
503513
php_error_docref(NULL, E_WARNING, "Failed to write session data using user "
504-
"defined save handler. (session.save_path: %s)", PS(save_path));
514+
"defined save handler. (session.save_path: %s, handler: %s)", PS(save_path),
515+
handler_function_name);
505516
}
506517
}
507518
}
@@ -2042,6 +2053,12 @@ PHP_FUNCTION(session_set_save_handler)
20422053
++i;
20432054
} ZEND_HASH_FOREACH_END();
20442055

2056+
2057+
if (PS(mod_user_class_name)) {
2058+
zend_string_release(PS(mod_user_class_name));
2059+
}
2060+
PS(mod_user_class_name) = zend_string_copy(Z_OBJCE_P(obj)->name);
2061+
20452062
if (register_shutdown) {
20462063
/* create shutdown function */
20472064
php_shutdown_function_entry shutdown_function_entry;
@@ -2095,6 +2112,11 @@ PHP_FUNCTION(session_set_save_handler)
20952112
RETURN_FALSE;
20962113
}
20972114

2115+
if (PS(mod_user_class_name)) {
2116+
zend_string_release(PS(mod_user_class_name));
2117+
PS(mod_user_class_name) = NULL;
2118+
}
2119+
20982120
/* remove shutdown function */
20992121
remove_user_shutdown_function("session_shutdown", sizeof("session_shutdown") - 1);
21002122

@@ -2775,6 +2797,7 @@ static PHP_GINIT_FUNCTION(ps) /* {{{ */
27752797
ps_globals->session_status = php_session_none;
27762798
ps_globals->default_mod = NULL;
27772799
ps_globals->mod_user_implemented = 0;
2800+
ps_globals->mod_user_class_name = NULL;
27782801
ps_globals->mod_user_is_open = 0;
27792802
ps_globals->session_vars = NULL;
27802803
ps_globals->set_handler = 0;

ext/session/tests/gh7787.phpt

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
--TEST--
2+
GH-7787: Provide more SessionHandler failure information
3+
--EXTENSIONS--
4+
session
5+
--SKIPIF--
6+
<?php include('skipif.inc'); ?>
7+
--INI--
8+
session.use_strict_mode=0
9+
session.save_handler=files
10+
--FILE--
11+
<?php
12+
class MySessionHandler extends SessionHandler implements SessionUpdateTimestampHandlerInterface
13+
{
14+
public function open($path, $sessname): bool {
15+
return true;
16+
}
17+
18+
public function close(): bool {
19+
return true;
20+
}
21+
22+
public function read($sessid): string|false {
23+
return 'foo|s:3:"foo";';
24+
}
25+
26+
public function write($sessid, $sessdata): bool {
27+
return false;
28+
}
29+
30+
public function destroy($sessid): bool {
31+
return true;
32+
}
33+
34+
public function gc($maxlifetime): int|false {
35+
return true;
36+
}
37+
38+
public function create_sid(): string {
39+
return sha1(random_bytes(32));
40+
}
41+
42+
public function validateId($sid): bool {
43+
return true;
44+
}
45+
46+
public function updateTimestamp($sessid, $sessdata): bool {
47+
return false;
48+
}
49+
}
50+
51+
ob_start();
52+
53+
$handler = new MySessionHandler();
54+
session_set_save_handler($handler);
55+
56+
session_start();
57+
$_SESSION['foo'] = 'bar';
58+
session_write_close();
59+
60+
session_start();
61+
session_write_close();
62+
63+
session_set_save_handler(
64+
fn() => true,
65+
fn() => true,
66+
fn() => 'foo|s:3:"foo";',
67+
fn() => false,
68+
fn() => true,
69+
fn() => true,
70+
fn() => sha1(random_bytes(32)),
71+
fn() => true,
72+
fn() => false,
73+
);
74+
75+
session_start();
76+
$_SESSION['foo'] = 'bar';
77+
session_write_close();
78+
79+
session_start();
80+
session_write_close();
81+
82+
?>
83+
--EXPECTF--
84+
Warning: session_write_close(): Failed to write session data using user defined save handler. (session.save_path: , handler: MySessionHandler::write) in %s on line %d
85+
86+
Warning: session_write_close(): Failed to write session data using user defined save handler. (session.save_path: , handler: MySessionHandler::updateTimestamp) in %s on line %d
87+
88+
Warning: session_write_close(): Failed to write session data using user defined save handler. (session.save_path: , handler: write) in %s on line %d
89+
90+
Warning: session_write_close(): Failed to write session data using user defined save handler. (session.save_path: , handler: update_timestamp) in %s on line %d

0 commit comments

Comments
 (0)