
默认情况下,Twig 的优化器会移除 |raw 过滤器(因其被视为无副作用的“空操作”),导致通过 AST 解析时无法捕获该节点;需显式禁用相关优化选项以确保 FilterExpression 节点完整保留。
默认情况下,twig 的优化器会移除 `|raw` 过滤器(因其被视为无副作用的“空操作”),导致通过 ast 解析时无法捕获该节点;需显式禁用相关优化选项以确保 `filterexpression` 节点完整保留。
在使用 Twig 的 parse() + tokenize() 流程分析模板 AST 时,若目标是检测或处理特定过滤器(如 |raw),开发者常遇到一个隐性陷阱:|raw 节点在默认配置下根本不会出现在最终语法树中。
这是因为 Twig 内置的 OptimizerNodeVisitor 在启用优化时(默认开启部分优化),会主动移除 raw 过滤器——其逻辑认为:raw 仅用于取消自动转义,不改变表达式值本身,在编译阶段可安全剥离,交由渲染时的上下文决定是否转义。因此,即使模板中明确写了 {{ attributes|raw|lower }},解析出的 \Twig\Node\Expression\FilterExpression 节点链里也只会剩下 |lower,raw 已被提前消除。
✅ 正确解决方案是:禁用影响 raw 保留的优化项。推荐做法是在初始化 Twig\Environment 时,将 optimizations 配置设为 0(完全关闭优化),或至少排除 OPTIMIZE_RAW_FILTER(Twig ≥ 3.10+ 支持细粒度控制):
use Twig\Environment;
use Twig\Loader\FilesystemLoader;
use Twig\NodeVisitor\OptimizerNodeVisitor;
$loader = new FilesystemLoader('/path/to/templates');
$options = [
'cache' => sys_get_temp_dir(),
'optimizations' => 0, // 关键:彻底禁用所有 AST 优化
// 或更精准地(Twig v3.10+):
// 'optimizations' => OptimizerNodeVisitor::OPTIMIZE_ALL & ~OptimizerNodeVisitor::OPTIMIZE_RAW_FILTER,
];
$twig = new Environment($loader, $options);
// 后续解析流程保持不变
$source = new \Twig\Source(file_get_contents($templatePath), 'example.twig');
$tree = $twig->parse($twig->tokenize($source));
// 现在 listFunctionCalls 可正确命中 raw 过滤器
function listFunctionCalls($node, array &$list) {
if ($node instanceof \Twig\Node\Expression\FilterExpression) {
$filterNode = $node->getNode('filter');
$filterName = $filterNode->getAttribute('value') ?? '';
if ($filterName === 'raw') {
$list[] = [
'line' => $node->getLine(),
'parent' => get_class($node->getNode('node')),
];
}
}
foreach ($node as $child) {
listFunctionCalls($child, $list);
}
}
$functions = [];
listFunctionCalls($tree, $functions);
var_dump($functions); // 输出包含 'raw' 的匹配项⚠️ 注意事项:
- 关闭优化仅影响 AST 解析与分析阶段,不影响运行时性能或安全性;
|raw在渲染时仍按预期生效(即跳过自动转义)。 - 若项目依赖其他优化(如变量访问优化),可采用位运算精确剔除
OPTIMIZE_RAW_FILTER,避免过度降级(需确认 Twig 版本支持)。 - 始终对
|raw的使用保持警惕:它绕过 Twig 默认的 XSS 防护,应确保传入内容绝对可信。
通过此配置调整,即可稳定、可靠地在静态分析流程中识别 raw 过滤器,满足模板审计、安全扫描或自定义编译规则等进阶需求。

















