定制 laobai/cloud-storage 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

laobai/cloud-storage

最新稳定版本:v1.6.0

Composer 安装命令:

composer require laobai/cloud-storage

包简介

云存储上传组件,支持七牛云/本地存储,自动生成视频封面、图片缩略图、文字水印,兼容ThinkPHP5/6/8

README 文档

README

适用于 ThinkPHP5/6/8 的云存储上传组件,支持七牛云/本地存储,自动生成视频封面、图片缩略图、文字水印,兼容 PHP7.0 - PHP8.*

设计理念

极简调用,智能处理 - 只需传入上传字段名,其他一切(文件验证、自动识别类型、生成缩略图/封面/水印、返回统一格式)全部由组件自动完成。

安装

composer require laobai/cloud-storage

配置 (.env)

CLOUD_STORAGE_DRIVER=qiniu

# 七牛云配置
QINIU_ACCESS_KEY=your_access_key
QINIU_SECRET_KEY=your_secret_key
QINIU_BUCKET=your_bucket
QINIU_DOMAIN=https://cdn.example.com
QINIU_ZONE=z0

# FFmpeg 路径(生成视频封面必需)
FFMPEG_PATH=/usr/bin/ffmpeg

# 水印配置
WATERMARK_TEXT=© YourSite.com

FFmpeg 安装

视频封面功能依赖 FFmpeg,必须安装:

# Debian/Ubuntu
apt install ffmpeg

# CentOS/RHEL
yum install epel-release && yum install ffmpeg

# macOS
brew install ffmpeg

注意

  • 如果未安装 FFmpeg,上传视频时不传 video_cover_size 选项可以正常上传
  • 如果传了 video_cover_size 选项但没有 FFmpeg,会抛出异常终止程序
  • 可在 .env 中配置 FFMPEG_PATH 指定安装路径

快速使用

ThinkPHP 控制器中使用

<?php
namespace app\index\controller;

use think\Controller;
use Laobai\CloudStorage\trait\CloudStorageTrait;

class Upload extends Controller
{
    use CloudStorageTrait;

    // 上传图片 + 缩略图
    public function image()
    {
        $result = $this->upload('image', [
            'thumbnail_size' => [300, 300],
        ]);
        
        return json($result);
    }

    // 上传视频 + 封面
    public function video()
    {
        $result = $this->upload('video', [
            'video_cover_size' => [640, 360],
        ]);
        
        return json($result);
    }

    // 上传图片 + 水印
    public function watermark()
    {
        $result = $this->upload('image', [
            'watermark' => true,
        ]);
        
        return json($result);
    }

    // 上传图片 + 缩略图 + 水印
    public function processed()
    {
        $result = $this->upload('image', [
            'thumbnail_size' => [200, 200],
            'watermark' => true,
        ]);
        
        return json($result);
    }

    // 通用上传(自动识别类型)
    public function upload()
    {
        // 不传选项,什么都不处理,只上传
        $result = $this->upload('file');
        
        // 只传字段名,自动识别 image/video/other
        return json($result);
    }

    // 删除文件
    public function delete()
    {
        $this->delete('cloud/20240101/xxx.jpg');
    }
}

返回格式(统一)

// 成功
[
    'code' => 0,
    'msg' => 'success',
    'data' => [
        'url' => 'https://cdn.example.com/cloud/20240101/xxx.jpg',  // 文件地址
        'path' => 'cloud/20240101/xxx.jpg',                         // 存储路径
        'type' => 'image',                                          // image/video/other
        'size' => 123456,                                           // 文件大小
        'mime' => 'image/jpeg',                                    // MIME类型
        'ext' => 'jpg',                                             // 扩展名
        'thumbnail_url' => '...',                                   // 缩略图地址(图片+thumbnail_size时)
        'thumbnail_path' => '...',                                   // 缩略图路径
        'cover_url' => '...',                                       // 封面地址(视频+video_cover_size时)
        'cover_path' => '...',                                       // 封面路径
        'duration' => 0,                                            // 视频时长(秒),仅视频类型返回
    ]
]

// 失败
[
    'code' => 400,
    'msg' => '不支持的文件类型: xxx',
    'data' => [
        'url' => '',
        'path' => '',
        // ... 其他字段全为空
    ]
]

