Changeset 48357
- Timestamp:
- 07/07/2020 03:20:34 AM (5 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/rest-api.php
r48307 r48357 1440 1440 1441 1441 /** 1442 * Checks if an array is made up of unique items. 1443 * 1444 * @since 5.5.0 1445 * 1446 * @param array $array The array to check. 1447 * @return bool True if the array contains unique items, false otherwise. 1448 */ 1449 function rest_validate_array_contains_unique_items( $array ) { 1450 $seen = array(); 1451 1452 foreach ( $array as $item ) { 1453 $stabilized = rest_stabilize_value( $item ); 1454 $key = serialize( $stabilized ); 1455 1456 if ( ! isset( $seen[ $key ] ) ) { 1457 $seen[ $key ] = true; 1458 1459 continue; 1460 } 1461 1462 return false; 1463 } 1464 1465 return true; 1466 } 1467 1468 /** 1469 * Stabilizes a value following JSON Schema semantics. 1470 * 1471 * For lists, order is preserved. For objects, properties are reordered alphabetically. 1472 * 1473 * @since 5.5.0 1474 * 1475 * @param mixed $value The value to stabilize. Must already be sanitized. Objects should have been converted to arrays. 1476 * @return mixed The stabilized value. 1477 */ 1478 function rest_stabilize_value( $value ) { 1479 if ( is_scalar( $value ) || is_null( $value ) ) { 1480 return $value; 1481 } 1482 1483 if ( is_object( $value ) ) { 1484 _doing_it_wrong( __FUNCTION__, __( 'Cannot stabilize objects. Convert the object to an array first.' ), '5.5.0' ); 1485 1486 return $value; 1487 } 1488 1489 ksort( $value ); 1490 1491 foreach ( $value as $k => $v ) { 1492 $value[ $k ] = rest_stabilize_value( $v ); 1493 } 1494 1495 return $value; 1496 } 1497 1498 /** 1442 1499 * Validate a value based on a schema. 1443 1500 * … … 1449 1506 * @since 5.5.0 Add the "uuid" and "hex-color" formats. 1450 1507 * Support the "minLength", "maxLength" and "pattern" keywords for strings. 1508 * Support the "minItems", "maxItems" and "uniqueItems" keywords for arrays. 1451 1509 * Validate required properties. 1452 * Support the "minItems" and "maxItems" keywords for arrays.1453 1510 * 1454 1511 * @param mixed $value The value to validate. … … 1493 1550 $value = rest_sanitize_array( $value ); 1494 1551 1495 foreach ( $value as $index => $v ) { 1496 $is_valid = rest_validate_value_from_schema( $v, $args['items'], $param . '[' . $index . ']' ); 1497 if ( is_wp_error( $is_valid ) ) { 1498 return $is_valid; 1552 if ( isset( $args['items'] ) ) { 1553 foreach ( $value as $index => $v ) { 1554 $is_valid = rest_validate_value_from_schema( $v, $args['items'], $param . '[' . $index . ']' ); 1555 if ( is_wp_error( $is_valid ) ) { 1556 return $is_valid; 1557 } 1499 1558 } 1500 1559 } … … 1508 1567 /* translators: 1: Parameter, 2: Number. */ 1509 1568 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must contain at most %2$s items.' ), $param, number_format_i18n( $args['maxItems'] ) ) ); 1569 } 1570 1571 if ( ! empty( $args['uniqueItems'] ) && ! rest_validate_array_contains_unique_items( $value ) ) { 1572 /* translators: 1: Parameter */ 1573 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s has duplicate items.' ), $param ) ); 1510 1574 } 1511 1575 } … … 1719 1783 * @param array $args Schema array to use for sanitization. 1720 1784 * @param string $param The parameter name, used in error messages. 1721 * @return mixed The sanitized value.1785 * @return mixed|WP_Error The sanitized value or a WP_Error instance if the value cannot be safely sanitized. 1722 1786 */ 1723 1787 function rest_sanitize_value_from_schema( $value, $args, $param = '' ) { … … 1751 1815 $value = rest_sanitize_array( $value ); 1752 1816 1753 if ( empty( $args['items'] ) ) { 1754 return $value; 1755 } 1756 1757 foreach ( $value as $index => $v ) { 1758 $value[ $index ] = rest_sanitize_value_from_schema( $v, $args['items'], $param . '[' . $index . ']' ); 1817 if ( ! empty( $args['items'] ) ) { 1818 foreach ( $value as $index => $v ) { 1819 $value[ $index ] = rest_sanitize_value_from_schema( $v, $args['items'], $param . '[' . $index . ']' ); 1820 } 1821 } 1822 1823 if ( ! empty( $args['uniqueItems'] ) && ! rest_validate_array_contains_unique_items( $value ) ) { 1824 /* translators: 1: Parameter */ 1825 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s has duplicate items.' ), $param ) ); 1759 1826 } 1760 1827 -
trunk/tests/phpunit/tests/rest-api/rest-schema-sanitization.php
r48306 r48357 465 465 $this->assertNull( rest_sanitize_value_from_schema( array( 'Hello!' ), $schema ) ); 466 466 } 467 468 /** 469 * @ticket 48821 470 */ 471 public function test_unique_items_after_sanitization() { 472 $schema = array( 473 'type' => 'array', 474 'uniqueItems' => true, 475 'items' => array( 476 'type' => 'string', 477 'format' => 'uri', 478 ), 479 ); 480 481 $data = array( 482 'https://example.org/hello%20world', 483 'https://example.org/hello world', 484 ); 485 486 $this->assertTrue( rest_validate_value_from_schema( $data, $schema ) ); 487 $this->assertWPError( rest_sanitize_value_from_schema( $data, $schema ) ); 488 } 467 489 } -
trunk/tests/phpunit/tests/rest-api/rest-schema-validation.php
r48306 r48357 508 508 509 509 /** 510 * @ticket 48818510 * @ticket 48818 511 511 * 512 512 * @dataProvider data_required_property … … 536 536 537 537 /** 538 * @ticket 48818538 * @ticket 48818 539 539 * 540 540 * @dataProvider data_required_property … … 578 578 579 579 /** 580 * @ticket 48818580 * @ticket 48818 581 581 * 582 582 * @dataProvider data_required_nested_property … … 611 611 612 612 /** 613 * @ticket 48818613 * @ticket 48818 614 614 * 615 615 * @dataProvider data_required_nested_property … … 670 670 671 671 /** 672 * @ticket 48818672 * @ticket 48818 673 673 * 674 674 * @dataProvider data_required_deeply_nested_property … … 710 710 711 711 /** 712 * @ticket 48818712 * @ticket 48818 713 713 * 714 714 * @dataProvider data_required_deeply_nested_property … … 750 750 751 751 /** 752 * @ticket 48818752 * @ticket 48818 753 753 * 754 754 * @dataProvider data_required_deeply_nested_property … … 906 906 $this->assertWPError( rest_validate_value_from_schema( 'foobar', $schema ) ); 907 907 } 908 909 /** 910 * @ticket 48821 911 * 912 * @dataProvider data_unique_items 913 */ 914 public function test_unique_items( $test, $suite ) { 915 $test_description = $suite['description'] . ': ' . $test['description']; 916 $message = $test_description . ': ' . var_export( $test['data'], true ); 917 918 $valid = rest_validate_value_from_schema( $test['data'], $suite['schema'] ); 919 920 if ( $test['valid'] ) { 921 $this->assertTrue( $valid, $message ); 922 } else { 923 $this->assertWPError( $valid, $message ); 924 } 925 } 926 927 public function data_unique_items() { 928 $all_types = array( 'object', 'array', 'null', 'number', 'integer', 'boolean', 'string' ); 929 930 // the following test suites is not supported at the moment 931 $skip = array( 932 'uniqueItems with an array of items', 933 'uniqueItems with an array of items and additionalItems=false', 934 'uniqueItems=false with an array of items', 935 'uniqueItems=false with an array of items and additionalItems=false', 936 ); 937 $suites = json_decode( file_get_contents( __DIR__ . '/json_schema_test_suite/uniqueitems.json' ), true ); 938 939 $tests = array(); 940 941 foreach ( $suites as $suite ) { 942 if ( in_array( $suite['description'], $skip, true ) ) { 943 continue; 944 } 945 // type is required for our implementation 946 if ( ! isset( $suite['schema']['type'] ) ) { 947 $suite['schema']['type'] = 'array'; 948 } 949 // items is required for our implementation 950 if ( ! isset( $suite['schema']['items'] ) ) { 951 $suite['schema']['items'] = array( 952 'type' => $all_types, 953 'items' => array( 954 'type' => $all_types, 955 ), 956 ); 957 } 958 foreach ( $suite['tests'] as $test ) { 959 $tests[] = array( $test, $suite ); 960 } 961 } 962 963 return $tests; 964 } 965 966 /** 967 * @ticket 48821 968 */ 969 public function test_unique_items_deep_objects() { 970 $schema = array( 971 'type' => 'array', 972 'uniqueItems' => true, 973 'items' => array( 974 'type' => 'object', 975 'properties' => array( 976 'release' => array( 977 'type' => 'object', 978 'properties' => array( 979 'name' => array( 980 'type' => 'string', 981 ), 982 'version' => array( 983 'type' => 'string', 984 ), 985 ), 986 ), 987 ), 988 ), 989 ); 990 991 $data = array( 992 array( 993 'release' => array( 994 'name' => 'Kirk', 995 'version' => '5.3', 996 ), 997 ), 998 array( 999 'release' => array( 1000 'version' => '5.3', 1001 'name' => 'Kirk', 1002 ), 1003 ), 1004 ); 1005 1006 $this->assertWPError( rest_validate_value_from_schema( $data, $schema ) ); 1007 1008 $data[0]['release']['version'] = '5.3.0'; 1009 $this->assertTrue( rest_validate_value_from_schema( $data, $schema ) ); 1010 } 1011 1012 /** 1013 * @ticket 48821 1014 */ 1015 public function test_unique_items_deep_arrays() { 1016 $schema = array( 1017 'type' => 'array', 1018 'uniqueItems' => true, 1019 'items' => array( 1020 'type' => 'array', 1021 'items' => array( 1022 'type' => 'string', 1023 ), 1024 ), 1025 ); 1026 1027 $data = array( 1028 array( 1029 'Kirk', 1030 'Jaco', 1031 ), 1032 array( 1033 'Kirk', 1034 'Jaco', 1035 ), 1036 ); 1037 1038 $this->assertWPError( rest_validate_value_from_schema( $data, $schema ) ); 1039 1040 $data[1] = array_reverse( $data[1] ); 1041 $this->assertTrue( rest_validate_value_from_schema( $data, $schema ) ); 1042 } 908 1043 }
Note: See TracChangeset
for help on using the changeset viewer.