README.md 11 KB

Longyi Image Upload Module

一个用于Bagisto的图片上传模块,支持上传到AWS S3或其他存储驱动。

功能特性

  • ✅ 支持单张图片上传
  • ✅ 支持多张图片批量上传
  • ✅ 支持AWS S3存储
  • ✅ 支持本地存储
  • ✅ 自动图片优化(转换为WebP格式)
  • ✅ 文件大小和类型验证
  • ✅ 自定义上传目录
  • ✅ 图片删除功能
  • ✅ 中英文界面支持
  • 管理后台和前端都支持
  • 提供Vue组件供前端使用

安装

1. 添加依赖

在项目的根目录运行:

composer require longyi/image-upload

或者手动添加到 composer.json

{
    "require": {
        "longyi/image-upload": "^1.0"
    }
}

2. 配置AWS S3(如果使用S3存储)

.env 文件中添加以下配置:

# 设置默认上传磁盘为s3
IMAGE_UPLOAD_DISK=s3

# AWS S3 配置
AWS_ACCESS_KEY_ID=your-access-key-id
AWS_SECRET_ACCESS_KEY=your-secret-access-key
AWS_DEFAULT_REGION=your-region
AWS_BUCKET=your-bucket-name
AWS_URL=https://your-bucket.s3.your-region.amazonaws.com
AWS_USE_PATH_STYLE_ENDPOINT=false

# 可选:设置最大上传大小(KB)
IMAGE_UPLOAD_MAX_SIZE=5120

3. 发布配置文件(可选)

php artisan vendor:publish --provider="Longyi\ImageUpload\Providers\ImageUploadServiceProvider" --tag=config

4. 清除缓存

php artisan config:clear
php artisan cache:clear

使用方法

管理后台访问

访问管理后台的图片上传页面:

/admin/image-upload

前端 API 使用

前端用户可以通过 API 上传图片,所有接口都在 /api/image-upload 路径下。

1. 上传单张图片(前端)

请求:

POST /api/image-upload/upload
Content-Type: multipart/form-data

image: [file]
directory: shop/uploads (可选,默认为 shop/uploads)

响应:

{
    "success": true,
    "message": "Image uploaded successfully",
    "data": {
        "success": true,
        "path": "shop/uploads/2026/05/27/abc123.webp",
        "url": "https://bucket.s3.region.amazonaws.com/shop/uploads/2026/05/27/abc123.webp",
        "original_name": "photo.jpg",
        "mime_type": "image/jpeg",
        "size": 102400,
        "disk": "s3"
    }
}

2. 上传多张图片(前端)

请求:

POST /api/image-upload/upload-multiple
Content-Type: multipart/form-data

images[]: [file1]
images[]: [file2]
directory: shop/uploads (可选)

限制:

  • 最多上传 10 张图片
  • 每张不超过配置的最大大小

Vue 组件使用

模块提供了一个现成的 Vue 组件,可以在前端页面中使用:

<template>
    <div>
        <!-- 单张图片上传 -->
        <image-upload
            :multiple="false"
            label="点击或拖拽上传头像"
            directory="user/avatars"
            @uploaded="handleUploaded"
        />
        
        <!-- 多张图片上传 -->
        <image-upload
            :multiple="true"
            label="点击或拖拽上传产品图片"
            :max-files="5"
            directory="product/images"
            @uploaded="handleMultipleUploaded"
        />
    </div>
</template>

<script>
import ImageUpload from './components/image-upload.blade.php';

export default {
    components: {
        ImageUpload
    },
    
    methods: {
        handleUploaded(data) {
            console.log('上传成功:', data);
            // data.url - 图片URL
            // data.path - 存储路径
        },
        
        handleMultipleUploaded(results) {
            console.log('批量上传结果:', results);
            results.forEach(result => {
                if (result.success) {
                    console.log('图片URL:', result.url);
                }
            });
        }
    }
};
</script>

JavaScript/Fetch 使用示例

如果你不使用 Vue,也可以直接用 JavaScript 调用 API:

// 单张图片上传
async function uploadImage(file) {
    const formData = new FormData();
    formData.append('image', file);
    formData.append('directory', 'custom/path');
    
    try {
        const response = await fetch('/api/image-upload/upload', {
            method: 'POST',
            body: formData,
            headers: {
                'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.content
            }
        });
        
        const data = await response.json();
        
        if (data.success) {
            console.log('上传成功:', data.data.url);
            return data.data;
        } else {
            console.error('上传失败:', data.message);
        }
    } catch (error) {
        console.error('错误:', error);
    }
}

// 多张图片上传
async function uploadMultipleImages(files) {
    const formData = new FormData();
    files.forEach(file => {
        formData.append('images[]', file);
    });
    formData.append('directory', 'custom/path');
    
    try {
        const response = await fetch('/api/image-upload/upload-multiple', {
            method: 'POST',
            body: formData,
            headers: {
                'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.content
            }
        });
        
        const data = await response.json();
        
        if (data.success) {
            console.log('上传成功:', data.data);
            return data.data;
        } else {
            console.error('上传失败:', data.message);
        }
    } catch (error) {
        console.error('错误:', error);
    }
}

// 使用示例
document.getElementById('imageInput').addEventListener('change', async (e) => {
    const file = e.target.files[0];
    if (file) {
        const result = await uploadImage(file);
        // 使用 result.url 显示图片或保存到数据库
        document.getElementById('preview').src = result.url;
    }
});

管理后台 API 使用

以下 API 端点用于管理后台(需要管理员权限):

1. 上传单张图片(管理后台)

