dec*_*eze 18 php post inputstream
PHP文档的状态是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";
Run Code Online (Sandbox Code Playgroud)
冰壶:
$ curl http://localhost:8888/tests/test.php -d "This is a test"
This is a test
This is a test
Run Code Online (Sandbox Code Playgroud)
显然它只限于每个打开手柄一次读取.
更多的挖掘表明php://input,对于PUT请求确实只能读取一次.上面的示例使用了POST请求.
Art*_*cto 23
对源代码进行一点检查即可得出答案.
首先,是的,由于底层流没有实现seek处理程序,因此每个句柄限制为一次读取:
php_stream_ops php_stream_input_ops = {
php_stream_input_write,
/* ... */
"Input",
NULL, /* seek */
/* ... */
};
Run Code Online (Sandbox Code Playgroud)
其次,读取处理程序有两种不同的行为,具体取决于是否已读取并存储"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;
}
Run Code Online (Sandbox Code Playgroud)
所以我们有三种可能性:
SG(request_info).raw_post_data.在这种情况下,由于存储了数据,我们可以打开和读取多个句柄php://input.php://input不能给我们任何东西.php://input并阅读一次.注意:以下是默认行为.不同的SAPI或其他扩展可能会更改此行为.
在POST请求的情况下,PHP根据内容类型定义不同的POST阅读器和POST处理程序.
案例1.当我们有POST请求时会发生这种情况:
application/x-www-form-encoded.sapi_activate检测具有内容类型和调用的POST请求sapi_read_post_data.这将检测内容类型并定义POST阅读器/处理程序对.POST阅读器sapi_read_standard_form_data,立即被调用,只是将请求体复制到SG(request_info).post_data.默认后读者php_default_post_reader然后被调用,它充满$HTTP_RAW_POST_DATA如果INI设置always_populate_post_data设置,然后拷贝SG(request_info).post_data到SG(request_info).raw_post_data并清除第一.对处理程序的调用在这里并不重要,并且推迟到构建超级全局(这可能不会发生,以防JIT被激活并且不使用超级全局).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充当混合reader/handler.在sapi_activate阶段中没有任何数据被读取.该函数sapi_handle_post最终在稍后阶段调用,该阶段又调用POST处理程序.rfc1867_post_handler读取请求数据,填充POST和FILES,但不留下任何内容SG(request_info).raw_post_data.
案例3.最后一种情况发生在与POST不同的请求(例如PUT).php_default_post_reader被直接调用.由于请求不是POST请求,因此吞下数据sapi_read_standard_form_data.由于没有读取数据,因此没有任何事情要做.