Совет по безопасности: Не используйте nl2br()!
nl2br()
может оставить вас уязвимым для межсайтового скриптинга (XSS)… Вместо него лучше использовать CSS!PHP изобилует интересными и полезными функциями для различных задач. Одной из таких часто используемых функций является nl2br()
! Если вы не знаете, nl2br()
добавляет символы <br>
в строки, где есть символы новой строки (\n
, \n\r
и \r
).
Например:
> nl2br("One\nTwo\nThree");
= """
One<br />\n
Two<br />\n
Three
"""
Наиболее распространённым вариантом использования, который я вижу для nl2br()
, является отображение введённых пользователем данных из полей <textarea>
. Она преобразует символы новой строки, введённые пользователем, в настоящие новые строки (через теги <br>
), которые отображаются на странице.
Однако риск заключается в том, что при использовании nl2br()
вам придётся выводить на страницу пользовательский ввод без экранирования, что может привести к появлению XSS уязвимостей.
Например, если мы используем такие данные введённые пользователем в следующих примерах:
One
Two
<img src=x onerror="alert('Boom!')">
Three
Вы не можете использовать nl2br()
внутри тегов экранирования шаблонов blade:
{{ nl2br($input) }}
Так как он будет экранировать и теги <br>
:

Но когда вы не экранируете вывод:
{!! nl2br($input) !!}
Вы получаете это:

Один из способов обойти эту проблему — экранировать внутри nl2br()
:
{!! nl2br(e($input)) !!}

Это работает, но выглядит довольно уродливо, и об этом легко забыть!
Гораздо лучший способ решить эту проблему — использовать CSS-правило white-space: pre-line;
для экранированного ввода, не внося в него никаких изменений:
<div style="white-space: pre-line;">{{ $input }}</div>
Или если вы используете Tailwind CSS (Смотрите https://tailwindcss.com/docs/whitespace для всех вариантов форматирования вывода пробельных символов — там есть ещё несколько полезных способов!):
<div class="whitespace-pre-line">{{ $input }}</div>

white-space: pre-line
(полезная нагрузка XSS видна) с переносами на новую строку.Этот подход обеспечивает невероятно чистое решение (Не обращайте внимания на встроенные стили, они нужны только для демонстрации. В целом, встроенных стилей следует избегать, так как они могут привести к нарушению Content Security Policy!), использующее преимущества стандартного экранирования вывода для предотвращения проникновения XSS и сохраняющее перевод на новую строку в том виде, в котором его задумал пользователь. Кроме того, вы вряд ли забудете экранировать вывод, поскольку {{ ... }}
должно использоваться по умолчанию.