PHP 8.5 OSS视频直传必须服务端签名+表单提交,核心问题在签名生成、CA证书配置和php://input仅读一次;Policy需ISO8601时间、content-length-range校验及严格字段顺序,签名须双重base64+正确JSON编码,回调验签前禁止任何预读操作。

PHP 视频文件走 OSS/S3 直传,必须用服务端签名 + 表单提交,前端不能碰 AccessKeyId 和 AccessKeySecret;回调验签失败、上传 403、PHP 8.5 下 cURL error 60 是高频问题,根源都在签名生成、证书配置和原始请求体读取这三处。
PostObject 表单直传必须带 Policy 且字段顺序固定
OSS 的 PostObject 接口不接受 URL 签名,只认 base64 编码的 policy 和对应 signature。Policy 不是可选字段,而是强制校验上传边界的策略文档。
-
expiration必须是 ISO8601 格式(如2026-06-11T13:17:00.000Z),不是 Unix 时间戳或秒数 -
conditions数组里至少包含:['content-length-range', 0, 20971520](限制 0–20MB),否则可能被用于 DoS 攻击 - 若限制上传目录,用
['starts-with', '$key', '/uploads/202606/'],注意末尾斜杠——漏掉会导致/uploads123.mp4也被放行 - 表单字段顺序必须严格为:
key、policy、signature、OSSAccessKeyId、success_action_redirect(不推荐)、callback(推荐)等,顺序错一位就 403 - 前端
<form></form>的enctype必须是multipart/form-data,不能是application/x-www-form-urlencoded
PHP 8.5 下签名生成三个硬坑:base64、JSON、换行符
很多 PHP 示例抄 Node.js 版本,但 PHP 的 hash_hmac 默认输出二进制,OSS 要的是 Base64 字符串;时间格式、JSON 编码细节稍错一点,签名就失效。
-
policy字符串必须用json_encode($policy, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),否则中文路径或/被转义会导致签名不匹配 - 计算
signature前,policy必须先base64_encode(),再hash_hmac('sha1', $policyBase64, $accessKeySecret, true),最后再base64_encode()——少一层就 403 -
gmt_iso8601()函数别用date('c'),要手动补.000Z并替换+00:00,例如:str_replace('+00:00', '.000Z', gmdate('c', $time)) - 确保
$accessKeySecret是非空字符串,PHP 8.5 下hash_hmac('sha1', ..., null, ...)会直接报Fatal error
PHP 8.5 回调验签失败:php://input 只能读一次
OSS 直传回调要求服务端对原始 POST body 做严格签名比对。PHP 8.5 对数组键名大小写、空格、换行符更敏感,file_get_contents('php://input') 若被提前读取过一次(比如框架自动解析了 JSON),就会返回空字符串,导致验签失败。
立即学习“PHP免费学习笔记(深入)”;
- 回调入口脚本第一行必须是
$rawBody = file_get_contents('php://input');,且仅调用一次 - 禁止在验签前使用
$_POST、$HTTP_RAW_POST_DATA或任何json_decode()——它们都会触发内部读取 - 验签时传入的
$callbackBody必须与前端生成的callback参数完全一致(含 key 顺序、缩进、引号类型),调试时可用base64_encode($rawBody)对比 - SDK 必须升级到
v2.6.3+,老版本OssClient::signCallbackRequest()在 PHP 8.5 下因参数类型声明不全直接崩溃
cURL error 60 / SSL 证书验证失败:不是 SDK 问题,是环境缺失 CA
PHP 8.5 默认启用更严格的 TLS 验证,而阿里云 OSS endpoint(如 oss-cn-hangzhou.aliyuncs.com)若未正确配置 CA 证书路径,会直接抛出 cURL error 60: SSL certificate problem。
- 确认系统已安装
ca-certificates(Ubuntu/Debian)或openssl(CentOS/RHEL),并更新到最新版 - 在
php.ini中显式指定证书路径:curl.cainfo = "/etc/ssl/certs/ca-certificates.crt"(路径需真实存在) - 禁止临时禁用 SSL 验证(如设
['ssl' => ['verify_peer' => false]]),这会让回调签名失效、OSS 拒绝直传请求 - SDK 初始化时不要手动传
ssl选项,让 Guzzle 或 curl 自行处理;若必须自定义 HTTP 客户端,请确保其底层使用系统 CA
最易被忽略的是:服务端生成的 host 必须是 https://<bucket>.<endpoint></endpoint></bucket>(如 https://my-bucket.oss-cn-hangzhou.aliyuncs.com),不能是控制台看到的“外网访问域名”,也不能漏掉 https://;还有就是视频文件名含中文或空格时,$key 字段必须用 rawurlencode() 处理,否则上传后对象名乱码或 400 错误。



















