Commit 6901c87aeab for php.net

commit 6901c87aeabf28cbb08dadc2ac64d1dabfdfdd3c
Author: Gina Peter Banyard <girgias@php.net>
Date:   Sat Aug 15 15:35:15 2026 +0100

    session: deprecate passing save handlers without create_sid() and validateId() methods

    RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_passing_a_sessionhandler_object_to_session_set_save_handler_which_does_not_contain_the_create_sid_and_validateid_methods

diff --git a/ext/session/mod_user_class.c b/ext/session/mod_user_class.c
index 9626dd27dfb..6e30ed32237 100644
--- a/ext/session/mod_user_class.c
+++ b/ext/session/mod_user_class.c
@@ -158,3 +158,22 @@ PHP_METHOD(SessionHandler, create_sid)

 	RETURN_STR(id);
 }
+
+PHP_METHOD(SessionHandler, validateId)
+{
+	zend_string *id;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &id) == FAILURE) {
+		RETURN_THROWS();
+	}
+
+	PS_SANITY_CHECK;
+	if (!PS(mod_user_is_open)) {
+		php_error_docref(NULL, E_WARNING, "Parent session handler is not open, ignoring ID validation");
+		RETURN_TRUE;
+	}
+
+	zend_result status = PS(default_mod)->s_validate_sid(&PS(mod_data), id);
+
+	RETURN_BOOL(status == SUCCESS);
+}
diff --git a/ext/session/session.c b/ext/session/session.c
index b1f1d2a3630..a6e698d4c0a 100644
--- a/ext/session/session.c
+++ b/ext/session/session.c
@@ -2158,6 +2158,9 @@ PHP_FUNCTION(session_set_save_handler)
 		} else if (zend_hash_find_ptr(object_methods, create_sid_name)) {
 			/* For BC reasons we accept methods even if the class does not implement the interface */
 			SESSION_SET_USER_HANDLER_OO(ps_create_sid, zend_string_copy(create_sid_name));
+		} else {
+			php_error_docref(NULL, E_DEPRECATED,
+				"Providing an object to argument #1 ($sessionhandler) which does not have the create_sid() method defined is deprecated");
 		}
 		zend_string_release_ex(create_sid_name, false);

@@ -2179,6 +2182,9 @@ PHP_FUNCTION(session_set_save_handler)
 			if (zend_hash_find_ptr(object_methods, validate_sid_name)) {
 				/* For BC reasons we accept methods even if the class does not implement the interface */
 				SESSION_SET_USER_HANDLER_OO(ps_validate_sid, zend_string_copy(validate_sid_name));
+			} else {
+				php_error_docref(NULL, E_DEPRECATED,
+					"Providing an object to argument #1 ($sessionhandler) which does not have the validateId() method defined is deprecated");
 			}
 			if (zend_hash_find_ptr(object_methods, update_timestamp_name)) {
 				/* For BC reasons we accept methods even if the class does not implement the interface */
@@ -2929,6 +2935,20 @@ static PHP_GINIT_FUNCTION(ps)
 	ps_globals->random_seeded = false;
 }

+static int session_handler_interface_gets_implemented(zend_class_entry *self, zend_class_entry *class) {
+	if (!zend_hash_str_exists(&class->function_table, ZEND_STRL("create_sid"))) {
+		zend_error(E_WARNING,
+			"Class %s implementing SessionHandlerInterface is missing the create_sid() method which will be required in PHP 9.0",
+			ZSTR_VAL(class->name));
+	}
+	if (!zend_hash_str_exists(&class->function_table, ZEND_STRL("validateid"))) {
+		zend_error(E_WARNING,
+			"Class %s implementing SessionHandlerInterface is missing the validateId() method which will be required in PHP 9.0",
+			ZSTR_VAL(class->name));
+	}
+	return SUCCESS;
+}
+
 static PHP_MINIT_FUNCTION(session)
 {
 	zend_register_auto_global(zend_string_init_interned(ZEND_STRL("_SESSION"), true), false, NULL);
@@ -2947,6 +2967,7 @@ static PHP_MINIT_FUNCTION(session)

 	/* Register interfaces */
 	php_session_iface_entry = register_class_SessionHandlerInterface();
+	php_session_iface_entry->interface_gets_implemented = session_handler_interface_gets_implemented;

 	php_session_id_iface_entry = register_class_SessionIdInterface();

diff --git a/ext/session/session.stub.php b/ext/session/session.stub.php
index bfb6849f45e..258715782d2 100644
--- a/ext/session/session.stub.php
+++ b/ext/session/session.stub.php
@@ -147,4 +147,7 @@ public function gc(int $max_lifetime): int|false {}

     /** @tentative-return-type */
     public function create_sid(): string {}
+
+    /** @tentative-return-type */
+    public function validateId(string $id): bool {}
 }
