Эта проблема может быть решена частично (если не полностью) с помощью специальной функции nl2br()
:
function nl2br_special($string){
// Step 1: Add <br /> tags for each line-break
$string = nl2br($string);
// Step 2: Remove the actual line-breaks
$string = str_replace("\n", "", $string);
$string = str_replace("\r", "", $string);
// Step 3: Restore the line-breaks that are inside <pre></pre> tags
if(preg_match_all('/\<pre\>(.*?)\<\/pre\>/', $string, $match)){
foreach($match as $a){
foreach($a as $b){
$string = str_replace('<pre>'.$b.'</pre>', "<pre>".str_replace("<br />", PHP_EOL, $b)."</pre>", $string);
}
}
}
// Step 4: Removes extra <br /> tags
// Before <pre> tags
$string = str_replace("<br /><br /><br /><pre>", '<br /><br /><pre>', $string);
// After </pre> tags
$string = str_replace("</pre><br /><br />", '</pre><br />', $string);
// Arround <ul></ul> tags
$string = str_replace("<br /><br /><ul>", '<br /><ul>', $string);
$string = str_replace("</ul><br /><br />", '</ul><br />', $string);
// Inside <ul> </ul> tags
$string = str_replace("<ul><br />", '<ul>', $string);
$string = str_replace("<br /></ul>", '</ul>', $string);
// Arround <ol></ol> tags
$string = str_replace("<br /><br /><ol>", '<br /><ol>', $string);
$string = str_replace("</ol><br /><br />", '</ol><br />', $string);
// Inside <ol> </ol> tags
$string = str_replace("<ol><br />", '<ol>', $string);
$string = str_replace("<br /></ol>", '</ol>', $string);
// Arround <li></li> tags
$string = str_replace("<br /><li>", '<li>', $string);
$string = str_replace("</li><br />", '</li>', $string);
return $string;
}
Это должно быть применено к содержимому до его очистки HTML. Никогда не обрабатывайте очищенный контент повторно, если вы не знаете, что делаете.
Обратите внимание: поскольку каждый перенос строки и двойной перенос строки уже сохранены, вам не следует использовать AutoFormat.AutoParagraph
функцию HTML Purifier:
// Process line-breaks
$string = nl2br_special($string);
// Initiate HTML Purifier config
$purifier_config = HTMLPurifier_Config::createDefault();
$purifier_config->set('HTML.Allowed', 'p,ul,ol,li,strong,b,em,i,u,a[href],code,pre,blockquote,cite,img[src|alt],br,hr,h3,h4');
//$purifier_config->set('AutoFormat.AutoParagraph', true); // Make sure to NOT use this
// Initiate HTML Purifier
$purifier = new HTMLPurifier($purifier_config);
// Purify the content!
$string = $purifier->purify($string);
Вот и все!
Кроме того, поскольку разрешение основных HTML-тегов изначально предназначалось для улучшить взаимодействие с пользователем, не добавляя другой синтаксис разметки, возможно, вы захотите разрешить пользователям публиковать код, особенно HTML-код, который не будет интерпретироваться / удаляться HTML Purifier.
HTML Purifier в настоящее время позволяет размещать код, но требует сложных маркеров CDATA:
<![CDATA[
Place code here
]]>
Трудно вспомнить и написать. Чтобы максимально упростить взаимодействие с пользователем, я считаю, что лучше всего разрешить пользователям добавлять код, встраивая его с помощью простых тегов <code>
(для встроенного кода) и <pre>
(для блоков кода). Вот как это сделать:
function custom_code_tag_callback($code) {
return '<code>'.trim(htmlspecialchars($code[1])).'</code>';
}
function custom_pre_tag_callback($code) {
return '<pre><code>'.trim(htmlspecialchars($code[1])).'</code></pre>';
}
// Don't require HTMLPurifier's CDATA enclosing, instead allow simple <code> or <pre> tags
$string = preg_replace_callback("/\<code\>(.*?)\<\/code\>/is", 'custom_code_tag_callback', $string);
$string = preg_replace_callback("/\<pre\>(.*?)\<\/pre\>/is", 'custom_pre_tag_callback', $string);
Обратите внимание, что, как и обработка nl2br, это должно быть выполнено до того, как содержимое будет очищено HTML. Также имейте в виду, что если пользователь помещает теги <code>
или <pre>
в свой собственный опубликованный код, он закроет родительский тег <code>
или <pre>
, содержащий его код. Это не может быть решено, и это также относится к исходным маркерам CDATA или к любой разметке, даже той, которая используется в StackOverflow (например, использование символа `в образце кода закроет тег кода).
Наконец, для удобства пользователей есть и другие вещи, которые мы можем автоматизировать, например, ссылки, которые мы хотим сделать интерактивными. К счастью, это можно сделать с помощью функции HTML Purifier AutoFormat.Linkify
.
Вот окончательный код, который включает в себя все для окончательной настройки:
// === Declare functions ===
function nl2br_special($string){
// Step 1: Add <br /> tags for each line-break
$string = nl2br($string);
// Step 2: Remove the actual line-breaks
$string = str_replace("\n", "", $string);
$string = str_replace("\r", "", $string);
// Step 3: Restore the line-breaks that are inside <pre></pre> tags
if(preg_match_all('/\<pre\>(.*?)\<\/pre\>/', $string, $match)){
foreach($match as $a){
foreach($a as $b){
$string = str_replace('<pre>'.$b.'</pre>', "<pre>".str_replace("<br />", PHP_EOL, $b)."</pre>", $string);
}
}
}
// Step 4: Removes extra <br /> tags
// Before <pre> tags
$string = str_replace("<br /><br /><br /><pre>", '<br /><br /><pre>', $string);
// After </pre> tags
$string = str_replace("</pre><br /><br />", '</pre><br />', $string);
// Arround <ul></ul> tags
$string = str_replace("<br /><br /><ul>", '<br /><ul>', $string);
$string = str_replace("</ul><br /><br />", '</ul><br />', $string);
// Inside <ul> </ul> tags
$string = str_replace("<ul><br />", '<ul>', $string);
$string = str_replace("<br /></ul>", '</ul>', $string);
// Arround <ol></ol> tags
$string = str_replace("<br /><br /><ol>", '<br /><ol>', $string);
$string = str_replace("</ol><br /><br />", '</ol><br />', $string);
// Inside <ol> </ol> tags
$string = str_replace("<ol><br />", '<ol>', $string);
$string = str_replace("<br /></ol>", '</ol>', $string);
// Arround <li></li> tags
$string = str_replace("<br /><li>", '<li>', $string);
$string = str_replace("</li><br />", '</li>', $string);
return $string;
}
function custom_code_tag_callback($code) {
return '<code>'.trim(htmlspecialchars($code[1])).'</code>';
}
function custom_pre_tag_callback($code) {
return '<pre><code>'.trim(htmlspecialchars($code[1])).'</code></pre>';
}
// === Process user's input ===
// Process line-breaks
$string = nl2br_special($string);
// Allow simple <code> or <pre> tags for posting code
$string = preg_replace_callback("/\<code\>(.*?)\<\/code\>/is", 'custom_code_tag_callback', $string);
$string = preg_replace_callback("/\<pre\>(.*?)\<\/pre\>/is", 'custom_pre_tag_callback', $string);
// Initiate HTML Purifier config
$purifier_config = HTMLPurifier_Config::createDefault();
$purifier_config->set('HTML.Allowed', 'p,ul,ol,li,strong,b,em,i,u,a[href],code,pre,blockquote,cite,img[src|alt],br,hr,h3,h4');
$purifier_config->set('AutoFormat.Linkify', true); // Make links clickable
//$purifier_config->set('HTML.TargetBlank', true); // Uncomment if you want links to open new tabs
//$purifier_config->set('AutoFormat.AutoParagraph', true); // Leave this commented as it conflicts with nl2br
// Initiate HTML Purifier
$purifier = new HTMLPurifier($purifier_config);
// Purify the content!
$string = $purifier->purify($string);
Ваше здоровье!
person
Community
schedule
05.08.2013
nl2br
следует использовать с открытым текстом, когда он помещается в контекст HTML. В вашем случае у вас уже есть HTML. Почему ваш HTML-код не содержит уже правильно<br>
для разрывов строк? - person deceze♦   schedule 15.07.2013<strong>
,<em>
,<pre>
или<ul>
, является новой тенденцией, которая, как правило, заменяет BBCode, Markdown и Textile, например. - person Community   schedule 15.07.2013<br>
. Возможно, он использует разрывы строк в HTML так, как они были задуманы: чтобы сделать разметку более читаемой без фактического введения разрывов строк в текст. Насколько я понимаю, у вас не может быть обоих вариантов. :) Вам действительно нужно проанализировать HTML и применитьnl2br
только к определенным текстовым узлам, за исключением элементов<pre>
. - person deceze♦   schedule 15.07.2013<strong>
и мне не нужно вручную писать<br />
теги! Это ерунда, ваше предложение совершенно недружелюбно к пользователю. Большинство людей не используют и не знают HTML, однако разрешение использования базовых тегов позволяет людям, которые знают, иметь возможность их использовать. - person Community   schedule 15.07.2013nl2br
только к определенным текстовым узлам, исключая<pre>
элементы.: Это именно то, что я хочу, любая идея, как я могу добиться этого с помощью HTML Purifier (или другого) ? Ваша помощь очень ценится;) - person Community   schedule 15.07.2013<br>
, вам нужно проанализировать HTML, чтобы сделать это только для определенных элементов. Но вы должны сделать это до того, как дезинфицируете HTML, что означает, что вы, вероятно, не сможете правильно проанализировать HTML. Это очень сложное предложение. Я понимаю, что вы пытаетесь сделать, но причина, по которой это сложно и подвержено ошибкам, - это причина, по которой Markdown & co. возникла в первую очередь. И SO не является хорошим примером того, как это работает, потому что это не так. - person deceze♦   schedule 15.07.2013nl2br
. Если Purifier по умолчанию портит разрывы строк, присущие входным данным, поэтому вы не можете выполнить второй шаг после этого, вам необходимо настроить Purifier, чтобы он вел себя по-другому, и / или включитеnl2br
прямо в его обработку. Вы исследовали такую возможность? Я не могу дать вам решение в коде ATM. - person deceze♦   schedule 15.07.2013<p></p>
. Все одиночные разрывы строк остаются необработанными. На самом деле меня не интересуют теги<p>
, я просто хочу, чтобы все разрывы строк, которые пользователь намеревался добавить, оставались нетронутыми (т.е. преобразовывались в теги<br />
, где это необходимо). - person Community   schedule 18.07.2013