Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scalar fixes #9744

Conversation

Cheddam
Copy link
Member

@Cheddam Cheddam commented Oct 23, 2020

PHP 8 limits method_exists() to accepting strings and objects, which was in particular impacting the /Security/ping endpoint (which returns an integer.)

I've included two changes:

  • A minor improvement to Controller::prepareResponse() that handles scalar values directly, rather than passing them through checks only relevant to objects
  • A fix to ClassInfo::hasMethod() that will enforce a false outcome if the provided value isn't a valid argument for method_exists(). I initially considered putting the same blanket is_scalar() check in place here, but that changes the behaviour when passing in FQCNs, which may be relied upon (despite the docblock clearly calling for an object.)

Copy link
Member

@emteknetnz emteknetnz left a comment

Choose a reason for hiding this comment

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

Looks good, could just use some unit tests on the public method for integers, bools, etc

src/Core/ClassInfo.php Show resolved Hide resolved
@sminnee
Copy link
Member

sminnee commented Oct 23, 2020

If the functionality of ClassInfo::hasMethod() is broader than the docblock, and those extra uses are known in the wild, then it might be more honest to update the docblock go bless that extra case. Otherwise someone might break it in the future.

@sminnee
Copy link
Member

sminnee commented Oct 23, 2020

It feels like there's a deeper issue here, though: why was the result of ping ending up in a method-exists check? That feels like there's an unguarded method execution that could potentially be tied to user input (ie security flaw) in there. It would be good to explore that.

@emteknetnz
Copy link
Member

emteknetnz commented Oct 23, 2020

@sminnee It doesn't look like a security thing, this is where the call to the ClassInfo::methodExists comes from on a ping.

Screen Shot 2020-10-24 at 12 07 35 PM

If we wanted to make it 'more nicer', then probably change the ping method to return a HTTPResponse::create()->setBody('1') rather than simply 1

image

@sminnee
Copy link
Member

sminnee commented Oct 24, 2020

Right. We can probably add an is_object check to that screen cap'd ClassInfo::methodExists call. If a class name ends up in the response it would be erroneous to check it for a method.

@sminnee
Copy link
Member

sminnee commented Oct 24, 2020

Returning a string '1' would also be nicer than the integer its currently returning, but you're right that returning an HTTPResponse object would be clearer in intent.

@emteknetnz
Copy link
Member

PR to update ping to return an HTTPResponse #9745

I'm not sure that if (is_object($response) && ClassInfo::hasMethod($response, 'getViewer')) { is enough of an improvement, since $response being an instance (e.g. a controller) doesn't really seem that much better than $response being a string of the a controller class. Neither of them are a "response" :-) I'm not sure the upside here is worth the risk of introducing regressions since there will be a lot of old code paths that go through here, some which may have a classname as a response.

This resolves an issue where method_exists() was being called on scalar
response values, which is not supported in PHP 8.
@Cheddam Cheddam force-pushed the pulls/4/improve-scalar-response-handling branch from b020a2d to c8ea6d9 Compare October 26, 2020 00:23
@Cheddam
Copy link
Member Author

Cheddam commented Oct 26, 2020

I've added some unit tests for the ClassInfo::hasMethod() method, and revised the new logic in Controller::prepareResponse() to use !is_object($response) over is_scalar($response), as this makes the intention a bit clearer (and covers the edge-case of arrays.) I could also loosen the docblock of both methods, but I'm a little torn. In general I'd rather we shift towards tighter interfaces over time, but these types of method do lend themselves to wider input (and the additional logic I'm adding here to harden it doesn't increase complexity too much.)

@brynwhyman brynwhyman assigned emteknetnz and Cheddam and unassigned emteknetnz Oct 26, 2020
This method should typehint the incoming value once union types are
available, but for now this ensures that method_exists() is not called
on scalar values, which is unsupported in PHP 8.
@Cheddam Cheddam force-pushed the pulls/4/improve-scalar-response-handling branch from c8ea6d9 to e89ae93 Compare October 27, 2020 20:34
@Cheddam Cheddam removed their assignment Oct 27, 2020
@Cheddam Cheddam mentioned this pull request Oct 27, 2020
22 tasks
@brynwhyman brynwhyman added this to the Sprint 71 milestone Oct 27, 2020
@emteknetnz emteknetnz merged commit cf79be8 into silverstripe:4 Oct 28, 2020
@emteknetnz emteknetnz deleted the pulls/4/improve-scalar-response-handling branch October 28, 2020 05:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants