【问题标题】:Include from/with function in php在 php 中包含 from/with 函数
【发布时间】:2015-02-03 23:38:55
【问题描述】:

我一直在为一个包含另一个的 php 脚本而苦苦挣扎,所以我想我可能需要一些帮助...

基本上我想要的是将一个php文件(称为content-1.php)包含在base.php中,并在functions.php中提供一个函数。

我的想法是我想根据 $_GET 变量包含不同的文件。我正在寻找这样的东西:

base.php

include("functions.php");
$api->getContent($_GET["content"]);

functions.php

class api {
function getContent($content) {
    if (isset($content)) {
        if (file_exists("/content/" . $content . ".php")) {
              return include("/content/" . $content . ".php");
        }
    }

    return include("/content/content-1.php");
}

function getName() {
   //Some function...
}

}
$api = new api;

content-1.php

echo "Hello world.";
echo $api->getName();

在我尝试从 content-1.php 访问 $api 之前,一切似乎都有效(与 Hello World 相呼应)。我收到“致命错误:调用非对象的成员函数”..

但是如果我将 content-1.php 直接包含到 base.php 中,它看起来就像这样:

base.php

include("functions.php");
include("/content/content-1.php");

调用 $api 一切正常!

所以,如果我没有太乱,我想知道如何使用 getContent() 函数包含内容,并且仍然能够传递变量,就像我立即包含文件一样?

(抱歉,描述太复杂了,我试图简化我真正使用的代码,所以如果路径或语法有任何错误,那不是真正的问题,而只是一些粘贴错误......!)

【问题讨论】:

    标签: php function include


    【解决方案1】:

    发生这种情况的原因是$api 变量仅在函数范围之外可见。您可以像这样在函数中添加一行:

    function getContent($content) {
    
        $api = $this;
    
        // The rest of the code
    
    }
    

    旁注!

    函数中的代码存在严重的安全问题!可以像现在一样包含任何文件。如果$_GET['content'] 的值等于'../../../passwords.txt'(仅作为示例),则将包含文件passwords.txt,并且访问者将能够查看您的所有密码。

    为了解决这个问题,您应该构建一个可用文件列表,以便您选择可以包含哪些文件。为了使这更容易,可以动态完成。

    function getContent($content) {
    
        $api = $this;  // Make the $api avaiable to included file.
    
        $path  = 'path/to/contents/directory';
        $files = scandir($path);
    
        // Remove the two 'dot' directories
        $files = array_diff($files, ['.', '..']);
    
        // Now you check if the provided $content file name exists and in fact is a file.
        $filename = trim($content, '/.') . '.php';
    
        if(in_array($filename, $files) && is_file($filename)) {
    
             return include('/content/' . $filename);
    
        }
    
        return include('/content/content-1.php');
    }
    

    现在您可以确定攻击者只能包含来自contents 目录的文件。

    更新

    问题:

    如何在包含的文件中声明新变量并在执行getContent()函数的脚本中使用它们?

    有一种方法可以在没有任何脆弱代码的情况下完成您的要求。您可以通过引用将另一个声明数组的变量传递给函数。该函数如下所示:

    function getContent($content, array &$variables = []) {...
    

    这种方法的限制是你只能像下面这样声明新变量:

    $variables['new_variable_name'] = 'new_variable_value';
    

    现在,当您调用该函数时,您可以选择向其传递另一个声明数组的参数。该数组将保存包含文件中声明的变量。

    $variables = [];
    
    $api->getContent($content, $variables);
    

    现在您可以像这样访问变量:

    $variables['new_variable'];
    

    你也可以extract()他们进入当前作用域。这可能会导致问题,所以我添加了标志EXTR_SKIP 来指示PHP 它应该忽略现有的同名变量。您可以设置标志EXTR_PREFIX_ALL 并为extract($variables, EXTR_PREFIX_ALL, 'prefix') 提供第三个参数。这将为所有提取的变量添加前缀,并帮助您避免命名冲突。

    extract($variables, EXTR_SKIP);
    

    使用函数包含文件时有一些限制,但我首先描述的方法(不提取)可以帮助您区分哪些变量与哪些包含相关联。

    希望有用。

    【讨论】:

    • 很棒的答案!非常感谢您提供有关安全性的意见!虽然我有一个解决方案,但你的更好!但是如何以另一种方式传递变量?如果我想声明或设置一个变量以供以后在 base.php 中使用?
    • 谢谢,只是想确保您意识到安全问题,因为这可能会在以后的开发过程中导致严重的头痛。
    • 我已经更新了答案,为您的问题提供解决方案。
    【解决方案2】:

    content-1.php里面的$api其实是$this

    <?php // content-1.php
    $this->getName();
    

    【讨论】:

    • 啊,谢谢!但是与包含在 content-1.php 中的真正区别是什么?如果我想在 content-1.php 中定义一个变量以便稍后在 base.php 中使用,我该怎么办?
    • 我不明白你的第一个问题。至于你的第二个问题,它会有点棘手,但你想要做的是在渲染子模板之前不渲染父模板。它有点涉及,并且已经有解决方案可以做到这一点。比如 zend 框架 2。
    【解决方案3】:

    试试 $this 而不是 $api:

    content-1.php

    echo "Hello world.";
    echo $this->getName();
    

    【讨论】:

      猜你喜欢
      • 2013-06-12
      • 2011-09-18
      • 2018-09-12
      • 2015-10-24
      • 2010-10-16
      • 2021-02-02
      • 2022-12-01
      • 2021-10-26
      • 2018-11-30
      相关资源
      最近更新 更多