eval()是高危操作,因将字符串直接当代码执行而抹除数据与代码边界;应禁用并改用配置数组、表达式引擎、模板引擎等安全替代方案。

PHP 的 eval() 函数本质是把字符串当作 PHP 代码直接执行,只要输入可控,就等于把服务器控制权交给了攻击者。它不是“有点危险”,而是高危操作的典型代表——一旦出现在生产环境且处理用户输入,基本等同于敞开后门。
为什么 eval() 一用就出事?
核心问题不是“它能不能算”,而是“谁决定这段字符串是代码”。eval() 完全抹掉了数据与代码的边界:
- 用户通过 URL、表单、API 或配置文件传入的内容,可能被拼进字符串后直接送进
eval() - 哪怕只有一处没过滤,攻击者就能注入类似
system('id'); unlink('config.php');这样的语句 - 转义变量没用——因为攻击者操纵的是整个代码结构,比如把
"func('$input')"变成"func(''); system('ls /'); //" - 正则黑名单容易绕过(Unicode 零宽字符、编码混淆、大小写混用),白名单又极难全覆盖
真正安全的替代思路
不靠“加固 eval”,而是换掉执行逻辑本身:
-
只是解析配置或规则? 用关联数组或 JSON:把行为定义为键值对,运行时查表调用对应函数,例如
$handlers[$action]['callback']($data) -
需要计算数学表达式? 用
symfony/expression-language或hoa/compiler,它们只认字面量和安全运算符,拒绝函数调用和副作用 - 要渲染动态内容? 用 Twig、Blade 等模板引擎,自带沙箱机制,变量自动转义,逻辑受严格限制
-
必须生成函数? 在可信上下文中优先用
new \ReflectionFunction(...)或匿名函数,避免字符串拼接代码
如果真没法绕开 eval(极少数场景)
必须满足全部条件才可考虑,缺一不可:
立即学习“PHP免费学习笔记(深入)”;
- 输入完全来自内部可信源(如运维人员手动维护的 JSON 配置文件,且该文件权限严格限制)
- 执行前对整条待执行字符串做 AST 解析(如用
nikic/PHP-Parser),确保只含允许的节点类型(Literal、BinaryOp) - 运行在隔离环境中:禁用
exec、system、shell_exec等所有危险函数,启用open_basedir,最好跑在 Docker 容器里 - 绝不依赖
try/catch捕获异常来“兜底”——错误拦不住 RCE
安全不是加一层防护,而是从设计源头拒绝把字符串当代码执行。



















