src/Access/CustomParameterNamesAccessCheck.php | 2 +- src/JsonApiSpec.php | 60 +++++++++++++++----------- tests/src/Unit/JsonApiSpecTest.php | 2 +- 3 files changed, 38 insertions(+), 26 deletions(-) diff --git a/src/Access/CustomParameterNamesAccessCheck.php b/src/Access/CustomParameterNamesAccessCheck.php index 88f0401..5f0d082 100644 --- a/src/Access/CustomParameterNamesAccessCheck.php +++ b/src/Access/CustomParameterNamesAccessCheck.php @@ -51,7 +51,7 @@ class CustomParameterNamesAccessCheck implements AccessInterface { protected function validate(array $json_api_params) { foreach (array_keys($json_api_params) as $name) { // Ignore reserved (official) query parameters. - if (in_array($name, JsonApiSpec::RESERVED_QUERY_PARAMETERS)) { + if (in_array($name, JsonApiSpec::getReservedQueryParameters())) { continue; } diff --git a/src/JsonApiSpec.php b/src/JsonApiSpec.php index b1e6ca6..ec9cc0d 100644 --- a/src/JsonApiSpec.php +++ b/src/JsonApiSpec.php @@ -36,30 +36,13 @@ final class JsonApiSpec { const MEMBER_NAME_INNER_ALLOWED_CHARACTERS = "[a-zA-Z0-9\x{80}-\x{10FFFF}\-_ ]"; /** - * Member name: regular expression. + * Checks whether the given member name is valid. * * Requirements: * - it MUST contain at least one character. * - it MUST contain only the allowed characters * - it MUST start and end with a "globally allowed character" * - * @see http://jsonapi.org/format/#document-member-names - */ - const MEMBER_NAME_REGEXP = '/^' . - // First character must be "globally allowed". Length must be >=1. - self::MEMBER_NAME_GLOBALLY_ALLOWED_CHARACTER_CLASS . '{1}' . - '(' . - // As many non-globally allowed characters as desired. - self::MEMBER_NAME_INNER_ALLOWED_CHARACTERS . '*' . - // If lenght is >1, then it must end in a "globally allowed" character. - self::MEMBER_NAME_GLOBALLY_ALLOWED_CHARACTER_CLASS . '{1}' . - // >1 characters is optional. - ')?' . - '$/u'; - - /** - * Checks whether the given member name is valid. - * * @param string $member_name * A member name to validate. * @@ -68,17 +51,40 @@ final class JsonApiSpec { * @see http://jsonapi.org/format/#document-member-names */ public static function isValidMemberName($member_name) { - return preg_match(JsonApiSpec::MEMBER_NAME_REGEXP, $member_name) === 1; + // @todo When D8 requires PHP >=5.6, move to a MEMBER_NAME_REGEXP constant. + static $regexp; + if (!isset($regexp)) { + $regexp = '/^' . + // First character must be "globally allowed". Length must be >=1. + self::MEMBER_NAME_GLOBALLY_ALLOWED_CHARACTER_CLASS . '{1}' . + '(' . + // As many non-globally allowed characters as desired. + self::MEMBER_NAME_INNER_ALLOWED_CHARACTERS . '*' . + // If lenght is >1, then it must end in a "globally allowed" character. + self::MEMBER_NAME_GLOBALLY_ALLOWED_CHARACTER_CLASS . '{1}' . + // >1 characters is optional. + ')?' . + '$/u'; + } + + return preg_match($regexp, $member_name) === 1; } /** * The reserved (official) query parameters. + * + * @todo When D8 requires PHP >= 5.6, convert to an array. */ - const RESERVED_QUERY_PARAMETERS = [ - 'sort', - 'page', - 'filter', - ]; + const RESERVED_QUERY_PARAMETERS = 'sort|page|filter'; + + /** + * Gets the reserved (official) JSON API query parameters. + * + * @return string[] + */ + public static function getReservedQueryParameters() { + return explode('|', static::RESERVED_QUERY_PARAMETERS); + } /** * Checks whether the given custom query parameter name is valid. @@ -86,6 +92,12 @@ final class JsonApiSpec { * A custom query parameter name must be a valid member name, with one * additional requirement: it MUST contain at least one non a-z character. * + * Requirements: + * - it MUST contain at least one character. + * - it MUST contain only the allowed characters + * - it MUST start and end with a "globally allowed character" + * - it MUST contain at least none a-z (U+0061 to U+007A) character + * * It is RECOMMENDED that a hyphen (U+002D), underscore (U+005F) or capital * letter is used (i.e. camelCasing). * diff --git a/tests/src/Unit/JsonApiSpecTest.php b/tests/src/Unit/JsonApiSpecTest.php index 2fa1716..7097b35 100644 --- a/tests/src/Unit/JsonApiSpecTest.php +++ b/tests/src/Unit/JsonApiSpecTest.php @@ -37,7 +37,7 @@ class JsonApiSpecTest extends UnitTestCase { $data['space-end'] = ['kittens ', FALSE]; // Additional test cases. - $data['unicode-above-u+0080-highest-allowed'] = ["12\u{10FFFF}", TRUE]; + $data['unicode-above-u+0080-highest-allowed'] = ["12􏿿", TRUE]; $data['single-character'] = ['a', TRUE]; $unsafe_chars = [