一个用于Bagisto的图片上传模块,支持上传到AWS S3或其他存储驱动。
在项目的根目录运行:
composer require longyi/image-upload
或者手动添加到 composer.json:
{
"require": {
"longyi/image-upload": "^1.0"
}
}
在 .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
php artisan vendor:publish --provider="Longyi\ImageUpload\Providers\ImageUploadServiceProvider" --tag=config
php artisan config:clear
php artisan cache:clear
访问管理后台的图片上传页面:
/admin/image-upload
前端用户可以通过 API 上传图片,所有接口都在 /api/image-upload 路径下。
请求:
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"
}
}
请求:
POST /api/image-upload/upload-multiple
Content-Type: multipart/form-data
images[]: [file1]
images[]: [file2]
directory: shop/uploads (可选)
限制:
模块提供了一个现成的 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>
如果你不使用 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 端点用于管理后台(需要管理员权限):
请求:
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"
}
}
请求:
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"
}
]
}
请求:
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"
}
请求:
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"
}
| 功能 | 管理后台路由 | 前端路由 | 说明 |
|---|---|---|---|
| 上传单张 | 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等),只需:
config/filesystems.php 中配置新的diskIMAGE_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 即可。
MIT License
Longyi Team dev@longyi.com