Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions ext/session/session.c
Original file line number Diff line number Diff line change
Expand Up @@ -2935,13 +2935,27 @@ static PHP_GINIT_FUNCTION(ps)
ps_globals->random_seeded = false;
}

/* Interfaces extending the given one are not flattened into ce->interfaces before they are
* themselves processed, so every entry has to be checked with instanceof. */
static bool session_interfaces_include(const zend_class_entry *ce, const zend_class_entry *iface)
{
for (uint32_t i = 0; i < ce->num_interfaces; i++) {
if (instanceof_function(ce->interfaces[i], iface)) {
return true;
}
}
Comment on lines +2942 to +2946

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather we iterate on ce->interfaces[i] and check that the CE is SessionIdInterface or SessionUpdateTimestampHandlerInterface rather than name checking.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in a783cff. It iterates ce->interfaces[i] and uses instanceof_function() per entry, so an interface that extends SessionIdInterface or SessionUpdateTimestampHandlerInterface is still recognised before it has been flattened into the list.

One case this drops, which the name check covered: a class that gets the methods from an unrelated interface. implements OwnMethods, SessionHandlerInterface stays quiet, implements SessionHandlerInterface, OwnMethods now warns again. session_set_save_handler() accepts the methods there regardless of the interface, so the two rules differ. Tell me if you want that case back and I will restore the method lookup.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considering the objective is to move the methods from those 2 interfaces to the "base" interface having another interface declare such a method is not something we should be supporting.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, that keeps the check aligned with the migration path, so I have left the behaviour as you asked.

Correction on my earlier reply though: a783cff only carried the test move. I botched the staging and the session.c change never made it into that commit. It is in 0c963e4 now, so the diff you reviewed was still the old name lookup. Sorry for the noise.

return 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"))) {
if (!zend_hash_str_exists(&class->function_table, ZEND_STRL("create_sid"))
&& !session_interfaces_include(class, php_session_id_iface_entry)) {
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"))) {
if (!zend_hash_str_exists(&class->function_table, ZEND_STRL("validateid"))
&& !session_interfaces_include(class, php_session_update_timestamp_iface_entry)) {
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));
Expand Down
32 changes: 32 additions & 0 deletions ext/session/tests/user_session_module/gh23328.phpt

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please move this test into the user_session_submodule subdirectory

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to ext/session/tests/user_session_module/gh23328.phpt in a783cff.

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
--TEST--
GH-23328: SessionHandlerInterface create_sid()/validateId() warning depends on interface order
--EXTENSIONS--
session
--FILE--
<?php

abstract class HandlerFirst implements SessionHandlerInterface, SessionIdInterface, SessionUpdateTimestampHandlerInterface {}
abstract class HandlerLast implements SessionIdInterface, SessionUpdateTimestampHandlerInterface, SessionHandlerInterface {}

interface CombinedInterface extends SessionIdInterface, SessionUpdateTimestampHandlerInterface {}
abstract class CombinedFirst implements CombinedInterface, SessionHandlerInterface {}
abstract class CombinedLast implements SessionHandlerInterface, CombinedInterface {}

interface NestedInterface extends CombinedInterface {}
abstract class NestedLast implements SessionHandlerInterface, NestedInterface {}

abstract class MissingBoth implements SessionHandlerInterface {}
abstract class MissingValidateId implements SessionHandlerInterface, SessionIdInterface {}
abstract class MissingCreateSid implements SessionHandlerInterface, SessionUpdateTimestampHandlerInterface {}

echo "Done\n";
?>
--EXPECTF--
Warning: Class MissingBoth implementing SessionHandlerInterface is missing the create_sid() method which will be required in PHP 9.0 in %s on line %d

Warning: Class MissingBoth implementing SessionHandlerInterface is missing the validateId() method which will be required in PHP 9.0 in %s on line %d

Warning: Class MissingValidateId implementing SessionHandlerInterface is missing the validateId() method which will be required in PHP 9.0 in %s on line %d

Warning: Class MissingCreateSid implementing SessionHandlerInterface is missing the create_sid() method which will be required in PHP 9.0 in %s on line %d
Done
Loading