完整选项

$result = $this->upload('field_name', [
    // ===== 必选 =====
    // 无,只需传字段名

    // ===== 缩略图(仅图片有效) =====
    'thumbnail_size' => [300, 300],  // [width, height]

    // ===== 视频封面(仅视频有效) =====
    'video_cover_size' => [640, 360], // [width, height]

    // ===== 水印(仅图片有效) =====
    'watermark' => true,  // 是否启用水印

    // ===== 自定义 =====
    'save_path' => 'custom/path/file.jpg',  // 自定义保存路径(不含前缀)
    'allowed_ext' => ['jpg', 'png', 'gif'],  // 允许的扩展名
    'max_size' => 5 * 1024 * 1024,           // 最大文件大小(字节)
]);

选项说明

选项适用类型说明
thumbnail_size图片缩略图尺寸 [width, height],不传则不生成
video_cover_size视频封面尺寸 [width, height],不传则不生成
watermark图片true 启用水印,false 或不传则不水印
save_path通用自定义保存路径
allowed_ext通用允许的扩展名数组
max_size通用最大文件大小(字节)

自动处理逻辑

用户上传文件
    ↓
自动识别类型 (image/video/other)
    ↓
┌─────────────────────────────────────┐
│ 是图片?                              │
│   ├─ 有 watermark 选项? → 添加水印    │
│   └─ 有 thumbnail_size? → 生成缩略图 │
├─────────────────────────────────────┤
│ 是视频?                              │
│   └─ 有 video_cover_size? → 生成封面 │
├─────────────────────────────────────┤
│ 是其他文件?                           │
│   └─ 直接上传                         │
└─────────────────────────────────────┘
    ↓
返回统一格式

配置说明

application/extra/cloud_storage.php

<?php
return [
    'default' => env('CLOUD_STORAGE_DRIVER', 'qiniu'),

    // 七牛云配置
    'access_key' => env('QINIU_ACCESS_KEY', ''),
    'secret_key' => env('QINIU_SECRET_KEY', ''),
    'bucket' => env('QINIU_BUCKET', ''),
    'domain' => env('QINIU_DOMAIN', ''),
    'zone' => env('QINIU_ZONE', 'z0'),

    // 本地存储配置
    'local_path' => 'uploads/',
    'local_url' => '/uploads/',

    // 上传配置
    'prefix' => 'cloud/',
    'upload' => [
        'allowed_ext' => ['jpg', 'jpeg', 'png', 'gif', 'mp4', 'pdf'],
        'max_size' => 100 * 1024 * 1024,
    ],

    // 缩略图默认配置
    'thumbnail' => [
        'default_size' => [200, 200],
        'quality' => 80,
    ],

    // 视频封面默认配置
    'video' => [
        'capture_time' => 1,              // 截取第几秒
        'default_size' => [480, 270],      // 默认尺寸
        'quality' => 85,                   // 图片质量
        'ffmpeg_path' => env('FFMPEG_PATH', '/usr/bin/ffmpeg'),  // FFmpeg 路径
    ],

    // 水印配置
    'watermark' => [
        'enabled' => false,      // 默认不启用
        'text' => '',
        'font' => '',            // 中文字体路径
        'size' => 14,
        'color' => '#FFFFFF',
        'position' => 'bottom-right',
        'margin' => 10,
    ],
];

环境要求

  • PHP >= 7.0
  • ext-gd
  • ext-fileinfo
  • FFmpeg(生成视频封面 必需,如果需要 video_cover_size 选项)

宝塔面板环境配置

如果使用 宝塔面板,需要进行以下配置:

1. 关闭站点防跨站(open_basedir)

否则组件可能无法正常读取临时文件

  • 登录宝塔面板
  • 点击 网站 → 选择对应站点 → 设置
  • 找到 网站目录 选项卡
  • 取消勾选 防跨站攻击(open_basedir)
  • 保存

2. 删除 exec 禁用函数

组件需要 exec 函数来执行 FFmpeg 命令生成视频封面

  • 登录宝塔面板
  • 点击 软件商店PHP版本(选择你使用的版本,如 PHP 8.0)
  • 点击 禁用函数 设置
  • 找到 exec删除(点击右侧删除按钮)
  • 保存

3. 安装 FFmpeg(如果还未安装)

