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

Using eval() in the code, and how would you avoid it?

提问人:Dwarf Vader 提问时间:3/14/2018 最后编辑:Dwarf Vader 更新时间:3/14/2018 访问量:207

问:

在我的代码中,我想尝试获取 $_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 [...]'

有趣的部分是处理输出。这是我的获取函数,我认为是最简单但最肮脏的方法:

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

// $_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.

但它在我的脚本中不起作用(.)。我想也许是因为在课堂上,但无论如何我都无法解决它。更重要的是,如果你把这些函数放在类之外并删除 -es,它们就会起作用!但不是在课堂上。Undefined variable: _POST [...]$this->

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

我想保留为一个单独的功能,但如果需要,我想我也可以在里面复制它。interface_get()fetch()

提前非常感谢你。

php eval unset variables

评论

0赞 SaganRitual 3/14/2018
我建议对你的问题进行两次更新,这将有助于这里的每个人更有效地帮助你。首先,讨论使用调试器单步执行代码时发现的内容。提供比“不起作用”更多的细节。其次,删除您发布的所有代码,并将其替换为人们可以复制/粘贴到其调试器中的内容。
0赞 Obsidian Age 3/14/2018
我不明白你为什么需要变量或变量。你不能简单地做一些事情吗?$requestif ($_POST) { unset($_POST); }if ($_GET) { unset($_GET); }
0赞 Dwarf Vader 3/14/2018
GreatBigBore - 好的,我开始了。黑曜石 - 在这种情况下,我基本上会将开关结构放在 fetch() 函数中。这没什么大不了的,但我想知道如何正确地将它们解耦,至少出于教育目的。
1赞 Syscall 3/14/2018
仅供参考,@DwarfVader,使用作品(而不是 ).$GLOBALS[$interface]${$interface}
2赞 Ignacio Vazquez-Abrams 3/14/2018
注意:变量 超全局变量不能用作函数或类方法中的变量。”

答:

1赞 Dwarf Vader 3/14/2018 #1

@Syscall和@Ignacio巴斯克斯-艾布拉姆斯在评论中提供了这个问题的答案。

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

超全局变量不能用作函数内部的变量,或者 类方法。

这就是为什么它在班级内不起作用的原因。为了让它工作,我必须像这样使用 $GLOBALS 变量:Input

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;
}

这段代码奏效了。非常感谢您的输入。也许有一种更好或更优雅的方式来实现我正在寻找的东西。在这种情况下,我们始终欢迎进一步的意见。

评论

0赞 Syscall 3/14/2018
解释得很好的答案。
1赞 ChristianM 3/14/2018
如果您使用包装器访问全局变量并且显然想要防止重复访问,我会直接处理这个问题。该类只接受全局变量作为构造函数中的数组,创建类后立即取消设置它们,这意味着不再可能进行外部访问。然后,您可以在访问后取消设置类属性,而无需弄乱类内部的全局变量。
0赞 Dwarf Vader 3/14/2018
@ChristianM这太棒了,而且更合乎逻辑。我实际上不喜欢在类函数内部必须调整全局变量的事实,这看起来很混乱。这样就更优雅了。
1赞 Syscall 3/14/2018 #2

您可以使用它来获取数据。$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;
}

评论

1赞 Syscall 3/14/2018
@DwarfVader,我添加了这个答案,它并不打算被接受,而只是希望有用。