$replacement ) { return null; } $after_name = $name_at + $name_length; /** * For historical reasons, a matched named character reference is left as literal * text (its decoded replacement is not used) when all of the following hold: * * 1. It was matched in attribute context. * 2. The match does not end in U+003B SEMICOLON (;) — i.e. it is one of the * legacy forms recognized without a trailing semicolon. * 3. The next input character is U+003D EQUALS SIGN (=) or an ASCII alphanumeric. * * Some illustrative examples follow. Note that both `not` and `not;` appear in the * named character references list. References start with `&` and typically end with * `;`, but the legacy forms are recognized without one. * * - In _data context_, "¬me" is decoded to "¬me": condition 1 fails (not an * attribute), so the reference is decoded. * - In _attribute context_, "¬me" is decoded to "¬me": the longest match is * "not;", which ends in a semicolon, so condition 2 fails. * - In _attribute context_, "¬己" is decoded to "¬己": the following character * "己" is a letter but not an ASCII alphanumeric (nor "="), so condition 3 fails. * - In _attribute context_, "¬" is decoded to "¬": there is no next input * character, so condition 3 fails. * - In _attribute context_, "¬=me" is left as the literal text "¬=me": all * three conditions hold. * - In _attribute context_, "¬me" is left as the literal text "¬me": all * three conditions hold. * * Without these special rules, ordinary URL query strings could have surprising * replacements applied. Consider: * * * * The literal attribute value `/?random°ree>=0<=360¬=90` is preserved * by the special handling. Otherwise, the value would decode to * `/?random°ree>=0<=360¬=90`, which is unlikely to be the author's intent. * * (Authors should not rely on this. Escaping the example as * `/?random&degree&gt=0&lt=360&not=90` produces the intended * value regardless of the following character.) * * @see https://html.spec.whatwg.org/multipage/parsing.html#named-character-reference-state * @see https://html.spec.whatwg.org/multipage/named-characters.html#named-character-references */ if ( 'attribute' !== $context || ';' === $text[ $after_name - 1 ] || $after_name >= $length ) { $match_byte_length = $after_name - $at; return $replacement; } $follower_byte = ord( $text[ $after_name ] ); if ( 0x3D === $follower_byte || // EQUALS SIGN ( $follower_byte >= 0x30 && $follower_byte <= 0x39 ) || // ASCII digits 0-9 ( $follower_byte >= 0x41 && $follower_byte <= 0x5A ) || // ASCII upper alpha A-Z ( $follower_byte >= 0x61 && $follower_byte <= 0x7A ) // ASCII lower alpha a-z ) { return null; } $match_byte_length = $after_name - $at; return $replacement; } /** * Encode a code point number into the UTF-8 encoding. * * This encoder implements the UTF-8 encoding algorithm for converting * a code point into a byte sequence. If it receives an invalid code * point it will return the Unicode Replacement Character U+FFFD `�`. * * Example: * * '🅰' === WP_HTML_Decoder::code_point_to_utf8_bytes( 0x1f170 ); * * // Half of a surrogate pair is an invalid code point. * '�' === WP_HTML_Decoder::code_point_to_utf8_bytes( 0xd83c ); * * @since 6.6.0 * * @see https://www.rfc-editor.org/rfc/rfc3629 For the UTF-8 standard. * * @param int $code_point Which code point to convert. * @return string Converted code point, or `�` if invalid. */ public static function code_point_to_utf8_bytes( $code_point ): string { $string = mb_chr( $code_point, 'UTF-8' ); return false !== $string ? $string : '�'; } }