请求:

POST /admin/image-upload/upload
Content-Type: multipart/form-data

image: [file]
directory: custom/path (可选)

响应:

{
    "success": true,
    "message": "Image uploaded successfully",
    "data": {
        "success": true,
        "path": "images/uploads/2026/05/27/abc123.webp",
        "url": "https://bucket.s3.region.amazonaws.com/images/uploads/2026/05/27/abc123.webp",
        "original_name": "photo.jpg",
        "mime_type": "image/jpeg",
        "size": 102400,
        "disk": "s3"
    }
}

2. 上传多张图片(管理后台)

请求:

POST /admin/image-upload/upload-multiple
Content-Type: multipart/form-data

images[]: [file1]
images[]: [file2]
directory: custom/path (可选)

响应:

{
    "success": true,
    "message": "2 images uploaded successfully, 0 failed",
    "data": [
        {
            "success": true,
            "path": "images/uploads/2026/05/27/abc123.webp",
            "url": "https://...",
            "original_name": "photo1.jpg",
            "mime_type": "image/jpeg",
            "size": 102400,
            "disk": "s3"
        },
        {
            "success": true,
            "path": "images/uploads/2026/05/27/def456.webp",
            "url": "https://...",
            "original_name": "photo2.jpg",
            "mime_type": "image/jpeg",
            "size": 204800,
            "disk": "s3"
        }
    ]
}

3. 删除图片(管理后台)

请求:

DELETE /admin/image-upload/delete
Content-Type: application/json

{
    "path": "images/uploads/2026/05/27/abc123.webp",
    "disk": "s3" (可选)
}

响应:

{
    "success": true,
    "message": "Image deleted successfully"
}

4. 获取图片URL(管理后台)

请求:

GET /admin/image-upload/url?path=images/uploads/2026/05/27/abc123.webp&disk=s3

响应:

{
    "success": true,
    "url": "https://bucket.s3.region.amazonaws.com/images/uploads/2026/05/27/abc123.webp"
}

API 路由对比

功能 管理后台路由 前端路由 说明
上传单张 POST /admin/image-upload/upload POST /api/image-upload/upload 前端默认目录为 shop/uploads
上传多张 POST /admin/image-upload/upload-multiple POST /api/image-upload/upload-multiple 前端最多10张
删除图片 DELETE /admin/image-upload/delete DELETE /api/image-upload/delete -
获取URL GET /admin/image-upload/url GET /api/image-upload/url -

主要区别:

  • 管理后台:需要管理员权限,路径为 /admin/*
  • 前端:无需特殊权限(或需要登录),路径为 /api/*,默认上传到 shop/uploads 目录

代码中使用

use Longyi\ImageUpload\Services\ImageUploadService;

// 注入服务
public function __construct(
    protected ImageUploadService $imageUploadService
) {}

// 上传单张图片
public function uploadImage(Request $request)
{
    $file = $request->file('image');
    $result = $this->imageUploadService->upload($file, 'custom/directory');
    
    if ($result['success']) {
        // 使用 $result['url'] 或 $result['path']
    }
}

// 上传多张图片
public function uploadImages(Request $request)
{
    $files = $request->file('images');
    $results = $this->imageUploadService->uploadMultiple($files, 'custom/directory');
    
    foreach ($results as $result) {
        if ($result['success']) {
            // 处理成功的上传
        }
    }
}

// 删除图片
public function deleteImage(string $path)
{
    $deleted = $this->imageUploadService->delete($path);
    
    if ($deleted) {
        // 删除成功
    }
}

// 获取图片URL
public function getImageUrl(string $path)
{
    $url = $this->imageUploadService->getUrl($path);
    
    return $url;
}

配置说明

配置文件位于 config/image_upload.php

return [
    // 默认存储磁盘:'local' 或 's3'
    'default_disk' => env('IMAGE_UPLOAD_DISK', 's3'),

    // 允许的图片类型
    'allowed_types' => [
        'image/jpeg',
        'image/jpg',
        'image/png',
        'image/gif',
        'image/webp',
        'image/svg+xml',
    ],

    // 最大文件大小(KB)
    'max_size' => env('IMAGE_UPLOAD_MAX_SIZE', 5120),

    // 上传目录
    'upload_directory' => 'images/uploads',

    // S3配置
    's3' => [
        'bucket' => env('AWS_BUCKET'),
        'region' => env('AWS_DEFAULT_REGION'),
        'visibility' => 'public',
    ],
];

扩展其他存储方式

要添加其他存储方式(如阿里云OSS、腾讯云COS等),只需:

  1. 安装相应的Flysystem适配器
  2. config/filesystems.php 中配置新的disk
  3. 修改 IMAGE_UPLOAD_DISK 环境变量或使用新的disk名称

例如,添加阿里云OSS:

composer require aliyuncs/oss-sdk-php
composer require jacobcyl/ali-oss-storage

config/filesystems.php 中添加:

'oss' => [
    'driver' => 'oss',
    'access_id' => env('ALIYUN_ACCESS_KEY_ID'),
    'access_key' => env('ALIYUN_ACCESS_KEY_SECRET'),
    'bucket' => env('ALIYUN_BUCKET'),
    'endpoint' => env('ALIYUN_ENDPOINT'),
],

然后设置 IMAGE_UPLOAD_DISK=oss 即可。

依赖要求

  • PHP >= 8.1
  • Laravel >= 10.0
  • intervention/image
  • league/flysystem-aws-s3-v3 (用于S3支持)

许可证

MIT License

作者

Longyi Team dev@longyi.com