From 888421a924b9e4b4ede8712276271eb77f3c32d5 Mon Sep 17 00:00:00 2001 From: Jake Spurlock Date: Tue, 23 Jun 2020 05:05:57 +0000 Subject: [PATCH] Formatting: Extend `wp_kses_hair` and `wp_kses_hair_parse` to allow digits and underscores. Fixes a lot of issues around parsing XML/HTML attributes. Fixes #49464. See #34406, #48608. Props codeforest, zodiac1978, johnpgreen, dlh, ayeshrajans, johnpgreen, rilwis, travisnorthcutt, miqrogroove, chriscct7, whyisjake. git-svn-id: https://develop.svn.wordpress.org/trunk@48132 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/kses.php | 42 ++++++++++++++++++------------------ tests/phpunit/tests/kses.php | 20 +++++++++++++++++ 2 files changed, 41 insertions(+), 21 deletions(-) diff --git a/src/wp-includes/kses.php b/src/wp-includes/kses.php index c157bd0fc6..300376197a 100644 --- a/src/wp-includes/kses.php +++ b/src/wp-includes/kses.php @@ -1261,11 +1261,11 @@ function wp_kses_hair( $attr, $allowed_protocols ) { switch ( $mode ) { case 0: - if ( preg_match( '/^([-a-zA-Z:]+)/', $attr, $match ) ) { + if ( preg_match( '/^([_a-zA-Z][-_a-zA-Z0-9:.]*)/', $attr, $match ) ) { $attrname = $match[1]; $working = 1; $mode = 1; - $attr = preg_replace( '/^[-a-zA-Z:]+/', '', $attr ); + $attr = preg_replace( '/^[_a-zA-Z][-_a-zA-Z0-9:.]*/', '', $attr ); } break; @@ -1451,25 +1451,25 @@ function wp_kses_hair_parse( $attr ) { // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- don't remove regex indentation $regex = - '(?:' - . '[-a-zA-Z:]+' // Attribute name. - . '|' - . '\[\[?[^\[\]]+\]\]?' // Shortcode in the name position implies unfiltered_html. - . ')' - . '(?:' // Attribute value. - . '\s*=\s*' // All values begin with '='. - . '(?:' - . '"[^"]*"' // Double-quoted. - . '|' - . "'[^']*'" // Single-quoted. - . '|' - . '[^\s"\']+' // Non-quoted. - . '(?:\s|$)' // Must have a space. - . ')' - . '|' - . '(?:\s|$)' // If attribute has no value, space is required. - . ')' - . '\s*'; // Trailing space is optional except as mentioned above. + '(?:' + . '[_a-zA-Z][-_a-zA-Z0-9:.]*' // Attribute name. + . '|' + . '\[\[?[^\[\]]+\]\]?' // Shortcode in the name position implies unfiltered_html. + . ')' + . '(?:' // Attribute value. + . '\s*=\s*' // All values begin with '='. + . '(?:' + . '"[^"]*"' // Double-quoted. + . '|' + . "'[^']*'" // Single-quoted. + . '|' + . '[^\s"\']+' // Non-quoted. + . '(?:\s|$)' // Must have a space. + . ')' + . '|' + . '(?:\s|$)' // If attribute has no value, space is required. + . ')' + . '\s*'; // Trailing space is optional except as mentioned above. // phpcs:enable // Although it is possible to reduce this procedure to a single regexp, diff --git a/tests/phpunit/tests/kses.php b/tests/phpunit/tests/kses.php index 0665c09e90..deda0c8cef 100644 --- a/tests/phpunit/tests/kses.php +++ b/tests/phpunit/tests/kses.php @@ -629,6 +629,26 @@ EOF; "array[1]='z'z'z'z", false, ), + // using digit in attribute name should work + array( + 'href="https://example.com/[shortcode attr=\'value\']" data-op3-timer-seconds="0"', + array( 'href="https://example.com/[shortcode attr=\'value\']" ', 'data-op3-timer-seconds="0"' ), + ), + // using underscore in attribute name should work + array( + 'href="https://example.com/[shortcode attr=\'value\']" data-op_timer-seconds="0"', + array( 'href="https://example.com/[shortcode attr=\'value\']" ', 'data-op_timer-seconds="0"' ), + ), + // using period in attribute name should work + array( + 'href="https://example.com/[shortcode attr=\'value\']" data-op.timer-seconds="0"', + array( 'href="https://example.com/[shortcode attr=\'value\']" ', 'data-op.timer-seconds="0"' ), + ), + // using digit at a beginning of attribute name should return false + array( + 'href="https://example.com/[shortcode attr=\'value\']" 3data-op-timer-seconds="0"', + false, + ), ); }