在 Yii 2 下,实现 html 富文本的标红,仅替换纯文本,避免替换 html 标签

1、将 html 富文本中的关键词(习近平)加上<em class=”key-word”>习近平</em>,如图1

图1

2、关键词(2017)加上<em class=”key-word”>2017</em>,由于 2017 本身是 src 属性的值,最终导致 html 结构被破坏,页面错乱,如图2

图2

3、查看源代码,src 属性的值被标红,如图3

图3

原始代码:

<img border="0" style="max-width:100%;" zcmsimagerela="125644" src="http://jnweb.sobeycloud.com/jntxqc//upload/Image/mrtp/bz/2017/08/14/1_e1ac78b7775a43e984a8842d57e703a3.jpg?1502693004515" alt="timg (2)"/>

被标红处理后的代码:

<img border="0" style="max-width:100%;" zcmsimagerela="125644" src="http://jnweb.sobeycloud.com/jntxqc//upload/Image/mrtp/bz/<em class="key-word">2017</em>/08/14/1_e1ac78b7775a43e984a8842d57e703a3.jpg?1502693004515" alt="timg (2)"/>

4、基于:garyjl/yii2-simple_html_dom,参考网址,http://www.shuijingwanwq.com/2018/03/20/2435/ ,安装配置

5、html 富文本内容如下:

<div>第1层节点1<p>第2层节点1,2017,习近平<img border="0"  src="http://jnweb.sobeycloud.com/jntxqc//upload/Image/mrtp/bz/2017/08/14/1_e1ac78b7775a43e984a8842d57e703a3.jpg?1502693004515"/></p><p>第2层节点2</p><p>第2层节点3,习近平<span>第3层节点1,2017</span></p>第1层节点2</div>

6、编辑 \common\logics\ContentAudit.php,代码如下:如图4

图4

<?php

namespace common\logics;

use Yii;
use yii\helpers\Json;
use garyjl\simplehtmldom\SimpleHtmlDom;

/**
 * This is the model class for table "{{%content_audit}}".
 *
 */class ContentAudit extends \common\models\ContentAudit
{
    /**
     * 标注关键词(<em class="key-word"></em>)
     * @param string $text
     * @param string $hitContent
     *
     * @return string
     */    public function labelKeyWord($text, $hitContent) {
        foreach ($hitContent as $hitContentvalue) {
            $search[] = $hitContentvalue['word'];
        }
        $searchUnique = array_unique($search);
        foreach ($searchUnique as $searchUniqueValue) {
            $replace[] = "<em class='key-word'>" . $searchUniqueValue . "</em>";
        }
        $replaceText = str_replace($searchUnique, $replace, $text);
        return $replaceText;
    }

    /**
     * 获取 HTML DOM 解析的纯文本
     * @param string $innerText 内部HTML文本
     *
     * @return array $plainText 纯文本
     */    public function getPlainText($innerText)
    {
        $plainText = [];
        $html = SimpleHtmlDom::str_get_html($innerText);
        $texts = $html->find('text');
        foreach ($texts as $text) {
            $plainText[] = $text->plaintext;
        }
        return $plainText;
    }

    /**
     * 标注关键词(设置 HTML DOM 解析的内部HTML文本)
     * @param string $innerText 内部HTML文本
     * @param string $plainText 纯文本
     * @param string $hitContent 触发敏感词
     *
     * @return string $replaceInnerText 内部HTML文本
     */    public function setInnerText($innerText, $plainText, $hitContent)
    {
        //标注关键词(<em class="key-word"></em)
        $labelContent = $this->labelKeyWord($plainText, $hitContent);
        $labelContent = Json::decode($labelContent, true);
        $html = SimpleHtmlDom::str_get_html($innerText);
        foreach ($labelContent as $key => $text) {
            $html->find('text', $key)->innertext = $labelContent[$key];
        }
        // 将内部 DOM 树转储回字符串
        $replaceInnerText = $html->save();
        return $replaceInnerText;
    }

}

7、编辑 \api\models\ContentAudit.php,代码如下:

 //获取 HTML DOM 解析的纯文本
 $plainText = $this->getPlainText($this->content);
 print_r($plainText);
 exit;
 $textScanContent = Json::encode($plainText);

8、打印 获取 HTML DOM 解析的纯文本,结果如下:如图5

图5

Array
(
    [0] => 第1层节点1
    [1] => 第2层节点1,2017,习近平
    [2] => 第2层节点2
    [3] => 第2层节点3,习近平
    [4] => 第3层节点1,2017
    [5] => 第1层节点2
)

9、编辑 \api\models\ContentAudit.php,代码如下:

 print_r($textScan);
 exit;
 //标注关键词(设置 HTML DOM 解析的内部HTML文本)
 $labelContent = $this->setInnerText($this->content, $textScan['text'], $textScan['hit_content']);
 $this->content = $labelContent;

10、敏感词过滤是否触发:是,打印触感词触发服务响应的结果,如图6

图6

Array
(
    [hit] => 1
    [text] => ["第1层节点1","第2层节点1,2017,习近平","第2层节点2","第2层节点3,习近平","第3层节点1,2017","第1层节点2"]
    [text_len] => 73
    [hit_content] => Array
        (
            [0] => Array
                (
                    [word] => 2017
                    [start] => 18
                    [end] => 21
                    [dic_name] => 王强开发专用,允许删除
                    [id] => 14046
                )

            [1] => Array
                (
                    [word] => 习近平
                    [start] => 23
                    [end] => 25
                    [dic_name] => 王强开发专用,允许删除
                    [id] => 14048
                )

            [2] => Array
                (
                    [word] => 习近平
                    [start] => 45
                    [end] => 47
                    [dic_name] => 王强开发专用,允许删除
                    [id] => 14048
                )

            [3] => Array
                (
                    [word] => 2017
                    [start] => 58
                    [end] => 61
                    [dic_name] => 王强开发专用,允许删除
                    [id] => 14046
                )

        )

)

11、编辑 \api\models\ContentAudit.php,打印 $labelContent,代码如下:

 //标注关键词(设置 HTML DOM 解析的内部HTML文本)
 $labelContent = $this->setInnerText($this->content, $textScan['text'], $textScan['hit_content']);
 print_r($labelContent);
 exit;
 $this->content = $labelContent;

12、打印 标注关键词(设置 HTML DOM 解析的内部HTML文本)结果,符合预期,仅替换了纯文本中的关键词,如图7

图7

<div>第1层节点1
    <p>第2层节点1,
        <em class='key-word'>2017</em>,
        <em class='key-word'>习近平</em>
        <img border="0"  src="http://jnweb.sobeycloud.com/jntxqc//upload/Image/mrtp/bz/2017/08/14/1_e1ac78b7775a43e984a8842d57e703a3.jpg?1502693004515"/>
    </p>
    <p>第2层节点2</p>
    <p>第2层节点3,
        <em class='key-word'>习近平</em>
        <span>第3层节点1,
            <em class='key-word'>2017</em>
        </span>
    </p>第1层节点2
</div>

13、测试 html 富文本,其长度为包含中文 10000 字以上,本地环境响应时间在 1000 ms 以内,可以接受,生产环境可以优化,如图8

图8

 

永夜