在 PHP 中使用变量是不好的做法吗?

Is it bad practice to use variable variables in PHP?

提问人:Jonathan Coe 提问时间:1/4/2012 最后编辑:AbraCadaverJonathan Coe 更新时间:3/13/2021 访问量:1379

问:

例如,一个简单的 MVC 类型系统:

/api/class/method使用 重写为 PHP 变量,然后执行如下操作:.htaccess/nginx.conf

<?php

// Set up class + method variables
$className = some_class_filter($_GET['class']);
$method = some_method_filter($_GET['method']);

// Check if class exists and execute
if(file_exists(BASE . "/controllers/" . $className . ".class.php")) {
    require BASE . "/controllers/" . $className . ".class.php";
    $$className = new $className();

    // Execute the method
    $$className->$method();
} else {
    // Spit out some error based on the problem
}

?>

这是可怕的坏做法吗?如果这是不好的做法,有人可以解释为什么吗?如果是这样,有没有更好的方法来做我正在做的事情?

编辑从本质上讲,我使用变量的原因是为了简化扩展核心系统 - 即 - 添加新控制器既好又简单。我绝对理解允许基本上任何函数或类在没有某种过滤器的情况下实例化的安全风险。

“some_filter_here”可以是允许的控制器列表 - 正如这里的一些人所提到的白名单。

PHP 变量

评论

0赞 Matt Ball 1/4/2012
变量几乎总是一个坏主意。不如换一个数组呢?stackoverflow.com/a/1817945/139010
1赞 Lightness Races in Orbit 1/4/2012
我想你的意思是$$className = new $className();
0赞 Jonathan Coe 1/4/2012
@LightnessRacesinOrbit - 你是对的,谢谢你指出这一点。

答:

1赞 Oomta 1/4/2012 #1

既然你正在编写“some_class_filter”和“some_method_filter”代码,我会说没关系。你也有一个错误或默认处理程序,我看到,所以最后,我会说没关系。

我相信许多 MVC 框架都以类似的方式运行。

6赞 cmbuckley 1/4/2012 #2

是的,这是相当糟糕的做法。该实例是否需要变量变量?换句话说,您是否需要在给定的请求中实例化多个类和方法?您的 URI 结构表明不是。如果没有,您可以使用:

$object = new $className();
$object->$method();

否则,您可能需要执行以下操作:

$objects = array();
$objects[$className] = new $className();
$objects[$className]->$method();

这避免了变量对范围的污染,因为变量更难跟踪。

就给定目录中是否存在检查您的类而言,这应该是一个足够的白名单(假设攻击者无法写入该目录)。

编辑:作为进一步的检查,您可能需要考虑在调用该方法之前检查对象上的method_exists

评论

0赞 Jonathan Coe 1/4/2012
我真的很喜欢这个,谢谢你的发帖!我不知道为什么我最初没有想到这一点。每个请求都有多个对象被实例化,尽管只有一个“动态”类 - 尽管可能调用了多个方法。但多种方法更容易管理谢谢!
1赞 Martin Bean 1/4/2012 #3

它们不是可取的,但可以随心所欲地使用它们。

不过,有几个提示:您的代码确实存在一个漏洞,攻击者可以使用 .如果该文件存在,则调用将返回,应用程序将尝试包含该文件并将其实例化为类。$_GET?class=../basefile_exists()true

安全的情况是将这些参数列入白名单,仅为字母、数字和下划线(如果您用下划线分隔单词,即 )。.php

另外,我更喜欢使用 和 的语法。在代码中使用这些函数将如下所示:call_user_funccall_user_func_array

<?php
$class_name = $_GET['class'];
$method_name = $_GET['method'];

$parameters = $_GET;
unset($parameters['class'], $parameters['method']); // grabs any other $_GET parameters

if (file_exists(BASE.'/controllers/'.$class_name.'.class.php')) {
    require BASE.'/controllers/'.$class_name.'.class.php';
    $controller = new $class_name();
    $response = call_user_func_array(array($controller, $action_name), $parameters);
}
else {
    header('HTTP/1.1 404 Not Found');
    // ...and display an error message
}

评论

0赞 Jonathan Coe 1/4/2012
感谢您的输入!这很有意义,而且我以前没有使用过 call_user_func/call_user_func_array,我会更多地研究这个问题。