В этой статье я хочу изложить некоторые аргументы за то, что такой оператор будет полезен. И, возможно, получить обоснованные аргументы против.
Я предлагаю оператор
<?~ $value ?> как короткую запись для <?= htmlspecialchars($value, ENT_QUOTES) ?>. Это позволит уменьшить копи-пасту вызовов и улучшить безопасность приложений без движков шаблонизации, так как в таких приложениях это частая операция. Обычно можно перевести приложение на новую версию языка программирования, но практически невозможно переписать все имеющиеся PHP-шаблоны на специальный шаблонизатор. Вариант сделать функцию <?= h($value) ?> это не выход, так как копи-паста все равно остается, и можно когда-нибудь забыть ее вызвать.Поискав на bugs.php.net, я нашел один активный feature request с 2012 года. Там в комментариях была предложена форма записи
<?~ ?>, которая показалась мне удобной. Написав там примерно то же самое, что и в статье про PHP7, получил ответ, что это потребует процесса RFC.Я пообщался с разработчиками в рассылке PHP Internals list и получил ответ, что это уже обсуждалось много раз.
Ссылки:
marc.info/?t=145851323800001
marc.info/?t=135082660600002
marc.info/?t=144225546000001
marc.info/?t=101129596100006
wiki.php.net/rfc/escaper
wiki.php.net/rfc/taint
bugs.php.net/bug.php?id=62574
bugs.php.net/bug.php?id=20310
bugs.php.net/bug.php?id=16007
bugs.php.net/bug.php?id=3284
Основной аргумент в том, что экранирование контекстно-зависимо. У нас есть разные контексты — HTML/URL/JS/CSS — и делать какой-то оператор только для одного контекста неправильно, а для всех сразу сложно.
На самом деле это немного не так. Это не взаимоисключающие контексты, HTML может присутствовать или нет независимо от остальных. Кроме того, для JS и CSS контекста нельзя применить понятие «экранирование» (escaping), потому что это другие языки со своим синтаксисом. Правильная запись для них не сводится к добавлению слэшей и замене спец-символов.
Рассмотрим пример.
<a href="/things/<?= $thing['name'] ?>" onclick="alert('<?= $thing['name'] ?>');"> <?= $thing['name'] ?> </a>
На первый взгляд может показаться, что тут везде нужно разное экранирование. Но это не так. Вызов htmlspecialchars() нужен во всех трех случаях.
<?php $thing = ['name' => 'Say "Hello")']; ?> <a href="/things/<?= htmlspecialchars(urlencode($thing['name'])) ?>" onclick="alert(<?= htmlspecialchars(json_encode($thing['name']), ENT_QUOTES) ?>);" > <?= htmlspecialchars($thing['name']) ?> </a>
Несмотря на то, что urlencode() возвращает безопасную для HTML строку, и можно не использовать htmlspecialchars(), сочетание htmlspecialchars() + urlencode() встречается в обработке различных фильтров.
Пример:
<?php $postData = ['contains_text' => 'Say "Hello")']; $filterUrl = '/my_route/?state=active'; if ($postData['contains_text']) $filterUrl .= '&' . 'contains_text=' . urlencode($postData['contains_text']); $pageNumber = 1; ?> <a href="<?= htmlspecialchars($filterUrl) ?>" onclick="alert(<?= htmlspecialchars(json_encode($postData['contains_text']), ENT_QUOTES) ?>);" > <?= $pageNumber ?> </a>
При обработке веб-страниц htmlspecialchars() не нужен только внутри тегов
style и script.1 HTML Содержимое тега, любые атрибуты тега (включает следующие 3 варианта) 2 HTML + URL Атрибуты href, action, различные варианты типа data-url 3 HTML + JS Атрибуты on-event - onclick, onkeypress и т.д. 4 HTML + CSS Атрибут style 5 URL - 6 JS Тег <script></script> 7 CSS Тег <style></style> 8 non-HTML Экранирование может зависеть не только от формата, но и от задачи.
Пункт 5 — отдельно в HTML-документе не встречается, только в составе других контекстов.
Пункт 6 — встречается довольно часто, это единственный практический случай, когда нам не надо применять html-экранирование. Но такая связка PHP+JS считается не очень хорошим стилем, лучше использовать data-атрибуты, особенно в мультиязычных приложениях. А для них нужен htmlspecialchars().
Пункт 7 — очень редкий случай, обычно PHP там не используется.
Пункт 8 — для этого случая безопасное экранирование принципиально невозможно придумать заранее.
Таким образом, для наиболее часто встречающихся на практике случаев экранировать HTML не надо только в одном случае, в остальных четырех экранирование необходимо. Следовательно, специальный оператор будет полезен, и многочисленные дискуссии тому подтверждение.
Оператор
<?~ ?> не требует настроек в «php.ini» и не влияет на остальные теги и операторы. Его удобно набирать, все символы набираются с Shift, и меньше вероятность написать <?= ?> вместо него, так как тильда находится с другой стороны клавиатуры. Если вы по каким-то причинам не используете htmlspecialchars(), то для вас ничего не поменяется. Он не является универсальным оператором для экранирования любых данных, это просто короткая запись для вызова <?php echo htmlspecialchars($str, ENT_QUOTES) ?>, так же как <?= ?> для <?php echo $str; ?>UPD:
Описание реализации
Ссылки:
RFC: https://wiki.php.net/rfc/escaping_operator
Коммит с изменениями: github
Первоначальное обсуждение: http://marc.info/?t=146619199100001
Обсуждение RFC: http://marc.info/?t=146868366400003
Внимание. Если вы пишете приложения, к примеру, только на Twig и Symfony, или последние N лет делаете только API, то большая просьба не голосовать, а то получится нерепрезентативная выборка. Для вас сделан третий опрос. В первых двух интересует мнение людей, которые реально с этим работают.
Аргументированные комментарии за и против приветствуются.