file_get_content('php://input') 和$_POST,post和put的一些疑问?

前天,在搞个功能的时候,发现页面ajax过来的值太多了,导致不论是$_POST还是php://input都为空了,很奇怪。

于是弄了demo测试找原因:

    <script>

        var data = 'username=111&email=222';
        for (var i = 0; i < 1750; i++)
        {
            data += '&a' + i + '=' + i;
        }

        var xhr = new XMLHttpRequest();
        xhr.open('post', './test.php');
        // xhr.open('put', './test.php');
        xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
        // xhr.setRequestHeader('Content-type', 'application/json;charset=utf-8');
        // data = JSON.stringify({a: data});

        xhr.onload = function () { console.log(xhr.responseText); }
        xhr.send(data);

    </script>

因为method和Content-type都感觉是对的,但为什么就是拿不到值呢?

我换了application/json和application/x-www-form-urlencoded都会出现这样的问题,

而且好像有个临界值,代码里循环1650就能看到打印数据,1750次就空了。test.php只是简单的

$content = file_get_contents('php://input');

// print_r(count($_POST) . "\n");
print_r($content);

有点纳闷,不停地google,百度找资料,知道post方法,php.ini里是有指令限制传参的个数、大小的,

但是我是file_get_contents('php://input')的拿的鸭,而且php输入流是不受php.ini配置文件指令的影响的啊。

为什么循环少点就可以,多点就不行呢?error_reporting(-1)也没报错,也没警告,没有头绪。

后来,我将ajax的请求方法,改成了PUT,就发现了点端倪(此时还没弄懂post和put的区别)

图片描述

报了一个warning,有错误才更容易找到踩坑的原因啊,继续追
图片描述

不能创建temporary临时文件,因为没有权限,而且看了数据,也不全,没有拿到循环到1749次的数据,好像截断了,然后报这个警告

接着查看PHP脚本执行时会操作到的临时文件目录

echo sys_get_temp_dir();

发现,果然没有权限!

然后,我发现我忘记了一项很重要的事情,就是看日志!啊啊啊啊啊,我忘了多少次排错找bug的时候,没去看日志

果然是有东西的,在apache的error_log,具体看自己配置的日志文件目录。
图片描述

其实就是上图那个Warning的信息。可是我将ajax的方法改为原先的post测试时,却得到不一样的错误日志。

打印数据依旧为空,但是从日志里好像知道了原因:

图片描述

看到没,因为没权限打开临时操作文件,无法将post传输的数据buffer缓冲起来,然后discard 全部舍弃掉了,所以print_r一直没空咯。

到这里,好像是找到问题的解决办法了?

就是设置临时操作文件的权限,图快又不考虑安全性的话,chmod 777 /tmp

。。。

将temp临时文件的权限设置好可写之后,我需要重新测试一遍。

图片描述

改为post请求,Content-type为application/x-www-form-urlencoded,将循环次数改为1750次或更大,

打印$_POST能得到数据,只要数据大小不超过post_max_size(默认是8m)就好,但是因为变量数超过max_input_vars(默认1000个)就被PHP解析器截断了。

打印file_get_content('php://input')能获取到所有的数据,因为php://input输入流不关配置文件影响,没被截断。

图片描述

改为put请求,打印$_POST为空,打印file_get_content('php://input')能获取到所有的数据正常。

但是,为什么?当临时文件没权限写入的情况下,情况是不一样呢????

没有权限的前提下,

post请求,循环1650次,正常打印,循环1750次,都变空了,看错误日志是被直接discard舍弃掉。

图片描述

put请求,循环1650次,正常打印,循环1750次,file_get_contents报了个Warning,然后打印出部分数据了,不完整

图片描述

为什么会这样的原因,我还没搞得彻底清除。猜测是这样,

file_get_content('php://input'),是可以获取所有输入流的数据,且不受php.ini指令影响,但是使用这个函数获取内容时,
有两个要点:
1.file_get_contents需要有可写入临时文件的权限
2.获取的内容大小存在一个设定值(具体是多少,还是配置文件控制,没搞懂),当内容大小超过这个值之后,会把剩下的内容写到一个临时文件里面。

为什么会出现这样的一个情况呢?

了解了一下post和put的区别,大概也就是基于restful规范上的语义本质区别吧。

没搞懂这其中的原因 = =

阅读 4k
1 个回答

猜想应该是PHP的输入流都需要拥有临时文件的写入权限,
不只是file_get_contents('php://input'),还有GPC
当传输内容大小没超过某个定值(好像是8k?)时,不需要操作临时文件,超过时
需要有临时文件的权限把内容写入,否则全部数据都会被丢空。

post和put请求出现结果的不同可能就再于:
当没临时文件写入权限时

post:传值大小超过某定值时,PHP会执行“ POST data can't be buffered; all data discarded”,所以file_get_contents('php://input')和$_POST都会空
put:传值大小超过某定值时,并没有discard all data,所file_get_contents('php://input')还能获取部分的值,strlen(file_get_contents('php://input'))看到为8192
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题