diff -r 3d4e9c994f10 -r a86126ab1dd4 wp/wp-includes/rest-api/class-wp-rest-request.php --- a/wp/wp-includes/rest-api/class-wp-rest-request.php Tue Oct 22 16:11:46 2019 +0200 +++ b/wp/wp-includes/rest-api/class-wp-rest-request.php Tue Dec 15 13:49:49 2020 +0100 @@ -24,7 +24,7 @@ * * @since 4.4.0 * - * @see ArrayAccess + * @link https://www.php.net/manual/en/class.arrayaccess.php */ class WP_REST_Request implements ArrayAccess { @@ -294,7 +294,9 @@ * * @since 4.4.0 * - * @return array Map containing 'value' and 'parameters' keys. + * @return array|null Map containing 'value' and 'parameters' keys + * or null when no valid content-type header was + * available. */ public function get_content_type() { $value = $this->get_header( 'content-type' ); @@ -308,7 +310,7 @@ } $value = strtolower( $value ); - if ( strpos( $value, '/' ) === false ) { + if ( false === strpos( $value, '/' ) ) { return null; } @@ -328,13 +330,13 @@ * * @since 4.4.0 * - * @return array List of types to check, in order of priority. + * @return string[] Array of types to check, in order of priority. */ protected function get_parameter_order() { $order = array(); $content_type = $this->get_content_type(); - if ( $content_type['value'] === 'application/json' ) { + if ( isset( $content_type['value'] ) && 'application/json' === $content_type['value'] ) { $order[] = 'JSON'; } @@ -348,7 +350,7 @@ } $accepts_body_data = array( 'POST', 'PUT', 'PATCH', 'DELETE' ); - if ( in_array( $this->method, $accepts_body_data ) ) { + if ( in_array( $this->method, $accepts_body_data, true ) ) { $order[] = 'POST'; } @@ -364,12 +366,8 @@ * * @since 4.4.0 * - * @param array $order { - * An array of types to check, in order of priority. - * - * @param string $type The type to check. - * } - * @param WP_REST_Request $this The request object. + * @param string[] $order Array of types to check, in order of priority. + * @param WP_REST_Request $this The request object. */ return apply_filters( 'rest_request_parameter_order', $order, $this ); } @@ -396,16 +394,54 @@ } /** + * Checks if a parameter exists in the request. + * + * This allows distinguishing between an omitted parameter, + * and a parameter specifically set to null. + * + * @since 5.3.0 + * + * @param string $key Parameter name. + * @return bool True if a param exists for the given key. + */ + public function has_param( $key ) { + $order = $this->get_parameter_order(); + + foreach ( $order as $type ) { + if ( is_array( $this->params[ $type ] ) && array_key_exists( $key, $this->params[ $type ] ) ) { + return true; + } + } + + return false; + } + + /** * Sets a parameter on the request. * + * If the given parameter key exists in any parameter type an update will take place, + * otherwise a new param will be created in the first parameter type (respecting + * get_parameter_order()). + * * @since 4.4.0 * * @param string $key Parameter name. * @param mixed $value Parameter value. */ public function set_param( $key, $value ) { - $order = $this->get_parameter_order(); - $this->params[ $order[0] ][ $key ] = $value; + $order = $this->get_parameter_order(); + $found_key = false; + + foreach ( $order as $type ) { + if ( 'defaults' !== $type && is_array( $this->params[ $type ] ) && array_key_exists( $key, $this->params[ $type ] ) ) { + $this->params[ $type ][ $key ] = $value; + $found_key = true; + } + } + + if ( ! $found_key ) { + $this->params[ $order[0] ][ $key ] = $value; + } } /** @@ -424,7 +460,7 @@ $params = array(); foreach ( $order as $type ) { - // array_merge / the "+" operator will mess up + // array_merge() / the "+" operator will mess up // numeric keys, so instead do a manual foreach. foreach ( (array) $this->params[ $type ] as $key => $value ) { $params[ $key ] = $value; @@ -637,26 +673,22 @@ /* * Check for a parsing error. - * - * Note that due to WP's JSON compatibility functions, json_last_error - * might not be defined: https://core.trac.wordpress.org/ticket/27799 */ - if ( null === $params && ( ! function_exists( 'json_last_error' ) || JSON_ERROR_NONE !== json_last_error() ) ) { + if ( null === $params && JSON_ERROR_NONE !== json_last_error() ) { // Ensure subsequent calls receive error instance. $this->parsed_json = false; $error_data = array( - 'status' => WP_Http::BAD_REQUEST, + 'status' => WP_Http::BAD_REQUEST, + 'json_error_code' => json_last_error(), + 'json_error_message' => json_last_error_msg(), ); - if ( function_exists( 'json_last_error' ) ) { - $error_data['json_error_code'] = json_last_error(); - $error_data['json_error_message'] = json_last_error_msg(); - } return new WP_Error( 'rest_invalid_json', __( 'Invalid JSON body passed.' ), $error_data ); } $this->params['JSON'] = $params; + return true; } @@ -688,15 +720,6 @@ parse_str( $this->get_body(), $params ); /* - * Amazingly, parse_str follows magic quote rules. Sigh. - * - * NOTE: Do not refactor to use `wp_unslash`. - */ - if ( get_magic_quotes_gpc() ) { - $params = stripslashes_deep( $params ); - } - - /* * Add to the POST parameters stored internally. If a user has already * set these manually (via `set_body_params`), don't override them. */ @@ -775,10 +798,12 @@ if ( empty( $this->params[ $type ] ) ) { continue; } + foreach ( $this->params[ $type ] as $key => $value ) { if ( ! isset( $attributes['args'][ $key ] ) ) { continue; } + $param_args = $attributes['args'][ $key ]; // If the arg has a type but no sanitize_callback attribute, default to rest_parse_request_arg. @@ -803,6 +828,7 @@ if ( $invalid_params ) { return new WP_Error( 'rest_invalid_param', + /* translators: %s: List of invalid parameters. */ sprintf( __( 'Invalid parameter(s): %s' ), implode( ', ', array_keys( $invalid_params ) ) ), array( 'status' => 400, @@ -848,6 +874,7 @@ if ( ! empty( $required ) ) { return new WP_Error( 'rest_missing_callback_param', + /* translators: %s: List of required parameters. */ sprintf( __( 'Missing parameter(s): %s' ), implode( ', ', $required ) ), array( 'status' => 400, @@ -883,6 +910,7 @@ if ( $invalid_params ) { return new WP_Error( 'rest_invalid_param', + /* translators: %s: List of invalid parameters. */ sprintf( __( 'Invalid parameter(s): %s' ), implode( ', ', array_keys( $invalid_params ) ) ), array( 'status' => 400, @@ -977,7 +1005,7 @@ $api_url_part = substr( $url, strlen( untrailingslashit( $api_root ) ) ); $route = parse_url( $api_url_part, PHP_URL_PATH ); } elseif ( ! empty( $query_params['rest_route'] ) ) { - // ?rest_route=... set directly + // ?rest_route=... set directly. $route = $query_params['rest_route']; unset( $query_params['rest_route'] ); }