在代码中使用eval(),你会如何避免它?

时间:2018-03-13 22:47:37

标签: php eval unset variable-variables

在我的代码中,我想尝试获取$ _POST或$ _GET变量,并在一次请求时立即取消它们。

此函数返回使用的方法,这很简单。不幸的是,我不能简单地直接或通过引用返回$ _POST或$ _GET变量,因为我无法取消它们(通过引用取消设置不起作用)。所以,我返回变量名称:

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 [...]'

有趣的部分是处理输出。这是我的fetch函数,我认为最容易但最脏的方法是:

我尝试使用变量变量,它在测试脚本中起作用:

// $_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 [...]。)。我想也许原因是它在课堂上,但无论如何我无法解决它。更重要的是,如果你将这些功能放在课堂之外并删除$this-> - es,它们就可以了!但不是在课堂上。

如果有人能告诉我为什么后面的代码不起作用,我将不胜感激。但无论如何,你会说使用eval()是合理的吗?我知道有些人无论如何都会避免它。显然,在这种情况下,它开辟了一个非常大的漏洞,所以我宁愿完全避免它而不是消毒和担心。

我想将interface_get()作为一个单独的函数,但如果需要,我也可以在fetch()内复制它,我猜想。

非常感谢你。

2 个答案:

答案 0 :(得分:1)

@Syscall和@Ignacio Vazquez-Abrams在评论中提供了问题的答案。

根据PHP文档(https://php.net/manual/en/language.variables.superglobals.php):

  

Superglobals不能用作函数内的变量变量   类方法。

这就是为什么它不在Input课程内工作的原因。为了它的工作,我不得不像这样使用$ 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;
}

此代码有效。非常感谢您的投入。可能有更好或更优雅的方式来实现我想要的。在这种情况下,总是欢迎进一步的投入。

答案 1 :(得分:1)

您可以使用$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;
}