[ Index ] |
PHP Cross Reference of WordPress |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * REST API: WP_REST_Request class 4 * 5 * @package WordPress 6 * @subpackage REST_API 7 * @since 4.4.0 8 */ 9 10 /** 11 * Core class used to implement a REST request object. 12 * 13 * Contains data from the request, to be passed to the callback. 14 * 15 * Note: This implements ArrayAccess, and acts as an array of parameters when 16 * used in that manner. It does not use ArrayObject (as we cannot rely on SPL), 17 * so be aware it may have non-array behaviour in some cases. 18 * 19 * Note: When using features provided by ArrayAccess, be aware that WordPress deliberately 20 * does not distinguish between arguments of the same name for different request methods. 21 * For instance, in a request with `GET id=1` and `POST id=2`, `$request['id']` will equal 22 * 2 (`POST`) not 1 (`GET`). For more precision between request methods, use 23 * WP_REST_Request::get_body_params(), WP_REST_Request::get_url_params(), etc. 24 * 25 * @since 4.4.0 26 * 27 * @link https://www.php.net/manual/en/class.arrayaccess.php 28 */ 29 class WP_REST_Request implements ArrayAccess { 30 31 /** 32 * HTTP method. 33 * 34 * @since 4.4.0 35 * @var string 36 */ 37 protected $method = ''; 38 39 /** 40 * Parameters passed to the request. 41 * 42 * These typically come from the `$_GET`, `$_POST` and `$_FILES` 43 * superglobals when being created from the global scope. 44 * 45 * @since 4.4.0 46 * @var array Contains GET, POST and FILES keys mapping to arrays of data. 47 */ 48 protected $params; 49 50 /** 51 * HTTP headers for the request. 52 * 53 * @since 4.4.0 54 * @var array Map of key to value. Key is always lowercase, as per HTTP specification. 55 */ 56 protected $headers = array(); 57 58 /** 59 * Body data. 60 * 61 * @since 4.4.0 62 * @var string Binary data from the request. 63 */ 64 protected $body = null; 65 66 /** 67 * Route matched for the request. 68 * 69 * @since 4.4.0 70 * @var string 71 */ 72 protected $route; 73 74 /** 75 * Attributes (options) for the route that was matched. 76 * 77 * This is the options array used when the route was registered, typically 78 * containing the callback as well as the valid methods for the route. 79 * 80 * @since 4.4.0 81 * @var array Attributes for the request. 82 */ 83 protected $attributes = array(); 84 85 /** 86 * Used to determine if the JSON data has been parsed yet. 87 * 88 * Allows lazy-parsing of JSON data where possible. 89 * 90 * @since 4.4.0 91 * @var bool 92 */ 93 protected $parsed_json = false; 94 95 /** 96 * Used to determine if the body data has been parsed yet. 97 * 98 * @since 4.4.0 99 * @var bool 100 */ 101 protected $parsed_body = false; 102 103 /** 104 * Constructor. 105 * 106 * @since 4.4.0 107 * 108 * @param string $method Optional. Request method. Default empty. 109 * @param string $route Optional. Request route. Default empty. 110 * @param array $attributes Optional. Request attributes. Default empty array. 111 */ 112 public function __construct( $method = '', $route = '', $attributes = array() ) { 113 $this->params = array( 114 'URL' => array(), 115 'GET' => array(), 116 'POST' => array(), 117 'FILES' => array(), 118 119 // See parse_json_params. 120 'JSON' => null, 121 122 'defaults' => array(), 123 ); 124 125 $this->set_method( $method ); 126 $this->set_route( $route ); 127 $this->set_attributes( $attributes ); 128 } 129 130 /** 131 * Retrieves the HTTP method for the request. 132 * 133 * @since 4.4.0 134 * 135 * @return string HTTP method. 136 */ 137 public function get_method() { 138 return $this->method; 139 } 140 141 /** 142 * Sets HTTP method for the request. 143 * 144 * @since 4.4.0 145 * 146 * @param string $method HTTP method. 147 */ 148 public function set_method( $method ) { 149 $this->method = strtoupper( $method ); 150 } 151 152 /** 153 * Retrieves all headers from the request. 154 * 155 * @since 4.4.0 156 * 157 * @return array Map of key to value. Key is always lowercase, as per HTTP specification. 158 */ 159 public function get_headers() { 160 return $this->headers; 161 } 162 163 /** 164 * Canonicalizes the header name. 165 * 166 * Ensures that header names are always treated the same regardless of 167 * source. Header names are always case insensitive. 168 * 169 * Note that we treat `-` (dashes) and `_` (underscores) as the same 170 * character, as per header parsing rules in both Apache and nginx. 171 * 172 * @link https://stackoverflow.com/q/18185366 173 * @link https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#missing-disappearing-http-headers 174 * @link https://nginx.org/en/docs/http/ngx_http_core_module.html#underscores_in_headers 175 * 176 * @since 4.4.0 177 * 178 * @param string $key Header name. 179 * @return string Canonicalized name. 180 */ 181 public static function canonicalize_header_name( $key ) { 182 $key = strtolower( $key ); 183 $key = str_replace( '-', '_', $key ); 184 185 return $key; 186 } 187 188 /** 189 * Retrieves the given header from the request. 190 * 191 * If the header has multiple values, they will be concatenated with a comma 192 * as per the HTTP specification. Be aware that some non-compliant headers 193 * (notably cookie headers) cannot be joined this way. 194 * 195 * @since 4.4.0 196 * 197 * @param string $key Header name, will be canonicalized to lowercase. 198 * @return string|null String value if set, null otherwise. 199 */ 200 public function get_header( $key ) { 201 $key = $this->canonicalize_header_name( $key ); 202 203 if ( ! isset( $this->headers[ $key ] ) ) { 204 return null; 205 } 206 207 return implode( ',', $this->headers[ $key ] ); 208 } 209 210 /** 211 * Retrieves header values from the request. 212 * 213 * @since 4.4.0 214 * 215 * @param string $key Header name, will be canonicalized to lowercase. 216 * @return array|null List of string values if set, null otherwise. 217 */ 218 public function get_header_as_array( $key ) { 219 $key = $this->canonicalize_header_name( $key ); 220 221 if ( ! isset( $this->headers[ $key ] ) ) { 222 return null; 223 } 224 225 return $this->headers[ $key ]; 226 } 227 228 /** 229 * Sets the header on request. 230 * 231 * @since 4.4.0 232 * 233 * @param string $key Header name. 234 * @param string $value Header value, or list of values. 235 */ 236 public function set_header( $key, $value ) { 237 $key = $this->canonicalize_header_name( $key ); 238 $value = (array) $value; 239 240 $this->headers[ $key ] = $value; 241 } 242 243 /** 244 * Appends a header value for the given header. 245 * 246 * @since 4.4.0 247 * 248 * @param string $key Header name. 249 * @param string $value Header value, or list of values. 250 */ 251 public function add_header( $key, $value ) { 252 $key = $this->canonicalize_header_name( $key ); 253 $value = (array) $value; 254 255 if ( ! isset( $this->headers[ $key ] ) ) { 256 $this->headers[ $key ] = array(); 257 } 258 259 $this->headers[ $key ] = array_merge( $this->headers[ $key ], $value ); 260 } 261 262 /** 263 * Removes all values for a header. 264 * 265 * @since 4.4.0 266 * 267 * @param string $key Header name. 268 */ 269 public function remove_header( $key ) { 270 $key = $this->canonicalize_header_name( $key ); 271 unset( $this->headers[ $key ] ); 272 } 273 274 /** 275 * Sets headers on the request. 276 * 277 * @since 4.4.0 278 * 279 * @param array $headers Map of header name to value. 280 * @param bool $override If true, replace the request's headers. Otherwise, merge with existing. 281 */ 282 public function set_headers( $headers, $override = true ) { 283 if ( true === $override ) { 284 $this->headers = array(); 285 } 286 287 foreach ( $headers as $key => $value ) { 288 $this->set_header( $key, $value ); 289 } 290 } 291 292 /** 293 * Retrieves the content-type of the request. 294 * 295 * @since 4.4.0 296 * 297 * @return array|null Map containing 'value' and 'parameters' keys 298 * or null when no valid content-type header was 299 * available. 300 */ 301 public function get_content_type() { 302 $value = $this->get_header( 'content-type' ); 303 if ( empty( $value ) ) { 304 return null; 305 } 306 307 $parameters = ''; 308 if ( strpos( $value, ';' ) ) { 309 list( $value, $parameters ) = explode( ';', $value, 2 ); 310 } 311 312 $value = strtolower( $value ); 313 if ( false === strpos( $value, '/' ) ) { 314 return null; 315 } 316 317 // Parse type and subtype out. 318 list( $type, $subtype ) = explode( '/', $value, 2 ); 319 320 $data = compact( 'value', 'type', 'subtype', 'parameters' ); 321 $data = array_map( 'trim', $data ); 322 323 return $data; 324 } 325 326 /** 327 * Checks if the request has specified a JSON content-type. 328 * 329 * @since 5.6.0 330 * 331 * @return bool True if the content-type header is JSON. 332 */ 333 public function is_json_content_type() { 334 $content_type = $this->get_content_type(); 335 336 return isset( $content_type['value'] ) && wp_is_json_media_type( $content_type['value'] ); 337 } 338 339 /** 340 * Retrieves the parameter priority order. 341 * 342 * Used when checking parameters in WP_REST_Request::get_param(). 343 * 344 * @since 4.4.0 345 * 346 * @return string[] Array of types to check, in order of priority. 347 */ 348 protected function get_parameter_order() { 349 $order = array(); 350 351 if ( $this->is_json_content_type() ) { 352 $order[] = 'JSON'; 353 } 354 355 $this->parse_json_params(); 356 357 // Ensure we parse the body data. 358 $body = $this->get_body(); 359 360 if ( 'POST' !== $this->method && ! empty( $body ) ) { 361 $this->parse_body_params(); 362 } 363 364 $accepts_body_data = array( 'POST', 'PUT', 'PATCH', 'DELETE' ); 365 if ( in_array( $this->method, $accepts_body_data, true ) ) { 366 $order[] = 'POST'; 367 } 368 369 $order[] = 'GET'; 370 $order[] = 'URL'; 371 $order[] = 'defaults'; 372 373 /** 374 * Filters the parameter priority order for a REST API request. 375 * 376 * The order affects which parameters are checked when using WP_REST_Request::get_param() 377 * and family. This acts similarly to PHP's `request_order` setting. 378 * 379 * @since 4.4.0 380 * 381 * @param string[] $order Array of types to check, in order of priority. 382 * @param WP_REST_Request $request The request object. 383 */ 384 return apply_filters( 'rest_request_parameter_order', $order, $this ); 385 } 386 387 /** 388 * Retrieves a parameter from the request. 389 * 390 * @since 4.4.0 391 * 392 * @param string $key Parameter name. 393 * @return mixed|null Value if set, null otherwise. 394 */ 395 public function get_param( $key ) { 396 $order = $this->get_parameter_order(); 397 398 foreach ( $order as $type ) { 399 // Determine if we have the parameter for this type. 400 if ( isset( $this->params[ $type ][ $key ] ) ) { 401 return $this->params[ $type ][ $key ]; 402 } 403 } 404 405 return null; 406 } 407 408 /** 409 * Checks if a parameter exists in the request. 410 * 411 * This allows distinguishing between an omitted parameter, 412 * and a parameter specifically set to null. 413 * 414 * @since 5.3.0 415 * 416 * @param string $key Parameter name. 417 * @return bool True if a param exists for the given key. 418 */ 419 public function has_param( $key ) { 420 $order = $this->get_parameter_order(); 421 422 foreach ( $order as $type ) { 423 if ( is_array( $this->params[ $type ] ) && array_key_exists( $key, $this->params[ $type ] ) ) { 424 return true; 425 } 426 } 427 428 return false; 429 } 430 431 /** 432 * Sets a parameter on the request. 433 * 434 * If the given parameter key exists in any parameter type an update will take place, 435 * otherwise a new param will be created in the first parameter type (respecting 436 * get_parameter_order()). 437 * 438 * @since 4.4.0 439 * 440 * @param string $key Parameter name. 441 * @param mixed $value Parameter value. 442 */ 443 public function set_param( $key, $value ) { 444 $order = $this->get_parameter_order(); 445 $found_key = false; 446 447 foreach ( $order as $type ) { 448 if ( 'defaults' !== $type && is_array( $this->params[ $type ] ) && array_key_exists( $key, $this->params[ $type ] ) ) { 449 $this->params[ $type ][ $key ] = $value; 450 $found_key = true; 451 } 452 } 453 454 if ( ! $found_key ) { 455 $this->params[ $order[0] ][ $key ] = $value; 456 } 457 } 458 459 /** 460 * Retrieves merged parameters from the request. 461 * 462 * The equivalent of get_param(), but returns all parameters for the request. 463 * Handles merging all the available values into a single array. 464 * 465 * @since 4.4.0 466 * 467 * @return array Map of key to value. 468 */ 469 public function get_params() { 470 $order = $this->get_parameter_order(); 471 $order = array_reverse( $order, true ); 472 473 $params = array(); 474 foreach ( $order as $type ) { 475 // array_merge() / the "+" operator will mess up 476 // numeric keys, so instead do a manual foreach. 477 foreach ( (array) $this->params[ $type ] as $key => $value ) { 478 $params[ $key ] = $value; 479 } 480 } 481 482 return $params; 483 } 484 485 /** 486 * Retrieves parameters from the route itself. 487 * 488 * These are parsed from the URL using the regex. 489 * 490 * @since 4.4.0 491 * 492 * @return array Parameter map of key to value. 493 */ 494 public function get_url_params() { 495 return $this->params['URL']; 496 } 497 498 /** 499 * Sets parameters from the route. 500 * 501 * Typically, this is set after parsing the URL. 502 * 503 * @since 4.4.0 504 * 505 * @param array $params Parameter map of key to value. 506 */ 507 public function set_url_params( $params ) { 508 $this->params['URL'] = $params; 509 } 510 511 /** 512 * Retrieves parameters from the query string. 513 * 514 * These are the parameters you'd typically find in `$_GET`. 515 * 516 * @since 4.4.0 517 * 518 * @return array Parameter map of key to value 519 */ 520 public function get_query_params() { 521 return $this->params['GET']; 522 } 523 524 /** 525 * Sets parameters from the query string. 526 * 527 * Typically, this is set from `$_GET`. 528 * 529 * @since 4.4.0 530 * 531 * @param array $params Parameter map of key to value. 532 */ 533 public function set_query_params( $params ) { 534 $this->params['GET'] = $params; 535 } 536 537 /** 538 * Retrieves parameters from the body. 539 * 540 * These are the parameters you'd typically find in `$_POST`. 541 * 542 * @since 4.4.0 543 * 544 * @return array Parameter map of key to value. 545 */ 546 public function get_body_params() { 547 return $this->params['POST']; 548 } 549 550 /** 551 * Sets parameters from the body. 552 * 553 * Typically, this is set from `$_POST`. 554 * 555 * @since 4.4.0 556 * 557 * @param array $params Parameter map of key to value. 558 */ 559 public function set_body_params( $params ) { 560 $this->params['POST'] = $params; 561 } 562 563 /** 564 * Retrieves multipart file parameters from the body. 565 * 566 * These are the parameters you'd typically find in `$_FILES`. 567 * 568 * @since 4.4.0 569 * 570 * @return array Parameter map of key to value 571 */ 572 public function get_file_params() { 573 return $this->params['FILES']; 574 } 575 576 /** 577 * Sets multipart file parameters from the body. 578 * 579 * Typically, this is set from `$_FILES`. 580 * 581 * @since 4.4.0 582 * 583 * @param array $params Parameter map of key to value. 584 */ 585 public function set_file_params( $params ) { 586 $this->params['FILES'] = $params; 587 } 588 589 /** 590 * Retrieves the default parameters. 591 * 592 * These are the parameters set in the route registration. 593 * 594 * @since 4.4.0 595 * 596 * @return array Parameter map of key to value 597 */ 598 public function get_default_params() { 599 return $this->params['defaults']; 600 } 601 602 /** 603 * Sets default parameters. 604 * 605 * These are the parameters set in the route registration. 606 * 607 * @since 4.4.0 608 * 609 * @param array $params Parameter map of key to value. 610 */ 611 public function set_default_params( $params ) { 612 $this->params['defaults'] = $params; 613 } 614 615 /** 616 * Retrieves the request body content. 617 * 618 * @since 4.4.0 619 * 620 * @return string Binary data from the request body. 621 */ 622 public function get_body() { 623 return $this->body; 624 } 625 626 /** 627 * Sets body content. 628 * 629 * @since 4.4.0 630 * 631 * @param string $data Binary data from the request body. 632 */ 633 public function set_body( $data ) { 634 $this->body = $data; 635 636 // Enable lazy parsing. 637 $this->parsed_json = false; 638 $this->parsed_body = false; 639 $this->params['JSON'] = null; 640 } 641 642 /** 643 * Retrieves the parameters from a JSON-formatted body. 644 * 645 * @since 4.4.0 646 * 647 * @return array Parameter map of key to value. 648 */ 649 public function get_json_params() { 650 // Ensure the parameters have been parsed out. 651 $this->parse_json_params(); 652 653 return $this->params['JSON']; 654 } 655 656 /** 657 * Parses the JSON parameters. 658 * 659 * Avoids parsing the JSON data until we need to access it. 660 * 661 * @since 4.4.0 662 * @since 4.7.0 Returns error instance if value cannot be decoded. 663 * @return true|WP_Error True if the JSON data was passed or no JSON data was provided, WP_Error if invalid JSON was passed. 664 */ 665 protected function parse_json_params() { 666 if ( $this->parsed_json ) { 667 return true; 668 } 669 670 $this->parsed_json = true; 671 672 // Check that we actually got JSON. 673 if ( ! $this->is_json_content_type() ) { 674 return true; 675 } 676 677 $body = $this->get_body(); 678 if ( empty( $body ) ) { 679 return true; 680 } 681 682 $params = json_decode( $body, true ); 683 684 /* 685 * Check for a parsing error. 686 */ 687 if ( null === $params && JSON_ERROR_NONE !== json_last_error() ) { 688 // Ensure subsequent calls receive error instance. 689 $this->parsed_json = false; 690 691 $error_data = array( 692 'status' => WP_Http::BAD_REQUEST, 693 'json_error_code' => json_last_error(), 694 'json_error_message' => json_last_error_msg(), 695 ); 696 697 return new WP_Error( 'rest_invalid_json', __( 'Invalid JSON body passed.' ), $error_data ); 698 } 699 700 $this->params['JSON'] = $params; 701 702 return true; 703 } 704 705 /** 706 * Parses the request body parameters. 707 * 708 * Parses out URL-encoded bodies for request methods that aren't supported 709 * natively by PHP. In PHP 5.x, only POST has these parsed automatically. 710 * 711 * @since 4.4.0 712 */ 713 protected function parse_body_params() { 714 if ( $this->parsed_body ) { 715 return; 716 } 717 718 $this->parsed_body = true; 719 720 /* 721 * Check that we got URL-encoded. Treat a missing content-type as 722 * URL-encoded for maximum compatibility. 723 */ 724 $content_type = $this->get_content_type(); 725 726 if ( ! empty( $content_type ) && 'application/x-www-form-urlencoded' !== $content_type['value'] ) { 727 return; 728 } 729 730 parse_str( $this->get_body(), $params ); 731 732 /* 733 * Add to the POST parameters stored internally. If a user has already 734 * set these manually (via `set_body_params`), don't override them. 735 */ 736 $this->params['POST'] = array_merge( $params, $this->params['POST'] ); 737 } 738 739 /** 740 * Retrieves the route that matched the request. 741 * 742 * @since 4.4.0 743 * 744 * @return string Route matching regex. 745 */ 746 public function get_route() { 747 return $this->route; 748 } 749 750 /** 751 * Sets the route that matched the request. 752 * 753 * @since 4.4.0 754 * 755 * @param string $route Route matching regex. 756 */ 757 public function set_route( $route ) { 758 $this->route = $route; 759 } 760 761 /** 762 * Retrieves the attributes for the request. 763 * 764 * These are the options for the route that was matched. 765 * 766 * @since 4.4.0 767 * 768 * @return array Attributes for the request. 769 */ 770 public function get_attributes() { 771 return $this->attributes; 772 } 773 774 /** 775 * Sets the attributes for the request. 776 * 777 * @since 4.4.0 778 * 779 * @param array $attributes Attributes for the request. 780 */ 781 public function set_attributes( $attributes ) { 782 $this->attributes = $attributes; 783 } 784 785 /** 786 * Sanitizes (where possible) the params on the request. 787 * 788 * This is primarily based off the sanitize_callback param on each registered 789 * argument. 790 * 791 * @since 4.4.0 792 * 793 * @return true|WP_Error True if parameters were sanitized, WP_Error if an error occurred during sanitization. 794 */ 795 public function sanitize_params() { 796 $attributes = $this->get_attributes(); 797 798 // No arguments set, skip sanitizing. 799 if ( empty( $attributes['args'] ) ) { 800 return true; 801 } 802 803 $order = $this->get_parameter_order(); 804 805 $invalid_params = array(); 806 $invalid_details = array(); 807 808 foreach ( $order as $type ) { 809 if ( empty( $this->params[ $type ] ) ) { 810 continue; 811 } 812 813 foreach ( $this->params[ $type ] as $key => $value ) { 814 if ( ! isset( $attributes['args'][ $key ] ) ) { 815 continue; 816 } 817 818 $param_args = $attributes['args'][ $key ]; 819 820 // If the arg has a type but no sanitize_callback attribute, default to rest_parse_request_arg. 821 if ( ! array_key_exists( 'sanitize_callback', $param_args ) && ! empty( $param_args['type'] ) ) { 822 $param_args['sanitize_callback'] = 'rest_parse_request_arg'; 823 } 824 // If there's still no sanitize_callback, nothing to do here. 825 if ( empty( $param_args['sanitize_callback'] ) ) { 826 continue; 827 } 828 829 /** @var mixed|WP_Error $sanitized_value */ 830 $sanitized_value = call_user_func( $param_args['sanitize_callback'], $value, $this, $key ); 831 832 if ( is_wp_error( $sanitized_value ) ) { 833 $invalid_params[ $key ] = implode( ' ', $sanitized_value->get_error_messages() ); 834 $invalid_details[ $key ] = rest_convert_error_to_response( $sanitized_value )->get_data(); 835 } else { 836 $this->params[ $type ][ $key ] = $sanitized_value; 837 } 838 } 839 } 840 841 if ( $invalid_params ) { 842 return new WP_Error( 843 'rest_invalid_param', 844 /* translators: %s: List of invalid parameters. */ 845 sprintf( __( 'Invalid parameter(s): %s' ), implode( ', ', array_keys( $invalid_params ) ) ), 846 array( 847 'status' => 400, 848 'params' => $invalid_params, 849 'details' => $invalid_details, 850 ) 851 ); 852 } 853 854 return true; 855 } 856 857 /** 858 * Checks whether this request is valid according to its attributes. 859 * 860 * @since 4.4.0 861 * 862 * @return true|WP_Error True if there are no parameters to validate or if all pass validation, 863 * WP_Error if required parameters are missing. 864 */ 865 public function has_valid_params() { 866 // If JSON data was passed, check for errors. 867 $json_error = $this->parse_json_params(); 868 if ( is_wp_error( $json_error ) ) { 869 return $json_error; 870 } 871 872 $attributes = $this->get_attributes(); 873 $required = array(); 874 875 $args = empty( $attributes['args'] ) ? array() : $attributes['args']; 876 877 foreach ( $args as $key => $arg ) { 878 $param = $this->get_param( $key ); 879 if ( isset( $arg['required'] ) && true === $arg['required'] && null === $param ) { 880 $required[] = $key; 881 } 882 } 883 884 if ( ! empty( $required ) ) { 885 return new WP_Error( 886 'rest_missing_callback_param', 887 /* translators: %s: List of required parameters. */ 888 sprintf( __( 'Missing parameter(s): %s' ), implode( ', ', $required ) ), 889 array( 890 'status' => 400, 891 'params' => $required, 892 ) 893 ); 894 } 895 896 /* 897 * Check the validation callbacks for each registered arg. 898 * 899 * This is done after required checking as required checking is cheaper. 900 */ 901 $invalid_params = array(); 902 $invalid_details = array(); 903 904 foreach ( $args as $key => $arg ) { 905 906 $param = $this->get_param( $key ); 907 908 if ( null !== $param && ! empty( $arg['validate_callback'] ) ) { 909 /** @var bool|\WP_Error $valid_check */ 910 $valid_check = call_user_func( $arg['validate_callback'], $param, $this, $key ); 911 912 if ( false === $valid_check ) { 913 $invalid_params[ $key ] = __( 'Invalid parameter.' ); 914 } 915 916 if ( is_wp_error( $valid_check ) ) { 917 $invalid_params[ $key ] = implode( ' ', $valid_check->get_error_messages() ); 918 $invalid_details[ $key ] = rest_convert_error_to_response( $valid_check )->get_data(); 919 } 920 } 921 } 922 923 if ( $invalid_params ) { 924 return new WP_Error( 925 'rest_invalid_param', 926 /* translators: %s: List of invalid parameters. */ 927 sprintf( __( 'Invalid parameter(s): %s' ), implode( ', ', array_keys( $invalid_params ) ) ), 928 array( 929 'status' => 400, 930 'params' => $invalid_params, 931 'details' => $invalid_details, 932 ) 933 ); 934 } 935 936 if ( isset( $attributes['validate_callback'] ) ) { 937 $valid_check = call_user_func( $attributes['validate_callback'], $this ); 938 939 if ( is_wp_error( $valid_check ) ) { 940 return $valid_check; 941 } 942 943 if ( false === $valid_check ) { 944 // A WP_Error instance is preferred, but false is supported for parity with the per-arg validate_callback. 945 return new WP_Error( 'rest_invalid_params', __( 'Invalid parameters.' ), array( 'status' => 400 ) ); 946 } 947 } 948 949 return true; 950 } 951 952 /** 953 * Checks if a parameter is set. 954 * 955 * @since 4.4.0 956 * 957 * @param string $offset Parameter name. 958 * @return bool Whether the parameter is set. 959 */ 960 #[ReturnTypeWillChange] 961 public function offsetExists( $offset ) { 962 $order = $this->get_parameter_order(); 963 964 foreach ( $order as $type ) { 965 if ( isset( $this->params[ $type ][ $offset ] ) ) { 966 return true; 967 } 968 } 969 970 return false; 971 } 972 973 /** 974 * Retrieves a parameter from the request. 975 * 976 * @since 4.4.0 977 * 978 * @param string $offset Parameter name. 979 * @return mixed|null Value if set, null otherwise. 980 */ 981 #[ReturnTypeWillChange] 982 public function offsetGet( $offset ) { 983 return $this->get_param( $offset ); 984 } 985 986 /** 987 * Sets a parameter on the request. 988 * 989 * @since 4.4.0 990 * 991 * @param string $offset Parameter name. 992 * @param mixed $value Parameter value. 993 */ 994 #[ReturnTypeWillChange] 995 public function offsetSet( $offset, $value ) { 996 $this->set_param( $offset, $value ); 997 } 998 999 /** 1000 * Removes a parameter from the request. 1001 * 1002 * @since 4.4.0 1003 * 1004 * @param string $offset Parameter name. 1005 */ 1006 #[ReturnTypeWillChange] 1007 public function offsetUnset( $offset ) { 1008 $order = $this->get_parameter_order(); 1009 1010 // Remove the offset from every group. 1011 foreach ( $order as $type ) { 1012 unset( $this->params[ $type ][ $offset ] ); 1013 } 1014 } 1015 1016 /** 1017 * Retrieves a WP_REST_Request object from a full URL. 1018 * 1019 * @since 4.5.0 1020 * 1021 * @param string $url URL with protocol, domain, path and query args. 1022 * @return WP_REST_Request|false WP_REST_Request object on success, false on failure. 1023 */ 1024 public static function from_url( $url ) { 1025 $bits = parse_url( $url ); 1026 $query_params = array(); 1027 1028 if ( ! empty( $bits['query'] ) ) { 1029 wp_parse_str( $bits['query'], $query_params ); 1030 } 1031 1032 $api_root = rest_url(); 1033 if ( get_option( 'permalink_structure' ) && 0 === strpos( $url, $api_root ) ) { 1034 // Pretty permalinks on, and URL is under the API root. 1035 $api_url_part = substr( $url, strlen( untrailingslashit( $api_root ) ) ); 1036 $route = parse_url( $api_url_part, PHP_URL_PATH ); 1037 } elseif ( ! empty( $query_params['rest_route'] ) ) { 1038 // ?rest_route=... set directly. 1039 $route = $query_params['rest_route']; 1040 unset( $query_params['rest_route'] ); 1041 } 1042 1043 $request = false; 1044 if ( ! empty( $route ) ) { 1045 $request = new WP_REST_Request( 'GET', $route ); 1046 $request->set_query_params( $query_params ); 1047 } 1048 1049 /** 1050 * Filters the REST API request generated from a URL. 1051 * 1052 * @since 4.5.0 1053 * 1054 * @param WP_REST_Request|false $request Generated request object, or false if URL 1055 * could not be parsed. 1056 * @param string $url URL the request was generated from. 1057 */ 1058 return apply_filters( 'rest_request_from_url', $request, $url ); 1059 } 1060 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Nov 21 01:00:03 2024 | Cross-referenced by PHPXref 0.7.1 |