我最近正在阅读此主题最糟糕的PHP实践。 在第二个答案中,有一个关于 extract()的使用的小型讨论,我只想知道所有的烦恼是什么。

我个人使用它来删除一个给定的数组,例如 $ _ GET $ _ POST ,然后我在那里清理变量,因为它们已经为我方便地命名了。

这是不好的做法吗?这有什么风险?您对 extract()的使用有何看法?

有帮助吗?

解决方案

我发现这只是一种不好的做法,因为它可能导致许多变量,未来的维护者(或者你自己在几周内)不知道他们来自哪里。请考虑以下情况:

extract($someArray); // could be 

我发现这只是一种不好的做法,因为它可能导致许多变量,未来的维护者(或者你自己在几周内)不知道他们来自哪里。请考虑以下情况:

$a = $someLongNameOfTheVariableArrayIDidntWantToType;

$a['myVariable'];

$ someVariable 来自哪里?谁能说出来?

我没有看到从他们开始的数组中访问变量的问题,所以你真的需要使用 extract()来提供的好例子代码>让我觉得它值得。如果您真的担心输入一些额外的字符,那么就这样做:

<*>

我认为这里关于安全方面的评论有些过分夸大了。该函数可以采用第二个参数,实际上可以很好地控制新创建的变量,包括不覆盖任何现有变量( EXTR_SKIP ),只覆盖现有变量(这样就可以创建白名单)( EXTR_IF_EXISTS ),或为变量添加前缀( EXTR_PREFIX_ALL )。

POST or anything /* snip a dozen or more lines */ echo $someVariable;

$ someVariable 来自哪里?谁能说出来?

我没有看到从他们开始的数组中访问变量的问题,所以你真的需要使用 extract()来提供的好例子代码>让我觉得它值得。如果您真的担心输入一些额外的字符,那么就这样做:

<*>

我认为这里关于安全方面的评论有些过分夸大了。该函数可以采用第二个参数,实际上可以很好地控制新创建的变量,包括不覆盖任何现有变量( EXTR_SKIP ),只覆盖现有变量(这样就可以创建白名单)( EXTR_IF_EXISTS ),或为变量添加前缀( EXTR_PREFIX_ALL )。

其他提示

现在来吧。人们责怪工具而不是用户。

这就像是在讨论 unlink(),因为你可以用它删除文件。 extract()是一个像任何其他函数一样的函数,明智且负责任地使用它。但不要声称它本身不好,那只是无知。

风险在于:不信任来自用户的数据,并提取到当前符号表意味着,您的变量可能会被用户提供的内容覆盖。

