Экранирование кавычек в атрибутах шорткодов WordPress

8 мар. 2013 г., 17:18:01
Просмотры: 15.6K
Голосов: 5

Я пытаюсь разобраться, как экранировать кавычки (одинарные и двойные) в атрибутах шорткодов.

Проблема в том, что контент вводится пользователем и может содержать кавычки " и '. С двойными кавычками атрибут шорткода перестаёт работать правильно, например:

attibute="текст с "кавычками" прерывает атрибут..."

Вместо получения всей строки обработка останавливается на второй паре кавычек.

Я знаю, что можно использовать одинарные кавычки, но тогда возникает та же проблема, если пользователь введёт одинарные кавычки.

Я пробовал различные решения на PHP/WP, такие как esc_html, htmlspecialchars, htmlentities, но ни одно не сработало.

Возможно, я неправильно их настраиваю или применяю не в том месте.

Вот текущий код шорткода (сокращённая версия без экранирования):

function aps_person_schema_shortcode( $atts, $content = null)   {

// Извлекаем атрибуты
extract( shortcode_atts( array(     
            'aps_person_description' => ''
        ), $atts
    )
);

// Формируем HTML
$aps_person_return = '<div class="aps_person_container aps_container">';
$aps_person_return .= '<p class="aps_person_description" itemprop="description">' . $aps_person_description . '</p>';
$aps_person_return .= '</div>';

return $aps_person_return;

}
// Регистрируем шорткод
add_shortcode('aps_person', 'aps_person_schema_shortcode');

Я пробовал добавлять после extract что-то вроде:

$aps_person_description = esc_html($atts['aps_person_description']); 

Но так как атрибут уже сломан (print_r показывает, что строка после кавычки разбивается на элементы массива для каждого слова), экранирование строки в этом месте не работает.

Пробовал до массива — тоже не работает, получаю Notice: Undefined index.

Итак, вопрос: как правильно санитизировать пользовательский ввод для данных атрибутов шорткода?

0
Все ответы на вопрос 3
1

Оказывается, система шорткодов WordPress использует функцию shortcode_parse_atts($text); для разбора записи шорткода, чтобы извлечь имена и значения атрибутов и сохранить их парами в массиве $atts, который затем передается в функцию шорткода. Таким образом, в вашем случае добавление экранирующих действий в функцию шорткода, например:

$aps_person_description = esc_html($atts['aps_person_description']); 

не сработает, потому что shortcode_parse_atts() уже извлек имена и значения атрибутов и мог неправильно интерпретировать кавычки в значениях атрибутов.

При ближайшем рассмотрении функция shortcode_parse_atts() использует такое регулярное выражение:

/(\w+)\s*=\s*"([^"]*)"(?:\s|$)|(\w+)\s*=\s*\'([^\']*)\'(?:\s|$)|(\w+)\s*=\s*([^\s\'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|(\S+)(?:\s|$)/

для распознавания имен и значений атрибутов в следующих форматах:

1. attr1="value1"
2. attr2='value2'
3. attr3=value3
4. "value4"
5. value5

Поэтому, если пользователь вставит кавычки в значения, это может легко привести к ошибке. Например:

[my_shortcode dog='Santa's Little Helper' /]    
// $attr будет Array ( [0] => dog='Santa's [1] => Little [2] => Helper' )
// а должно быть Array ( [dog] => Santa's Little Helper )

Санитизация после разбора явно слишком запоздалая. А что насчет санитизации перед разбором? Придется обрабатывать всю запись, так как у нас еще нет значений атрибутов для работы. Но это тоже вызывает проблемы, например:

html_entities("[my_shortcode dog='Santa's Little Helper' /]", ENT_QUOTES);
// теперь запись выглядит как [my_shortcode dog=&#039;Santa&#039;s Little Helper&#039; /]
// после разбора: 
Array
(
    [dog] => &#039;Santa&#039;s
    [0] => Little
    [1] => Helper&#039;
)

Парадокс в том, что для корректного разбора парсером необходимо санитизировать значения атрибутов, но чтобы это сделать, сначала нужно запустить парсер и получить эти значения.

В заключение, я считаю, что разумным способом обеспечить корректную работу является требование к пользователям вводить атрибуты в правильном формате. Если пользователь введет плохо отформатированные атрибуты, это станет большой головной болью. Для справки, мой опыт подсказывает использовать $content. В вашем случае я бы поместил aps_person_description в $content, это может выглядеть так:

[my_shortcode]текст здесь с "кавычками", которые могут прерывать атрибут...[/my_shortcode]

и кавычки будут меньше проблемой.

28 июл. 2013 г. 06:09:01
Комментарии

Нет никакого парадокса, это простая, но существенная ошибка в функции shortcode_parse_atts(). Это просто неправильный способ разбора атрибутов в кавычках. Экранирующие последовательности необходимы - вы не найдёте ни одного языка программирования без них. Это должно было быть встроено с самого начала. Ваш пример можно было бы легко записать как [my_shortcode dog='Santa\'s Little Helper' /], если бы парсер имел представление об этом.

Walf Walf
27 февр. 2015 г. 04:51:03
1

Кажется, вы работаете не с той стороны.

Попробуйте санировать пользовательский ввод, например, с помощью sanitize_text_field, а не вывод шорткода.

8 мар. 2013 г. 17:25:30
Комментарии

Спасибо! Хотя я не использовал sanitize_textfield, вы направили меня туда, куда нужно. Ввод добавляется через jQuery, поэтому я добавил .replace для замены кавычек — решение не идеальное, но предотвращает поломку.

Apina Apina
8 мар. 2013 г. 20:41:32
0

Я столкнулся с похожей проблемой при выводе PHP-переменной в атрибут шорткода. В моем случае это было название термина таксономии, а не пользовательский ввод, поэтому не требовалось санитизации.

Использование htmlentities() с флагом ENT_QUOTES позволяет использовать строки, содержащие ' и ", в качестве атрибутов шорткода. Однако это также преобразует другие символы в HTML-сущности, например, & в &amp;, что в моем случае было нежелательно.

Чтобы преобразовывать только символы ' и " в HTML-сущности, не затрагивая другие символы, такие как &:

htmlspecialchars_decode( htmlentities($value_to_print, ENT_QUOTES), ENT_NOQUOTES )

htmlspecialchars_decode() отменяет все преобразования, выполненные функцией htmlentities(). Использование флага ENT_NOQUOTES предотвращает обратное преобразование символов ' и ".

19 мар. 2022 г. 03:51:45