diff --git a/ext/session/session_arginfo.h b/ext/session/session_arginfo.h
index 3860731a535..dfcccc64341 100644
Binary files a/ext/session/session_arginfo.h and b/ext/session/session_arginfo.h differ
diff --git a/ext/session/tests/user_session_module/gh9583-extra.phpt b/ext/session/tests/user_session_module/gh9583-extra.phpt
index 2193ab035df..d82e0d8b2f0 100644
--- a/ext/session/tests/user_session_module/gh9583-extra.phpt
+++ b/ext/session/tests/user_session_module/gh9583-extra.phpt
@@ -5,6 +5,8 @@
 --FILE--
 <?php

+ob_start();
+
 class SessionHandlerTester implements \SessionHandlerInterface
 {

@@ -42,6 +44,13 @@ public function write($id, $data): bool { return true; }
 var_dump($originalSessionId == $newSessionId);

 ?>
---EXPECT--
+--EXPECTF--
+Warning: Class SessionHandlerTester implementing SessionHandlerInterface is missing the create_sid() method which will be required in PHP 9.0 in %s on line %d
+
+Warning: Class SessionHandlerTester implementing SessionHandlerInterface is missing the validateId() method which will be required in PHP 9.0 in %s on line %d
+
+Deprecated: session_set_save_handler(): Providing an object to argument #1 ($sessionhandler) which does not have the create_sid() method defined is deprecated in %s on line %d
+
+Deprecated: session_set_save_handler(): Providing an object to argument #1 ($sessionhandler) which does not have the validateId() method defined is deprecated in %s on line %d
 validateId() is commented out
 bool(true)
diff --git a/ext/session/tests/user_session_module/gh9583.phpt b/ext/session/tests/user_session_module/gh9583.phpt
index 24c1481eb7b..040c2103d1e 100644
--- a/ext/session/tests/user_session_module/gh9583.phpt
+++ b/ext/session/tests/user_session_module/gh9583.phpt
@@ -5,6 +5,8 @@
 --FILE--
 <?php

+ob_start();
+
 class SessionHandlerTester implements \SessionHandlerInterface
 {

@@ -38,6 +40,14 @@ public function write($id, $data): bool { return true; }

 ?>
 --EXPECTF--
+Warning: Class SessionHandlerTester implementing SessionHandlerInterface is missing the create_sid() method which will be required in PHP 9.0 in %s on line %d
+
+Warning: Class SessionHandlerTester implementing SessionHandlerInterface is missing the validateId() method which will be required in PHP 9.0 in %s on line %d
+
+Deprecated: session_set_save_handler(): Providing an object to argument #1 ($sessionhandler) which does not have the create_sid() method defined is deprecated in %s on line %d
+
+Deprecated: session_set_save_handler(): Providing an object to argument #1 ($sessionhandler) which does not have the validateId() method defined is deprecated in %s on line %d
+
 validateId() is commented out

 Session ID:%s
diff --git a/ext/session/tests/user_session_module/session_set_save_handler_class_016.phpt b/ext/session/tests/user_session_module/session_set_save_handler_class_016.phpt
index 61eecc7141d..c31ffd935e3 100644
--- a/ext/session/tests/user_session_module/session_set_save_handler_class_016.phpt
+++ b/ext/session/tests/user_session_module/session_set_save_handler_class_016.phpt
@@ -80,6 +80,8 @@ public function create_sid(): string {
   ["foo"]=>
   string(5) "hello"
 }
+
+Warning: SessionHandler::validateId(): Parent session handler is not open, ignoring ID validation in %s on line %d
 array(1) {
   ["foo"]=>
   string(5) "hello"
diff --git a/ext/session/tests/user_session_module/session_set_save_handler_class_017.phpt b/ext/session/tests/user_session_module/session_set_save_handler_class_017.phpt
index 6c1ecbe7e7e..4556c5f26ad 100644
--- a/ext/session/tests/user_session_module/session_set_save_handler_class_017.phpt
+++ b/ext/session/tests/user_session_module/session_set_save_handler_class_017.phpt
@@ -71,7 +71,7 @@ public function create_sid(): string {
 <?php
 @unlink(session_save_path().'/u_sess_PHPSESSIDsession_set_save_handler_class_017');
 ?>
---EXPECT--
+--EXPECTF--
 *** Testing session_set_save_handler() function: class with create_sid ***
 string(34) "session_set_save_handler_class_017"
 string(4) "user"
@@ -79,6 +79,8 @@ public function create_sid(): string {
   ["foo"]=>
   string(5) "hello"
 }
+
+Warning: SessionHandler::validateId(): Parent session handler is not open, ignoring ID validation in %s on line %d
 array(1) {
   ["foo"]=>
   string(5) "hello"
diff --git a/ext/session/tests/user_session_module/session_set_save_handler_iface_001.phpt b/ext/session/tests/user_session_module/session_set_save_handler_iface_001.phpt
index f25755dc350..023680c4a5d 100644
--- a/ext/session/tests/user_session_module/session_set_save_handler_iface_001.phpt
+++ b/ext/session/tests/user_session_module/session_set_save_handler_iface_001.phpt
@@ -83,6 +83,10 @@ public function gc($maxlifetime): int|false {
 --EXPECTF--
 *** Testing session_set_save_handler() function: interface ***

+Warning: Class MySession2 implementing SessionHandlerInterface is missing the create_sid() method which will be required in PHP 9.0 in %s on line %d
+
+Warning: Class MySession2 implementing SessionHandlerInterface is missing the validateId() method which will be required in PHP 9.0 in %s on line %d
+
 Deprecated: session_set_save_handler(): Providing individual callbacks instead of an object implementing SessionHandlerInterface is deprecated in %s on line %d
 string(%d) "%s"
 string(4) "user"
@@ -94,6 +98,10 @@ public function gc($maxlifetime): int|false {
   ["foo"]=>
   string(5) "hello"
 }
+
+Deprecated: session_set_save_handler(): Providing an object to argument #1 ($sessionhandler) which does not have the create_sid() method defined is deprecated in %s on line %d
+
+Deprecated: session_set_save_handler(): Providing an object to argument #1 ($sessionhandler) which does not have the validateId() method defined is deprecated in %s on line %d
 string(%d) "%s"
 string(4) "user"
 array(1) {
diff --git a/ext/session/tests/user_session_module/session_set_save_handler_iface_003.phpt b/ext/session/tests/user_session_module/session_set_save_handler_iface_003.phpt
index 2bdb830296c..66a813fa663 100644
--- a/ext/session/tests/user_session_module/session_set_save_handler_iface_003.phpt
+++ b/ext/session/tests/user_session_module/session_set_save_handler_iface_003.phpt
@@ -70,8 +70,12 @@ public function create_sid(): string {
 <?php
 @unlink(session_save_path().'/u_sess_PHPSESSIDsession_set_save_handler_iface_003');
 ?>
---EXPECT--
+--EXPECTF--
 *** Testing session_set_save_handler() function: id interface ***
+
+Warning: Class MySession2 implementing SessionHandlerInterface is missing the validateId() method which will be required in PHP 9.0 in %s on line %d
+
+Deprecated: session_set_save_handler(): Providing an object to argument #1 ($sessionhandler) which does not have the validateId() method defined is deprecated in %s on line %d
 string(34) "session_set_save_handler_iface_003"
 string(4) "user"
 array(1) {