Indicates if an attribute value starts with a given raw string value.
Description
Use this method to determine if an attribute value starts with a given string, regardless of how it might be encoded in HTML. For instance, http: could be represented as http: or as http: or as http: or as http:, or in many other ways.
This is equivalent to a byte-prefix test against the decoded attribute value, without the need to allocate and decode the full string.
Example:
$value = 'http://wordpress.org/';
true === WP_HTML_Decoder::attribute_starts_with( $value, 'http:', 'ascii-case-insensitive' );
false === WP_HTML_Decoder::attribute_starts_with( $value, 'https:', 'ascii-case-insensitive' );Parameters
$haystackstringrequired- String containing the raw non-decoded attribute value.
$search_textstringrequired- Does the attribute value start with this plain string.
$case_sensitivitystringoptional- Pass
'ascii-case-insensitive'to ignore ASCII case when matching.
Default'case-sensitive'.Default:
'case-sensitive'
Source
public static function attribute_starts_with( $haystack, $search_text, $case_sensitivity = 'case-sensitive' ): bool {
$search_length = strlen( $search_text );
$loose_case = 'ascii-case-insensitive' === $case_sensitivity;
$haystack_end = strlen( $haystack );
$search_at = 0;
$haystack_at = 0;
while ( $search_at < $search_length && $haystack_at < $haystack_end ) {
$chars_match = $loose_case
? strtolower( $haystack[ $haystack_at ] ) === strtolower( $search_text[ $search_at ] )
: $haystack[ $haystack_at ] === $search_text[ $search_at ];
$is_introducer = '&' === $haystack[ $haystack_at ];
$next_chunk = $is_introducer
? self::read_character_reference( 'attribute', $haystack, $haystack_at, $token_length )
: null;
// If there's no character reference and the characters don't match, the match fails.
if ( null === $next_chunk && ! $chars_match ) {
return false;
}
// If there's no character reference but the characters do match, then it could still match.
if ( null === $next_chunk && $chars_match ) {
++$haystack_at;
++$search_at;
continue;
}
/**
* The decoded character reference in `$next_chunk` must be compared with the
* corresponding `$search_text` bytes checking for matching prefixes. The remaining
* search text may be shorter than the decoded chunk, in which case a partial match
* satisfies the prefix. Otherwise, if the decoded chunk is fully matched, the
* comparison must continue after advancing the appropriate byte lengths: the character
* reference token length in the haystack and the decoded chunk length in the
* search text.
*
* For example, consider searches that have reached the character reference
* `fj` (7 bytes), decoded into the 2-byte chunk `fj`:
*
* $haystack_at
* │
* │ ┌─after matching `fj` continue here
* │ │ (advance by $token_length, 7 bytes)
* ↓ ↓
* Haystack: startfjord
* ╰──┬──╯
* fj - the decoded chunk, tested against the search text.
*
* $search_at
* │
* │ ┌─after matching `fj` continue here
* │ │ (advance by $match_length, 2 bytes)
* ↓ ↓
* Search A: startfjord Compare 2 bytes: `fj` matches,
* continue matching at `o`.
*
* $search_at
* ↓
* Search B: startf Compare 1 byte: `f` matches and the
* search text is exhausted — prefix confirmed.
*
* $search_at
* ↓
* Search C: startfr Compare 2 bytes: `fj` differs
* from `fr`, no match is possible.
*
* The `min()` is required in both directions: Search A fails if the
* comparison length comes from the search text, Search B if it comes
* from the chunk.
*
* After a match each cursor must advance by the appropriate length, the haystack
* cursor by the character reference token length, and the search cursor by the
* matched length.
*/
$match_length = min( strlen( $next_chunk ), $search_length - $search_at );
if ( 0 !== substr_compare( $search_text, $next_chunk, $search_at, $match_length, $loose_case ) ) {
return false;
}
// The character reference matched, so continue checking.
$haystack_at += $token_length;
$search_at += $match_length;
}
return $search_at === $search_length;
}
Changelog
| Version | Description |
|---|---|
| 6.6.0 | Introduced. |
User Contributed Notes
You must log in before being able to contribute a note or feedback.