Функция WP_KSES_HAIR() в WordPress: Примеры использования и изменения

## WP_KSES_HAIR() │ WP 1.0.0

Функция WP_KSES_HAIR создаёт список атрибутов из строки, содержащей эти атрибуты.

Эта функция выполняет много работы. Она разбивает список атрибутов на массив с данными атрибутов и старается правильно обработать даже странные входные данные. Она добавляет кавычки вокруг значений атрибутов, если те их не содержат, чтобы упростить создание HTML-кода в соответствии с W3C спецификацией HTML. Также она удаляет недопустимые протоколы URL из значений атрибутов и уменьшает дублирование атрибутов, оставляя первый определённый (например, если вы написали foo='bar' foo='baz', то результат будет foo='bar').

**Пример производительности:**
- 1 вызов — 0.000145 сек (быстро)
- 50000 вызовов — 2.85 сек (быстро)

### Результат работы функции

Функция возвращает массив. Он содержит информацию об атрибутах после обработки.

### Использование

```php
wp_kses_hair( $attr, $allowed_protocols );

Параметры:

  • $attr (строка) (обязательный) — список атрибутов из HTML элемента.
  • $allowed_protocols (массив строк) (обязательный) — массив допустимых протоколов URL.

Примеры использования

Пример 1: Демонстрация работы

$attrs = wp_kses_hair(' src="http://example.com/jpg.jpg"   alt="aaaaa"   foo=bar', 'http');

/*
$attrs будет содержать:

Array
(
    [src] => Array
        (
            [name] => src
            [value] => http://example.com/jpg.jpg
            [whole] => src="http://example.com/jpg.jpg"
            [vless] => n
        )

    [alt] => Array
        (
            [name] => alt
            [value] => aaaaa
            [whole] => alt="aaaaa"
            [vless] => n
        )

    [foo] => Array
        (
            [name] => foo
            [value] => bar
            [whole] => foo="bar"
            [vless] => n
        )

)
*/

Пример 2: Протокол, который отличается от значения атрибута

Если вы укажете протокол, который отличается, функция просто удалит протокол, оставив URL относительным:

$attrs = wp_kses_hair('src=http://example.com/jpg.jpg', 'https');

/*
Получаем:

Array
(
    [src] => Array
        (
            [name] => src
            [value] => //example.com/jpg.jpg
            [whole] => src="//example.com/jpg.jpg"
            [vless] => n
        )
)
*/

Изменения в истории

  • С версии 1.0.0 — функция была впервые представлена.

Код функции

Вот реализация функции wp_kses_hair:

function wp_kses_hair( $attr, $allowed_protocols ) {
$attrarr = array();
$mode = 0;
$attrname = '';
$uris = wp_kses_uri_attributes();

// Проходим по всему списку атрибутов.

while ( strlen( $attr ) !== 0 ) {
    $working = 0; // Успешна ли последняя операция?

    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 ) ) { // Знак равенства.
                $working = 1;
                $mode    = 2;
                $attr    = preg_replace( '/^s*=s*/', '', $attr );
                break;
            }

            if ( preg_match( '/^s+/', $attr ) ) { // Атрибут без значения.
                $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 ) ) {
                // "значение"
                $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;
            }

            if ( preg_match( "%^'([^']*)'(s+|/?$)%", $attr, $match ) ) {
                // 'значение'
                $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;
            }

            if ( preg_match( "%^([^s"']+)(s+|/?$)%", $attr, $match ) ) {
                // значение
                $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',
                    );
                }

                // Добавляем кавычки для соответствия спецификации HTML от W3C.
                $working = 1;
                $mode    = 0;
                $attr    = preg_replace( "%^[^s"']+(s+|$)%", '', $attr );
            }
            break;
    } // Конец switch.

    if ( 0 === $working ) { // Неправильный формат, удаляем и пробуем снова.
        $attr = wp_kses_html_error( $attr );
        $mode = 0;
    }
} // Конец while.

if ( 1 === $mode && false === array_key_exists( $attrname, $attrarr ) ) {
    // Специальный случай для атрибута без значения, например "selected".
    $attrarr[ $attrname ] = array(
        'name'  => $attrname,
        'value' => '',
        'whole' => $attrname,
        'vless' => 'y',
    );
}

return $attrarr;

}

Leave a Reply

Ваш адрес email не будет опубликован. Обязательные поля помечены *