Ну уж для такой-то простой функции должно быть достаточно написанного на странице документации.
И, в частности, про ENT_QUOTES ;)
Эта функция заменяет спецсимволы, которые являются управляющими в контексте HTML, на безобидные HTML-сущности. Вот и всё.
Чисто визуально управляющие символы будут выглядеть так же, как и должны, но в коде не будут представлять ни малейшей опасности.
Для XSS важно, будут ли экранироваться одинарные кавычки или нет, если одинарные кавычки используются для ограничения атрибута.
Пример
<?php $name = "' onclick='alert(\"pwned!\")"; ?>
<input value="<?=htmlspecialchars($name) ?>"> Не важно. Весь текст так и заключен в двойные кавычки
<input value='<?=htmlspecialchars($name) ?>'> Важно. Закрыли одинарную, вписываем, что хотим
Во втором случае этот код отрендерится, как
<input value='' onclick='alert("pwned!")'>
(но при этом " отрендерятся в двойные кавычки, и в onclick будет уже валидный яваскрипт
alert("pwned!")
А с взведенным флагом ENT_QUOTES мы получим
<input value='' onclick='alert("pwned!")'>
И хотя значение внутри атрибута отрендерится, как
' onclick='alert("pwned!")
, но оно все целиком будет внутри атрибута value.
Разумеется, лучше всего сделать применение функции
универсальным, чтобы не проверять кавычки каждый раз, и не обливаться холодным потом, если кавычки вдруг поменяются. И использовать ENT_QUOTES всегда.
К счастью, РНР уже позаботился о вас и ваших друзьях. Начиная с версии 8.1, флаг ENT_QUOTES ставится по умолчанию. И приведенный выше пример будет работать только на устаревших версиях. Так что ручное добавление уже уходит в область легаси-практик.
Чтобы не ломать пальцы, каждый раз набирая всё это htmlspecialchars ENT_QUOTES, толковые джуны всегда пишут пользовательскую функцию-макрос, типа
function esc($var) {
return htmlspecialchars($var, ENT_QUOTES);
}
Правда, надолго с этой функцией не задерживаются, потому что она годится только при обучении. А любой проект сложнее, чем домашняя страничка про любимого котика, в обязательном порядке уже должен для вывода использовать специальный шаблонизатор, например Twig. Где весь вывод идет с помощью специального оператора, который уже по умолчанию экранирует HTML
<input value="{{$name}}"> Не важно. Все уже проэкранировано до нас
Важно помнить, что это экранирование работает только в контексте HTML.
Если выводим данные внутри кода яваскрипт, то htmlspecialchars поможет как мертвому припарки. И в этом случае надо использовать json_encode.
Ну и разумеется, надо не забывать комбинировать все варианты экранирования.
Например, код яваскрипт, который пишется в атрибут HTML тега, надо
весь целиком экранировать c с помощью htmlspecialchars. А данные для этого кода - c с помощью json_encode:
<button onclick="<?= htmlspecialchars("window.open(".json_encode($name).")", ENT_QUOTES) ?>">