如何防止转义Twig节点表达式?

时间:2015-07-22 16:54:26

标签: php twig

我正在尝试在spread attributes中实施Twig。我几乎得到了它,但我不确定如何防止输出被HTML转义。

我在Twig_Extension注册了我的新运营商:

public function getOperators() {
    return [
        [/* Unary Operators */
            '...' => array('precedence' => 10, 'class' => SpreadAttributes::class),
        ],
        [/* Binary Operators */
            // ...
        ]
    ];
}

我的班级看起来像这样:

class SpreadAttributes extends Twig_Node_Expression_Unary {
    public function compile(Twig_Compiler $compiler) {
        $compiler
            ->raw(\WXUtility::class . '::html_attrs(')
            ->subcompile($this->getNode('node'))
            ->raw(')');
    }

    public function operator(Twig_Compiler $compiler) {
        throw new \Exception("Unused");
    }
}

用法:

<label{{ ...label_attrs }}>

但编译后的输出如下:

 echo twig_escape_filter($this->env, WXUtility::html_attrs((isset($context["label_attrs"]) ? $context["label_attrs"] : $this->getContext($context, "label_attrs"))), "html", null, true);

我需要摆脱twig_escape_filterWXUtility::html_attrs已生成转义HTML。

如何防止逃跑?

我认为这是可行的,但它很复杂。在某个时间点,编译器会创建一个Twig_Node_Print来写出echo语句。在vendor/twig/twig/lib/Twig/NodeVisitor/Escaper.php的第73行,我们可以看到它在escapePrintNode中调用leaveNodeescapePrintNode调用$node->getNode('expr'),它会返回SpreadAttributes的实例。然后传递给isSafeFor,如果它是安全的(不需要转义),则返回true。如果不安全,则适用twig_escape_filter

因此我们只需要覆盖Twig_NodeVisitor_Escaper::isSafeForTwig_NodeVisitor_SafeAnalysis::getSafe

不推荐使用

$twig->removeExtension,因此我无法删除默认的Escaper扩展名。我想我必须覆盖Twig_Environment才能将其从构造函数中删除。然后从那里覆盖getNodeVisitors。然后isSafeFor。但Twig_Node_Expression没有任何有用的属性我可以检查;我能做的最好的是instanceof SpreadAttributes,这是一个重大的黑客攻击。

有没有更好的方法?

1 个答案:

答案 0 :(得分:1)

我不确定为什么不早点发生这种情况,但我终于看了twig_escape_filter。如果它是Twig_Markup的实例,它将不会转义字符串。因此,我们所要做的就是将输出包装在:

class SpreadAttributes extends Twig_Node_Expression_Unary {
    public function compile(Twig_Compiler $compiler) {
        $compiler
            ->raw(__CLASS__ . '::attrs(')
            ->subcompile($this->getNode('node'))
            ->raw(', $this->env->getCharset())'); // not sure if this is the best way to pass the charset along, but it seems to work
    }

    public function operator(Twig_Compiler $compiler) {
        throw new \Exception("Unused");
    }

    public static function attrs($attrs, $charset) {
        return new Twig_Markup(WXU::html_attrs($attrs), $charset);
    }
}

的Bam!不再逃避。

有关html_attrs的示例实现,请参阅Ptilz