Skip to content

Commit

Permalink
WIP: Replace wp_kses_hair
Browse files Browse the repository at this point in the history
  • Loading branch information
dmsnell committed Sep 20, 2024
1 parent 03b12dc commit 7361a3c
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 135 deletions.
152 changes: 24 additions & 128 deletions src/wp-includes/kses.php
Original file line number Diff line number Diff line change
Expand Up @@ -1389,143 +1389,39 @@ function wp_kses_attr_check( &$name, &$value, &$whole, $vless, $element, $allowe
* @return array[] Array of attribute information after parsing.
*/
function wp_kses_hair( $attr, $allowed_protocols ) {
$attrarr = array();
$mode = 0;
$attrname = '';
$uris = wp_kses_uri_attributes();

// Loop through the whole attribute list.

while ( strlen( $attr ) !== 0 ) {
$working = 0; // Was the last operation successful?
switch ( $mode ) {
case 0:
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][-_a-zA-Z0-9:.]*/', '', $attr );
}

break;

case 1:
if ( preg_match( '/^\s*=\s*/', $attr ) ) { // Equals sign.
$working = 1;
$mode = 2;
$attr = preg_replace( '/^\s*=\s*/', '', $attr );
break;
}

if ( preg_match( '/^\s+/', $attr ) ) { // Valueless.
$working = 1;
$mode = 0;

if ( false === array_key_exists( $attrname, $attrarr ) ) {
$attrarr[ $attrname ] = array(
'name' => $attrname,
'value' => '',
'whole' => $attrname,
'vless' => 'y',
);
}

$attr = preg_replace( '/^\s+/', '', $attr );
}

break;

case 2:
if ( preg_match( '%^"([^"]*)"(\s+|/?$)%', $attr, $match ) ) {
// "value"
$thisval = $match[1];
if ( in_array( strtolower( $attrname ), $uris, true ) ) {
$thisval = wp_kses_bad_protocol( $thisval, $allowed_protocols );
}

if ( false === array_key_exists( $attrname, $attrarr ) ) {
$attrarr[ $attrname ] = array(
'name' => $attrname,
'value' => $thisval,
'whole' => "$attrname=\"$thisval\"",
'vless' => 'n',
);
}

$working = 1;
$mode = 0;
$attr = preg_replace( '/^"[^"]*"(\s+|$)/', '', $attr );
break;
}
$uri_names = wp_kses_uri_attributes();
$processor = new WP_HTML_Tag_Processor( "<my-tag {$attr}>" );
$processor->next_tag();

if ( preg_match( "%^'([^']*)'(\s+|/?$)%", $attr, $match ) ) {
// 'value'
$thisval = $match[1];
if ( in_array( strtolower( $attrname ), $uris, true ) ) {
$thisval = wp_kses_bad_protocol( $thisval, $allowed_protocols );
}

if ( false === array_key_exists( $attrname, $attrarr ) ) {
$attrarr[ $attrname ] = array(
'name' => $attrname,
'value' => $thisval,
'whole' => "$attrname='$thisval'",
'vless' => 'n',
);
}

$working = 1;
$mode = 0;
$attr = preg_replace( "/^'[^']*'(\s+|$)/", '', $attr );
break;
}
$attribute_names = $processor->get_attribute_names_with_prefix( '' );
if ( ! isset( $attribute_names ) ) {
return array();
}

if ( preg_match( "%^([^\s\"']+)(\s+|/?$)%", $attr, $match ) ) {
// value
$thisval = $match[1];
if ( in_array( strtolower( $attrname ), $uris, true ) ) {
$thisval = wp_kses_bad_protocol( $thisval, $allowed_protocols );
}

if ( false === array_key_exists( $attrname, $attrarr ) ) {
$attrarr[ $attrname ] = array(
'name' => $attrname,
'value' => $thisval,
'whole' => "$attrname=\"$thisval\"",
'vless' => 'n',
);
}

// We add quotes to conform to W3C's HTML spec.
$working = 1;
$mode = 0;
$attr = preg_replace( "%^[^\s\"']+(\s+|$)%", '', $attr );
}
$attributes = array();
foreach ( $attribute_names as $attribute_name ) {
$value = $processor->get_attribute( $attribute_name );
$is_boolean = true === $value;

break;
} // End switch.
if ( ! $is_boolean ) {
$value = str_replace( "\x00", "\u{FFFD}", $value );
}

if ( 0 === $working ) { // Not well-formed, remove and try again.
$attr = wp_kses_html_error( $attr );
$mode = 0;
if ( ! $is_boolean && in_array( $attribute_name, $uri_names, true ) ) {
$value = wp_kses_bad_protocol( $value, $allowed_protocols );
}
} // End while.

if ( 1 === $mode && false === array_key_exists( $attrname, $attrarr ) ) {
/*
* Special case, for when the attribute list ends with a valueless
* attribute like "selected".
*/
$attrarr[ $attrname ] = array(
'name' => $attrname,
'value' => '',
'whole' => $attrname,
'vless' => 'y',
$attributes[ $attribute_name ] = array(
'name' => $attribute_name,
'value' => $is_boolean ? '' : $processor->get_attribute( $attribute_name ),
'whole' => $is_boolean
? $attribute_name
: ( "{$attribute_name}=\"" . htmlspecialchars( $value, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5, 'UTF-8' ) . '"' ),
'vless' => $is_boolean,
);
}

return $attrarr;
return $attributes;
}

/**
Expand Down
15 changes: 8 additions & 7 deletions tests/phpunit/tests/kses.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public function data_wp_filter_post_kses_address() {
foreach ( $attributes as $name => $values ) {
foreach ( (array) $values as $value ) {
$content = "<address $name='$value'>1 WordPress Avenue, The Internet.</address>";
$expected = "<address $name='" . str_replace( '; ', ';', trim( $value, ';' ) ) . "'>1 WordPress Avenue, The Internet.</address>";
$expected = "<address $name=\"" . str_replace( '; ', ';', trim( $value, ';' ) ) . '">1 WordPress Avenue, The Internet.</address>';

$data[] = array( $content, $expected );
}
Expand Down Expand Up @@ -95,13 +95,14 @@ public function data_wp_filter_post_kses_a() {
foreach ( $attributes as $name => $value ) {
if ( $value ) {
$attr = "$name='$value'";
$expected_attr = "$name='" . trim( $value, ';' ) . "'";
$expected_attr = "$name=\"" . trim( $value, ';' ) . "\"";
} else {
$attr = $name;
$expected_attr = $name;
}
$content = "<a $attr>I link this</a>";
$expected = "<a $expected_attr>I link this</a>";

$data[] = array( $content, $expected );
}

Expand Down Expand Up @@ -194,7 +195,7 @@ public function data_wp_filter_post_kses_abbr() {

foreach ( $attributes as $name => $value ) {
$content = "<abbr $name='$value'>WP</abbr>";
$expected = "<abbr $name='" . trim( $value, ';' ) . "'>WP</abbr>";
$expected = "<abbr {$name}=\"" . trim( $value, ';' ) . '">WP</abbr>';
$data[] = array( $content, $expected );
}

Expand Down Expand Up @@ -1994,7 +1995,7 @@ public function data_wp_kses_allowed_values_list() {
),
'valid dir attribute value, upper case' => array(
'<p DIR="RTL">foo</p>',
'<p DIR="RTL">foo</p>',
'<p dir="RTL">foo</p>',
),
'invalid dir attribute value' => array(
'<p dir="up">foo</p>',
Expand Down Expand Up @@ -2054,9 +2055,9 @@ public function data_wp_kses_required_attribute() {
),
'valid dir attribute value, upper case' => array(
'<p DIR="RTL">foo</p>',
'<p DIR="RTL">foo</p>',
'<p DIR="RTL">foo</p>',
'<p DIR="RTL">foo</p>',
'<p dir="RTL">foo</p>',
'<p dir="RTL">foo</p>',
'<p dir="RTL">foo</p>',
),
'invalid dir attribute value' => array(
'<p dir="up">foo</p>',
Expand Down

0 comments on commit 7361a3c

Please sign in to comment.