活动:限时7折!去购买
yii2 HtmlPurifier 过滤了a标签的name属性怎么处理,急急急!!! 有偿15元
2 151 2021-06-01

使用yii2 HtmlPurifier 组件过滤要输出的内容,发现过滤了a标签的name属性,想请教下怎么处理?

已结算
  • 2 个回答
  • 等了几天,看来这个问题还是留给我了。 为了避免xss攻击,yii2官方首选推荐HtmlPurifier,一些小白玩不转更喜欢自己去封装一堆的方法处理,这是不合适的。 我们来看问题。 name属性有些特殊,先看下对于普通属性是怎么处理的。

    假设 
    $content = '<a name="_name1" id="_id1" target="_blank">foo</a>';

    对于一般属性,比如 id, target ,或者其他属性,可以像下面这样处理

    use yii\helpers\HtmlPurifier;
    
    echo HtmlPurifier::process($content, function ($config) {
                $htmlDefinition = $config->getHTMLDefinition(true);
                $htmlDefinition->addAttribute('a', 'id', 'Text');
                $htmlDefinition->addAttribute('a', 'target', 'Enum#_blank');
            });

    结果如下:

    <a id="_id1" target="_blank">foo</a>

    也就是说我们添加一个attribute属性以及其对应的类型即可,具体的类型可以参考 HTMLPurifier_AttrTypes类 对于a标签的name属性,查了一些资料,说是可以设置 Attr.EnableID 处理,这个群里大神也给过你建议了。 我们来试一下

    $content = '<a name="name1">foo</a>';
    echo HtmlPurifier::process($content, function ($config) {
            $config->set('Attr.EnableID', true);
            $htmlDefinition = $config->getHTMLDefinition(true);
            $htmlDefinition->addAttribute('a', 'name', 'Text');
    });
    
    输出:<a name="name1">foo</a>

    结果ok,但是细心的小伙伴会发现,在我们最初的例子中,name="_name1",我们试一下这个属性值,会发现这样设置是无效的

    $content = '<a name="_name1">foo</a>';
    echo HtmlPurifier::process($content, function ($config) {
            $config->set('Attr.EnableID', true);
            $htmlDefinition = $config->getHTMLDefinition(true);
            $htmlDefinition->addAttribute('a', 'name', 'Text');
    });
    
    输出:<a>foo</a>

    这是怎么回事?鉴于官方对于HtmlPurifier的介绍并不多,我们看下源码。 找到 HTMLPurifier_AttrDef_HTML_ID 类,你可以全局搜索找到它。

    public function validate($id, $config, $context)
    {
        ......
            if (ctype_alpha($id)) {
                $result = true;
            } else {
                    if (!ctype_alpha(@$id[0])) {
                            return false;
                    }
                    ......
            }
            ......
    }

    到此就简单明了了,原来是被 ctype_alpha 函数处理了,为了安全起见,该函数只允许字符 [A-Za-z] 。 那现在我们有其他办法吗?我们继续从源码中找呀找...... 功夫不负有些人,我们找到 HTMLPurifier_HTMLModule_Name 类的 setup 方法,可以设置 HTML.Attr.Name.UseCDATA 就可以搞定我们的问题。

    $content = '<a name="_name2" id="foo">foo</a>';
    echo HtmlPurifier::process($content, function ($config) {
            $config->set('HTML.Attr.Name.UseCDATA', true);
            $htmlDefinition = $config->getHTMLDefinition(true);
    });
    
    输出:
    <a name="_name2">foo</a>

    另外其他属性仍然需要按照上面的方法设置。

    最佳答案
  • 果然有效,原来是我的name属性有特殊字符导致的,感谢狼哥!

登录 去赚佣金