在 PHP 字符串中解析变量

3

注意: 这里的Eval完全是基于知识的运用,被解析的字符串仅由管理员输入,目的是将指令存储在数据库中,而不限制指令。 如果您有更好的替代方案,我们始终欢迎,但请不要只说“eval不好”。

我在PHP中有一个字符串,例如

$myString = "(35*$var1*64)/$var2";

我想要对这个字符串进行eval()操作,但在此之前,我希望修改字符串中的所有变量,使其符合以下格式:

$var2 -> $_POST['var2']

$myString 变量之后可能有空格,也可能没有。

当我使用 eval 函数执行 $myString 时,PHP 抛出错误 "Undefined variable $var1"。PHP 会读取字符串并解析其中的变量,所以我猜应该有一种方法可以解析字符串中的所有变量。

输出结果应该是:

$myStringParsed = "(35*$_POST['var1']*64)/$_POST['var2']";

或者等价物。

1
不要使用 " 作字符串,因为解析器会将变量添加到字符串中,而这不会进入 eval 函数。另外,你的 eval 代码在哪里? - Justinas
$myStringParsed = "(35*$_POST[$var1]*64)/$_POST[$var2]"; 应该改为 $myStringParsed = "(35*{$_POST[$var1]}*64)/{$_POST[$var2]}";,所以请添加 { } - nl-x
3个回答

1

也许不是最好的解决方案,但您可以预处理 $_POST 变量并生成如下 $variablesString:

$variablesString = '';
foreach($_POST as $key => $val) {
    $variablesString .= '$' . $key . ' = ' . $val . ';' . PHP_EOL;
}

eval($variablesString . PHP_EOL . $myString)

对于字符串支持,您可以检查 $val 是否为字符串,如果是,则用引号括起来。

第二种方法

$myString = 'return (35 * $var1 * 64) / $var2;';
$re = "/\\$(\\w*)/im";

preg_match_all($re, $myString, $matches);

foreach($matches[1] as $match) {
    $search = '$' . $match;
    $replace = '$_POST[\'' . $match . '\']';
    $myString = str_replace($search, $replace, $myString);
}
echo eval($myString);

你可以在这里检查它。

我可以在POST中发送任何东西,例如0; unlink('/') - Pred
可以。但是Nathan注意到:“这里使用了完全知识的Eval,解析的字符串仅由管理员输入”。 - Igor R
这仍然值得注意,因为不仅是楼主会阅读这个帖子。你知道我们有像搜索引擎这样的太空技术,可以在一个神秘的网络叫做互联网上找到东西。 - Pred
这个解决方案是我现在正在使用的。问题是我必须为$_POST中的每个元素创建变量。此外,问题集中在字符串解析上。这个解决方案在我的情况下有效,但可能有其他情况下它不够高效。如果没有人提供解析解决方案,我将接受这个。 - Turtle
1
@IgorRynkovoy 是的,这正是我想要的。当 * 接触到 $var2 时也有效。我还不懂正则表达式,对于 *, +, -, / 是否有效呢?在您的示例上尝试了一下,似乎可以。无论如何,这就是解决方案。谢谢。 - Turtle
显示剩余2条评论

0

你正在使用错误的字符串包含引号。请使用'(35*$var1*64)/$var2'

//$var1 = $_POST['var1'];
//$var2 = $_POST['var2'];

$var1 = '10';
$var2 = '20';

$myString = 'return (35 * $var1 * 64) / $var2;';

echo eval($myString);
//1120

Working example of eval


If you want to take any variable from POST, than you can use extract() to get array keys as variables with associated values:

<?php
// Change it to real $_POST
$POST = [
    'var1' => '10',
    'var2' => '20',
];

extract($POST, EXTR_SKIP);

$myString = 'return (35 * $var1 * 64) / $var2;';

echo eval($myString);


谢谢你的回答。不,变量$var1和$var2没有被定义。我只是指出它们被PHP解析了。我想替换这些表达式。 - Turtle
@Nathan 你不能使用未定义的变量。这就是为什么我已经注释了如何使用 $_POST 定义它们。此外,如果 $var2 没有被定义,那么 $_POST[$var2] 就没有意义。 - Justinas
对不起,你是正确的。我的问题是错误的。事实是$var2没有被定义,但是$_POST['var2']有定义。我忘记去掉了$符号。已经编辑过问题了。 - Turtle
@Nathan,请查看更新的答案,了解如何将POST提取为变量。 - Justinas

0

假设您的意思是...

$myString = '(35*$var1*64)/$var2';

一个比ASGM建议的解决方案更加健壮(考虑$myvar10)的方法是:

$replace=array(
   '/\b\$var1\b/'=>$_POST['var1'], 
   '/\b\$var2\b/'=>$_POST['var2'],
   ...
);
$interpolated=preg_replace(array_keys($replace)
    , $replace, $myString);

请注意,我建议您使用文字插值而不是替换一个占位符。除了消除不必要的处理外,这还意味着您可以检查生成的字符串内容,以确保它仅包含数字和运算符(如果适用,则包括受限数量的函数)。

似乎问题不太清楚。我事先无法知道变量的名称是$var1还是$myVar或类似的名称。我想解析字符串以查找任何可能是变量的表达式。 - Turtle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接