为何Paypal IPN监听器中数组转换列存为字符串"0"?
根据你描述的配置(Eloquent的$casts = ['data' => 'array']、MySQL的text字段),data列最终存储"0"的核心原因是:赋值给$model->data的是整数0,Eloquent会将其JSON编码为字符串"0"并存入数据库。下面是几种可能导致这种情况的POST数据或代码处理场景:
1. POST数据为空(或未被正确接收),且代码存在强制类型转换
虽然Paypal的IPN历史显示发送了有效数据,但如果由于服务器配置问题(比如max_input_vars超限、POST数据传输中断)或代码错误(比如误用$_GET而非$_POST、Laravel中错误调用$request->query()而非$request->post()),导致你实际拿到的POST数据是空数组。
如果你的代码里存在类似这样的强制转换:
$model->data = (int)$request->all();
空数组在PHP中强制转为整数会得到0,最终Eloquent将其编码为"0"存入数据库。
2. POST数据包含非UTF-8字符,导致JSON编码失败
Paypal的IPN数据通常是UTF-8编码,但如果传输过程中出现字符集乱码,或者POST数据里包含了json_encode无法处理的非UTF-8字符,json_encode($request->all())会返回false。
如果你的代码错误地将这个失败结果强制转为整数:
$model->data = (int)json_encode($request->all());
false转为整数就是0,最终存储为"0"。
3. 代码错误地将单个整数/布尔值赋值给data字段
如果你的监听器代码没有正确获取整个POST数组,而是误取了某个返回0的字段或验证结果,比如:
- 错误地读取了某个不存在的字段,且设置默认值为
0:$model->data = $request->input('non_existent_field', 0); - 将IPN验证的布尔结果(比如验证失败返回
false,但被强制转为0)赋值给data:$model->data = (int)$paypal_validator->verify($request);
这种情况下,赋值的整数0会被Eloquent编码为"0"存入数据库。
4. 极端情况:POST数据仅包含一个值为0的键值对
虽然Paypal的标准IPN数据不会是这种格式,但如果POST数据是类似cmd=0这样的单一键值对,且你的代码错误地只提取了值而非整个数组:
$model->data = $request->input('cmd');
那赋值的0会被编码为"0"。不过这种情况和Paypal显示发送有效数据的描述不符,可能性较低。
你提到正在更新监听器记录原始POST内容,这是排查问题的关键。建议同时记录json_encode($request->all())的返回值,这样就能直接看到是否是编码失败导致的false,进而追踪到根源。
内容的提问来源于stack exchange,提问作者laketuna

