什么时候(如果有的话) eval 不是邪恶的?

发布于 2024-09-15 08:31:30 字数 1106 浏览 5 评论 0原文

我听说过很多放置 PHP 的eval 函数是 通常不是答案。根据 PHP 5.3 的 LSB 和 < a href="http://php.net/manual/en/functions.anonymous.php" rel="nofollow noreferrer">闭包 我们已经没有理由依赖 eval 或 create_function

是否存在任何可能的情况,其中eval是 PHP 5.3 中最好(唯一?)的答案?

这个问题不是关于eval总体上是否是邪恶的,因为它显然不是。

答案摘要:

  • 评估数值表达式(或 PHP 的其他“安全”子集)
  • 单元测试
  • 交互式 PHP “shell”
  • 受信任的 var_export 反序列化
  • 一些模板语言
  • 为管理员和/或黑客创建后门
  • var_export 的兼容性PHP 5.3
  • 检查语法(可能不安全)

I've heard many places that PHP's eval function is often not the answer. In light of PHP 5.3's LSB and closures we're running out of reasons to depend on eval or create_function.

Are there any conceivable cases where eval is the best (only?) answer in PHP 5.3?

This question is not about whether eval is evil in general, as it obviously is not.

Summary of Answers:

  • Evaluating numerical expressions (or other "safe" subsets of PHP)
  • Unit testing
  • Interactive PHP "shell"
  • Deserialization of trusted var_export
  • Some template languages
  • Creating backdoors for administers and/or hackers
  • Compatibility with < PHP 5.3
  • Checking syntax (possibly not safe)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

厌倦 2024-09-22 08:31:30

如果您正在编写恶意软件,并且想让试图清理您的系统管理员的日子不好过。根据我的经验,这似乎是最常见的用例。

If you're writing malware and you want to make life hard for the sysadmin who's trying to clean up after you. That seems to be the most common usage case in my experience.

嘦怹 2024-09-22 08:31:30

Eric Lippert 总结了三篇博客文章的评估。这是一本非常有趣的读物。

据我所知,以下是使用 eval 的一些唯一原因。

例如,当您根据用户输入构建复杂的数学表达式时,或者当您将对象状态序列化为字符串以便可以存储或传输以及稍后重构时。

Eric Lippert sums eval up over three blog posts. It's a very interesting read.

As far as I'm aware, the following are some of the only reasons eval is used.

For example, when you are building up complex mathematical expressions based on user input, or when you are serializing object state to a string so that it can be stored or transmitted, and reconstituted later.

不爱素颜 2024-09-22 08:31:30

eval 的主要问题是它成为恶意代码的网关。因此,您永远不应该在可以从外部利用它的上下文中使用它,例如用户提供的输入。

一种有效的用例是模拟框架。

来自 PHPUnit_Framework_TestCase::getMock() 的示例

// ... some code before

    $mock = PHPUnit_Framework_MockObject_Generator::generate(
      $originalClassName,
      $methods,
      $mockClassName,
      $callOriginalClone,
      $callAutoload
    );

    if (!class_exists($mock['mockClassName'], FALSE)) {
        eval($mock['code']);
    }

// ... some code after

实际上,generate 方法中发生了很多事情。通俗地说:PHPUnit 将采用 generate 的参数并从中创建一个类模板。然后它将eval该类模板以使其可用于实例化。当然,这样做的目的是让 TestDoubles 模拟 UnitTests 中的依赖关系。

The main problem with eval is it being a gateway for malicious code. Thus you should never use it in a context where it can be exploited from the outside, e.g. user provided input.

One valid UseCase would be in Mocking Frameworks.

Example from PHPUnit_Framework_TestCase::getMock()

// ... some code before

    $mock = PHPUnit_Framework_MockObject_Generator::generate(
      $originalClassName,
      $methods,
      $mockClassName,
      $callOriginalClone,
      $callAutoload
    );

    if (!class_exists($mock['mockClassName'], FALSE)) {
        eval($mock['code']);
    }

// ... some code after

There is actually a lot of things happening in the generate method. In laymens terms: PHPUnit will take the arguments to generate and create a class template from it. It will then eval that class template to make it available for instantiation. The point of this is to have TestDoubles to mock dependencies in UnitTests of course.

你在我安 2024-09-22 08:31:30

如果您正在编写一个解释和执行 PHP 代码的网站,就像交互式 shell 一样。

