375 lines
12 KiB
PHP
375 lines
12 KiB
PHP
<?php
|
|
|
|
namespace app\common\controller;
|
|
|
|
use app\common\service\OssService;
|
|
use app\common\service\UploadedFilesService;
|
|
use app\common\service\UploadService;
|
|
use app\common\traits\ResponseTrait;
|
|
use support\Log;
|
|
use support\Request;
|
|
use support\exception\BusinessException;
|
|
use Shopwwi\WebmanFilesystem\Facade\Storage;
|
|
|
|
class UploadController
|
|
{
|
|
|
|
use ResponseTrait;
|
|
|
|
protected $noNeedLogin = ['proxy'];
|
|
|
|
protected $noNeedHeaderData = ['proxy'];
|
|
|
|
public function upload(Request $request)
|
|
{
|
|
try {
|
|
$scene = $request->input('scene', 'image');
|
|
$file = $request->file('file');
|
|
if ($file && $file->isValid()) {
|
|
$fileName = md5($file->getUploadName() . time()).'.'.$file->getUploadExtension();
|
|
$pathUrl = '/uploads/'.$scene.'/'.date('Ymd').'/'.$fileName;
|
|
$fullPathUrl = public_path() . $pathUrl;
|
|
$file->move($fullPathUrl);
|
|
|
|
$data = [
|
|
'domain' => getenv('MAIN_DOMAIN'),
|
|
'file_url' => $pathUrl,
|
|
'full_url' => getenv('MAIN_DOMAIN') . $pathUrl,
|
|
'scene' => $scene,
|
|
];
|
|
|
|
// 记录文件信息到数据库
|
|
try {
|
|
$uploadedFilesService = new UploadedFilesService();
|
|
$partition = $scene;
|
|
$category = $request->input('category', 'general');
|
|
|
|
$fileInfo = [
|
|
'file_name' => basename($fileName),
|
|
'file_path' => $pathUrl,
|
|
'file_size' => $file->getSize(),
|
|
'file_type' => $file->getUploadMimeType(),
|
|
'original_name' => $file->getUploadName(),
|
|
];
|
|
|
|
$recordResult = $uploadedFilesService->recordFileInfo($fileInfo, $request, $partition, $category);
|
|
$data['file_id'] = $recordResult['id'];
|
|
$data['partition'] = $partition;
|
|
$data['category'] = $category;
|
|
} catch (\Throwable $e) {
|
|
// 记录失败不影响上传结果,只记录日志
|
|
Log::error('记录文件信息失败: ' . $e->getMessage());
|
|
}
|
|
|
|
return $this->success($data, 'upload success');
|
|
}
|
|
return $this->error('file not found');
|
|
} catch (\Throwable $e) {
|
|
Log::info('uploadFile',[$e->getMessage(),$e->getFile(),$e->getLine()]);
|
|
return $this->error($e->getMessage());
|
|
}
|
|
}
|
|
|
|
// 上传单文件附件
|
|
public function uploadFile(Request $request)
|
|
{
|
|
try {
|
|
$scene = $request->input('scene');
|
|
$file = $request->file('file');
|
|
|
|
if (!$file || !$file->isValid()) {
|
|
return $this->error('上传失败');
|
|
}
|
|
if (empty($scene)) {
|
|
// return $this->error('上传场景不能为空');
|
|
$sceneUrl = '';
|
|
}else{
|
|
$sceneUrl = $scene . '/';
|
|
}
|
|
$originalName = $file->getUploadName();
|
|
|
|
$ossservice = new OssService();
|
|
$mimes = $ossservice->getMimeTypes(['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'zip', 'rar']);
|
|
|
|
$result = Storage::adapter('oss')
|
|
->path(config('oss.oss_main_dir') . $sceneUrl . date('Ymd'))
|
|
->size(1024*1024*50)
|
|
->extYes($mimes)
|
|
->upload($file);
|
|
|
|
|
|
$data = [
|
|
'original_name' => $originalName,
|
|
'file_name' => $result->file_name,
|
|
'file_url' => $ossservice->generatePrivateUrl($result->file_name)
|
|
];
|
|
|
|
// 记录文件信息到数据库
|
|
$category = $request->input('category', 'general');
|
|
$res = $this->recordFileInfo($result,$request,$file,$scene,$category);
|
|
$data = array_merge($data, $res);
|
|
|
|
return $this->success($data);
|
|
}catch (\Throwable $e){
|
|
Log::info('uploadFile',[$e->getMessage(),$e->getFile(),$e->getLine()]);
|
|
return $this->error($e->getMessage());
|
|
}
|
|
}
|
|
|
|
// 上传单文件图片
|
|
public function uploadImage(Request $request)
|
|
{
|
|
try {
|
|
$scene = trim((string)$request->input('scene', ''));
|
|
$sceneUrl = $scene ? $scene . '/' : '';
|
|
|
|
$file = $request->file('image');
|
|
if (!$file || !$file->isValid()) {
|
|
return $this->error('上传失败');
|
|
}
|
|
|
|
// 允许的 MIME
|
|
$allowMime = [
|
|
'image/jpeg',
|
|
'image/png',
|
|
'image/webp',
|
|
];
|
|
|
|
$mime = $file->getMimeType();
|
|
if (!in_array($mime, $allowMime, true)) {
|
|
return $this->error('不支持的图片类型,支持jpeg、png、webp');
|
|
}
|
|
|
|
// 临时目录
|
|
$tmpDir = runtime_path('upload_tmp');
|
|
if (!is_dir($tmpDir)) {
|
|
mkdir($tmpDir, 0755, true);
|
|
}
|
|
|
|
$tmpPath = $tmpDir . '/' . uniqid('img_', true);
|
|
$file->move($tmpPath);
|
|
|
|
// 压缩处理
|
|
$finalPath = $this->compressImage($tmpPath, $mime);
|
|
|
|
$result = Storage::adapter('oss')
|
|
->path(config('oss.oss_main_dir') . $sceneUrl . date('Ymd'))
|
|
->size(1024*1024*30)
|
|
->extYes(['image/jpeg','image/png'])
|
|
->extNo(['image/gif'])
|
|
->upload($file);
|
|
|
|
// 清理临时文件
|
|
@unlink($tmpPath);
|
|
if ($finalPath !== $tmpPath) {
|
|
@unlink($finalPath);
|
|
}
|
|
|
|
$ossservice = new OssService();
|
|
|
|
$data = [
|
|
'href' => $result->file_name,
|
|
'alt' => '',
|
|
'url' => $ossservice->generatePrivateUrl($result->file_name)
|
|
];
|
|
|
|
// 记录文件信息到数据库
|
|
$category = $request->input('category', 'general');
|
|
$res = $this->recordFileInfo($result,$request,$file,$scene,$category);
|
|
$data = array_merge($data, $res);
|
|
|
|
// return json(['errno' => 0, 'data' => $data]);
|
|
return $this->success($data);
|
|
} catch (\Throwable $e) {
|
|
// return json(['errno' => 1, 'message' => $e->getMessage()]);
|
|
Log::info('uploadFile',[$e->getMessage(),$e->getFile(),$e->getLine()]);
|
|
return $this->error($e->getMessage());
|
|
}
|
|
}
|
|
|
|
protected function compressImage(string $srcPath, string $mime): string
|
|
{
|
|
// 不支持 imagick 直接返回原图
|
|
if (!extension_loaded('imagick')) {
|
|
return $srcPath;
|
|
}
|
|
|
|
try {
|
|
$image = new \Imagick();
|
|
$image->readImage($srcPath);
|
|
|
|
// 防止超大图
|
|
$maxWidth = 2000;
|
|
$maxHeight = 2000;
|
|
|
|
$image->thumbnailImage($maxWidth, $maxHeight, true);
|
|
|
|
// 自动方向修正(拍照图必备)
|
|
if (method_exists($image, 'autoOrient')) {
|
|
$image->autoOrient();
|
|
}
|
|
|
|
// PNG / JPEG → WebP
|
|
if (in_array($mime, ['image/png', 'image/jpeg'], true)) {
|
|
$image->setImageFormat('webp');
|
|
$image->setImageCompressionQuality(80);
|
|
|
|
$dstPath = $srcPath . '.webp';
|
|
$image->writeImage($dstPath);
|
|
} else {
|
|
// 其他类型直接原样
|
|
$dstPath = $srcPath;
|
|
}
|
|
|
|
$image->clear();
|
|
$image->destroy();
|
|
|
|
return $dstPath;
|
|
|
|
} catch (\Throwable $e) {
|
|
// 压缩失败直接返回原图
|
|
return $srcPath;
|
|
}
|
|
}
|
|
|
|
public function recordFileInfo($result, $request, $file, $scene, $category)
|
|
{
|
|
try {
|
|
$uploadedFilesService = new UploadedFilesService();
|
|
$partition = $scene;
|
|
|
|
$fileInfo = [
|
|
'file_name' => basename($result->file_name),
|
|
'file_path' => $result->file_name, // OSS存储路径
|
|
'file_size' => $file->getSize(),
|
|
'file_type' => $file->getUploadMimeType(),
|
|
'original_name' => $file->getUploadName(),
|
|
];
|
|
|
|
$partition = !empty($partition)?$partition:'other';
|
|
$category = !empty($category)?$category:'other';
|
|
$recordResult = $uploadedFilesService->recordFileInfo($fileInfo, $request, $partition, $category);
|
|
$data = [];
|
|
$data['file_id'] = $recordResult['id'];
|
|
$data['partition'] = $partition;
|
|
$data['category'] = $category;
|
|
return $data;
|
|
} catch (\Throwable $e) {
|
|
// 记录失败不影响上传结果,只记录日志
|
|
Log::error('记录文件信息失败: ' . $e->getMessage());
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取文件信息
|
|
*
|
|
* @param Request $request
|
|
* @return \support\Response
|
|
*/
|
|
public function getFileInfo(Request $request)
|
|
{
|
|
try {
|
|
$fileId = $request->input('id');
|
|
|
|
if (!$fileId) {
|
|
return $this->error('文件ID不能为空');
|
|
}
|
|
|
|
$uploadedFilesService = new UploadedFilesService();
|
|
$fileInfo = $uploadedFilesService->getFileInfo($fileId);
|
|
|
|
if (!$fileInfo) {
|
|
return $this->error('文件不存在');
|
|
}
|
|
|
|
return $this->success($fileInfo);
|
|
} catch (\Throwable $e) {
|
|
return $this->error('获取文件信息失败: ' . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 删除文件
|
|
*
|
|
* @param Request $request
|
|
* @return \support\Response
|
|
*/
|
|
public function deleteFile(Request $request)
|
|
{
|
|
try {
|
|
$fileId = $request->input('id');
|
|
$path = $request->input('path');
|
|
|
|
$uploadedFilesService = new UploadedFilesService();
|
|
if(!empty($path) && empty($fileId)){
|
|
$where = ['file_path' => $path];
|
|
$file = $uploadedFilesService->getFile($where);
|
|
$fileId = $file->id;
|
|
}elseif(empty($path) && !empty($fileId)){
|
|
$where = ['id' => $fileId];
|
|
$file = $uploadedFilesService->getFile($where);
|
|
$path = $file->file_path;
|
|
}
|
|
if (!$fileId) {
|
|
return $this->error('文件ID与路径不能为空');
|
|
}
|
|
|
|
// 删除 OSS 上的文件
|
|
$ossService = new OssService();
|
|
$ossService->deleteFile($path);
|
|
|
|
$result = $uploadedFilesService->deleteFile($fileId);
|
|
|
|
if ($result) {
|
|
return $this->success([], '文件删除成功');
|
|
} else {
|
|
return $this->error('文件删除失败');
|
|
}
|
|
} catch (\Throwable $e) {
|
|
return $this->error('文件删除失败: ' . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取分区配置
|
|
*
|
|
* @param Request $request
|
|
* @return \support\Response
|
|
*/
|
|
public function getPartitionConfig(Request $request)
|
|
{
|
|
try {
|
|
$uploadedFilesService = new UploadedFilesService();
|
|
$config = $uploadedFilesService->getPartitionConfig();
|
|
|
|
return $this->success($config);
|
|
} catch (\Throwable $e) {
|
|
return $this->error('获取分区配置失败: ' . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public function proxy(Request $request)
|
|
{
|
|
$filePath = $request->get('file'); // 原OSS文件路径
|
|
try {
|
|
// 生成签名URL
|
|
$signedUrl = (new \app\common\service\OssService())->generatePrivateUrl($filePath);
|
|
|
|
// 获取图片数据并返回
|
|
$imageData = file_get_contents($signedUrl);
|
|
|
|
// 根据文件类型设置Content-Type
|
|
$mime = mime_content_type('data://application/octet-stream;base64,'.base64_encode($imageData));
|
|
|
|
return response($imageData, 200, [
|
|
'Content-Type' => $mime,
|
|
'Cache-Control' => 'public, max-age=600' // 客户端缓存10分钟
|
|
]);
|
|
} catch (\Exception $e) {
|
|
return response('Image not found '.$e->getMessage(), 404);
|
|
}
|
|
}
|
|
} |