Changeset 63513
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/html-api/class-wp-html-tag-processor.php
r63463 r63513 4093 4093 * HTML structure is rejected here. It’s the responsibility of calling code to 4094 4094 * perform whatever semantic escaping is necessary to avoid problematic strings. 4095 * 4096 * Both the start tag `<script` and the end tag `</script` are rejected. It’s 4097 * easy to assume that only an end tag can alter the HTML structure, but a 4098 * start tag which follows `<!--` moves the tokenizer into the double-escaped 4099 * states, where a later `</script>` no longer closes the element. 4100 * 4101 * In both cases the tag name ends only at one of the characters matched 4102 * below, so text such as `</scriptx>` cannot change that structure and is 4103 * safe to set. 4104 * 4105 * @link https://html.spec.whatwg.org/#script-data-end-tag-name-state 4106 * @link https://html.spec.whatwg.org/#script-data-double-escape-start-state 4095 4107 */ 4096 if ( 4097 false !== stripos( $plaintext_content, '<script' ) || 4098 false !== stripos( $plaintext_content, '</script' ) 4099 ) { 4108 if ( 1 === preg_match( '~</?script[ \t\f\r\n/>]~i', $plaintext_content ) ) { 4100 4109 _doing_it_wrong( 4101 4110 __METHOD__, … … 4117 4126 case 'XMP': 4118 4127 $tag_name = $this->get_tag(); 4119 if ( false !== stripos( $plaintext_content, "</{$tag_name}" ) ) { 4128 4129 /* 4130 * A tag name ends only at one of the characters matched below, so text 4131 * such as `</xmp-tag>` cannot close the element and is safe to set. 4132 * 4133 * @link https://html.spec.whatwg.org/#rawtext-end-tag-name-state 4134 */ 4135 if ( 1 === preg_match( '~</' . preg_quote( $tag_name, '~' ) . '[ \t\f\r\n/>]~i', $plaintext_content ) ) { 4120 4136 _doing_it_wrong( 4121 4137 __METHOD__, -
trunk/tests/phpunit/tests/html-api/wpHtmlTagProcessorModifiableText.php
r63418 r63513 661 661 * @ticket 61617 662 662 * @ticket 62797 663 * @ticket 65824 663 664 * 664 665 * @dataProvider data_unallowed_modifiable_text_updates … … 715 716 'Non-JS SCRIPT with <script attributes>' => array( '<script language="text">Replace me</script>', '<!-- <script sneaky>after' ), 716 717 'Non-JS SCRIPT with </script attributes>' => array( '<script language="text">Replace me</script>', 'before</script sneaky>after' ), 718 'XMP with </xmp/>' => array( '<xmp>Replace me</xmp>', 'Also closed by </xmp/>' ), 719 'XMP with </xmp\f>' => array( '<xmp>Replace me</xmp>', "Also closed by </xmp\f>" ), 720 'Non-JS SCRIPT with </script\r>' => array( '<script language="text">Replace me</script>', "before</script\r>after" ), 721 ); 722 } 723 724 /** 725 * Ensures that raw text which resembles a closing tag, but cannot close its 726 * element, is allowed as modifiable text. 727 * 728 * @ticket 65824 729 * 730 * @dataProvider data_raw_text_resembling_a_closing_tag 731 * 732 * @param string $html HTML whose first tag holds the raw text to replace. 733 * @param string $update Text resembling, but not forming, that element's closing tag. 734 * @param string $expected Expected document after the update. 735 */ 736 public function test_allows_raw_text_which_cannot_close_its_element( string $html, string $update, string $expected ): void { 737 $processor = new WP_HTML_Tag_Processor( $html ); 738 $processor->next_tag(); 739 740 $this->assertTrue( 741 $processor->set_modifiable_text( $update ), 742 'Should have allowed text which cannot close the element.' 743 ); 744 745 $this->assertSame( 746 $expected, 747 $processor->get_updated_html(), 748 'Should have updated the document as expected.' 749 ); 750 751 $reparsed = new WP_HTML_Tag_Processor( $expected ); 752 $reparsed->next_tag(); 753 754 $this->assertSame( 755 $update, 756 $reparsed->get_modifiable_text(), 757 'Should have preserved the text when re-parsing the updated document.' 758 ); 759 } 760 761 /** 762 * Data provider. 763 * 764 * @return array[] 765 */ 766 public static function data_raw_text_resembling_a_closing_tag(): array { 767 return array( 768 'IFRAME with </iframely>' => array( '<iframe>Replace me</iframe>', 'Just a </iframely>', '<iframe>Just a </iframely></iframe>' ), 769 'NOEMBED with </NOEMBEDDED>' => array( '<noembed>Replace me</noembed>', 'Just a </NOEMBEDDED>', '<noembed>Just a </NOEMBEDDED></noembed>' ), 770 'NOFRAMES with </noframes->' => array( '<noframes>Replace me</noframes>', 'before</noframes->after', '<noframes>before</noframes->after</noframes>' ), 771 'XMP with </xmp-tag>' => array( '<xmp>Replace me</xmp>', 'Just a </xmp-tag>', '<xmp>Just a </xmp-tag></xmp>' ), 772 'XMP ending in </xmp' => array( '<xmp>Replace me</xmp>', 'Trailing </xmp', '<xmp>Trailing </xmp</xmp>' ), 773 'Non-JS SCRIPT with <scriptish>' => array( '<script type="text/plain">Replace me</script>', '<!-- <scriptish> -->', '<script type="text/plain"><!-- <scriptish> --></script>' ), 774 'Non-JS SCRIPT with </scriptx>' => array( '<script type="text/plain">Replace me</script>', 'Just a </scriptx>', '<script type="text/plain">Just a </scriptx></script>' ), 775 'Non-JS SCRIPT ending in <script' => array( '<script type="text/plain">Replace me</script>', '<!-- <script', '<script type="text/plain"><!-- <script</script>' ), 776 'Non-JS SCRIPT ending in </script' => array( '<script type="text/plain">Replace me</script>', 'Trailing </script', '<script type="text/plain">Trailing </script</script>' ), 717 777 ); 718 778 }
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)