根据用户输入创建一个类

Joh*_*ohn 19 php

要求$输入是不安全的.'.PHP'.然后开始上课.如何使其安全,无需使用可以被提及的类的白名单.

例1.(错误代码).

<?php

$input = $_GET['controller'];

require $input . '.php';

new $input;

?>
Run Code Online (Sandbox Code Playgroud)

Ja͢*_*͢ck 13

放弃

我首先应该说,在您的系统中定义静态路由是安全的设计,而这个答案,即使我已经努力减轻安全问题,应该在信任其操作之前进行全面测试和理解.

基础

首先,使用从手册中获取的正则表达式确保控制器包含有效的变量名称; 这清除了明显错误的条目:

$controller = filter_input(INPUT_GET, FILTER_VALIDATE_REGEXP, [
    'options' => [
        'regexp' => '/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/',
        'flags' => FILTER_NULL_ON_FAILURE,
    ]
]);

if ($controller !== null) {
    // load and use controller
    require_once("$controller.php");
    $c = new $controller();
}
Run Code Online (Sandbox Code Playgroud)

执行层次结构

这很好用,但如果有人试图加载内部类呢?它可能会使应用程序失败.

您可以引入一个所有控制器必须扩展或实现的抽象基类或接口:

abstract class Controller {}

// e.g. controller for '?controller=admin'
class Admin extends Controller {}
Run Code Online (Sandbox Code Playgroud)

顺便说一句,为避免名称冲突,您可以在单独的命名空间中定义它们.

这就是你如何强制执行这样的层次结构:

if ($controller !== null) {
    // load and use controller
    require_once("$controller.php");
    if (is_subclass_of($controller, 'Controller')) {
        $c = new $controller();
    }
}
Run Code Online (Sandbox Code Playgroud)

is_subclass_of()在实例化类之前用来键入check.

自动加载

而不是使用的require_once()在这种情况下,你可以使用自动加载器来代替:

// register our custom auto loader
spl_autoload_register(function($class) {
    $file = "$class.php"; // admin -> admin.class.php
    if (file_exists($file)) {
        require_once $file; // this can be changed
    }
});
Run Code Online (Sandbox Code Playgroud)

这也是您可以规范化类名称的地方,以便它更好地映射到文件名,以及强制执行自定义命名空间,例如"App\\$class.php".

这会将代码减少一行,但使加载更加灵活:

if ($controller !== null) {
    // check hierarchy (this will attempt auto loading)
    if (class_exists($controller) && is_subclass_of($controller, 'Controller')) {
        $c = new $controller();
    }
}
Run Code Online (Sandbox Code Playgroud)

所有这些代码都假定您有适当的错误处理代码; 对于实施建议,您可以查看此答案.