我正在尝试在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_filter
,WXUtility::html_attrs
已生成转义HTML。
如何防止逃跑?
我认为这是可行的,但它很复杂。在某个时间点,编译器会创建一个Twig_Node_Print
来写出echo
语句。在vendor/twig/twig/lib/Twig/NodeVisitor/Escaper.php
的第73行,我们可以看到它在escapePrintNode
中调用leaveNode
。 escapePrintNode
调用$node->getNode('expr')
,它会返回SpreadAttributes
的实例。然后传递给isSafeFor
,如果它是安全的(不需要转义),则返回true。如果不安全,则适用twig_escape_filter
。
因此我们只需要覆盖Twig_NodeVisitor_Escaper::isSafeFor
或Twig_NodeVisitor_SafeAnalysis::getSafe
。
$twig->removeExtension
,因此我无法删除默认的Escaper
扩展名。我想我必须覆盖Twig_Environment
才能将其从构造函数中删除。然后从那里覆盖getNodeVisitors
。然后isSafeFor
。但Twig_Node_Expression
没有任何有用的属性我可以检查;我能做的最好的是instanceof SpreadAttributes
,这是一个重大的黑客攻击。
有没有更好的方法?
答案 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。