猿问

如何让 PHP 包含数据 URI(不打开 allow_url_include)?

在我的 PHP 设置中,出于安全原因,我已经allow_url_include设置FALSE并且很乐意保持这种状态。

当我想

include 'https://example.com/path/to/include.php'; // <= THIS WON'T WORK

我可以用:

include $_SERVER['DOCUMENT_ROOT'].'/path/to/include.php'; // <= BUT THIS WILL

到目前为止,一切都很好。


然而,现在,我正在尝试在运行时在 PHP 中创建include 虚拟文件的方法。

我想知道 PHP 中是否有等同于 javascript 的东西URL.createObjectURL(),之后我发现 PHP 可以读取data:URI。

这听起来很有希望......但是因为我已经allow_url_include设置为FALSE,PHP 告诉我它不能include以以下开头的 URI data:

警告:包装器在服务器配置中被禁用 include(): data://allow_url_include=0

所以,而不是:

include 'data:application/x-php;base64,ZnVuY3Rpb24gdGVzdDIoKSB7ZWNobyAnVGhpcyB0ZXN0IGZ1bmN0aW9uIDIgaXMgd29ya2luZy4nO30gdGVzdDIoKTs=';

我必须file_get_contentseval这样使用:

$Test_Function = file_get_contents('data:application/x-php;base64,ZnVuY3Rpb24gdGVzdDIoKSB7ZWNobyAnVGhpcyB0ZXN0IGZ1bmN0aW9uIDIgaXMgd29ya2luZy4nO30gdGVzdDIoKTs=');
eval("$Test_Function");

后一种方法有效eval(),但(尤其是因为它很慢)除非绝对必要,否则我不想使用。

有什么方法可以让 PHP 访问includeURI data:而无需打开allow_url_include


注一:

您可能对我在这里使用 base-64 编码的内容感到好奇:

ZnVuY3Rpb24gdGVzdDIoKSB7ZWNobyAnVGhpcyB0ZXN0IGZ1bmN0aW9uIDIgaXMgd29ya2luZy4nO30gdGVzdDIoKTs=

它只是以下内容:

function test2() {echo 'This test function 2 is working.';} test2();

笔记2:

当我第一次尝试创建一个数据 URI 时(很久之前我在这里发布)我在百分比编码上犯了一个错误,使数据 URI 无效。

我尝试对 Data URI 进行 base-64 编码(这有效),之后我没有返回到原始百分比编码的 Data URI 来找出我哪里出错了。

但是,重要的是要注意(除了混淆)根本没有理由在数据 URI 中使用 base-64 编码。

以下百分比编码的数据 URI 在功能上是相同的:

data:application/x-php,function%20test2%28%29%20%7Becho%20%27This%20test%20function%202%20is%20working.%27%3B%7D%20test2%28%29%3B

注3:

虽然,到目前为止,我还没有成功使用includeData URI while allow_url_includeremains set to FALSE,但我想我会比较一下:

  1. 编写一个字符串并eval()在该字符串上运行以执行它

  2. 创建文件并include在该文件上运行

测试包括运行其中一个进程超过 10,000 次我没有运行一次单个测试,而是连续运行了一组 6 个测试。总的来说,我跑了 5 组。

这就涉及到 10,000 个流程的 5 组 6 次测试。

综上所述:

  • 运行eval()(通常但不总是)比简单地声明和执行一个函数慢 10 多倍。

  • 创建、写入和保存文件,然后include在该文件上运行比声明和执行函数慢 1000 多倍。

  • 声明和执行一个简单函数的平均时间(来自 60,000 个样本)是 0.000002194s

  • 运行相同简单函数的平均时间eval()(来自 60,000 个样本)是 0.00009262s

因此,任何花费eval()100 倍的时间来解析和执行的字符串,仍然只需要不到百分之一秒< 0.01s) 的时间即可完成。


扬帆大鱼
浏览 165回答 3
3回答

呼如林

我想到的一个想法是将生成的代码保存在一个临时文件中(在tmpfs中),然后include对其进行处理。$Test_Function = file_get_contents('data:application/x-php;base64,ZnVuY3Rpb24gdGVzdCgpe2VjaG8nVGhpcyB0ZXN0IGRhdGEgdXJsIGZ1bmN0aW9uIDEgaXMgd29ya2luZy4nO30gdGVzdCgpOw==');file_put_contents("/mnt/tempfs/<name>.php", "<?php\n$Test_Function");include "/mnt/tempfs/<name>.php";关于性能:tmpfs 工具允许创建内容驻留在虚拟内存中的文件系统。由于此类文件系统上的文件通常驻留在 RAM 中,因此文件访问速度非常快。

慕码人2483693

我闻到了X/Y 问题的味道——您已经将URIeval和data:URI 视为特定问题的可能解决方案,并发现了两者的缺点,但没有回到最初的问题陈述。从各种评论中,我们可以将问题定义为找到一种机制:可以执行任意动态代码具有与正常相似的解析性能include将允许代码缓存在 OpCache 中不需要在其他地方放松安全你说eval在第 2 点(因为它启动了一个新的解析器)和第 3 点(因为没有可供 OpCache 使用的密钥)失败。您已经确定data:URI 在第 4 点失败(因为它们需要allow_url_include),但我怀疑它们在第 2 点(因为 base64 解码是一项重要的开销)和第 3 点(因为 OpCache 不支持缓存任意流;我相信它只支持文件路径和 PHAR 内容)更好的整体解决方案是将代码写入“真实”文件,使用内存文件系统(例如tmpfs提高性能)。这符合上述所有四个标准,因为就 PHP 而言,它与任何其他源文件相同;唯一的额外开销是将文件写入虚拟文件系统的 I/O 速度。关键优化将确保您跟踪动态内容何时更改,从某种修订 ID 或字符串的哈希生成唯一的文件路径。这可以实现两件事:您可以跳过写入磁盘上已存在的文件,从而节省 I/O 时间OpCache 将能够缓存此文件的内容并重新使用它,即使您设置opcache.validate_timestamps为 false ,您也可以确信正确的代码会运行

一只甜甜圈

您可以尝试编写您的data:php://memory。因为它在那里就像普通文件一样,你可以包括它吗?
随时随地看视频慕课网APP
我要回答