<?php
    $systemCall = 'ls -lh';
    $i = 0;

    extract(

风险在于:不信任来自用户的数据,并提取到当前符号表意味着,您的变量可能会被用户提供的内容覆盖。

yourscript.php?i=10&systemCall=rm%20-rf

(一个荒谬的例子)

但现在是猜测或知道代码调用的恶意用户:

yourscript.php?data[]=a&data[]=b&data[]=c

而不是

<*>

现在,$ systemCall和$ i被覆盖,导致您的脚本首先删除您的数据然后挂起。

GET); system($systemCall); do { print_r($data[$i]; $i++; } while ($i != 3); ?>

(一个荒谬的例子)

但现在是猜测或知道代码调用的恶意用户:

<*>

而不是

<*>

现在,$ systemCall和$ i被覆盖,导致您的脚本首先删除您的数据然后挂起。

它没有任何问题。否则就不会实施。当您向视图传递(赋值)变量时,许多(MVC)框架都会使用它。你只需要仔细使用它。在将这些数组传递给extract()之前清理它们并确保它不会覆盖您的变量。别忘了这个函数还接受了一些参数! 如果发生碰撞,使用第二个和第三个参数可以控制行为。您可以覆盖,跳过或添加前缀。 http://www.php.net/extract

如果不小心使用,可能会使你工作的其他人感到困惑:

<?php

    $array = array('huh' => 'var_dump', 'whatThe' => 'It\'s tricky!', 'iDontGetIt' => 'This Extract Function');
    extract($array);
    $huh($whatThe, $iDontGetIt);


?>

收益率:

string(12) "It's tricky!"
string(21) "This Extract Function"

在混淆中使用会很有用。但我无法克服“变量来自何处?”我遇到的问题。

人们对提取物全面了解,因为它会滥用潜力。做任何类似提取($ _ POST)的事情在任何情况下都不是一个好主意,即使你知道你在做什么。但是,当您执行诸如将变量暴露给视图模板或类似的东西时,它确实具有它的用途。基本上,只有当你非常确定你有充分理由这样做时才使用它,并且如果你想要把像$ _POST这样疯狂的东西传递给它,那么就要理解如何使用extract类型参数。

我想很多人不推荐使用它的原因是提取 $ _ GET $ _ POST (甚至 $ _ REQUEST )superglobals在全局命名空间中注册变量,其名称与这些数组中的每个键相同,基本上模拟REGISTER_GLOBALS = 1.

我会让 PHP手册进行讨论我

背景: extract($ _ REQUEST)与在php.ini中设置 register_globals = On 相同

如果在函数中提取,则变量仅在该范围内可用。这通常用在视图中。简单的例子:

//View.php
class View {
    function render($filename = null) {
        if ($filename !== null) {
            $this->filename = $filename;
        }
        unset($filename);
        extract($this->variables);
        ob_start();
        $this->returned = include($this->dir . $this->filename);
        return ob_get_clean();
    }
}

//test.php
$view = new View;
$view->filename = 'test.phtml';
$view->dir = './';
$view->variables = array('test' => 'tset');
echo $view->render('test.phtml');
var_dump($view->returned);

//test.phtml
<p><?php echo $test; ?></p>

使用一些替代目录,检查文件是否存在以及定义的变量和方法 - 您几乎已经复制了Zend_View。

您还可以在include之后添加 $ this-&gt; outVariables = get_defined_vars(); 以运行具有特定变量的代码,并获取这些变量以使用旧的PHP代码。

只要您以安全的方式使用,提取物就是安全的。你想要做的是将数组的键过滤到你想要使用的键,如果你的场景需要它们,可以检查所有这些键是否存在。

#Extract only the specified keys.
$extract=array_intersect_key(
    get_data()
    ,$keys=array_flip(['key1','key2','key3','key4','key5'])
);

#Make sure all the keys exist.
if ($missing=array_keys(array_diff_key($keys,$extract))) {
    throw new Exception('Missing variables: '.implode(', ',$missing));
}

#Everything is good to go, you may proceed.
extract($extract);

#If you don't care to check that all keys exist, you could just do this.
extract(array_intersect_key(
    get_data()
    ,array_flip(['key1','key2','key3','key4','key5'])
));

风险与register_globals相同。您可以让攻击者在脚本中设置变量,只需篡改请求即可。

永远不要在全局范围内提取($ _ GET)。除此之外,它有其用途,比如调用一个可能(可能)有很多可选参数的函数。

对于WordPress开发人员来说,这应该看起来很模糊:

function widget (Array $args = NULL)
{
    extract($args);

    if($before_widget) echo $before_widget;

    // do the widget stuff

    if($after_widget) echo $after_widget;
}

widget(array(
    'before_widget' => '<div class="widget">',
    'after_widget' => '</div>'
));

正如有人在另一个主题中提到的那样,这里是一种更安全的方式使用提取,只允许它提取您指定的变量,而不是数组包含的所有内容。

这有双重目的,即记录变量的来源,因此跟踪变量不会那么困难。

每种方法的使用都可能导致某些情况,它可能成为应用程序的失败点。 我个人觉得extract()不应该用于用户输入(不可预测)和未清理的数据。

即使CodeIgniter核心代码使用提取,因此如果数据被清理并处理得当,使用该方法一定不会有任何损害。

我使用了带有EXTR_IF_EXISTS开关的CodeIgniter模型中的extract并限制了变量的数量,它运行得很好。

请注意,如果您正在使用用户数据(如请求结果), extract()是不安全的,因此最好将此函数与标志 EXTR_IF_EXISTS EXTR_PREFIX_ALL

如果使用正确,可以安全使用

稍微解释一下以前的答案......只要你正确地过滤输入(正如其他人已经说过的那样),extract()没有任何问题;否则你最终会遇到这样的巨大安全问题:

<?php

// http://foobar.doo?isLoggedIn=1

$isLoggedIn = (new AdminLogin())->isLoggedIn(); // Let's assume this returns FALSE

extract(

稍微解释一下以前的答案......只要你正确地过滤输入(正如其他人已经说过的那样),extract()没有任何问题;否则你最终会遇到这样的巨大安全问题:

<*>GET); if ($isLoggedIn) { echo "Okay, Houston, we've had a problem here."; } else { echo "This is Houston. Say again, please."; }

不再使用extract()的另一个好理由是PHP中有动力使用 HHVM 声称PHP的速度提高了约10倍。 Facebook(制作它)正在使用它,维基百科正在使用它,而传言WordPress正在研究它。

HHVM不允许提取()

它仍然是一种阿尔法,所以它不是最大的问题

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top