diff --git a/src/wp-includes/rest-api/class-wp-rest-request.php b/src/wp-includes/rest-api/class-wp-rest-request.php index 80c58bf5b1..15c4728941 100644 --- a/src/wp-includes/rest-api/class-wp-rest-request.php +++ b/src/wp-includes/rest-api/class-wp-rest-request.php @@ -780,10 +780,9 @@ class WP_REST_Request implements ArrayAccess { * @since 4.4.0 * @access public * - * @return true|null True if there are no parameters to sanitize, null otherwise. + * @return true|WP_Error True if parameters were sanitized, WP_Error if an error occurred during sanitization. */ public function sanitize_params() { - $attributes = $this->get_attributes(); // No arguments set, skip sanitizing. @@ -793,18 +792,33 @@ class WP_REST_Request implements ArrayAccess { $order = $this->get_parameter_order(); + $invalid_params = array(); + foreach ( $order as $type ) { if ( empty( $this->params[ $type ] ) ) { continue; } foreach ( $this->params[ $type ] as $key => $value ) { // Check if this param has a sanitize_callback added. - if ( isset( $attributes['args'][ $key ] ) && ! empty( $attributes['args'][ $key ]['sanitize_callback'] ) ) { - $this->params[ $type ][ $key ] = call_user_func( $attributes['args'][ $key ]['sanitize_callback'], $value, $this, $key ); + if ( ! isset( $attributes['args'][ $key ] ) || empty( $attributes['args'][ $key ]['sanitize_callback'] ) ) { + continue; + } + + $sanitized_value = call_user_func( $attributes['args'][ $key ]['sanitize_callback'], $value, $this, $key ); + + if ( is_wp_error( $sanitized_value ) ) { + $invalid_params[ $key ] = $sanitized_value->get_error_message(); + } else { + $this->params[ $type ][ $key ] = $sanitized_value; } } } - return null; + + if ( $invalid_params ) { + return new WP_Error( 'rest_invalid_param', sprintf( __( 'Invalid parameter(s): %s' ), implode( ', ', array_keys( $invalid_params ) ) ), array( 'status' => 400, 'params' => $invalid_params ) ); + } + + return true; } /** @@ -817,7 +831,6 @@ class WP_REST_Request implements ArrayAccess { * WP_Error if required parameters are missing. */ public function has_valid_params() { - $attributes = $this->get_attributes(); $required = array(); diff --git a/src/wp-includes/rest-api/class-wp-rest-server.php b/src/wp-includes/rest-api/class-wp-rest-server.php index 7a45906690..1e5914bfe7 100644 --- a/src/wp-includes/rest-api/class-wp-rest-server.php +++ b/src/wp-includes/rest-api/class-wp-rest-server.php @@ -866,9 +866,12 @@ class WP_REST_Server { $check_required = $request->has_valid_params(); if ( is_wp_error( $check_required ) ) { $response = $check_required; + } else { + $check_sanitized = $request->sanitize_params(); + if ( is_wp_error( $check_sanitized ) ) { + $response = $check_sanitized; + } } - - $request->sanitize_params(); } if ( ! is_wp_error( $response ) ) { diff --git a/tests/phpunit/tests/rest-api/rest-request.php b/tests/phpunit/tests/rest-api/rest-request.php index bd6548341e..925853c8cd 100644 --- a/tests/phpunit/tests/rest-api/rest-request.php +++ b/tests/phpunit/tests/rest-api/rest-request.php @@ -309,6 +309,27 @@ class Tests_REST_Request extends WP_UnitTestCase { $this->assertEquals( 0, $this->request->get_param( 'somestring' ) ); } + public function test_sanitize_params_error() { + $this->request->set_url_params( array( + 'successparam' => '123', + 'failparam' => '123', + )); + $this->request->set_attributes( array( + 'args' => array( + 'successparam' => array( + 'sanitize_callback' => 'absint', + ), + 'failparam' => array( + 'sanitize_callback' => array( $this, '_return_wp_error_on_validate_callback' ), + ), + ), + )); + + $valid = $this->request->sanitize_params(); + $this->assertWPError( $valid ); + $this->assertEquals( 'rest_invalid_param', $valid->get_error_code() ); + } + public function test_has_valid_params_required_flag() { $this->request->set_attributes( array( 'args' => array(