-
-
Notifications
You must be signed in to change notification settings - Fork 495
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
Checking callbacks for restricted functions #843
Checking callbacks for restricted functions #843
Conversation
89ec41b
to
433ff15
Compare
433ff15
to
360566a
Compare
@jrfnl @GaryJones Can this be merged? |
@grappler Reviewing this now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@grappler Thank you for your efforts on this.
I'm sorry, but I think this PR still needs quite a lot of work and possibly a rethink on the principle of it.
The original issue only mentioned sniffing for functions through the AbstractFunctionRestrictionsSniff
, but the principle behind it can - and probably should - also be applied when checking for sanitization functions and such.
For that to be possible, we need to implement this with more abstraction.
First off, I'd like to suggest moving the $callback_functions
list to the WordPress_Sniff
as this list might also be useful for other sniffs in the future.
We may even want to split the list in two (or three) - there are callback functions which directly execute (the PHP ones) and callback functions which are used in specific circumstances and even functions which take a callback, but don't execute it. For different purposes we may want to use a different subsection of the list. Splitting the list up would allow for that, in combination with a retrieval function which could get them all:
protected function get_all_callback_functions() {
static $list;
if ( ! isset( $list ) ) {
$list = array_merge( $array1, $array2, $array3 );
}
return $list;
}
In a similar vain, a is_callback_function()
method in the WordPress_Sniff
which would return false
or an array of the names of the callback functions would allow other sniffs to use the logic as well.
At a later point we could add an is_callback_method()
for class methods which take callbacks.
Apart from that I have left quite a lot of comments on the code itself. Main points:
- We're missing quite a lot of functions (I know you based it on a list I posted, but I did say that was a start, not complete).
- Array callbacks could be misidentified as function callbacks
- Another function parameter could be misidentified as a function callback.
Altogether, this PR is IMHO not ready for merge.
From #611 (comment):
Also - don't forget eval() and create_function()
I imagine this may need to be addressed separately. In that case, please open a new issue for it.
*/ | ||
|
||
/** | ||
* Unit test class for the DontExtract sniff. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment seems incorrect.
'foobar*', | ||
), | ||
), | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove this as - in the unlikely event that a theme/plugin would have a function prefixed with foobar
, it would trigger.
If you need to add a function group for unit testing only, please use the setUp()
method in the unit test file. See https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/blob/develop/WordPress/Tests/DB/RestrictedClassesUnitTest.php for an example.
@@ -69,6 +69,51 @@ | |||
protected $excluded_groups = array(); | |||
|
|||
/** | |||
* List of known PHP and WP function which take a callback as an argument. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
function
=> functions
* | ||
* @var array <string function name> => <int callback argument position> | ||
*/ | ||
protected $callback_functions = array( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While these functions won't execute the callback, they do take a callback argument. Should these be checked as well ?
has_action
has_filter
remove_action
remove_filter
* | ||
* @var array <string function name> => <int callback argument position> | ||
*/ | ||
protected $callback_functions = array( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm missing these WP functions in the list (not claiming completeness by any means - this is just a summary of the result of the first two pages returned by https://wordpress.org/search/callable ):
register_activation_hook()
register_deactivation_hook()
register_uninstall_hook()
add_menu_page()
,add_submenu_page()
and all other variants of itregister_setting()
- subkey within argument array + old format?register_meta()
- 2 x subkey within argument array + old formatwp_add_dashboard_widget()
x 2add_shortcode()
add_meta_box()
spl_autoload_register()
add_custom_background()
(deprecated)add_custom_image_header()
(deprecated)
|
||
// Only get function name not anonymous funtions. | ||
$callback = $this->phpcsFile->findNext( | ||
array( T_CONSTANT_ENCAPSED_STRING ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need for the array()
wrapper here.
$callback = $this->phpcsFile->findNext( | ||
array( T_CONSTANT_ENCAPSED_STRING ), | ||
$parameters[ $position ]['start'], | ||
null, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please pass the end position too to prevent incorrect results.
if ( ! isset( $parameters[ $position ] ) ) { | ||
return false; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A callback can be an array. In that case, you want to pass the stack pointer of the T_ARRAY
or T_SHORT_ARRAY_OPEN
to the get_function_call_parameters()
method again.
if ( ! isset( $parameters[ $position ] ) ) { | ||
return false; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could bow out early for closures.
|
||
// Check if the function is used as a callback. | ||
if ( ! isset( $this->callback_functions[ $token_content ] ) ) { | ||
return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the function return false or just return ?
Thank you @jrfnl for your comments. I think an extra level of abstraction is good. When we move My concern is that with the additional utility the functions I have fixed a few of the things mentioned. |
Not if you split the logic for determining whether something is a callback off from the The sniff specific logic - checking for excluded groups etc - should stay in the sniff. |
737390a
to
c85c692
Compare
Create a new untility function `is_callback_function()` and allow other Classes access the `$callback_functions` array.
I need to find another to solve this. May need to compare the perfomance of `is_targetted_token()` and `is_callback_function()` with the `prelim_check_regex`
c85c692
to
fa2ca4d
Compare
I think this can be improved but can’t see a way the moment.
@jrfnl It would be great if you could have a look at this PR. The "Preliminary check" only checks for functions in the list but not for the callback functions which was causing the code to fail. So I had to disable it for the callback functions but I am not sure if that is the best way. You can find more info in the commits. What is still missing is:
|
Thank you @grappler for working on this and I'm sorry that it took us so long to get back to it. As I mentioned in the comment in the original ticket which I left today, I think it would be better if we have some utility function with regards to callbacks in PHPCSUtils before we try to address this for WPCS, especially as the code which would be needed will need additional changes to be able to include handling PHP 8.0 named parameters etc. With that in mind, I'm closing this PR. I'm really sorry about this and hope you may want to work with me on getting the utility functions sorted in PHPCSUtils. |
fixes #611
I removed
preg_replace_callback_array()
from the list as the callback is not a parameter but part of the value. In the following example wherefoobar
is a restricted function.We could make a separate issue for this.
I was not sure where to place the tests for the abstract so I ended up using the old
FunctionRestrictionsSniff
. If there is a better place to add the tests I can move them there.