关于PHP5中eval的问题

关于PHP5中eval的问题,php,eval,Php,Eval,我做PHP已经快一年了,我从来没有使用过函数eval(),尽管我知道它的用法。 但是我在SO中发现了很多关于它的问题。那么有人能给我举个简单的例子,说明有必要使用eval()?这是一种好的做法还是一种坏的做法?使用eval()是一种坏的做法,如果结果证明有必要实现某些东西,这通常是潜在设计错误的标志 我想不出有什么情况需要使用eval()。(即,使用其他语言构造或修复损坏的设计无法实现的东西。)有兴趣看看是否出现了任何真正的案例,其中eval实际上是必要的,或者替代方案会非常复杂 唯一需要它的实

我做PHP已经快一年了,我从来没有使用过函数
eval()
,尽管我知道它的用法。 但是我在SO中发现了很多关于它的问题。那么有人能给我举个简单的例子,说明有必要使用
eval()
?这是一种好的做法还是一种坏的做法?

使用
eval()
是一种坏的做法,如果结果证明有必要实现某些东西,这通常是潜在设计错误的标志

我想不出有什么情况需要使用
eval()
。(即,使用其他语言构造或修复损坏的设计无法实现的东西。)有兴趣看看是否出现了任何真正的案例,其中eval实际上是必要的,或者替代方案会非常复杂


唯一需要它的实例是执行来自外部源(例如数据库记录)的代码,但这本身就是一个设计错误。

糟糕的应用程序设计总是这样一个例子。

我曾经使用过eval。这是一个系统,用户可以使用从底层系统中获取的常量输入公式

像这样的字符串:

(N * (G - 2,7)) / E
然后使用系统评估中的值替换常量以获取值。评估似乎是最简单的方法。 该语句被过滤为只允许运算符和大写字母(没有两个相邻),因此这可能不是eval的“真实”用例,但它可以工作并且可读性很好

也就是说,任务中的系统非常庞大(超过200k行),这是唯一使用eval的地方。

eval()是实现“编译”模板引擎所必需的,比如Smarty,它使用自己的语言,并动态编译到php。这种发动机的主要功能通常是

 function render_template($path) {
    $code = file_get_contents($path);
    $php = $this->compile_to_php($code);
    eval($php);
 }

除此之外,每次使用“include”或“require”,实际上都是在暗中使用“eval”——因此,实际上,eval是最常用的php构造之一。

如果从安全角度看,使用eval是相当危险的。无论如何,很多模板引擎都使用eval,因为它们应该解析页面并获取一些变量或进行计算。

命令行php shell就是一个很好的例子。我想您可以使用实际的php代码,用C编写shell扩展,但用php编写shell扩展似乎更明智。因为提供代码的人应该已经拥有对系统的完全访问权限,所以根本没有安全问题。一旦用readline编译了php,这类东西实际上非常有用


Drupal(可选)使用eval来支持现成的可扩展性。要实现这一点,需要用户(通常仅限管理员)输入要评估的代码并将其存储在数据库中。Drupal也有很多人来确保没有安全漏洞。

评估在这种情况下很有用,例如在wordpress中注册cycle中的小部件 创建自定义主题:

class PluginusNetWPTF_Widget extends PluginusNetWPTF_Core {

    public static $widgets = array(
        'PLUGINUSNET_RECENT_POSTS_WIDGET' => array(
            'description' => 'Recent posts of selected category',
            'creation' => 'PluginusNet Recent Posts',
            'fields' => array('title' => 'Recent Posts', 'category' => '', 'post_number' => 3, 'show_thumbnail' => 1, 'show_exerpt' => 0),
            'view' => 'recent_posts',
            'form' => 'recent_posts_form'
        ),
            //'PLUGINUSNET_RECENT_POSTS_WIDGET2' => array(),
    );

    public static function register_widgets() {
        foreach (self::$widgets as $widget_class_name => $widget_data) {
            $code = '

class '.$widget_class_name.' extends WP_Widget {

    //Widget Setup
    function __construct() {
        //Basic settings
        $settings = array("classname" => __CLASS__, "description" => __(PluginusNetWPTF_Widget::$widgets[__CLASS__]["description"], PLUGINUSNET_THEME_NAME));

        //Creation
        $this->WP_Widget(__CLASS__, __(PluginusNetWPTF_Widget::$widgets[__CLASS__]["creation"], PLUGINUSNET_THEME_NAME), $settings);
    }

    //Widget view
    function widget($args, $instance) {
        $args["instance"] = $instance;
        echo PluginusNetWPTF_Widget::draw_html("widget/" . PluginusNetWPTF_Widget::$widgets[__CLASS__]["view"], $args);
    }

    //Update widget
    function update($new_instance, $old_instance) {
        $instance = $old_instance;
        if (!empty(PluginusNetWPTF_Widget::$widgets[__CLASS__]["fields"])) {
            foreach (PluginusNetWPTF_Widget::$widgets[__CLASS__]["fields"] as $key => $value) {
                $instance[$key] = $new_instance[$key];
            }
        }

        return $instance;
    }

    //Widget form
    function form($instance) {
        //Defaults
        $defaults = PluginusNetWPTF_Widget::$widgets[__CLASS__]["fields"];
        $instance = wp_parse_args((array) $instance, $defaults);
        $args = array();
        $args["instance"] = $instance;
        $args["widget"] = $this;
        echo PluginusNetWPTF_Widget::draw_html("widget/" . PluginusNetWPTF_Widget::$widgets[__CLASS__]["form"], $args);
    }

}

';
            eval($code);
            register_widget($widget_class_name);
        }
    }

}

但是,如果在我们自己的代码中使用,这似乎是不好的做法,是吗?:)好吧,我认为99%的人谈论“不好的做法”都无法解释原因。他们只是重复他们从别人那里听到的废话。但这不是“必要的”,如果你想的话,还有其他方法可以实现。把“坏习惯”变成一个循环论证:如果99%的人不能解释原因,那么几乎同样数量的人不能决定何时(以及如何)使用eval()是安全的,并且应该远离它,这难道不是一个安全的赌注吗?+1因为“坏习惯”无法解释原因。他们只是重复他们从别人那里听到的胡说八道。.+1用于消除毫无意义的短语“糟糕做法”的神秘性-任何时候当你调用
require
include
时,你实际上已经在幕后使用了eval()。例如表达式解析。虽然很少见,但我已经做过很多次了。当然,它是一个复杂而完整的表达式,而不是用最多圆括号支持的常规数学。这就是说,eval上通常的预防措施总是适用的:它们很慢(缓存结果修复),可能不必要(在我的情况下不是这样),并且存在安全问题(但是,相关代码由系统管理员自己运行,因此不是问题)。