PHP原生不支持Smile格式,需用cURL获取二进制数据后,通过php-smile扩展(smile_decode/smile_encode)或Java工具解析;注意UTF-8编码、嵌套深度参数及扩展兼容性。

PHP 读 Smile 格式数据要用 ext-curl + smile 解析库,原生不支持
PHP 标准库完全不识别 Smile(一种二进制 JSON 超集格式),json_decode() 会直接报错 JSON_ERROR_SYNTAX。Smile 数据必须先解码为 UTF-8 字符串(即还原成 JSON),再交给 PHP 原生函数处理。目前最可行的路径是:用 cURL 获取原始二进制内容 → 调用外部工具(如 jackson-dataformat-smile 的 CLI 封装)或使用已编译的 PHP 扩展(如 php-smile)。
注意:php-smile 扩展并非 PECL 官方收录,需手动编译安装,且仅支持 PHP 7.4–8.2;它提供两个核心函数:smile_decode() 和 smile_encode(),行为接近 json_decode()/json_encode(),但底层走二进制解析。
- 若服务端可控,优先编译安装
php-smile扩展(GitHub 搜索mwolfson/php-smile) - 若只能用纯 PHP,可调用 Java 工具:用
shell_exec("java -jar jackson-smile-cli.jar decode")管道传入二进制流 —— 但要求服务器装 JDK 且存在安全风险 - 别尝试用
gzuncompress()或base64_decode()猜解:Smile 不是压缩或编码格式,强行转换只会得到乱码
smile_decode() 的第三个参数 $depth 容易被忽略,超深嵌套会静默失败
和 json_decode() 类似,smile_decode() 支持第三个整数参数控制递归深度,默认是 512。但 Smile 二进制结构对嵌套层级更敏感:一旦实际数据嵌套超过该值,函数返回 null 且不触发任何 warning —— 很难排查。
常见现象:接口返回空数组或 null,但用 file_get_contents() 确认二进制数据已完整接收,gettype($result) 显示 NULL,此时大概率是深度不够。
立即学习“PHP免费学习笔记(深入)”;
- 先用
smile_decode($data, false, 2048)测试是否恢复正常 - 生产环境建议显式传参,例如
smile_decode($raw, true, 1024),避免依赖默认值 - 无法预估深度时,可配合
strlen($raw) < 1024 * 1024做粗略保护:超 1MB 的 Smile 数据通常需调高 depth
写 Smile 数据必须确保输入是 UTF-8 字符串,否则 smile_encode() 会输出损坏字节
smile_encode() 不做字符集转换。如果传入含 GBK、ISO-8859-1 字节的字符串(比如从旧数据库或文件直接读取),输出的 Smile 流在下游(如 Java 服务)解析时会抛 UTF8StreamJsonParser 异常。
典型错误信息:Invalid UTF-8 start byte 0x81 或 Unexpected end-of-input in field name —— 实际是编码污染导致二进制帧错位。
- 强制转码:用
$utf8 = mb_convert_encoding($input, 'UTF-8', 'auto'),'auto'可识别 GBK/GB2312/UTF-8 - 验证是否合法:用
mb_check_encoding($utf8, 'UTF-8')返回false就得清洗或丢弃 - 数组输入无需额外处理,但注意
json_encode()默认不转义中文,而smile_encode()会严格按 UTF-8 字节写入,所以确保json_encode()输出也是 UTF-8(即没开JSON_UNESCAPED_UNICODE以外的干扰选项)
PHP 8.1+ 中 smile_encode() 的 JSON_INVALID_UTF8_IGNORE 不生效
PHP 8.1 引入了 JSON_INVALID_UTF8_IGNORE 标志给 json_encode(),但 php-smile 扩展未同步实现该行为。如果你依赖这个标志来“容错”脏数据,smile_encode() 仍会因非法 UTF-8 字节直接返回 false。
这意味着:不能靠标志兜底,必须在调用前清理字符串。尤其要注意 MySQL TEXT 字段存入时用了 latin1 而应用层没指定 charset,读出来就是乱码字节。
- 清洗方案:用正则
preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]/u', '', $str)删除控制字符(保留常用 Unicode) - 更稳妥的是用
iconv('UTF-8', 'UTF-8//IGNORE', $str),自动跳过非法序列 - 别依赖扩展未来兼容 ——
php-smile当前最新版(v1.0.2)仍未处理该 flag
Smile 的二进制特性决定了它对 PHP 的“透明度”极低,所有读写操作都卡在编码、深度、扩展可用性这三个硬约束上。没有扩展就几乎没法用,有扩展又容易栽在字符集和嵌套深度这种隐性参数上。



















