codeigniter 3 读取原始 post 数据应使用 file_get_contents('php://input'),因框架不自动解析 json/xml;注意该流仅可读一次,且 multipart 请求中不可用。

CodeIgniter 3 怎么读取原始 POST 数据(如 JSON、XML)
CodeIgniter 3 默认会自动解析 application/x-www-form-urlencoded 和 multipart/form-data 请求体,但对 application/json 或纯文本等类型,$this->input->post() 返回空数组——因为框架没触发解析逻辑,原始字节还在输入流里。
正确做法是直接从 PHP 输入流读取:
-
file_get_contents('php://input')是最常用且可靠的方式(注意:该流只能读一次,且在$_POST已被填充后可能为空) - 不要用
fgets(fopen('php://input', 'r')),容易截断或阻塞 - 若请求含文件上传(
multipart),php://input会被清空,此时无法读取原始数据——这是硬限制,不是 bug
CodeIgniter 4 的 $request->getRawInput() 为什么有时返回空
CI4 的 $request->getRawInput() 底层仍是调用 file_get_contents('php://input'),但它加了缓存和条件判断。常见空值原因:
- 控制器方法执行前,其他代码(如中间件、钩子)已提前读过
php://input - 请求 Content-Type 被识别为可自动解析类型(如
application/json),CI4 默认已解析并清空流 - 使用了
$request->getJSON()或$request->getPost()后再调用getRawInput(),流已不可重复读
稳妥方案:在控制器构造函数或最早可执行位置就调用 file_get_contents('php://input') 并缓存到属性中。
如何安全地解析原始 JSON 并兼容 CI3/CI4
不能直接 json_decode($raw, true) 就完事——原始数据可能为空、非法 JSON、超大 Payload,或编码异常。
- 先检查
$_SERVER['CONTENT_TYPE']是否含application/json,避免误解析非 JSON 请求 - 用
json_last_error()判定解析失败原因,而非只看null返回值 - CI3 中建议封装成辅助函数:
function get_raw_json() { $raw = file_get_contents('php://input'); if (empty($raw)) return null; $data = json_decode($raw, true); return json_last_error() === JSON_ERROR_NONE ? $data : null; } - CI4 可复用
$request->getJSON(true)(第二个参数为true表示允许失败返回null),它内部已处理边界情况
InputStream 读取失败的典型错误信息与排查点
遇到读不到数据时,优先查这些地方:
-
PHP Warning: file_get_contents(): php://input not readable→ 检查是否启用了enable_post_data_reading = Off(极少见,多见于自定义 SAPI) -
Content-Length: 0却有 body → Nginx/Apache 配置拦截了非标准请求头,或客户端未正确发送 body - CI3 中
$this->input->raw_input_stream属性为空 → 这个属性只在第一次调用$this->input->post()等方法时才被初始化,不是实时流镜像 - cURL 测试时漏传
-H "Content-Type: application/json"→ CI 会按默认表单逻辑处理,跳过原始流读取路径
原始数据读取这件事,表面只是调一行函数,实际依赖请求生命周期、SAPI 行为、框架解析时机三者严格对齐。少一个环节,数据就丢了,而且不报错,只静默为空。











