ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

PHP:如何使用HTML Purifier使用nl2br()来保持换行符?

2019-06-25 01:19:11  阅读:263  来源: 互联网

标签:php regex line-breaks html nl2br


问题:当使用HTML Purifier处理用户输入的内容时,换行符不会被转换为< br />标签.

请考虑以下用户输入的内容:

Lorem ipsum dolor sit amet.
This is another line.

<pre>
.my-css-class {
    color: blue;
}
</pre>

Lorem ipsum:

<ul>
<li>Lorem</li>
<li>Ipsum</li>
<li>Dolor</li>
</ul>

Dolor sit amet,
MyName

使用HTML Purifier处理时,以上内容将更改为以下内容:

Lorem ipsum dolor sit amet. This is another line.

06001

Lorem ipsum:

  • Lorem
  • Ipsum
  • Dolor

Dolor sit amet, MyName

正如您所看到的,用户在一条单独的行上的“MyName”与前一行一起显示.

怎么修?

当然,使用PHP nl2br()功能.但是,无论我们在净化内容之前还是之后使用它都会出现新问题.

以下是在HTML Purifier之前使用nl2br()时的示例:

Lorem ipsum dolor sit amet.
This is another line.

06002

Lorem ipsum:

  • Lorem
  • Ipsum
  • Dolor

Dolor sit amet,
MyName

会发生什么是nl2br()添加< br />对于每个换行符,因此即使是< pre>中的换行符也是如此.正在处理块,以及每个< li>之后的换行符.标签.

我尝试了什么

我试过custom nl2br() function用< br />取代换行符.标签,然后删除所有< br />标签来自< pre>块.它工作得很好,但问题仍然存在于< li>项目.

为< ul>尝试相同的方法块也会删除所有< br />来自< li>的标签孩子,除非我们使用更复杂的正则表达式删除< br />里面的标签< ul>元素但在外面< li>元素.但那么嵌套< ul>呢?在< li>内项目?要处理所有这些情况,我们必须拥有更复杂的正则表达式!

>如果这是正确的方法,你能帮我解决正则表达式吗?
>如果这不是正确的方法,我怎么能解决这个问题?我也愿意接受HTML Purifier的替代方案.

我已经看过的其他资源:

> HTMLPurifier: auto br
> http://htmlpurifier.org/phorum/read.php?2,3034

解决方法:

使用自定义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-Purified之前将其应用于内容.除非您知道自己在做什么,否则永远不要重新处理纯化的内容.

请注意,因为已经保留了每个换行符和双换行符,所以不应使用HTML Purifier的AutoFormat.AutoParagraph功能:

// 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标记最初用于improve user experience by not adding another markup syntax,因此您可能希望允许用户发布代码,尤其是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 Purified之前完成.另外,请记住,如果用户放置< 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);

干杯!

标签:php,regex,line-breaks,html,nl2br
来源: https://codeday.me/bug/20190625/1283395.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有