Если вы откроете исходный код ядра WordPress или какого-нибудь плагина, то скорее всего вы заметите, что значения атрибутов перед выводом пропускаются через функцию esc_attr()
.
Что конкретно делает функция: преобразует символы < > & " '
в HTML-сущности, а именно в< > & " '
соответственно. Повторное преобразование не производится.
Также есть похожие функции – esc_attr__() и esc_attr_e() – они нужны при работе с локализацией.
esc_attr( $text )
Параметры
- $text
- (строка) Текст, который планируется использоваться в качестве значения HTML-атрибута.
Примеры
1. Результат действия функции
$text = "<span>(тег) '(кавычка) "(двойная кавычка) &(амперсанд)"; echo esc_attr( $text ); // Будет выведено // <span>(тег) '(кавычка) "(двойная кавычка) &(амперсанд)
Обратный слэш кстати исчез, потому что он вообще никак не участвует в строке, он нужен лишь для того, чтобы в неё можно было добавить двойные кавычки (ведь сама строка в двойных кавычках).
2. Спасаемся от взломанной базы данных
Чуть выше я упоминал пример с изображением и атрибутом alt
. Пришло время разобрать его по шагам, почему бы и нет.
$alt = // получили из базы данных что-то echo '<img src="" alt="' . $alt . '" />';
Так вот, что если в базу данных каким-то образом загнали JavaScript-код майнинга (предположим), и мы получаем оттуда значения для alt
равное "><script>код майнинга</script>
Тогда, когда оно подставится в alt
атрибут, мы получим, что атрибут alt
закроется, тег <img>
закроется, и начнёт выполняться тег <script>
. А после ещё выведется обычным текстом />
.
<img src="" alt=""><script>код майнинга</script> />
Однако, если мы защитим атрибут функцией esc_attr()
, вот так:
$alt = // получили из базы данных что-то echo '<img src="" alt="' . esc_attr( $alt ) . '" />';
Тогда весь вредоносный код будет проэкранирован и он никак не выполнится, лишь выведется внутри атрибута alt
.
<img src="" alt=""><script>код майнинга</script>" />
3. Двойное экранирование
Выше я упоминал, что если у вас в строке уже есть HTML-сущности, то повторному экранированию они подвергнуты не будут, то есть <
не превратится в <
.
Окей, а что делать, если вам это нужно сделать? Тут нас может выручить PHP-функция htmlspecialchars()
.
$text = "<span>"; echo esc_attr( $text ); // <span> echo htmlspecialchars( $text ); // <span>
4. Использование в формах
В интернете можно встретить пример по использованию функции esc_attr()
внутри атрибута value
в поле формы. Он примерно такой:
$fname = ( isset( $_POST['fname'] ) ) ? $_POST['fname'] : ''; echo '<input type="text" name="fname" value="' . esc_attr( $fname ) . '">';
Но к этому примеру важно добавить некоторые пояснения, и я сейчас их и добавлю.
Итак, при использовании функции для очистки атрибута value в формах, вы будете терять HTML-сущности!
Предположим, что у нас есть какой-то текст в базе данных, содержащий экранированный HTML-тег и обычные двойные кавычки, например Используйте тег "br" (<br>)
. А также у нас есть обычное текстовое поле, значение которого очищается функцией esc_attr()
.
echo '<input type="text" value="' . esc_attr( $value ) . '">';
Подставим в value
значение из базы данных?
Но (!) браузер обрабатывает HTML-сущности внутри полей формы и пользователю отобразится: Используйте тег "br" (<br>)
, и поля в принципе так работают, что и значение поля станет таким же. А значит, при отправке формы и сохранении её в базу данных мы теряем все HTML-сущности в строке и значение в базе данных становится Используйте тег "br" (<br>)
.
В таком случае ситуацию поможет спасти использование esc_textarea(), которая осуществляет повторные преобразования.
esc_attr: <input value="Используйте тег "br" (<br>)"> esc_textarea: <input value="Используйте тег "br" (&lt;br&gt;)">
Хуки
attribute_escape
К возвращаемую результату функции esc_attr()
дополнительно применяется фильтр-хук attribute_escape
, который позволяет модифицировать очищенное значение.
return apply_filters( 'attribute_escape', $safe_text, $text );
- $safe_text
- (строка) Очищенный функцией текст.
- $text
- Оригинальный текст, переданный в функцию.
В дополнении предыдущего примера, покажу вам, как при помощи этого фильтра не очищать одну определённую строку.
add_filter( 'attribute_escape', 'true_skip_escaping_specific_string', 25, 2 ); function true_skip_escaping_specific_string( $safe_text, $text ) { if( 'Используйте тег "br" (<br>)' === $text ) { return $text; } return $safe_text; }
Не знаете, как работать с фильтрами? Смотрите этот урок.