UCloud官方PHP SDK已停止维护,直接composer require ucloud/ufile-sdk会失败或拉取过期版本;推荐改用cURL手动构造签名上传/下载,注意GMT时间戳、urlencode签名、Region域名及Bucket命名规范。

UCloud对象存储(UFile)的PHP SDK怎么装不报错
UCloud官方PHP SDK已停止维护,直接 composer require ucloud/ufile-sdk 会失败或拉到过期版本(如 v2.0.0,不兼容 PHP 8+,且签名逻辑有缺陷)。必须手动指定兼容分支或改用通用方案。
推荐做法是绕过官方SDK,用标准 curl + 签名构造,或改用社区维护的轻量封装(如 ucloud/ufile-php 的 fork 版本)。若坚持用原版,需降级到 PHP 7.4 并锁死 "ucloud/ufile-sdk": "2.0.0",同时打补丁修复 UFileUtil::sign() 中的 HMAC 签名拼接顺序问题。
- PHP 8.0+ 用户不要尝试
composer install原版 SDK,会卡在ext-mcrypt或mcrypt_encrypt报错 - 签名密钥必须用
urlencode()处理一次再参与 HMAC-SHA1 计算,否则403 Forbidden(错误信息:InvalidSignature) - 请求头中
Authorization字段格式为UCloud <publickey>:<signature></signature></publickey>,注意冒号后无空格
PHP怎么用cURL上传文件到UFile(带签名)
核心是构造合法的 Authorization 头和 X-Ufile-Date 时间戳。UFile 要求时间误差不能超过 15 分钟,且 X-Ufile-Date 必须是 GMT 格式(不是 UTC+8)。
$bucket = 'your-bucket';
$key = 'test/image.jpg';
$publicKey = 'your-public-key';
$privateKey = 'your-private-key';
$filePath = '/path/to/local.jpg';
$method = 'PUT';
$contentType = 'image/jpeg';
$date = gmdate('D, d M Y H:i:s \G\M\T'); // 注意:必须是 GMT
// 构造待签名字符串
$stringToSign = sprintf("%s\n%s\n%s\n%s\n%s", $method, '', $contentType, $date, "/{$bucket}/{$key}");
$signature = base64_encode(hash_hmac('sha1', $stringToSign, $privateKey, true));
$headers = [
"Authorization: UCloud {$publicKey}:{$signature}",
"X-Ufile-Date: {$date}",
"Content-Type: {$contentType}",
"Content-Length: " . filesize($filePath),
];
$ch = curl_init("https://{$bucket}.ufileos.com/{$key}");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
curl_setopt($ch, CURLOPT_POSTFIELDS, file_get_contents($filePath));
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
- 上传大文件(>100MB)要分片,UFile 不支持单次 PUT 超 5GB;小文件建议加
Expect:头避免 100-continue 延迟 -
file_get_contents()读大文件会爆内存,换成CURLOPT_UPLOAD+fopen(..., 'rb')流式上传 - 如果返回
400 Bad Request且 body 是 XML,大概率是X-Ufile-Date格式不对(比如用了date('r'))
PHP怎么从UFile下载文件(含私有Bucket鉴权)
私有 Bucket 下载必须带签名,不能直接用 public URL。GET 请求的签名字符串不含 Content-MD5 和 Content-Type,但必须包含 X-Ufile-Date 和完整 query 参数(含 Expires)。
立即学习“PHP免费学习笔记(深入)”;
更稳妥的做法是生成带时效的预签名 URL,尤其用于前端直传或临时分享:
$expires = time() + 3600; // 1小时有效期
$stringToSign = sprintf("GET\n\n\n%s\n/%s/%s?Expires=%d",
gmdate('D, d M Y H:i:s \G\M\T'), $bucket, $key, $expires);
$signature = base64_encode(hash_hmac('sha1', $stringToSign, $privateKey, true));
$signedUrl = "https://{$bucket}.ufileos.com/{$key}?Expires={$expires}&UCloudPublicKey={$publicKey}&UCloudSignature=" . urlencode($signature);
- 生成的
UCloudSignature必须urlencode(),否则 URL 解析失败导致403 - 如果用
file_get_contents($signedUrl)下载,注意 PHP 默认不跟随 302 重定向,需设stream_context_create(['http'=>['follow_location'=>true]]) - 私有资源直接 GET 返回
404 Not Found(不是 403),这是 UFile 的设计:隐藏资源是否存在
PHP读写UFile时最常踩的三个坑
不是代码写错,而是环境、配置、协议细节没对齐。
- 地区(Region)写错:UFile endpoint 不是统一域名,
cn-bj区域用ufileos.com,cn-sh2区域要用ufileos.cn;填错就Connection refused - Bucket 名含下划线(
_):UFile 不支持,创建时提示成功但实际无效,后续所有请求返回400 InvalidBucketName - 本地开发机时间不准:哪怕差 2 分钟,
X-Ufile-Date就失效,403 InvalidDate—— 建议用ntpdate -q ntp.api.bz校时
签名逻辑看着简单,但每个字段的空行、换行符、编码方式都卡得死。与其反复调 var_dump($stringToSign),不如先用 UCloud 控制台的「API调试」生成一个正确签名,再反推自己代码哪步漏了 urlencode 或多加了空格。



