# 方式一:使用宝塔软件商店
# 软件商店 → 搜索 "ffmpeg" → 安装

# 方式二:SSH 终端安装
yum install ffmpeg -y   # CentOS
apt install ffmpeg -y   # Ubuntu/Debian

项目说明

功能特性

功能说明
云存储集成支持七牛云、本地存储双驱动,可快速扩展其他云存储
自动识别类型自动识别上传文件类型(图片/视频/其他),智能处理
图片缩略图上传图片时自动生成指定尺寸的缩略图
视频封面图上传视频时自动截取指定时间点的画面作为封面
视频时长上传视频时自动获取并返回视频时长(秒)
文字水印支持文字水印,可配置内容、位置、颜色、大小
统一返回格式上传结果统一返回格式,调用方无需关心处理细节
链式配置支持按需配置选项,不传则不处理对应功能
断点续传支持大文件分片上传,应对网络不稳定场景
FFmpeg 集成自动检测 FFmpeg,缺失时给出友好提示

目录结构

laobai/cloud-storage/
├── src/
│   ├── CloudStorage.php          # 核心类
│   ├── CloudStorageService.php   # ThinkPHP 服务注册
│   ├── ChunkUpload.php           # 断点续传
│   ├── helper.php                # 助手函数
│   ├── config.php                # 默认配置
│   ├── Storage/
│   │   ├── StorageInterface.php  # 存储驱动接口
│   │   ├── QiniuStorage.php      # 七牛云驱动
│   │   └── LocalStorage.php      # 本地存储驱动
│   ├── Exception/
│   │   └── CloudStorageException.php
│   ├── command/
│   │   └── CloudStorageCommand.php
│   └── trait/
│       └── CloudStorageTrait.php
├── examples/                     # 使用示例
├── composer.json
└── README.md

使用说明

1. 安装组件

composer require laobai/cloud-storage

2. 配置环境变量

在项目根目录的 .env 文件中添加:

# 选择存储驱动:qiniu / local
CLOUD_STORAGE_DRIVER=qiniu

# 七牛云配置
QINIU_ACCESS_KEY=your_access_key_here
QINIU_SECRET_KEY=your_secret_key_here
QINIU_BUCKET=your_bucket_name
QINIU_DOMAIN=https://your-domain.com
QINIU_ZONE=z0

# FFmpeg 路径(Linux 默认路径,如需生成视频封面必须配置)
FFMPEG_PATH=/usr/bin/ffmpeg

# 水印文字(可选)
WATERMARK_TEXT=© YourWebsite.com

3. ThinkPHP 集成

在控制器中引入 Trait:

<?php
namespace app\index\controller;

use think\Controller;
use Laobai\CloudStorage\trait\CloudStorageTrait;

class Upload extends Controller
{
    use CloudStorageTrait;
    
    // 方式一:使用 Trait 方式(推荐)
    public function uploadImage()
    {
        $result = $this->upload('image', [
            'thumbnail_size' => [300, 300],
            'watermark' => true,
        ]);
        
        return json($result);
    }
    
    // 方式二:直接实例化
    public function uploadVideo()
    {
        $cloud = \Laobai\CloudStorage\CloudStorage::init();
        
        $result = $cloud->upload($this->request, 'video', [
            'video_cover_size' => [640, 360],
        ]);
        
        return json($result);
    }
}

4. 基础用法示例

// 简单上传(自动识别类型)
$result = $this->upload('file');

// 上传图片 + 生成缩略图
$result = $this->upload('avatar', [
    'thumbnail_size' => [200, 200],
]);

// 上传图片 + 添加水印
$result = $this->upload('image', [
    'watermark' => true,
]);

// 上传视频 + 生成封面
$result = $this->upload('video', [
    'video_cover_size' => [640, 360],
]);

// 上传图片 + 缩略图 + 水印
$result = $this->upload('photo', [
    'thumbnail_size' => [400, 400],
    'watermark' => true,
]);

// 自定义保存路径
$result = $this->upload('file', [
    'save_path' => 'avatars/user_' . $userId . '.jpg',
]);

// 自定义允许类型和大小
$result = $this->upload('file', [
    'allowed_ext' => ['jpg', 'png'],
    'max_size' => 5 * 1024 * 1024,  // 5MB
]);

