1535 foreach ( $value as $k => $v ) { |
1664 foreach ( $value as $k => $v ) { |
1536 $value[ $k ] = rest_stabilize_value( $v ); |
1665 $value[ $k ] = rest_stabilize_value( $v ); |
1537 } |
1666 } |
1538 |
1667 |
1539 return $value; |
1668 return $value; |
|
1669 } |
|
1670 |
|
1671 /** |
|
1672 * Validates if the JSON Schema pattern matches a value. |
|
1673 * |
|
1674 * @since 5.6.0 |
|
1675 * |
|
1676 * @param string $pattern The pattern to match against. |
|
1677 * @param string $value The value to check. |
|
1678 * @return bool True if the pattern matches the given value, false otherwise. |
|
1679 */ |
|
1680 function rest_validate_json_schema_pattern( $pattern, $value ) { |
|
1681 $escaped_pattern = str_replace( '#', '\\#', $pattern ); |
|
1682 |
|
1683 return 1 === preg_match( '#' . $escaped_pattern . '#u', $value ); |
|
1684 } |
|
1685 |
|
1686 /** |
|
1687 * Finds the schema for a property using the patternProperties keyword. |
|
1688 * |
|
1689 * @since 5.6.0 |
|
1690 * |
|
1691 * @param string $property The property name to check. |
|
1692 * @param array $args The schema array to use. |
|
1693 * @return array|null The schema of matching pattern property, or null if no patterns match. |
|
1694 */ |
|
1695 function rest_find_matching_pattern_property_schema( $property, $args ) { |
|
1696 if ( isset( $args['patternProperties'] ) ) { |
|
1697 foreach ( $args['patternProperties'] as $pattern => $child_schema ) { |
|
1698 if ( rest_validate_json_schema_pattern( $pattern, $property ) ) { |
|
1699 return $child_schema; |
|
1700 } |
|
1701 } |
|
1702 } |
|
1703 |
|
1704 return null; |
|
1705 } |
|
1706 |
|
1707 /** |
|
1708 * Formats a combining operation error into a WP_Error object. |
|
1709 * |
|
1710 * @since 5.6.0 |
|
1711 * |
|
1712 * @param string $param The parameter name. |
|
1713 * @param array $error The error details. |
|
1714 * @return WP_Error |
|
1715 */ |
|
1716 function rest_format_combining_operation_error( $param, $error ) { |
|
1717 $position = $error['index']; |
|
1718 $reason = $error['error_object']->get_error_message(); |
|
1719 |
|
1720 if ( isset( $error['schema']['title'] ) ) { |
|
1721 $title = $error['schema']['title']; |
|
1722 |
|
1723 return new WP_Error( |
|
1724 'rest_no_matching_schema', |
|
1725 /* translators: 1: Parameter, 2: Schema title, 3: Reason. */ |
|
1726 sprintf( __( '%1$s is not a valid %2$s. Reason: %3$s' ), $param, $title, $reason ), |
|
1727 array( 'position' => $position ) |
|
1728 ); |
|
1729 } |
|
1730 |
|
1731 return new WP_Error( |
|
1732 'rest_no_matching_schema', |
|
1733 /* translators: 1: Parameter, 2: Reason. */ |
|
1734 sprintf( __( '%1$s does not match the expected format. Reason: %2$s' ), $param, $reason ), |
|
1735 array( 'position' => $position ) |
|
1736 ); |
|
1737 } |
|
1738 |
|
1739 /** |
|
1740 * Gets the error of combining operation. |
|
1741 * |
|
1742 * @since 5.6.0 |
|
1743 * |
|
1744 * @param array $value The value to validate. |
|
1745 * @param string $param The parameter name, used in error messages. |
|
1746 * @param array $errors The errors array, to search for possible error. |
|
1747 * @return WP_Error The combining operation error. |
|
1748 */ |
|
1749 function rest_get_combining_operation_error( $value, $param, $errors ) { |
|
1750 // If there is only one error, simply return it. |
|
1751 if ( 1 === count( $errors ) ) { |
|
1752 return rest_format_combining_operation_error( $param, $errors[0] ); |
|
1753 } |
|
1754 |
|
1755 // Filter out all errors related to type validation. |
|
1756 $filtered_errors = array(); |
|
1757 foreach ( $errors as $error ) { |
|
1758 $error_code = $error['error_object']->get_error_code(); |
|
1759 $error_data = $error['error_object']->get_error_data(); |
|
1760 |
|
1761 if ( 'rest_invalid_type' !== $error_code || ( isset( $error_data['param'] ) && $param !== $error_data['param'] ) ) { |
|
1762 $filtered_errors[] = $error; |
|
1763 } |
|
1764 } |
|
1765 |
|
1766 // If there is only one error left, simply return it. |
|
1767 if ( 1 === count( $filtered_errors ) ) { |
|
1768 return rest_format_combining_operation_error( $param, $filtered_errors[0] ); |
|
1769 } |
|
1770 |
|
1771 // If there are only errors related to object validation, try choosing the most appropriate one. |
|
1772 if ( count( $filtered_errors ) > 1 && 'object' === $filtered_errors[0]['schema']['type'] ) { |
|
1773 $result = null; |
|
1774 $number = 0; |
|
1775 |
|
1776 foreach ( $filtered_errors as $error ) { |
|
1777 if ( isset( $error['schema']['properties'] ) ) { |
|
1778 $n = count( array_intersect_key( $error['schema']['properties'], $value ) ); |
|
1779 if ( $n > $number ) { |
|
1780 $result = $error; |
|
1781 $number = $n; |
|
1782 } |
|
1783 } |
|
1784 } |
|
1785 |
|
1786 if ( null !== $result ) { |
|
1787 return rest_format_combining_operation_error( $param, $result ); |
|
1788 } |
|
1789 } |
|
1790 |
|
1791 // If each schema has a title, include those titles in the error message. |
|
1792 $schema_titles = array(); |
|
1793 foreach ( $errors as $error ) { |
|
1794 if ( isset( $error['schema']['title'] ) ) { |
|
1795 $schema_titles[] = $error['schema']['title']; |
|
1796 } |
|
1797 } |
|
1798 |
|
1799 if ( count( $schema_titles ) === count( $errors ) ) { |
|
1800 /* translators: 1: Parameter, 2: Schema titles. */ |
|
1801 return new WP_Error( 'rest_no_matching_schema', wp_sprintf( __( '%1$s is not a valid %2$l.' ), $param, $schema_titles ) ); |
|
1802 } |
|
1803 |
|
1804 /* translators: %s: Parameter. */ |
|
1805 return new WP_Error( 'rest_no_matching_schema', sprintf( __( '%s does not match any of the expected formats.' ), $param ) ); |
|
1806 } |
|
1807 |
|
1808 /** |
|
1809 * Finds the matching schema among the "anyOf" schemas. |
|
1810 * |
|
1811 * @since 5.6.0 |
|
1812 * |
|
1813 * @param mixed $value The value to validate. |
|
1814 * @param array $args The schema array to use. |
|
1815 * @param string $param The parameter name, used in error messages. |
|
1816 * @return array|WP_Error The matching schema or WP_Error instance if all schemas do not match. |
|
1817 */ |
|
1818 function rest_find_any_matching_schema( $value, $args, $param ) { |
|
1819 $errors = array(); |
|
1820 |
|
1821 foreach ( $args['anyOf'] as $index => $schema ) { |
|
1822 if ( ! isset( $schema['type'] ) && isset( $args['type'] ) ) { |
|
1823 $schema['type'] = $args['type']; |
|
1824 } |
|
1825 |
|
1826 $is_valid = rest_validate_value_from_schema( $value, $schema, $param ); |
|
1827 if ( ! is_wp_error( $is_valid ) ) { |
|
1828 return $schema; |
|
1829 } |
|
1830 |
|
1831 $errors[] = array( |
|
1832 'error_object' => $is_valid, |
|
1833 'schema' => $schema, |
|
1834 'index' => $index, |
|
1835 ); |
|
1836 } |
|
1837 |
|
1838 return rest_get_combining_operation_error( $value, $param, $errors ); |
|
1839 } |
|
1840 |
|
1841 /** |
|
1842 * Finds the matching schema among the "oneOf" schemas. |
|
1843 * |
|
1844 * @since 5.6.0 |
|
1845 * |
|
1846 * @param mixed $value The value to validate. |
|
1847 * @param array $args The schema array to use. |
|
1848 * @param string $param The parameter name, used in error messages. |
|
1849 * @param bool $stop_after_first_match Optional. Whether the process should stop after the first successful match. |
|
1850 * @return array|WP_Error The matching schema or WP_Error instance if the number of matching schemas is not equal to one. |
|
1851 */ |
|
1852 function rest_find_one_matching_schema( $value, $args, $param, $stop_after_first_match = false ) { |
|
1853 $matching_schemas = array(); |
|
1854 $errors = array(); |
|
1855 |
|
1856 foreach ( $args['oneOf'] as $index => $schema ) { |
|
1857 if ( ! isset( $schema['type'] ) && isset( $args['type'] ) ) { |
|
1858 $schema['type'] = $args['type']; |
|
1859 } |
|
1860 |
|
1861 $is_valid = rest_validate_value_from_schema( $value, $schema, $param ); |
|
1862 if ( ! is_wp_error( $is_valid ) ) { |
|
1863 if ( $stop_after_first_match ) { |
|
1864 return $schema; |
|
1865 } |
|
1866 |
|
1867 $matching_schemas[] = array( |
|
1868 'schema_object' => $schema, |
|
1869 'index' => $index, |
|
1870 ); |
|
1871 } else { |
|
1872 $errors[] = array( |
|
1873 'error_object' => $is_valid, |
|
1874 'schema' => $schema, |
|
1875 'index' => $index, |
|
1876 ); |
|
1877 } |
|
1878 } |
|
1879 |
|
1880 if ( ! $matching_schemas ) { |
|
1881 return rest_get_combining_operation_error( $value, $param, $errors ); |
|
1882 } |
|
1883 |
|
1884 if ( count( $matching_schemas ) > 1 ) { |
|
1885 $schema_positions = array(); |
|
1886 $schema_titles = array(); |
|
1887 |
|
1888 foreach ( $matching_schemas as $schema ) { |
|
1889 $schema_positions[] = $schema['index']; |
|
1890 |
|
1891 if ( isset( $schema['schema_object']['title'] ) ) { |
|
1892 $schema_titles[] = $schema['schema_object']['title']; |
|
1893 } |
|
1894 } |
|
1895 |
|
1896 // If each schema has a title, include those titles in the error message. |
|
1897 if ( count( $schema_titles ) === count( $matching_schemas ) ) { |
|
1898 return new WP_Error( |
|
1899 'rest_one_of_multiple_matches', |
|
1900 /* translators: 1: Parameter, 2: Schema titles. */ |
|
1901 wp_sprintf( __( '%1$s matches %2$l, but should match only one.' ), $param, $schema_titles ), |
|
1902 array( 'positions' => $schema_positions ) |
|
1903 ); |
|
1904 } |
|
1905 |
|
1906 return new WP_Error( |
|
1907 'rest_one_of_multiple_matches', |
|
1908 /* translators: %s: Parameter. */ |
|
1909 sprintf( __( '%s matches more than one of the expected formats.' ), $param ), |
|
1910 array( 'positions' => $schema_positions ) |
|
1911 ); |
|
1912 } |
|
1913 |
|
1914 return $matching_schemas[0]['schema_object']; |
|
1915 } |
|
1916 |
|
1917 /** |
|
1918 * Checks the equality of two values, following JSON Schema semantics. |
|
1919 * |
|
1920 * Property order is ignored for objects. |
|
1921 * |
|
1922 * Values must have been previously sanitized/coerced to their native types. |
|
1923 * |
|
1924 * @since 5.7.0 |
|
1925 * |
|
1926 * @param mixed $value1 The first value to check. |
|
1927 * @param mixed $value2 The second value to check. |
|
1928 * @return bool True if the values are equal or false otherwise. |
|
1929 */ |
|
1930 function rest_are_values_equal( $value1, $value2 ) { |
|
1931 if ( is_array( $value1 ) && is_array( $value2 ) ) { |
|
1932 if ( count( $value1 ) !== count( $value2 ) ) { |
|
1933 return false; |
|
1934 } |
|
1935 |
|
1936 foreach ( $value1 as $index => $value ) { |
|
1937 if ( ! array_key_exists( $index, $value2 ) || ! rest_are_values_equal( $value, $value2[ $index ] ) ) { |
|
1938 return false; |
|
1939 } |
|
1940 } |
|
1941 |
|
1942 return true; |
|
1943 } |
|
1944 |
|
1945 if ( is_int( $value1 ) && is_float( $value2 ) |
|
1946 || is_float( $value1 ) && is_int( $value2 ) |
|
1947 ) { |
|
1948 return (float) $value1 === (float) $value2; |
|
1949 } |
|
1950 |
|
1951 return $value1 === $value2; |
|
1952 } |
|
1953 |
|
1954 /** |
|
1955 * Validates that the given value is a member of the JSON Schema "enum". |
|
1956 * |
|
1957 * @since 5.7.0 |
|
1958 * |
|
1959 * @param mixed $value The value to validate. |
|
1960 * @param array $args The schema array to use. |
|
1961 * @param string $param The parameter name, used in error messages. |
|
1962 * @return true|WP_Error True if the "enum" contains the value or a WP_Error instance otherwise. |
|
1963 */ |
|
1964 function rest_validate_enum( $value, $args, $param ) { |
|
1965 $sanitized_value = rest_sanitize_value_from_schema( $value, $args, $param ); |
|
1966 if ( is_wp_error( $sanitized_value ) ) { |
|
1967 return $sanitized_value; |
|
1968 } |
|
1969 |
|
1970 foreach ( $args['enum'] as $enum_value ) { |
|
1971 if ( rest_are_values_equal( $sanitized_value, $enum_value ) ) { |
|
1972 return true; |
|
1973 } |
|
1974 } |
|
1975 |
|
1976 $encoded_enum_values = array(); |
|
1977 foreach ( $args['enum'] as $enum_value ) { |
|
1978 $encoded_enum_values[] = is_scalar( $enum_value ) ? $enum_value : wp_json_encode( $enum_value ); |
|
1979 } |
|
1980 |
|
1981 if ( count( $encoded_enum_values ) === 1 ) { |
|
1982 /* translators: 1: Parameter, 2: Valid values. */ |
|
1983 return new WP_Error( 'rest_not_in_enum', wp_sprintf( __( '%1$s is not %2$s.' ), $param, $encoded_enum_values[0] ) ); |
|
1984 } |
|
1985 |
|
1986 /* translators: 1: Parameter, 2: List of valid values. */ |
|
1987 return new WP_Error( 'rest_not_in_enum', wp_sprintf( __( '%1$s is not one of %2$l.' ), $param, $encoded_enum_values ) ); |
|
1988 } |
|
1989 |
|
1990 /** |
|
1991 * Get all valid JSON schema properties. |
|
1992 * |
|
1993 * @since 5.6.0 |
|
1994 * |
|
1995 * @return string[] All valid JSON schema properties. |
|
1996 */ |
|
1997 function rest_get_allowed_schema_keywords() { |
|
1998 return array( |
|
1999 'title', |
|
2000 'description', |
|
2001 'default', |
|
2002 'type', |
|
2003 'format', |
|
2004 'enum', |
|
2005 'items', |
|
2006 'properties', |
|
2007 'additionalProperties', |
|
2008 'patternProperties', |
|
2009 'minProperties', |
|
2010 'maxProperties', |
|
2011 'minimum', |
|
2012 'maximum', |
|
2013 'exclusiveMinimum', |
|
2014 'exclusiveMaximum', |
|
2015 'multipleOf', |
|
2016 'minLength', |
|
2017 'maxLength', |
|
2018 'pattern', |
|
2019 'minItems', |
|
2020 'maxItems', |
|
2021 'uniqueItems', |
|
2022 'anyOf', |
|
2023 'oneOf', |
|
2024 ); |
1540 } |
2025 } |
1541 |
2026 |
1542 /** |
2027 /** |
1543 * Validate a value based on a schema. |
2028 * Validate a value based on a schema. |
1544 * |
2029 * |
1549 * @since 5.4.0 Convert an empty string to an empty object. |
2034 * @since 5.4.0 Convert an empty string to an empty object. |
1550 * @since 5.5.0 Add the "uuid" and "hex-color" formats. |
2035 * @since 5.5.0 Add the "uuid" and "hex-color" formats. |
1551 * Support the "minLength", "maxLength" and "pattern" keywords for strings. |
2036 * Support the "minLength", "maxLength" and "pattern" keywords for strings. |
1552 * Support the "minItems", "maxItems" and "uniqueItems" keywords for arrays. |
2037 * Support the "minItems", "maxItems" and "uniqueItems" keywords for arrays. |
1553 * Validate required properties. |
2038 * Validate required properties. |
|
2039 * @since 5.6.0 Support the "minProperties" and "maxProperties" keywords for objects. |
|
2040 * Support the "multipleOf" keyword for numbers and integers. |
|
2041 * Support the "patternProperties" keyword for objects. |
|
2042 * Support the "anyOf" and "oneOf" keywords. |
1554 * |
2043 * |
1555 * @param mixed $value The value to validate. |
2044 * @param mixed $value The value to validate. |
1556 * @param array $args Schema array to use for validation. |
2045 * @param array $args Schema array to use for validation. |
1557 * @param string $param The parameter name, used in error messages. |
2046 * @param string $param The parameter name, used in error messages. |
1558 * @return true|WP_Error |
2047 * @return true|WP_Error |
1559 */ |
2048 */ |
1560 function rest_validate_value_from_schema( $value, $args, $param = '' ) { |
2049 function rest_validate_value_from_schema( $value, $args, $param = '' ) { |
|
2050 if ( isset( $args['anyOf'] ) ) { |
|
2051 $matching_schema = rest_find_any_matching_schema( $value, $args, $param ); |
|
2052 if ( is_wp_error( $matching_schema ) ) { |
|
2053 return $matching_schema; |
|
2054 } |
|
2055 |
|
2056 if ( ! isset( $args['type'] ) && isset( $matching_schema['type'] ) ) { |
|
2057 $args['type'] = $matching_schema['type']; |
|
2058 } |
|
2059 } |
|
2060 |
|
2061 if ( isset( $args['oneOf'] ) ) { |
|
2062 $matching_schema = rest_find_one_matching_schema( $value, $args, $param ); |
|
2063 if ( is_wp_error( $matching_schema ) ) { |
|
2064 return $matching_schema; |
|
2065 } |
|
2066 |
|
2067 if ( ! isset( $args['type'] ) && isset( $matching_schema['type'] ) ) { |
|
2068 $args['type'] = $matching_schema['type']; |
|
2069 } |
|
2070 } |
|
2071 |
1561 $allowed_types = array( 'array', 'object', 'string', 'number', 'integer', 'boolean', 'null' ); |
2072 $allowed_types = array( 'array', 'object', 'string', 'number', 'integer', 'boolean', 'null' ); |
1562 |
2073 |
1563 if ( ! isset( $args['type'] ) ) { |
2074 if ( ! isset( $args['type'] ) ) { |
1564 /* translators: 1. Parameter */ |
2075 /* translators: %s: Parameter. */ |
1565 _doing_it_wrong( __FUNCTION__, sprintf( __( 'The "type" schema keyword for %s is required.' ), $param ), '5.5.0' ); |
2076 _doing_it_wrong( __FUNCTION__, sprintf( __( 'The "type" schema keyword for %s is required.' ), $param ), '5.5.0' ); |
1566 } |
2077 } |
1567 |
2078 |
1568 if ( is_array( $args['type'] ) ) { |
2079 if ( is_array( $args['type'] ) ) { |
1569 $best_type = rest_handle_multi_type_schema( $value, $args, $param ); |
2080 $best_type = rest_handle_multi_type_schema( $value, $args, $param ); |
1570 |
2081 |
1571 if ( ! $best_type ) { |
2082 if ( ! $best_type ) { |
1572 /* translators: 1: Parameter, 2: List of types. */ |
2083 return new WP_Error( |
1573 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s is not of type %2$s.' ), $param, implode( ',', $args['type'] ) ) ); |
2084 'rest_invalid_type', |
|
2085 /* translators: 1: Parameter, 2: List of types. */ |
|
2086 sprintf( __( '%1$s is not of type %2$s.' ), $param, implode( ',', $args['type'] ) ), |
|
2087 array( 'param' => $param ) |
|
2088 ); |
1574 } |
2089 } |
1575 |
2090 |
1576 $args['type'] = $best_type; |
2091 $args['type'] = $best_type; |
1577 } |
2092 } |
1578 |
2093 |
1579 if ( ! in_array( $args['type'], $allowed_types, true ) ) { |
2094 if ( ! in_array( $args['type'], $allowed_types, true ) ) { |
1580 _doing_it_wrong( |
2095 _doing_it_wrong( |
1581 __FUNCTION__, |
2096 __FUNCTION__, |
1582 /* translators: 1. Parameter 2. The list of allowed types. */ |
2097 /* translators: 1: Parameter, 2: The list of allowed types. */ |
1583 wp_sprintf( __( 'The "type" schema keyword for %1$s can only be one of the built-in types: %2$l.' ), $param, $allowed_types ), |
2098 wp_sprintf( __( 'The "type" schema keyword for %1$s can only be one of the built-in types: %2$l.' ), $param, $allowed_types ), |
1584 '5.5.0' |
2099 '5.5.0' |
1585 ); |
2100 ); |
1586 } |
2101 } |
1587 |
2102 |
1588 if ( 'array' === $args['type'] ) { |
2103 switch ( $args['type'] ) { |
1589 if ( ! rest_is_array( $value ) ) { |
2104 case 'null': |
1590 /* translators: 1: Parameter, 2: Type name. */ |
2105 $is_valid = rest_validate_null_value_from_schema( $value, $param ); |
1591 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s is not of type %2$s.' ), $param, 'array' ) ); |
2106 break; |
1592 } |
2107 case 'boolean': |
1593 |
2108 $is_valid = rest_validate_boolean_value_from_schema( $value, $param ); |
1594 $value = rest_sanitize_array( $value ); |
2109 break; |
1595 |
2110 case 'object': |
1596 if ( isset( $args['items'] ) ) { |
2111 $is_valid = rest_validate_object_value_from_schema( $value, $args, $param ); |
1597 foreach ( $value as $index => $v ) { |
2112 break; |
1598 $is_valid = rest_validate_value_from_schema( $v, $args['items'], $param . '[' . $index . ']' ); |
2113 case 'array': |
1599 if ( is_wp_error( $is_valid ) ) { |
2114 $is_valid = rest_validate_array_value_from_schema( $value, $args, $param ); |
1600 return $is_valid; |
2115 break; |
1601 } |
2116 case 'number': |
1602 } |
2117 $is_valid = rest_validate_number_value_from_schema( $value, $args, $param ); |
1603 } |
2118 break; |
1604 |
2119 case 'string': |
1605 if ( isset( $args['minItems'] ) && count( $value ) < $args['minItems'] ) { |
2120 $is_valid = rest_validate_string_value_from_schema( $value, $args, $param ); |
1606 /* translators: 1: Parameter, 2: Number. */ |
2121 break; |
1607 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must contain at least %2$s items.' ), $param, number_format_i18n( $args['minItems'] ) ) ); |
2122 case 'integer': |
1608 } |
2123 $is_valid = rest_validate_integer_value_from_schema( $value, $args, $param ); |
1609 |
2124 break; |
1610 if ( isset( $args['maxItems'] ) && count( $value ) > $args['maxItems'] ) { |
2125 default: |
1611 /* translators: 1: Parameter, 2: Number. */ |
2126 $is_valid = true; |
1612 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must contain at most %2$s items.' ), $param, number_format_i18n( $args['maxItems'] ) ) ); |
2127 break; |
1613 } |
2128 } |
1614 |
2129 |
1615 if ( ! empty( $args['uniqueItems'] ) && ! rest_validate_array_contains_unique_items( $value ) ) { |
2130 if ( is_wp_error( $is_valid ) ) { |
1616 /* translators: 1: Parameter */ |
2131 return $is_valid; |
1617 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s has duplicate items.' ), $param ) ); |
|
1618 } |
|
1619 } |
|
1620 |
|
1621 if ( 'object' === $args['type'] ) { |
|
1622 if ( ! rest_is_object( $value ) ) { |
|
1623 /* translators: 1: Parameter, 2: Type name. */ |
|
1624 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s is not of type %2$s.' ), $param, 'object' ) ); |
|
1625 } |
|
1626 |
|
1627 $value = rest_sanitize_object( $value ); |
|
1628 |
|
1629 if ( isset( $args['required'] ) && is_array( $args['required'] ) ) { // schema version 4 |
|
1630 foreach ( $args['required'] as $name ) { |
|
1631 if ( ! array_key_exists( $name, $value ) ) { |
|
1632 /* translators: 1: Property of an object, 2: Parameter. */ |
|
1633 return new WP_Error( 'rest_property_required', sprintf( __( '%1$s is a required property of %2$s.' ), $name, $param ) ); |
|
1634 } |
|
1635 } |
|
1636 } elseif ( isset( $args['properties'] ) ) { // schema version 3 |
|
1637 foreach ( $args['properties'] as $name => $property ) { |
|
1638 if ( isset( $property['required'] ) && true === $property['required'] && ! array_key_exists( $name, $value ) ) { |
|
1639 /* translators: 1: Property of an object, 2: Parameter. */ |
|
1640 return new WP_Error( 'rest_property_required', sprintf( __( '%1$s is a required property of %2$s.' ), $name, $param ) ); |
|
1641 } |
|
1642 } |
|
1643 } |
|
1644 |
|
1645 foreach ( $value as $property => $v ) { |
|
1646 if ( isset( $args['properties'][ $property ] ) ) { |
|
1647 $is_valid = rest_validate_value_from_schema( $v, $args['properties'][ $property ], $param . '[' . $property . ']' ); |
|
1648 if ( is_wp_error( $is_valid ) ) { |
|
1649 return $is_valid; |
|
1650 } |
|
1651 } elseif ( isset( $args['additionalProperties'] ) ) { |
|
1652 if ( false === $args['additionalProperties'] ) { |
|
1653 /* translators: %s: Property of an object. */ |
|
1654 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s is not a valid property of Object.' ), $property ) ); |
|
1655 } |
|
1656 |
|
1657 if ( is_array( $args['additionalProperties'] ) ) { |
|
1658 $is_valid = rest_validate_value_from_schema( $v, $args['additionalProperties'], $param . '[' . $property . ']' ); |
|
1659 if ( is_wp_error( $is_valid ) ) { |
|
1660 return $is_valid; |
|
1661 } |
|
1662 } |
|
1663 } |
|
1664 } |
|
1665 } |
|
1666 |
|
1667 if ( 'null' === $args['type'] ) { |
|
1668 if ( null !== $value ) { |
|
1669 /* translators: 1: Parameter, 2: Type name. */ |
|
1670 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s is not of type %2$s.' ), $param, 'null' ) ); |
|
1671 } |
|
1672 |
|
1673 return true; |
|
1674 } |
2132 } |
1675 |
2133 |
1676 if ( ! empty( $args['enum'] ) ) { |
2134 if ( ! empty( $args['enum'] ) ) { |
1677 if ( ! in_array( $value, $args['enum'], true ) ) { |
2135 $enum_contains_value = rest_validate_enum( $value, $args, $param ); |
1678 /* translators: 1: Parameter, 2: List of valid values. */ |
2136 if ( is_wp_error( $enum_contains_value ) ) { |
1679 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s is not one of %2$s.' ), $param, implode( ', ', $args['enum'] ) ) ); |
2137 return $enum_contains_value; |
1680 } |
|
1681 } |
|
1682 |
|
1683 if ( in_array( $args['type'], array( 'integer', 'number' ), true ) && ! is_numeric( $value ) ) { |
|
1684 /* translators: 1: Parameter, 2: Type name. */ |
|
1685 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s is not of type %2$s.' ), $param, $args['type'] ) ); |
|
1686 } |
|
1687 |
|
1688 if ( 'integer' === $args['type'] && ! rest_is_integer( $value ) ) { |
|
1689 /* translators: 1: Parameter, 2: Type name. */ |
|
1690 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s is not of type %2$s.' ), $param, 'integer' ) ); |
|
1691 } |
|
1692 |
|
1693 if ( 'boolean' === $args['type'] && ! rest_is_boolean( $value ) ) { |
|
1694 /* translators: 1: Parameter, 2: Type name. */ |
|
1695 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s is not of type %2$s.' ), $param, 'boolean' ) ); |
|
1696 } |
|
1697 |
|
1698 if ( 'string' === $args['type'] ) { |
|
1699 if ( ! is_string( $value ) ) { |
|
1700 /* translators: 1: Parameter, 2: Type name. */ |
|
1701 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s is not of type %2$s.' ), $param, 'string' ) ); |
|
1702 } |
|
1703 |
|
1704 if ( isset( $args['minLength'] ) && mb_strlen( $value ) < $args['minLength'] ) { |
|
1705 return new WP_Error( |
|
1706 'rest_invalid_param', |
|
1707 sprintf( |
|
1708 /* translators: 1: Parameter, 2: Number of characters. */ |
|
1709 _n( '%1$s must be at least %2$s character long.', '%1$s must be at least %2$s characters long.', $args['minLength'] ), |
|
1710 $param, |
|
1711 number_format_i18n( $args['minLength'] ) |
|
1712 ) |
|
1713 ); |
|
1714 } |
|
1715 |
|
1716 if ( isset( $args['maxLength'] ) && mb_strlen( $value ) > $args['maxLength'] ) { |
|
1717 return new WP_Error( |
|
1718 'rest_invalid_param', |
|
1719 sprintf( |
|
1720 /* translators: 1: Parameter, 2: Number of characters. */ |
|
1721 _n( '%1$s must be at most %2$s character long.', '%1$s must be at most %2$s characters long.', $args['maxLength'] ), |
|
1722 $param, |
|
1723 number_format_i18n( $args['maxLength'] ) |
|
1724 ) |
|
1725 ); |
|
1726 } |
|
1727 |
|
1728 if ( isset( $args['pattern'] ) ) { |
|
1729 $pattern = str_replace( '#', '\\#', $args['pattern'] ); |
|
1730 if ( ! preg_match( '#' . $pattern . '#u', $value ) ) { |
|
1731 /* translators: 1: Parameter, 2: Pattern. */ |
|
1732 return new WP_Error( 'rest_invalid_pattern', sprintf( __( '%1$s does not match pattern %2$s.' ), $param, $args['pattern'] ) ); |
|
1733 } |
|
1734 } |
2138 } |
1735 } |
2139 } |
1736 |
2140 |
1737 // The "format" keyword should only be applied to strings. However, for backward compatibility, |
2141 // The "format" keyword should only be applied to strings. However, for backward compatibility, |
1738 // we allow the "format" keyword if the type keyword was not specified, or was set to an invalid value. |
2142 // we allow the "format" keyword if the type keyword was not specified, or was set to an invalid value. |
1758 } |
2162 } |
1759 break; |
2163 break; |
1760 case 'ip': |
2164 case 'ip': |
1761 if ( ! rest_is_ip_address( $value ) ) { |
2165 if ( ! rest_is_ip_address( $value ) ) { |
1762 /* translators: %s: IP address. */ |
2166 /* translators: %s: IP address. */ |
1763 return new WP_Error( 'rest_invalid_param', sprintf( __( '%s is not a valid IP address.' ), $param ) ); |
2167 return new WP_Error( 'rest_invalid_ip', sprintf( __( '%s is not a valid IP address.' ), $param ) ); |
1764 } |
2168 } |
1765 break; |
2169 break; |
1766 case 'uuid': |
2170 case 'uuid': |
1767 if ( ! wp_is_uuid( $value ) ) { |
2171 if ( ! wp_is_uuid( $value ) ) { |
1768 /* translators: %s is the name of a JSON field expecting a valid uuid. */ |
2172 /* translators: %s: The name of a JSON field expecting a valid UUID. */ |
1769 return new WP_Error( 'rest_invalid_uuid', sprintf( __( '%s is not a valid UUID.' ), $param ) ); |
2173 return new WP_Error( 'rest_invalid_uuid', sprintf( __( '%s is not a valid UUID.' ), $param ) ); |
1770 } |
2174 } |
1771 break; |
2175 break; |
1772 } |
2176 } |
1773 } |
2177 } |
1774 |
2178 |
1775 if ( in_array( $args['type'], array( 'number', 'integer' ), true ) && ( isset( $args['minimum'] ) || isset( $args['maximum'] ) ) ) { |
2179 return true; |
1776 if ( isset( $args['minimum'] ) && ! isset( $args['maximum'] ) ) { |
2180 } |
1777 if ( ! empty( $args['exclusiveMinimum'] ) && $value <= $args['minimum'] ) { |
2181 |
|
2182 /** |
|
2183 * Validates a null value based on a schema. |
|
2184 * |
|
2185 * @since 5.7.0 |
|
2186 * |
|
2187 * @param mixed $value The value to validate. |
|
2188 * @param string $param The parameter name, used in error messages. |
|
2189 * @return true|WP_Error |
|
2190 */ |
|
2191 function rest_validate_null_value_from_schema( $value, $param ) { |
|
2192 if ( null !== $value ) { |
|
2193 return new WP_Error( |
|
2194 'rest_invalid_type', |
|
2195 /* translators: 1: Parameter, 2: Type name. */ |
|
2196 sprintf( __( '%1$s is not of type %2$s.' ), $param, 'null' ), |
|
2197 array( 'param' => $param ) |
|
2198 ); |
|
2199 } |
|
2200 |
|
2201 return true; |
|
2202 } |
|
2203 |
|
2204 /** |
|
2205 * Validates a boolean value based on a schema. |
|
2206 * |
|
2207 * @since 5.7.0 |
|
2208 * |
|
2209 * @param mixed $value The value to validate. |
|
2210 * @param string $param The parameter name, used in error messages. |
|
2211 * @return true|WP_Error |
|
2212 */ |
|
2213 function rest_validate_boolean_value_from_schema( $value, $param ) { |
|
2214 if ( ! rest_is_boolean( $value ) ) { |
|
2215 return new WP_Error( |
|
2216 'rest_invalid_type', |
|
2217 /* translators: 1: Parameter, 2: Type name. */ |
|
2218 sprintf( __( '%1$s is not of type %2$s.' ), $param, 'boolean' ), |
|
2219 array( 'param' => $param ) |
|
2220 ); |
|
2221 } |
|
2222 |
|
2223 return true; |
|
2224 } |
|
2225 |
|
2226 /** |
|
2227 * Validates an object value based on a schema. |
|
2228 * |
|
2229 * @since 5.7.0 |
|
2230 * |
|
2231 * @param mixed $value The value to validate. |
|
2232 * @param array $args Schema array to use for validation. |
|
2233 * @param string $param The parameter name, used in error messages. |
|
2234 * @return true|WP_Error |
|
2235 */ |
|
2236 function rest_validate_object_value_from_schema( $value, $args, $param ) { |
|
2237 if ( ! rest_is_object( $value ) ) { |
|
2238 return new WP_Error( |
|
2239 'rest_invalid_type', |
|
2240 /* translators: 1: Parameter, 2: Type name. */ |
|
2241 sprintf( __( '%1$s is not of type %2$s.' ), $param, 'object' ), |
|
2242 array( 'param' => $param ) |
|
2243 ); |
|
2244 } |
|
2245 |
|
2246 $value = rest_sanitize_object( $value ); |
|
2247 |
|
2248 if ( isset( $args['required'] ) && is_array( $args['required'] ) ) { // schema version 4 |
|
2249 foreach ( $args['required'] as $name ) { |
|
2250 if ( ! array_key_exists( $name, $value ) ) { |
|
2251 return new WP_Error( |
|
2252 'rest_property_required', |
|
2253 /* translators: 1: Property of an object, 2: Parameter. */ |
|
2254 sprintf( __( '%1$s is a required property of %2$s.' ), $name, $param ) |
|
2255 ); |
|
2256 } |
|
2257 } |
|
2258 } elseif ( isset( $args['properties'] ) ) { // schema version 3 |
|
2259 foreach ( $args['properties'] as $name => $property ) { |
|
2260 if ( isset( $property['required'] ) && true === $property['required'] && ! array_key_exists( $name, $value ) ) { |
|
2261 return new WP_Error( |
|
2262 'rest_property_required', |
|
2263 /* translators: 1: Property of an object, 2: Parameter. */ |
|
2264 sprintf( __( '%1$s is a required property of %2$s.' ), $name, $param ) |
|
2265 ); |
|
2266 } |
|
2267 } |
|
2268 } |
|
2269 |
|
2270 foreach ( $value as $property => $v ) { |
|
2271 if ( isset( $args['properties'][ $property ] ) ) { |
|
2272 $is_valid = rest_validate_value_from_schema( $v, $args['properties'][ $property ], $param . '[' . $property . ']' ); |
|
2273 if ( is_wp_error( $is_valid ) ) { |
|
2274 return $is_valid; |
|
2275 } |
|
2276 continue; |
|
2277 } |
|
2278 |
|
2279 $pattern_property_schema = rest_find_matching_pattern_property_schema( $property, $args ); |
|
2280 if ( null !== $pattern_property_schema ) { |
|
2281 $is_valid = rest_validate_value_from_schema( $v, $pattern_property_schema, $param . '[' . $property . ']' ); |
|
2282 if ( is_wp_error( $is_valid ) ) { |
|
2283 return $is_valid; |
|
2284 } |
|
2285 continue; |
|
2286 } |
|
2287 |
|
2288 if ( isset( $args['additionalProperties'] ) ) { |
|
2289 if ( false === $args['additionalProperties'] ) { |
|
2290 return new WP_Error( |
|
2291 'rest_additional_properties_forbidden', |
|
2292 /* translators: %s: Property of an object. */ |
|
2293 sprintf( __( '%1$s is not a valid property of Object.' ), $property ) |
|
2294 ); |
|
2295 } |
|
2296 |
|
2297 if ( is_array( $args['additionalProperties'] ) ) { |
|
2298 $is_valid = rest_validate_value_from_schema( $v, $args['additionalProperties'], $param . '[' . $property . ']' ); |
|
2299 if ( is_wp_error( $is_valid ) ) { |
|
2300 return $is_valid; |
|
2301 } |
|
2302 } |
|
2303 } |
|
2304 } |
|
2305 |
|
2306 if ( isset( $args['minProperties'] ) && count( $value ) < $args['minProperties'] ) { |
|
2307 return new WP_Error( |
|
2308 'rest_too_few_properties', |
|
2309 sprintf( |
|
2310 /* translators: 1: Parameter, 2: Number. */ |
|
2311 _n( |
|
2312 '%1$s must contain at least %2$s property.', |
|
2313 '%1$s must contain at least %2$s properties.', |
|
2314 $args['minProperties'] |
|
2315 ), |
|
2316 $param, |
|
2317 number_format_i18n( $args['minProperties'] ) |
|
2318 ) |
|
2319 ); |
|
2320 } |
|
2321 |
|
2322 if ( isset( $args['maxProperties'] ) && count( $value ) > $args['maxProperties'] ) { |
|
2323 return new WP_Error( |
|
2324 'rest_too_many_properties', |
|
2325 sprintf( |
|
2326 /* translators: 1: Parameter, 2: Number. */ |
|
2327 _n( |
|
2328 '%1$s must contain at most %2$s property.', |
|
2329 '%1$s must contain at most %2$s properties.', |
|
2330 $args['maxProperties'] |
|
2331 ), |
|
2332 $param, |
|
2333 number_format_i18n( $args['maxProperties'] ) |
|
2334 ) |
|
2335 ); |
|
2336 } |
|
2337 |
|
2338 return true; |
|
2339 } |
|
2340 |
|
2341 /** |
|
2342 * Validates an array value based on a schema. |
|
2343 * |
|
2344 * @since 5.7.0 |
|
2345 * |
|
2346 * @param mixed $value The value to validate. |
|
2347 * @param array $args Schema array to use for validation. |
|
2348 * @param string $param The parameter name, used in error messages. |
|
2349 * @return true|WP_Error |
|
2350 */ |
|
2351 function rest_validate_array_value_from_schema( $value, $args, $param ) { |
|
2352 if ( ! rest_is_array( $value ) ) { |
|
2353 return new WP_Error( |
|
2354 'rest_invalid_type', |
|
2355 /* translators: 1: Parameter, 2: Type name. */ |
|
2356 sprintf( __( '%1$s is not of type %2$s.' ), $param, 'array' ), |
|
2357 array( 'param' => $param ) |
|
2358 ); |
|
2359 } |
|
2360 |
|
2361 $value = rest_sanitize_array( $value ); |
|
2362 |
|
2363 if ( isset( $args['items'] ) ) { |
|
2364 foreach ( $value as $index => $v ) { |
|
2365 $is_valid = rest_validate_value_from_schema( $v, $args['items'], $param . '[' . $index . ']' ); |
|
2366 if ( is_wp_error( $is_valid ) ) { |
|
2367 return $is_valid; |
|
2368 } |
|
2369 } |
|
2370 } |
|
2371 |
|
2372 if ( isset( $args['minItems'] ) && count( $value ) < $args['minItems'] ) { |
|
2373 return new WP_Error( |
|
2374 'rest_too_few_items', |
|
2375 sprintf( |
|
2376 /* translators: 1: Parameter, 2: Number. */ |
|
2377 _n( |
|
2378 '%1$s must contain at least %2$s item.', |
|
2379 '%1$s must contain at least %2$s items.', |
|
2380 $args['minItems'] |
|
2381 ), |
|
2382 $param, |
|
2383 number_format_i18n( $args['minItems'] ) |
|
2384 ) |
|
2385 ); |
|
2386 } |
|
2387 |
|
2388 if ( isset( $args['maxItems'] ) && count( $value ) > $args['maxItems'] ) { |
|
2389 return new WP_Error( |
|
2390 'rest_too_many_items', |
|
2391 sprintf( |
|
2392 /* translators: 1: Parameter, 2: Number. */ |
|
2393 _n( |
|
2394 '%1$s must contain at most %2$s item.', |
|
2395 '%1$s must contain at most %2$s items.', |
|
2396 $args['maxItems'] |
|
2397 ), |
|
2398 $param, |
|
2399 number_format_i18n( $args['maxItems'] ) |
|
2400 ) |
|
2401 ); |
|
2402 } |
|
2403 |
|
2404 if ( ! empty( $args['uniqueItems'] ) && ! rest_validate_array_contains_unique_items( $value ) ) { |
|
2405 /* translators: %s: Parameter. */ |
|
2406 return new WP_Error( 'rest_duplicate_items', sprintf( __( '%s has duplicate items.' ), $param ) ); |
|
2407 } |
|
2408 |
|
2409 return true; |
|
2410 } |
|
2411 |
|
2412 /** |
|
2413 * Validates a number value based on a schema. |
|
2414 * |
|
2415 * @since 5.7.0 |
|
2416 * |
|
2417 * @param mixed $value The value to validate. |
|
2418 * @param array $args Schema array to use for validation. |
|
2419 * @param string $param The parameter name, used in error messages. |
|
2420 * @return true|WP_Error |
|
2421 */ |
|
2422 function rest_validate_number_value_from_schema( $value, $args, $param ) { |
|
2423 if ( ! is_numeric( $value ) ) { |
|
2424 return new WP_Error( |
|
2425 'rest_invalid_type', |
|
2426 /* translators: 1: Parameter, 2: Type name. */ |
|
2427 sprintf( __( '%1$s is not of type %2$s.' ), $param, $args['type'] ), |
|
2428 array( 'param' => $param ) |
|
2429 ); |
|
2430 } |
|
2431 |
|
2432 if ( isset( $args['multipleOf'] ) && fmod( $value, $args['multipleOf'] ) !== 0.0 ) { |
|
2433 return new WP_Error( |
|
2434 'rest_invalid_multiple', |
|
2435 /* translators: 1: Parameter, 2: Multiplier. */ |
|
2436 sprintf( __( '%1$s must be a multiple of %2$s.' ), $param, $args['multipleOf'] ) |
|
2437 ); |
|
2438 } |
|
2439 |
|
2440 if ( isset( $args['minimum'] ) && ! isset( $args['maximum'] ) ) { |
|
2441 if ( ! empty( $args['exclusiveMinimum'] ) && $value <= $args['minimum'] ) { |
|
2442 return new WP_Error( |
|
2443 'rest_out_of_bounds', |
1778 /* translators: 1: Parameter, 2: Minimum number. */ |
2444 /* translators: 1: Parameter, 2: Minimum number. */ |
1779 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be greater than %2$d' ), $param, $args['minimum'] ) ); |
2445 sprintf( __( '%1$s must be greater than %2$d' ), $param, $args['minimum'] ) |
1780 } elseif ( empty( $args['exclusiveMinimum'] ) && $value < $args['minimum'] ) { |
2446 ); |
|
2447 } |
|
2448 |
|
2449 if ( empty( $args['exclusiveMinimum'] ) && $value < $args['minimum'] ) { |
|
2450 return new WP_Error( |
|
2451 'rest_out_of_bounds', |
1781 /* translators: 1: Parameter, 2: Minimum number. */ |
2452 /* translators: 1: Parameter, 2: Minimum number. */ |
1782 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be greater than or equal to %2$d' ), $param, $args['minimum'] ) ); |
2453 sprintf( __( '%1$s must be greater than or equal to %2$d' ), $param, $args['minimum'] ) |
1783 } |
2454 ); |
1784 } elseif ( isset( $args['maximum'] ) && ! isset( $args['minimum'] ) ) { |
2455 } |
1785 if ( ! empty( $args['exclusiveMaximum'] ) && $value >= $args['maximum'] ) { |
2456 } |
|
2457 |
|
2458 if ( isset( $args['maximum'] ) && ! isset( $args['minimum'] ) ) { |
|
2459 if ( ! empty( $args['exclusiveMaximum'] ) && $value >= $args['maximum'] ) { |
|
2460 return new WP_Error( |
|
2461 'rest_out_of_bounds', |
1786 /* translators: 1: Parameter, 2: Maximum number. */ |
2462 /* translators: 1: Parameter, 2: Maximum number. */ |
1787 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be less than %2$d' ), $param, $args['maximum'] ) ); |
2463 sprintf( __( '%1$s must be less than %2$d' ), $param, $args['maximum'] ) |
1788 } elseif ( empty( $args['exclusiveMaximum'] ) && $value > $args['maximum'] ) { |
2464 ); |
|
2465 } |
|
2466 |
|
2467 if ( empty( $args['exclusiveMaximum'] ) && $value > $args['maximum'] ) { |
|
2468 return new WP_Error( |
|
2469 'rest_out_of_bounds', |
1789 /* translators: 1: Parameter, 2: Maximum number. */ |
2470 /* translators: 1: Parameter, 2: Maximum number. */ |
1790 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be less than or equal to %2$d' ), $param, $args['maximum'] ) ); |
2471 sprintf( __( '%1$s must be less than or equal to %2$d' ), $param, $args['maximum'] ) |
1791 } |
2472 ); |
1792 } elseif ( isset( $args['maximum'] ) && isset( $args['minimum'] ) ) { |
2473 } |
1793 if ( ! empty( $args['exclusiveMinimum'] ) && ! empty( $args['exclusiveMaximum'] ) ) { |
2474 } |
1794 if ( $value >= $args['maximum'] || $value <= $args['minimum'] ) { |
2475 |
1795 /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */ |
2476 if ( isset( $args['minimum'], $args['maximum'] ) ) { |
1796 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be between %2$d (exclusive) and %3$d (exclusive)' ), $param, $args['minimum'], $args['maximum'] ) ); |
2477 if ( ! empty( $args['exclusiveMinimum'] ) && ! empty( $args['exclusiveMaximum'] ) ) { |
1797 } |
2478 if ( $value >= $args['maximum'] || $value <= $args['minimum'] ) { |
1798 } elseif ( empty( $args['exclusiveMinimum'] ) && ! empty( $args['exclusiveMaximum'] ) ) { |
2479 return new WP_Error( |
1799 if ( $value >= $args['maximum'] || $value < $args['minimum'] ) { |
2480 'rest_out_of_bounds', |
1800 /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */ |
2481 sprintf( |
1801 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be between %2$d (inclusive) and %3$d (exclusive)' ), $param, $args['minimum'], $args['maximum'] ) ); |
2482 /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */ |
1802 } |
2483 __( '%1$s must be between %2$d (exclusive) and %3$d (exclusive)' ), |
1803 } elseif ( ! empty( $args['exclusiveMinimum'] ) && empty( $args['exclusiveMaximum'] ) ) { |
2484 $param, |
1804 if ( $value > $args['maximum'] || $value <= $args['minimum'] ) { |
2485 $args['minimum'], |
1805 /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */ |
2486 $args['maximum'] |
1806 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be between %2$d (exclusive) and %3$d (inclusive)' ), $param, $args['minimum'], $args['maximum'] ) ); |
2487 ) |
1807 } |
2488 ); |
1808 } elseif ( empty( $args['exclusiveMinimum'] ) && empty( $args['exclusiveMaximum'] ) ) { |
2489 } |
1809 if ( $value > $args['maximum'] || $value < $args['minimum'] ) { |
2490 } |
1810 /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */ |
2491 |
1811 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be between %2$d (inclusive) and %3$d (inclusive)' ), $param, $args['minimum'], $args['maximum'] ) ); |
2492 if ( ! empty( $args['exclusiveMinimum'] ) && empty( $args['exclusiveMaximum'] ) ) { |
1812 } |
2493 if ( $value > $args['maximum'] || $value <= $args['minimum'] ) { |
1813 } |
2494 return new WP_Error( |
1814 } |
2495 'rest_out_of_bounds', |
|
2496 sprintf( |
|
2497 /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */ |
|
2498 __( '%1$s must be between %2$d (exclusive) and %3$d (inclusive)' ), |
|
2499 $param, |
|
2500 $args['minimum'], |
|
2501 $args['maximum'] |
|
2502 ) |
|
2503 ); |
|
2504 } |
|
2505 } |
|
2506 |
|
2507 if ( ! empty( $args['exclusiveMaximum'] ) && empty( $args['exclusiveMinimum'] ) ) { |
|
2508 if ( $value >= $args['maximum'] || $value < $args['minimum'] ) { |
|
2509 return new WP_Error( |
|
2510 'rest_out_of_bounds', |
|
2511 sprintf( |
|
2512 /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */ |
|
2513 __( '%1$s must be between %2$d (inclusive) and %3$d (exclusive)' ), |
|
2514 $param, |
|
2515 $args['minimum'], |
|
2516 $args['maximum'] |
|
2517 ) |
|
2518 ); |
|
2519 } |
|
2520 } |
|
2521 |
|
2522 if ( empty( $args['exclusiveMinimum'] ) && empty( $args['exclusiveMaximum'] ) ) { |
|
2523 if ( $value > $args['maximum'] || $value < $args['minimum'] ) { |
|
2524 return new WP_Error( |
|
2525 'rest_out_of_bounds', |
|
2526 sprintf( |
|
2527 /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */ |
|
2528 __( '%1$s must be between %2$d (inclusive) and %3$d (inclusive)' ), |
|
2529 $param, |
|
2530 $args['minimum'], |
|
2531 $args['maximum'] |
|
2532 ) |
|
2533 ); |
|
2534 } |
|
2535 } |
|
2536 } |
|
2537 |
|
2538 return true; |
|
2539 } |
|
2540 |
|
2541 /** |
|
2542 * Validates a string value based on a schema. |
|
2543 * |
|
2544 * @since 5.7.0 |
|
2545 * |
|
2546 * @param mixed $value The value to validate. |
|
2547 * @param array $args Schema array to use for validation. |
|
2548 * @param string $param The parameter name, used in error messages. |
|
2549 * @return true|WP_Error |
|
2550 */ |
|
2551 function rest_validate_string_value_from_schema( $value, $args, $param ) { |
|
2552 if ( ! is_string( $value ) ) { |
|
2553 return new WP_Error( |
|
2554 'rest_invalid_type', |
|
2555 /* translators: 1: Parameter, 2: Type name. */ |
|
2556 sprintf( __( '%1$s is not of type %2$s.' ), $param, 'string' ), |
|
2557 array( 'param' => $param ) |
|
2558 ); |
|
2559 } |
|
2560 |
|
2561 if ( isset( $args['minLength'] ) && mb_strlen( $value ) < $args['minLength'] ) { |
|
2562 return new WP_Error( |
|
2563 'rest_too_short', |
|
2564 sprintf( |
|
2565 /* translators: 1: Parameter, 2: Number of characters. */ |
|
2566 _n( |
|
2567 '%1$s must be at least %2$s character long.', |
|
2568 '%1$s must be at least %2$s characters long.', |
|
2569 $args['minLength'] |
|
2570 ), |
|
2571 $param, |
|
2572 number_format_i18n( $args['minLength'] ) |
|
2573 ) |
|
2574 ); |
|
2575 } |
|
2576 |
|
2577 if ( isset( $args['maxLength'] ) && mb_strlen( $value ) > $args['maxLength'] ) { |
|
2578 return new WP_Error( |
|
2579 'rest_too_long', |
|
2580 sprintf( |
|
2581 /* translators: 1: Parameter, 2: Number of characters. */ |
|
2582 _n( |
|
2583 '%1$s must be at most %2$s character long.', |
|
2584 '%1$s must be at most %2$s characters long.', |
|
2585 $args['maxLength'] |
|
2586 ), |
|
2587 $param, |
|
2588 number_format_i18n( $args['maxLength'] ) |
|
2589 ) |
|
2590 ); |
|
2591 } |
|
2592 |
|
2593 if ( isset( $args['pattern'] ) && ! rest_validate_json_schema_pattern( $args['pattern'], $value ) ) { |
|
2594 return new WP_Error( |
|
2595 'rest_invalid_pattern', |
|
2596 /* translators: 1: Parameter, 2: Pattern. */ |
|
2597 sprintf( __( '%1$s does not match pattern %2$s.' ), $param, $args['pattern'] ) |
|
2598 ); |
|
2599 } |
|
2600 |
|
2601 return true; |
|
2602 } |
|
2603 |
|
2604 /** |
|
2605 * Validates an integer value based on a schema. |
|
2606 * |
|
2607 * @since 5.7.0 |
|
2608 * |
|
2609 * @param mixed $value The value to validate. |
|
2610 * @param array $args Schema array to use for validation. |
|
2611 * @param string $param The parameter name, used in error messages. |
|
2612 * @return true|WP_Error |
|
2613 */ |
|
2614 function rest_validate_integer_value_from_schema( $value, $args, $param ) { |
|
2615 $is_valid_number = rest_validate_number_value_from_schema( $value, $args, $param ); |
|
2616 if ( is_wp_error( $is_valid_number ) ) { |
|
2617 return $is_valid_number; |
|
2618 } |
|
2619 |
|
2620 if ( ! rest_is_integer( $value ) ) { |
|
2621 return new WP_Error( |
|
2622 'rest_invalid_type', |
|
2623 /* translators: 1: Parameter, 2: Type name. */ |
|
2624 sprintf( __( '%1$s is not of type %2$s.' ), $param, 'integer' ), |
|
2625 array( 'param' => $param ) |
|
2626 ); |
1815 } |
2627 } |
1816 |
2628 |
1817 return true; |
2629 return true; |
1818 } |
2630 } |
1819 |
2631 |
1820 /** |
2632 /** |
1821 * Sanitize a value based on a schema. |
2633 * Sanitize a value based on a schema. |
1822 * |
2634 * |
1823 * @since 4.7.0 |
2635 * @since 4.7.0 |
1824 * @since 5.5.0 Added the `$param` parameter. |
2636 * @since 5.5.0 Added the `$param` parameter. |
|
2637 * @since 5.6.0 Support the "anyOf" and "oneOf" keywords. |
1825 * |
2638 * |
1826 * @param mixed $value The value to sanitize. |
2639 * @param mixed $value The value to sanitize. |
1827 * @param array $args Schema array to use for sanitization. |
2640 * @param array $args Schema array to use for sanitization. |
1828 * @param string $param The parameter name, used in error messages. |
2641 * @param string $param The parameter name, used in error messages. |
1829 * @return mixed|WP_Error The sanitized value or a WP_Error instance if the value cannot be safely sanitized. |
2642 * @return mixed|WP_Error The sanitized value or a WP_Error instance if the value cannot be safely sanitized. |
1830 */ |
2643 */ |
1831 function rest_sanitize_value_from_schema( $value, $args, $param = '' ) { |
2644 function rest_sanitize_value_from_schema( $value, $args, $param = '' ) { |
|
2645 if ( isset( $args['anyOf'] ) ) { |
|
2646 $matching_schema = rest_find_any_matching_schema( $value, $args, $param ); |
|
2647 if ( is_wp_error( $matching_schema ) ) { |
|
2648 return $matching_schema; |
|
2649 } |
|
2650 |
|
2651 if ( ! isset( $args['type'] ) ) { |
|
2652 $args['type'] = $matching_schema['type']; |
|
2653 } |
|
2654 |
|
2655 $value = rest_sanitize_value_from_schema( $value, $matching_schema, $param ); |
|
2656 } |
|
2657 |
|
2658 if ( isset( $args['oneOf'] ) ) { |
|
2659 $matching_schema = rest_find_one_matching_schema( $value, $args, $param ); |
|
2660 if ( is_wp_error( $matching_schema ) ) { |
|
2661 return $matching_schema; |
|
2662 } |
|
2663 |
|
2664 if ( ! isset( $args['type'] ) ) { |
|
2665 $args['type'] = $matching_schema['type']; |
|
2666 } |
|
2667 |
|
2668 $value = rest_sanitize_value_from_schema( $value, $matching_schema, $param ); |
|
2669 } |
|
2670 |
1832 $allowed_types = array( 'array', 'object', 'string', 'number', 'integer', 'boolean', 'null' ); |
2671 $allowed_types = array( 'array', 'object', 'string', 'number', 'integer', 'boolean', 'null' ); |
1833 |
2672 |
1834 if ( ! isset( $args['type'] ) ) { |
2673 if ( ! isset( $args['type'] ) ) { |
1835 /* translators: 1. Parameter */ |
2674 /* translators: %s: Parameter. */ |
1836 _doing_it_wrong( __FUNCTION__, sprintf( __( 'The "type" schema keyword for %s is required.' ), $param ), '5.5.0' ); |
2675 _doing_it_wrong( __FUNCTION__, sprintf( __( 'The "type" schema keyword for %s is required.' ), $param ), '5.5.0' ); |
1837 } |
2676 } |
1838 |
2677 |
1839 if ( is_array( $args['type'] ) ) { |
2678 if ( is_array( $args['type'] ) ) { |
1840 $best_type = rest_handle_multi_type_schema( $value, $args, $param ); |
2679 $best_type = rest_handle_multi_type_schema( $value, $args, $param ); |