关于使用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代码之外提供这些变量?
答案 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
(可能是compact
和extract
的组合,或者自己替换这些函数。但是,此函数返回所有已定义变量的名称(包括$_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()”方式。 您获得的好处:
SELECT ... WHERE name IN ('code1', 'code2', ...)
查询runCode()
函数调用的范围内(以便在函数执行终止时它们被销毁)然后,您可以通过两种方式操作:
eval()
从数据库结果中获取行时逐个implode()
他们使用换行符来一次将单个代码段添加到eval()
。