我搜索了不同的表格,但不明白如何解决这里首先发现的问题(first link,second link),但它给了我eval中的错误。我无法弄清楚如何在foreach循环中解决该代码。
foreach($_POST as $key => $value) {
if(!strstr($key, 'removeFile')){
//initialize variables using eval
eval("$" . $key . " = '" . sanitize($value) . "';");
}
}
答案 0 :(得分:2)
首先,我对您的代码存在的问题:
eval
是非常非常需要的,非常危险,谨慎使用。我已经在PHP中开发了超过10年,并且从未真正遇到需要eval
的情况。这也不例外。不需要评估$_POST
数组。这很棒,但是有这样的特殊功能,例如:filter_input_array
,array_filter
以及更多......更不用说现成的开源项目和框架了已经包含一个可靠的请求验证组件。strstr
,但要厌倦返回不同类型的函数(如strstr
:如果返回false
,则返回0
没有找到针,但如果在干草堆字符串的开头找到针,则返回if
。您的sanitize($value)
声明可能无法正常使用。$sanitized = array_filter($_POST, 'sanitize');//call sanitize on all values
foreach ($sanitized as $key => $value)
{
if (!isset($$key) && strstr($key, 'removeFile') === false)
$$key = $value;
}
值不包含任何单引号。为什么?因为如果他们这样做,你最终会在你的evaled字符串中出现语法错误尽管如此,您可以使用变量 轻松编写代码 添加一个简单的检查,不要踩到现有变量范围:
$_POST
但实际上,null
值属于一起,它们是请求的一部分,并且应该保持分组...在数组中,或在某种对象中。不要将每个值分配给它自己的变量,因为很快你就会忘记设置哪些变量,哪些变量没有。使用unset变量创建该变量,赋值//request 1: POST => id=123&foo=bar
foreach ($sanitized as $k => $v)
$$k = $v;
$query = 'SELECT x, y, z FROM tbl WHERE id = ?';//using posted ID as value
$stmt = $db->prepare($query);
$stmt->execute(array($id));
,因此您现在所拥有的 非常 容易出错的代码:
$id
一切都很好,因为$_POST
已设置,但从不信任网络,请不要认为只是因为设置了//request 2: POST => foo=bar&page=2
foreach ($sanitized as $k => $v)
$$k = $v;
$query = 'SELECT x, y, z FROM tbl WHERE id = ?';//using posted ID as value
$stmt = $db->prepare($query);
$stmt->execute(array($id));//id is null
所有密钥将被设置,它们的值将是正确的:
//request 3: POST => id=123&foo=bar&page=2
foreach ($sanitized as $k => $v)
$$k = $v;
//$id is 123, $foo is bar and $page = 2
$query = 'SELECT x, y, z FROM tbl WHERE id = ? LIMIT 10';//using posted ID as value
//a lot more code containing this statement:
$page = someFunc();
$log->write('someFunc returned log: '.$page);
//more code
$offset = 10*($page-1);//<-- page is not what we expected it to be
$query .= sprintf(' OFFSET %d', $offset);
$stmt = $db->prepare($query);
$stmt->execute(array($id));
现在我们遇到了问题。这只是一个示例,说明代码可能会导致问题。想象一下脚本增长了一点,看看这个:
{{1}}
现在这可能看起来很牵强,而且很愚蠢,但请相信我:所有这些事情发生,比我想知道的还要多。添加一些意外覆盖现有变量的代码会一直发生。特别是在程序代码中。不要盲目解开阵列。保留该单个变量,并使用键来避免:
答案 1 :(得分:1)
作为您链接的帖子的第一个答案,问题是当使用双引号时,PHP认为您的eval()
代码以变量开头。由于情况并非如此,您有两种选择。使用单引号并记住转义单引号,在代码中声明一个字符串或转义美元符号。
加分说明
对于您要解决的问题,存在更优雅的解决方案。我能想到的最佳解决方案是使用extract
函数。这有两个主要好处。
您可以使用的一个标志是EXTR_PREFIX_ALL
。这将使用您自己的前缀为所有提取的变量添加前缀。然后,您将使用前缀“PREFIX_”访问变量,如下所示:
$array = [
'variable1' => 'foo',
'variable2' => 'bar'
];
extract($array, EXTR_PREFIX_ALL, 'PREFIX_');
$value1 = $PREFIX_variable1; // Equals: foo
$value2 = $PREFIX_variable2; // Equals: bar
关于代码注入的一点
假设您有一些代码:
$login = false;
$login
变量确定用户是否已登录。
然后在某处使用''extract'函数和以下数组而不使用任何标志。
$array = [
'login' => true,
'foo' => 'bar'
];
extract($array);
现在,您的$login
变量将设置为true
,发布数据的用户将覆盖初始设置,并且无需有效登录即可访问您的网站。请记住,这是一个过于简化的示例,但仍然有效。
为了克服这个问题,您可以像我之前展示的那样使用标志EXTR_SKIP
或前缀。如果已经定义了具有相同名称的变量,则EXTR_SKIP
标志将跳过数组元素。所以现在你的代码不会覆盖你的$login
变量。
extract($array, EXTR_SKIP); // Skip existing variables
// Or
extract($array, EXTR_PREFIX_ALL, 'prefix'); // Prefix them all.
希望这可以为您的需求提供正确的选择。
问候。