在代码中使用 eval(),您将如何避免它?
Using eval() in the code, and how would you avoid it?
在我的代码中,我想尝试获取 $_POST 或 $_GET 变量,并在请求一次后立即取消设置。
这个函数return是使用的方法,很简单。不幸的是,我不能简单地直接或通过引用 return $_POST 或 $_GET 变量,因为我无法取消设置它们(通过引用取消设置不起作用)。所以,我 return 变量名:
class Input {
protected function interface_get($method): string {
switch ($method) {
case 'post':
return '_POST';
break;
case 'get':
return '_GET';
break;
case 'ajax':
// Not supported yet.
return null;
break;
default:
return null; // returns '_GET' or '_POST'
}
}
public function fetch_eval(string $method, ?string $request = null) { // ...fetch('post', 'username')
if ($request !== null) {
$request = '[\'' . $request . '\']'; // "['username']"
}
$request = $this->interface_get($method) . $request; #"$_POST['username']"
eval('$return = $' . $request . ';'); #$return = $_POST['username'];
eval('unset($' . $request . ');'); #unset($_POST['username']);
return $return;
}
public function fetch_varvar(string $method, ?string $request = null) {
$interface = $this->interface_get($method); #$interface = '_POST';
if ($request === null) {
$return = (${$interface});
unset(${$interface});
} else {
$return = ${$interface}; #"Notice: Undefined variable: _POST in [...]"
$return = ${$interface}[$request]; #"Warning: Illegal string offset 'email' in [...]"
unset($interface[$request]);
}
return $result;
}
}
// set $_POST = ['email'=>'spam@me'];
$in = new Input();
echo $in->fetch_eval('post', 'email'); #'spam@me'
// $_POST = [];
// set $_POST = ['email'=>'spam@me']; again
echo $in->fetch_varvar('post', 'email'); #'Notice: Undefined variable: _POST [...]'
有趣的部分是处理输出。这是我的获取函数,我认为这是最简单但最脏的方法:
我尝试使用可变变量,它在测试脚本中有效:
// $_POST = [0 => 5, 'bob' => 5];
$e = '_POST';
$var = 'bob';
echo ${$e}[$var]; #5
unset(${$e}[$var]);
echo ${$e}[$var ]; #NOTICE Undefined index: bob on line number 22
// Works as expected.
但它在我的脚本中不起作用 (Undefined variable: _POST [...]
)。我想可能是因为它在class中,但无论如何我无法解决它。更重要的是,如果将这些函数放在 class 之外并删除 $this->
-es,它们就可以工作了!但不在 class.
里面
如果有人能告诉我为什么我后面的代码不起作用,我将不胜感激。但无论如何,你会说使用 eval() 是合理的吗?我知道有些人无论如何都会避免它。显然,在这种情况下,它打开了一个相当大的漏洞,所以与其净化和担心,我宁愿完全避免它。
我想将 interface_get()
保留为一个单独的函数,但如果需要,我想我也可以在 fetch()
中复制它。
非常感谢您。
@Syscall 和@Ignacio Vazquez-Abrams 在评论中提供了问题的答案。
根据 PHP 文档 (https://php.net/manual/en/language.variables.superglobals.php):
Superglobals cannot be used as variable variables inside functions or
class methods.
这就是它无法在 Input
class 中工作的原因。为了让它工作,我必须像这样使用 $GLOBALS 变量:
public function fetch(string $method, ?string $request = null) {
$interface = $this->interface_get($method); #$interface = '_POST';
if ($request === null) {
$return = $GLOBALS[$interface];
unset($GLOBALS[$interface]);
} else {
$return = $GLOBALS[$interface][$request];
unset($GLOBALS[$interface][$request]);
}
return $return;
}
此代码有效。非常感谢您的意见。可能有更好或更优雅的方式来实现我正在寻找的东西。在这种情况下,我们随时欢迎您提供进一步的意见。
您可以使用 $GLOBALS[$interface]
获取您的数据。
假设 $_POST
和 $_GET
始终被定义,但是,您可以在获取和取消设置之前检查键是否被定义,以避免警告。
public function fetch(string $method, ?string $request = null) {
$interface = $this->interface_get($method); #$interface = '_POST';
if ($request === null) {
$result = $GLOBALS[$interface];
unset($GLOBALS[$interface]);
return $result;
}
if (isset($GLOBALS[$interface][$request])) {
$result = $GLOBALS[$interface][$request];
unset($GLOBALS[$interface][$request]);
return $result;
}
return null;
}
在我的代码中,我想尝试获取 $_POST 或 $_GET 变量,并在请求一次后立即取消设置。
这个函数return是使用的方法,很简单。不幸的是,我不能简单地直接或通过引用 return $_POST 或 $_GET 变量,因为我无法取消设置它们(通过引用取消设置不起作用)。所以,我 return 变量名:
class Input {
protected function interface_get($method): string {
switch ($method) {
case 'post':
return '_POST';
break;
case 'get':
return '_GET';
break;
case 'ajax':
// Not supported yet.
return null;
break;
default:
return null; // returns '_GET' or '_POST'
}
}
public function fetch_eval(string $method, ?string $request = null) { // ...fetch('post', 'username')
if ($request !== null) {
$request = '[\'' . $request . '\']'; // "['username']"
}
$request = $this->interface_get($method) . $request; #"$_POST['username']"
eval('$return = $' . $request . ';'); #$return = $_POST['username'];
eval('unset($' . $request . ');'); #unset($_POST['username']);
return $return;
}
public function fetch_varvar(string $method, ?string $request = null) {
$interface = $this->interface_get($method); #$interface = '_POST';
if ($request === null) {
$return = (${$interface});
unset(${$interface});
} else {
$return = ${$interface}; #"Notice: Undefined variable: _POST in [...]"
$return = ${$interface}[$request]; #"Warning: Illegal string offset 'email' in [...]"
unset($interface[$request]);
}
return $result;
}
}
// set $_POST = ['email'=>'spam@me'];
$in = new Input();
echo $in->fetch_eval('post', 'email'); #'spam@me'
// $_POST = [];
// set $_POST = ['email'=>'spam@me']; again
echo $in->fetch_varvar('post', 'email'); #'Notice: Undefined variable: _POST [...]'
有趣的部分是处理输出。这是我的获取函数,我认为这是最简单但最脏的方法:
我尝试使用可变变量,它在测试脚本中有效:
// $_POST = [0 => 5, 'bob' => 5];
$e = '_POST';
$var = 'bob';
echo ${$e}[$var]; #5
unset(${$e}[$var]);
echo ${$e}[$var ]; #NOTICE Undefined index: bob on line number 22
// Works as expected.
但它在我的脚本中不起作用 (Undefined variable: _POST [...]
)。我想可能是因为它在class中,但无论如何我无法解决它。更重要的是,如果将这些函数放在 class 之外并删除 $this->
-es,它们就可以工作了!但不在 class.
如果有人能告诉我为什么我后面的代码不起作用,我将不胜感激。但无论如何,你会说使用 eval() 是合理的吗?我知道有些人无论如何都会避免它。显然,在这种情况下,它打开了一个相当大的漏洞,所以与其净化和担心,我宁愿完全避免它。
我想将 interface_get()
保留为一个单独的函数,但如果需要,我想我也可以在 fetch()
中复制它。
非常感谢您。
@Syscall 和@Ignacio Vazquez-Abrams 在评论中提供了问题的答案。
根据 PHP 文档 (https://php.net/manual/en/language.variables.superglobals.php):
Superglobals cannot be used as variable variables inside functions or class methods.
这就是它无法在 Input
class 中工作的原因。为了让它工作,我必须像这样使用 $GLOBALS 变量:
public function fetch(string $method, ?string $request = null) {
$interface = $this->interface_get($method); #$interface = '_POST';
if ($request === null) {
$return = $GLOBALS[$interface];
unset($GLOBALS[$interface]);
} else {
$return = $GLOBALS[$interface][$request];
unset($GLOBALS[$interface][$request]);
}
return $return;
}
此代码有效。非常感谢您的意见。可能有更好或更优雅的方式来实现我正在寻找的东西。在这种情况下,我们随时欢迎您提供进一步的意见。
您可以使用 $GLOBALS[$interface]
获取您的数据。
假设 $_POST
和 $_GET
始终被定义,但是,您可以在获取和取消设置之前检查键是否被定义,以避免警告。
public function fetch(string $method, ?string $request = null) {
$interface = $this->interface_get($method); #$interface = '_POST';
if ($request === null) {
$result = $GLOBALS[$interface];
unset($GLOBALS[$interface]);
return $result;
}
if (isset($GLOBALS[$interface][$request])) {
$result = $GLOBALS[$interface][$request];
unset($GLOBALS[$interface][$request]);
return $result;
}
return null;
}