ThinkPHP 6+ 可通过自定义 OSS 上传驱动实现流式上传:创建实现 upload() 方法的驱动类,用 fopen($file->getTmpName(), 'rb') 获取资源句柄直传 OSS SDK v3,避免本地落盘;需配置 composer autoloading 并正确设置 bucket 权限、endpoint 和 CORS。

ThinkPHP 上传文件后怎么直接写到 OSS,不走本地临时目录
默认情况下 ThinkPHP 的 File::move() 会先保存到 runtime/upload 这类本地路径,再手动传 OSS——这多一次 I/O,还容易因磁盘满或权限失败中断。真正要的是「流式上传」:上传请求一来,边读边推到 OSS,不落地。
关键在替换上传驱动,不是改控制器逻辑。ThinkPHP 6+ 的 think-file 支持自定义 UploadDriver,OSS 驱动必须实现 upload() 方法并返回 UploadFile 兼容对象。
- 别用
file_get_contents($_FILES['xxx']['tmp_name'])—— tmp_name 是临时路径,不是内存流,且 PHP-FPM 可能已删掉它 - 必须用
$_FILES['xxx']['tmp_name']打开资源句柄:fopen($tmpName, 'rb'),再传给 OSS SDK 的putObject(支持 stream) - OSS SDK v2 不支持流式上传,必须用 v3:
aliyuncs/oss-sdk-php:^3.0
如何写一个最小可用的 OSS 上传驱动类
驱动类不需继承任何基类,只要提供 upload() 方法,接收 UploadedFile 实例,返回数组格式的上传结果(含 url、path 等字段)。
注意:ThinkPHP 调用驱动时,不会自动注入配置,所有 OSS 参数(endpoint、accessKeyId 等)得从 config/filesystems.php 或环境变量里手动读取。
立即学习“PHP免费学习笔记(深入)”;
class OssUploadDriver
{
public function upload($file): array
{
$client = new OSSOssClient(
$_ENV['OSS_ACCESS_KEY_ID'],
$_ENV['OSS_ACCESS_KEY_SECRET'],
$_ENV['OSS_ENDPOINT']
);
$objectKey = 'uploads/' . date('Ym') . '/' . uniqid() . '_' . $file->getOriginalName();
$client->putObject(
$_ENV['OSS_BUCKET'],
$objectKey,
fopen($file->getTmpName(), 'rb') // ← 关键:必须是 resource,不能是字符串路径
);
return [
'url' => 'https://' . $_ENV['OSS_BUCKET'] . '.' . $_ENV['OSS_ENDPOINT'] . '/' . $objectKey,
'path' => $objectKey,
'name' => $file->getOriginalName(),
];
}
}
- 别漏掉
fopen(..., 'rb')的'rb'模式,二进制安全,Windows 下尤其重要 -
$objectKey中避免使用用户可控的原始文件名直拼(防路径遍历),uniqid()+ 后缀更稳妥 - 返回的
url必须是可访问地址,如果 bucket 是私有读,这里得生成带签名的 URL,不能直接拼
为什么用 filesystems.php 配置驱动总报 Class not found
ThinkPHP 不会自动加载你写的驱动类,它只认 vendor 里已注册的类,或者你手动加到 composer.json 的 autoload 中。
常见错误是把驱动类放在 app/common/driver/OssUploadDriver.php,但没在 composer.json 里声明 PSR-4 映射,导致 new OssUploadDriver() 失败,报 Class 'OssUploadDriver' not found。
- 在
composer.json的autoload→psr-4下加一行:"App\Common\Driver\": "app/common/driver/" - 然后运行
composer dump-autoload,不是dump或autoloader - 驱动类命名必须和文件名一致,且首字母大写:
OssUploadDriver.php对应class OssUploadDriver - 别在
config/filesystems.php里写'driver' => OssUploadDriver::class—— 类名要用字符串:'driver' => 'App\Common\Driver\OssUploadDriver'
OSS 上传成功但前端拿不到图片,HTTP 403 或 404 怎么查
403 多半是 bucket 权限问题;404 则是 object key 写错或 CDN 缓存了旧 404 响应。不要急着重传,先确认三件事:
- 用
ossutil ls oss://your-bucket/uploads/直接查 OSS 里有没有那个objectKey,排除 SDK 上传静默失败 - 检查 bucket 的读写权限:如果是私有 bucket,
url必须用$client->signUrl()生成,不能硬拼 - 如果用了 CDN 或自定义域名,确认 CNAME 已生效、HTTPS 证书正常,且 OSS 的跨域(CORS)配置允许该域名:
AllowedOrigin不能写*(当带 credential 时无效)
最易被忽略的一点:OSS 的 endpoint 区分内网/外网。开发机直连要用外网 endpoint(如 oss-cn-hangzhou.aliyuncs.com),ECS 同地域部署建议切内网(oss-cn-hangzhou-internal.aliyuncs.com),否则流量走公网,慢还计费。


