5. 删除文件

// 删除单个文件
$result = $this->delete('cloud/20240101/abc123.jpg');

// 批量删除
$result = $this->deleteMultiple([
    'cloud/20240101/abc123.jpg',
    'cloud/20240101/thumb_200x200.jpg',
]);

6. 处理返回结果

$result = $this->upload('image', [
    'thumbnail_size' => [300, 300],
]);

if ($result['code'] === 0) {
    $data = $result['data'];

    echo '文件地址:' . $data['url'];
    echo '存储路径:' . $data['path'];
    echo '文件类型:' . $data['type'];        // image/video/other
    echo '文件大小:' . $data['size'];
    echo '缩略图地址:' . $data['thumbnail_url'];  // 有则返回,无则空
    echo '视频封面:' . $data['cover_url'];        // 有则返回,无则空
    echo '视频时长:' . $data['duration'];          // 视频时长(秒),仅视频类型返回
} else {
    echo '上传失败:' . $result['msg'];
}

高级用法

自定义配置

$result = $this->upload('image', [
    // 缩略图配置
    'thumbnail_size' => [300, 300],
    'thumbnail_quality' => 80,  // 可选,默认 80
    
    // 视频封面配置
    'video_cover_size' => [640, 360],
    'video_capture_time' => 2,   // 截取第几秒,默认 1
    
    // 水印配置
    'watermark' => true,
    'watermark_text' => '© MySite',
    'watermark_position' => 'bottom-right',
    'watermark_color' => '#FFFFFF',
    'watermark_size' => 16,
    'watermark_margin' => 10,
    
    // 文件验证
    'allowed_ext' => ['jpg', 'jpeg', 'png'],
    'max_size' => 10 * 1024 * 1024,
    
    // 存储配置
    'save_path' => 'custom/path/file.jpg',
]);

使用原生 PHP(非 ThinkPHP)

<?php
require_once __DIR__ . '/vendor/autoload.php';

use Laobai\CloudStorage\CloudStorage;

// 初始化
$cloud = CloudStorage::init([
    'default' => 'qiniu',
    'access_key' => 'your_access_key',
    'secret_key' => 'your_secret_key',
    'bucket' => 'your_bucket',
    'domain' => 'https://cdn.example.com',
]);

// 直接上传本地文件
$result = $cloud->uploadFile('/path/to/local/file.jpg', [
    'thumbnail_size' => [200, 200],
]);

print_r($result);

常见问题

Q: 上传视频报 "FFmpeg 未安装" 错误?

A: 这是因为你传了 video_cover_size 选项,需要 FFmpeg 来生成视频封面。解决方案:

  1. 安装 FFmpeg:apt install ffmpeg
  2. 或者在 .env 中配置正确的 FFmpeg 路径:FFMPEG_PATH=/usr/local/bin/ffmpeg
  3. 如果不需要封面,不传 video_cover_size 选项即可

Q: 水印文字显示乱码?

A: 水印默认使用系统字体,不支持中文。需要配置中文字体文件:

'watermark' => [
    'font' => '/path/to/chinese_font.ttf',  // 使用支持中文的 TTF 字体
    'text' => '你的网站名',
],

Q: 如何切换到本地存储?

A: 在 .env 中修改:

CLOUD_STORAGE_DRIVER=local
STORAGE_LOCAL_PATH=/var/www/uploads/
STORAGE_LOCAL_URL=https://your-domain.com/uploads/

Q: 支持哪些图片格式?

A: 支持:jpg、jpeg、png、gif、bmp、webp、svg

Q: 支持哪些视频格式?

A: 支持:mp4、avi、mov、wmv、flv、mkv、3gp

更新日志

v1.1.0 (2026-05-11)

  • 新增视频时长获取功能
  • 上传视频时自动返回视频时长(秒)

v1.0.0 (2026-05-11)

  • 首发版本
  • 支持七牛云、本地存储双驱动
  • 支持图片缩略图、视频封面、文字水印
  • 统一返回格式
  • FFmpeg 集成与检测

联系作者

  • 作者:别知己
  • 邮箱:369758482@qq.com

如有问题或建议,欢迎邮件联系!

License

MIT

统计信息

  • 总下载量: 5
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 8
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-05-11

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固