PHP - 来自DB的eval代码

时间:2010-12-01 23:36:52

标签: php function eval

关于使用PHP的eval(),有数百篇甚至数千篇帖子;从数据库运行代码。通过我的所有搜索,我没有找到我的问题的答案(不久解释)。

首先,我将向您介绍我的申请。

我有三条存储在数据库中的有效代码记录:
例如:
[ '代码1']

$num1 = 1;
$num2 = 3;
$num3 = $num1+$num2;  //4

[ '代码2']

$num4 = $num3;        //4
$num5 = 5;
$num6 = $num4+$num5;  //9

[ 'CODE3']

$num7 = $num4;        //4
$num8 = $num6;        //9
$num9 = $num7+$num8;  //13
echo $num9;           //13

接下来我有一个调用和运行记录的功能:
例如:

function runCode($codeName) {
    // assume db connection is established
    $result = mysql_query("SELECT `code` FROM CodeStore WHERE `name` = '".$codeName."'");
    if ($result) {
        // Fetch one row
        $row = mysql_fetch_assoc($result);
        if (!$row) {
            die('No rows returned.');
        } else {
            return eval($row['code']);
        }
    } else {
        die('Invalid query: '.mysql_error());
    }
}

现在,需要做的是调用上面三个片段,一个接着一个,并让里面的变量($ numX)可以在彼此之间使用。
例如:

runCode('code1');
runCode('code2');
runCode('code3');

以上对db中三个片段的调用应该回显'13',但事实并非如此。还有我的问题:

如何在eval'd代码之外提供这些变量?

4 个答案:

答案 0 :(得分:2)

您没有从数据库中获取结果。 mysql_query() 会返回所有SELECT行。

function runCode($codeName) {
    // assume db connection is established
    $result = mysql_query("SELECT `code` FROM CodeStore WHERE `name` = '".$codeName."'");
    if ($result) {
        // Fetch one row
        $row = mysql_fetch_assoc($result);
        if (!$row)
            die('No rows returned.');
        $valid = eval($row['code']);
        if($valid) {
            return $valid;
        } else {
            die('Error executing: '.$codeName);
        }
    } else {
        die('Invalid query: '.mysql_error());
    }
}

请参阅mysql_fetch_assoc手册。

  

如何制作这些变量   在eval'd代码之外可用吗?

这有点困难,没有简单的方法可以做到这一点 eval'd代码片段不在同一范围内运行,因此您必须以某种方式保存当前符号表并在之后恢复它。

如果保留变量对您来说足够了,您可以尝试get_defined_vars(可能是compactextract的组合,或者自己替换这些函数。但是,此函数返回所有已定义变量的名称(包括$_GET等超级全局。) 如果您构建了一个聪明的diff算法,您可以比较在eval'd代码之前和之后定义的变量,并找出哪些变量是新的。祝你好运:)。

答案 1 :(得分:1)

除了svens's answer之外,我认为您没有正确检查eval()的返回值。来自PHP manual

  

eval()返回NULL,除非在计算代码中调用return,在这种情况下返回传递给return的值。如果计算代码中存在解析错误,则eval()返回FALSE并继续执行以下代码。

如果FALSE === eval($code),您应该只将其视为失败。即使这样,如果您的代码返回FALSE,也可能会遇到麻烦。

答案 2 :(得分:0)

DB中的变量在函数中是本地的。让它们成为全球性的。

因此,您可以使用global关键字来更改变量范围:

<?php
error_reporting (E_ALL);

$txt = array(
'$num1 = 1;
$num2 = 3;
global $num3; // make it global, will be used later
$num3 = $num1+$num2;
echo "num3=" . $num3 . "<br>"; //4',

'global $num3; // need to use value from this var
global $num4; // make it global, will be used later
$num4 = $num3;        //4
$num5 = 5;
global $num6; // make it global, will be used later
$num6 = $num3+$num5; 
echo "num6=" . $num6 . "<br>"; //9',

'global $num4; // need to use value from this var
global $num6; // need to use value from this var
$num7 = $num4;        //4
$num8 = $num6;        //9
global $num9; // make it global, will be used later (maybe)
$num9 = $num7+$num8;  //13
echo "num9=" . $num9 . "<br>";           //13'
);

function runCode($codeName) { // just for example
    eval($codeName);
}

runCode($txt[0]);
runCode($txt[1]);
runCode($txt[2]);
?>

此解决方案要求更改数据库中的现有代码。这可能很困难。

所以,这是一个不同的算法。首先,将所有代码块连接在一起。然后运行eval函数并将连接的代码传递给它。例如:

function composeCode($codeName) {
    // assume db connection is established
    $result = mysql_query("SELECT `code` FROM CodeStore WHERE `name` = '".$codeName."'");
    if ($result) {
        // Fetch one row
        $row = mysql_fetch_assoc($result);
        if (!$row) {
            die('No rows returned.');
        } else {
            return $row['code']; // CHANGED ORIGINAL CODE
        }
    } else {
        die('Invalid query: '.mysql_error());
    }
}
$code = '';
$code .= composeCode('code1');
$code .= composeCode('code2');
$code .= composeCode('code3');
eval($code);

答案 3 :(得分:0)

我肯定会使用“将一组代码名称传递给runCode()”方式。 您获得的好处:

  1. 您可以使用单个SELECT ... WHERE name IN ('code1', 'code2', ...)查询
  2. 获取所有代码段
  3. 您在片段之间共享变量,同时将它们保留在runCode()函数调用的范围内(以便在函数执行终止时它们被销毁)
  4. 然后,您可以通过两种方式操作:

    1. eval()从数据库结果中获取行时逐个
    2. implode()他们使用换行符来一次将单个代码段添加到eval()