...

我是一个系统人员,这就是我所拥有的一切。

If you are writing a site that interprets and executes PHP code, like an interactive shell would.

...

I'm a systems guy, that's all I got.

疯到世界奔溃 2024-09-22 08:31:30

您可以使用 eval 来创建临时类:

function myAutoLoad($sClassName){

   # classic part
   if (file_exists($sClassName.'.php'){

      require $sClassName.'.php';

    } else {

      eval("
            class $sClassName{
                public function __call($sMethod,$aArgs){
                     return 'No such class: ' . $sClassName;
                 }
                }");

    }

} 

当然,尽管使用非常有限(一些 API 或可能是 DI 容器、测试框架、必须处理具有动态结构的数据库的 ORM、代码游乐场)

You can use eval to create ad-hoc classes:

function myAutoLoad($sClassName){

   # classic part
   if (file_exists($sClassName.'.php'){

      require $sClassName.'.php';

    } else {

      eval("
            class $sClassName{
                public function __call($sMethod,$aArgs){
                     return 'No such class: ' . $sClassName;
                 }
                }");

    }

} 

Although, of course, usage is quite limited (some API's or maybe DI containers, testing frameworks, ORMs which have to deal with databases with dynamic structure, code playgrounds)

不弃不离 2024-09-22 08:31:30

eval 是一个可用于检查语法错误的构造。

假设您有以下两个 PHP 脚本:

script1.php

<?php
// This is a valid syntax
$a = 1;

script2.php

<?php
// This is an invalid syntax
$a = abcdef

您可以使用 eval 检查语法错误:

$code1 = 'return true; ?>'.file_get_contents('script1.php');
$code2 = 'return true; ?>'.file_get_contents('script2.php');

echo eval($code1) ? 'script1 has valid syntax' : 'script1 has syntax errors';
echo eval($code2) ? 'script2 has valid syntax' : 'script2 has syntax errors';

php_check_syntax (无论如何已弃用并删除),代码将不会被执行。

编辑:

另一个(首选)替代方案是 php -l 。如果您无权访问 system() 或 shell 执行命令,则可以使用上述解决方案。

此方法可以在代码中注入类/函数。执行此操作之前,请务必强制执行 preg_replace 调用或 namespace,以防止它们在后续调用中执行。

至于OP主题:什么时候(如果有的话)eval不是邪恶的? eval根本就不是邪恶的。程序员无缘无故地使用eval是邪恶的。 eval 可以缩短您的代码(例如数学表达式评估)。

eval is a construct that can be used to check for syntax errors.

Say you have these two PHP scripts:

script1.php

<?php
// This is a valid syntax
$a = 1;

script2.php

<?php
// This is an invalid syntax
$a = abcdef

You can check for syntax errors using eval:

$code1 = 'return true; ?>'.file_get_contents('script1.php');
$code2 = 'return true; ?>'.file_get_contents('script2.php');

echo eval($code1) ? 'script1 has valid syntax' : 'script1 has syntax errors';
echo eval($code2) ? 'script2 has valid syntax' : 'script2 has syntax errors';

Unlike php_check_syntax (which is deprecated and removed anyway), the code will not be executed.

EDIT:

The other (preferred) alternative being php -l. You can use the solution above if you don't have access to system() or shell execution commands.

This method can inject classes/functions in your code. Be sure to enforce a preg_replace call or a namespace before doing so, to prevent them from being executed in subsequent calls.

As for the OP topic: When (if ever) is eval NOT evil? eval is simply not evil. Programmers are evil for using eval for no reason. eval can shorten your code (mathematical expression evaluation, per example).

憧憬巴黎街头的黎明 2024-09-22 08:31:30

我发现有时一种语言的大多数功能都是有用的。毕竟,即使 GOTO 有其支持者。 Eval 在许多框架中都有使用,并且使用得很好。例如,CodeIgniter 使用 eval 来区分 PHP 4 和 PHP 5 实现的类层次结构。允许执行 PHP 代码的博客插件肯定需要它(这是 Expression Engine、Wordpress 等中可用的功能)。我还将它用于一个网站,其中一系列视图几乎相同,但每个视图都需要自定义代码,并且创建某种疯狂的规则引擎要复杂得多且速度慢得多。

虽然我知道这不是 PHP,但我发现 Python 的 eval 使基本计算器的实现变得更加简单。

基本上,问题是:

  1. eval 是否使它更容易阅读?我们的主要目标之一是与其他程序员交流我们编写本文时的想法。在 CodeIgniter 示例中,他们想要实现的目标非常清楚。
  2. 还有别的办法吗?如果您使用 eval(或变量,或任何其他形式的字符串查找或反射语法),很可能还有另一种方法可以实现。您是否已用尽其他选择?您的输入集是否受到合理限制?可以使用switch语句吗?

其他考虑因素:

  1. 它可以安全吗?有没有办法让一段杂散的代码进入 eval 语句?
  2. 可以使其一致吗?在给定输入的情况下,您能否始终一致地产生相同的输出?

I've found that there are times when most features of a language are useful. After all, even GOTO has had its proponents. Eval is used in a number of frameworks and it is used well. For example, CodeIgniter uses eval to distinguish between class hierarchy of PHP 4 and PHP 5 implementations. Blog plugins which allow for execution of PHP code definitely need it (and that is a feature available in Expression Engine, Wordpress, and others). I've also used it for one website where a series of views are almost identical, but custom code was needed for each and creating some sort of insane rules engine was far more complicated and slower.

While I know that this isn't PHP, I found that Python's eval makes implementation of a basic calculator much simpler.

Basically, here's the question:

  1. Does eval make it easier to read? One of our chief goals is communicating to other programmers what was going through our head when we wrote this. In the CodeIgniter example it is very clear what they were trying to accomplish.
  2. Is there another way? Chances are, if you're using eval (or variable variables, or any other form of string look-up or reflection syntax), there is another way to do it. Have you exhausted your other options? Do you have a reasonably limitted input set? Can a switch statement be used?

Other considerations:

  1. Can it be made safe? Is there a way that a stray piece of code can work its way into the eval statement?
  2. Can it be made consistent? Can you, given an input, always and consistently produce the same output?
禾厶谷欠 2024-09-22 08:31:30

合适的场合(考虑到缺乏简单的替代方案)是使用 var_export 序列化可信数据并且有必要对其进行反序列化。当然,它不应该以这种方式序列化,但有时错误已经完成。

An appropriate occasion (given the lack of easy alternatives) would be when trusted data was serialized with var_export and it's necessary to unserialize it. Of course, it should never have been serialized in that fashion, but sometimes the error is already done.

那伤。 2024-09-22 08:31:30

我想,应该在代码实际需要编译的地方使用 eval。我的意思是这样的情况,比如模板文件编译(为了性能而将模板语言编译成 PHP)、插件钩子编译、出于性能原因的编译等。

I suppose, eval should be used where the code is actually needs to be compiled. I mean such cases like template file compilations (template language into PHP for the sake of performance), plugin hook compilation, compilations for performance reasons etc.

醉南桥 2024-09-22 08:31:30

您可以使用 eval 创建一个设置,以便在安装系统后添加代码。通常,如果您想更改服务器上的代码,则必须添加/更改现有的 PHP 文件。另一种方法是将代码存储在数据库中并使用 eval 来执行它。不过,您必须确保添加的代码是安全的。

将其视为一个插件,只是一个可以做任何事情的插件...

您可以想到一个网站,该网站允许人们贡献代码片段,然后用户可以将这些代码片段动态添加到他们的网页中 - 而无需他们实际将代码保留在网站上。网络服务器文件系统。不过,您需要的是批准流程......

You could use eval to create a setup for adding code after the system installed. Normally if you would want to change the code on the server you would have to add/change existing PHP files. An alternative to this would be to store the code in a database and use eval to execute it. You'd have to be sure that the code added is safe though.

Think of it like a plugin, just one that can do about anything...

You could think of a site that would allow people to contribute code snippets that the users could then dynamically add into their web pages - without them actually persisting code on the webservers filesystem. What you would need is an approval process though...

一口甜 2024-09-22 08:31:30

这个 eval 争论实际上是对 php 的一个很大的误解。人们被洗脑认为 eval 是邪恶的,但通常他们使用 include 没有问题,尽管 include 本质上是同一件事。 Include foo 与 eval file_get_contents foo 相同,因此每次包含某些内容时,您都会犯下 eval 的大罪。

This eval debate is actually one big misunderstanding in context of php. People are brainwasched about eval being evil, but usually they have no problem using include, although include is essentially the same thing. Include foo is the same as eval file_get_contents foo, so everytime you're including something you commit the mortal sin of eval.

青衫负雪 2024-09-22 08:31:30

兼容性。提供 PHP4 后备方案是很常见的。但同样,也可能希望在 5.3 中模拟 PHP5.4 功能,例如 SplString。虽然简单地提供两个包含变体(include.php4 与 include.php5)很常见,但有时使用 eval() 会更有效或更具可读性:

 $IMPL_AA = PHP_VERSION >= 5 ? "implements ArrayAccess" : "";
 eval(<<<END
     class BaseFeature $IMPL_AA {

在这种情况下,代码可以在 PHP4 上工作,但仅在 PHP5 上公开更好的 API/语法。请注意,该示例是虚构的。

Compatibility. It's quite frequent to provide PHP4 fallbacks. But likewise it's a possible desire to emulate PHP5.4 functionality in 5.3, as example SplString. While simply providing two include variants (include.php4 vs. include.php5) is frequent, it's sometimes more efficient or readable to resort to eval():

 $IMPL_AA = PHP_VERSION >= 5 ? "implements ArrayAccess" : "";
 eval(<<<END
     class BaseFeature $IMPL_AA {

Where in this case the code would work on PHP4, but expose the nicer API/syntax only on PHP5. Note that the example is fictional.

望喜 2024-09-22 08:31:30

当我有一个 php 引擎的机器人与我通信时,我使用了 eval,我可以告诉它通过 EVAL:此处的 php 命令执行命令。仍然是邪恶的,但如果您的代码不知道会发生什么(如果您从数据库中提取一段 PHP 代码),那么 eval 是唯一的解决方案。

I've used eval when I had a php-engined bot that communicated with me and I could tell it to do commands via EVAL: php commands here. Still evil, but if your code has no idea what to expect (in case you pull a chunk of PHP code from a database) eval is the only solution.

喜爱纠缠 2024-09-22 08:31:30

因此,这对于所有带有 eval 的语言都适用:

基本上,除了少数例外,如果您正在构建传递给 eval 的值或从非可信源获取它你做错了什么。如果您在静态字符串上调用 eval,同样如此。

除了在运行时初始化解析器的性能问题和安全问题之外,您通常还会弄乱类型系统。

更严重的是,事实证明,在绝大多数情况下,有更优雅的解决方案。然而,与其完全禁止该构造,不如将其视为人们可能goto的做法。两者都有合法的用途,但这是一个很好的危险信号,应该让您思考是否以正确的方式解决问题。

根据我的经验,我只发现属于插件和特权用户(例如网站管理员,而不是此类用户)扩展类别的合法用途。基本上,充当来自可信来源的代码的东西。

So, this should hold true for all languages with eval:

Basically, with few exceptions, if you are building the value passed to eval or getting it from a non-truested source you are doing something wrong. The same holds true if you are calling eval on a static string.

Beyond the performance problems with initializing the parser at runtime, and the security issues, You generally mess with the type system.

More seriously, it's just been shown that in the vast majority of cases, there are much more elegant approaches to the solution. However, instead of banning the construct outright, it's nice to think of it as one might goto. There are legitimate uses for both, but it is a good red flag that should get you thinking about if you are approaching the problem the correct way.

In my experience, I've only found legitimate uses that fall in the categories of plugins and privileged user (for instance, the administrator of a website, not the user of such) extensions. Basically things that act as code coming from trusted sources.

折戟 2024-09-22 08:31:30

不是直接使用,而是 preg_replace 的 /e 修饰符利用 eval 并且非常方便。请参阅 http://php.net/preg_replace 上的示例 #4。

它是否是邪恶/坏是主观的,完全取决于你在特定背景下认为“好”的东西。当处理不受信任的输入时,它通常被认为是不好的。但是,在其他情况下它可能很有用。想象一下在极端的截止日期压力下编写一次性数据转换脚本。在这种情况下,如果 eval 起作用并且使事情变得更容易,我就很难称其为邪恶。

Not direct use but the /e modifier to preg_replace utilizes eval and can be quite handy. See example #4 on http://php.net/preg_replace.

Whether or not it's evil/bad is subjective and depends entirely on what you consider "good" in a specific context. When dealing with untrusted inputs it is usually considered bad. However, in other situations it can be useful. Imagine writing a one-time data conversion script under extreme deadline pressure. In this situation, if eval works and makes things easier, I would have trouble calling it evil.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文