gpt4 book ai didi

php - 为什么php ://input be read more than once despite the documentation saying otherwise?可以

转载 作者:IT王子 更新时间:2023-10-29 00:07:30 24 4
gpt4 key购买 nike

PHP 文档 states php://input 只能读取一次。

在我的应用程序中,我需要读取它两次,一次用于身份验证,一次用于实际处理内容,并且这两个功能由不同的独立模块处理。疯狂的是:有效

我可以指望它在任何地方都能正常工作吗,还是我的 PHP 版本 (5.2.10) 中出现了这种情况?我能找到的关于此的唯一文档是声明它不应该工作的文档,没有提到版本限制。


按照丹尼斯的直觉,我做了这个测试:

$in = fopen('php://input', 'r');
echo fread($in, 1024) . "\n";
fseek($in, 0);
echo fread($in, 1024) . "\n";
fclose($in);
echo file_get_contents('php://input') . "\n";

冰壶:

$ curl http://localhost:8888/tests/test.php -d "This is a test"
This is a test

This is a test

显然,每个打开的句柄只能读取一次。


更多的挖掘表明 php://input 确实只能被读取一次,永远,对于 PUT 请求。上面的例子使用了 POST 请求。

最佳答案

稍微检查一下源代码就会得出答案。

首先,是的,每个句柄只能读取一次,因为底层流没有实现 seek 处理程序:

php_stream_ops php_stream_input_ops = {
php_stream_input_write,
/* ... */
"Input",
NULL, /* seek */
/* ... */
};

其次,读取处理程序有两种不同的行为,具体取决于“POST 数据”是否已被读取并存储在 SG(request_info).raw_post_data 中。

if (SG(request_info).raw_post_data) {
read_bytes = SG(request_info).raw_post_data_length - *position;
/* ...*/
if (read_bytes) {
memcpy(buf, SG(request_info).raw_post_data + *position, read_bytes);
}
} else if (sapi_module.read_post) {
read_bytes = sapi_module.read_post(buf, count TSRMLS_CC);
/* ... */
} else {
stream->eof = 1;
}

所以我们这里有三种可能性:

  1. 请求正文数据已被读取并存储在SG(request_info).raw_post_data 中。在这种情况下,由于数据已存储,我们可以打开并读取 php://input 的多个句柄。
  2. 已读取请求正文数据,但其内容未存储在任何地方。 php://input 不能给我们任何东西。
  3. 尚未读取请求数据。这意味着我们可以打开 php://input 并只读取一次。

注意:以下是默认行为。不同的 SAPI 或其他扩展可能会改变此行为。

对于 POST 请求,PHP 根据内容类型定义不同的 POST 阅读器和 POST 处理程序。

情况 1。当我们有一个 POST 请求时会发生这种情况:

  • 使用内容类型 application/x-www-form-encodedsapi_activate 检测带有内容类型的 POST 请求并调用 sapi_read_post_data。这会检测内容类型并定义 POST 读取器/处理程序对。 POST 阅读器是 sapi_read_standard_form_data,它会立即被调用,并将请求主体复制到 SG(request_info).post_data。然后调用默认的帖子阅读器 php_default_post_reader,如果设置了 ini 设置 always_populate_post_data,它会填充 $HTTP_RAW_POST_DATA,然后复制 SG(request_info ).post_dataSG(request_info).raw_post_data 并清除第一个。对处理程序的调用在这里无关紧要,并且会被推迟到构建超全局变量(如果 JIT 已激活且未使用超全局变量,则可能不会发生)。
  • 具有无法识别或不存在的内容类型。在这种情况下,没有定义的 POST 阅读器和处理程序。这两种情况都以 php_default_post_reader 结束,没有读取任何数据。由于这是一个 POST 请求并且没有读取器/处理程序对,因此将调用 sapi_read_standard_form_data。这与内容类型 application/x-www-form-encoded 的读取处理程序功能相同,因此所有数据都被吞入 SG(request_info).post_data。从现在开始唯一的区别是 $HTTP_RAW_POST_DATA 总是被填充(无论 always_populate_post_data 的值如何)并且没有用于构建超全局变量的处理程序。

情况 2. 当我们有一个内容类型为“multipart/form-data”的表单请求时,就会发生这种情况。 POST 读取器为 NULL,因此处理程序 rfc1867_post_handler 充当混合的读取器/处理程序。在 sapi_activate 阶段没有读取任何数据。函数 sapi_handle_post 最终在后面的阶段被调用,它又调用 POST 处理程序。 rfc1867_post_handler 读取请求数据,填充POSTFILES,但不在SG(request_info).raw_post_data 中留下任何内容。

案例 3。最后一个案例发生在不同于 POST(例如 PUT)的请求中。 php_default_post_reader 是直接调用的。因为请求不是POST请求,数据被sapi_read_standard_form_data吞噬。由于未读取任何数据,因此无需执行任何操作。

关于php - 为什么php ://input be read more than once despite the documentation saying otherwise?可以,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3107624/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com