wp/wp-includes/rest-api/class-wp-rest-request.php
changeset 16 a86126ab1dd4
parent 9 177826044cd9
child 18 be944660c56a
--- 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'] );
 		}