diff --git a/NEWS b/NEWS index 7dd05a2b1c72..e8088f6f86aa 100644 --- a/NEWS +++ b/NEWS @@ -42,6 +42,10 @@ PHP NEWS . Fixed segfault in ReflectionMethod::createFromMethodName() on an uninstantiable subclass. (iliaal) +- Session: + . Fixed session.use_strict_mode being a no-op for the built-in + SessionHandler. (iliaal) + - Standard: . Added the "filter.max_filter_count" stream context option for php://filter URLs. Using more than 16 filters without configuring this option is now diff --git a/ext/session/mod_user.c b/ext/session/mod_user.c index 71b8abdea8b0..b5d23c80f907 100644 --- a/ext/session/mod_user.c +++ b/ext/session/mod_user.c @@ -266,6 +266,16 @@ PS_VALIDATE_SID_FUNC(user) return ret; } + if (PS(default_mod) && PS(default_mod)->s_validate_sid + && PS(default_mod)->s_validate_sid != php_session_validate_sid + && !Z_ISUNDEF(PSF(open)) && Z_TYPE(PSF(open)) == IS_ARRAY) { + zval *handler_obj = zend_hash_index_find(Z_ARRVAL(PSF(open)), 0); + if (handler_obj && Z_TYPE_P(handler_obj) == IS_OBJECT + && Z_OBJCE_P(handler_obj) == php_session_class_entry) { + return PS(default_mod)->s_validate_sid(mod_data, key); + } + } + /* dummy function defined by PS_MOD */ return php_session_validate_sid(mod_data, key); } diff --git a/ext/session/tests/session_strict_handler_validate.phpt b/ext/session/tests/session_strict_handler_validate.phpt new file mode 100644 index 000000000000..d3f3676ead11 --- /dev/null +++ b/ext/session/tests/session_strict_handler_validate.phpt @@ -0,0 +1,100 @@ +--TEST-- +use_strict_mode distinguishes SessionHandler from custom-storage subclasses +--EXTENSIONS-- +session +--INI-- +session.use_strict_mode=1 +session.use_cookies=0 +session.cache_limiter= +session.gc_probability=0 +--FILE-- + 'value|s:6:"loaded";', + ]; + + public function open(string $path, string $name): bool + { + return true; + } + + public function close(): bool + { + return true; + } + + public function read(string $id): string|false + { + return $this->sessions[$id] ?? ''; + } + + public function write(string $id, string $data): bool + { + $this->sessions[$id] = $data; + return true; + } + + public function destroy(string $id): bool + { + unset($this->sessions[$id]); + return true; + } + + public function gc(int $max_lifetime): int|false + { + return 0; + } +} + +session_set_save_handler(new CustomStorageHandler, true); +$id = 'valid-custom-session-id'; +session_id($id); +session_start(); +$custom_handler_preserved = session_id() === $id; +$custom_handler_loaded = $_SESSION['value'] ?? null; +session_write_close(); + +foreach (glob($save_path . '/*') as $f) { + @unlink($f); +} +@rmdir($save_path); + +echo "SessionHandler preserved: "; +var_dump($session_handler_preserved); +echo "SessionHandler loaded: "; +var_dump($session_handler_loaded); +echo "SessionHandler adopted unknown: "; +var_dump($session_handler_adopted); +echo "Custom handler preserved: "; +var_dump($custom_handler_preserved); +echo "Custom handler loaded: "; +var_dump($custom_handler_loaded); +?> +--EXPECT-- +SessionHandler preserved: bool(true) +SessionHandler loaded: string(5) "files" +SessionHandler adopted unknown: bool(false) +Custom handler preserved: bool(true) +Custom handler loaded: string(6) "loaded"