使用file_get_contents('php://input')获取cURL POST数据始终为空,该如何排查?
file_get_contents('php://input')返回空值的问题 我来帮你梳理这个问题——你已经确认请求确实发送了JSON数据,allow_url_fopen也开启了,PHP错误日志没相关报错,那大概率是下面几个容易被忽略的细节导致的:
检查
post_max_size配置是否过小
如果你的POST请求数据大小超过了PHP配置中post_max_size的值,PHP会直接丢弃整个请求体,导致php://input读取为空。你可以在脚本中添加echo ini_get('post_max_size');查看当前值,比如默认的8M如果满足不了你的数据量,需要修改php.ini中的post_max_size(例如改成20M),之后重启PHP服务生效。避免提前消耗请求体数据流
PHP中php://input是一次性的数据流,一旦被读取就会耗尽。如果你的脚本在调用file_get_contents('php://input')之前,有其他代码读取了请求体(比如fopen('php://input', 'r'),或者某些框架的中间件自动解析了请求),后续再读就会返回空值。另外,虽然JSON请求默认不会被PHP解析到$_POST,但如果请求的Content-Type设置错误,PHP可能尝试自动解析,间接消耗了php://input。确认cURL请求的
Content-Type头是否正确
即便mitmproxy看到发送了JSON,若cURL没有设置Content-Type: application/json头,部分服务器配置或PHP拦截逻辑可能会处理请求体,导致php://input为空。正确的POST请求示例应该包含这个头:curl -X POST -H "Content-Type: application/json" -d '{"name": "test", "data": "sample"}' http://your-script-path.php检查安全扩展或服务器模块的拦截
像Suhosin这类PHP安全扩展,或者服务器的mod_security模块,可能会在某些规则下截断或丢弃请求体。你可以尝试临时禁用这些扩展/模块,测试问题是否消失;同时查看服务器访问日志,确认请求是否完整到达服务器。验证
always_populate_raw_post_data配置
虽然PHP7.0之后这个配置已被废弃,但如果你的环境中手动设置过它(值不为-1),可能会影响php://input的读取。可以在脚本中输出echo ini_get('always_populate_raw_post_data');,如果不是-1,请在php.ini中设置always_populate_raw_post_data = -1并重启PHP。
测试脚本推荐
你可以用下面的脚本快速排查环境和请求问题:
<?php // 输出关键配置信息 echo "post_max_size: " . ini_get('post_max_size') . PHP_EOL; echo "allow_url_fopen: " . ini_get('allow_url_fopen') . PHP_EOL; echo "always_populate_raw_post_data: " . ini_get('always_populate_raw_post_data') . PHP_EOL; // 读取原始请求体 $rawInput = file_get_contents('php://input'); echo "Raw request content: " . $rawInput . PHP_EOL; // 输出请求的Content-Type echo "Request Content-Type: " . (isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : 'Not set') . PHP_EOL; ?>
用正确的cURL命令发送请求后,查看输出结果就能快速定位问题所在。
内容的提问来源于stack exchange,提问作者DonovanChan




