request->file('file'); // 检测文件是否存在 if (!$file) { return json(['code' => 400, 'message' => 'No file uploaded']); } // 验证文件类型和大小, 限制20M $maxSize = 20 * 1024 * 1024; if ($file->getSize() > $maxSize) { return json(['code' => 400, 'message' => 'Upload file is too large']); } // 打开文件 $openFile = fopen($file->getRealPath(), 'r'); if (!$openFile) { return json(['code' => 400, 'message' => 'Failed to open the file']); } // 验证上传文件类型 if (!in_array($file->getOriginalMime(), ['image/jpeg','image/png','image/webp','image/bm'])) { return json(['code' => 400, 'message' => 'Upload file type error']); } // 生成唯一的文件名 $fileName = bin2hex(random_bytes(16)) . '.' . $file->getOriginalExtension(); // 初始化s3客户端 $s3Config = Config::get('common.aws_s3'); $s3Client = new S3Client([ 'version' => '2006-03-01', 'region' => $s3Config['aws_region'], 'credentials' => [ 'key' => $s3Config['aws_key'], 'secret' => $s3Config['aws_secret'], ], ]); // 上传文件到S3 $result = $s3Client->putObject([ 'Bucket' => $s3Config['aws_bucket'], 'Key' => 'bourse-avatar/' . $fileName, // s3中的存储路径 'Body' => $openFile, 'ContentType' => $file->getOriginalMime(), // 设置文件的MIME, 不然s3会以流式存储 ])->toArray(); if (empty($result['ObjectURL'])) { return json(['code' => 400, 'message' => '上传s3失败']); } // 记录上传的文件 $resData = AwsS3Model::create([ 'name' => $fileName, 's3_url' => $result['ObjectURL'], 'size' => $file->getSize(), 'mime' => $file->getOriginalMime(), 'ext' => $file->getOriginalExtension(), ]); fclose($openFile); // 返回路径 return json(['code' => '0', 'message' => '上传成功', 'data' => ['path' => $resData->s3_url]]); } catch (\Exception $exception) { if (isset($openFile)) { fclose($openFile); } return json(['code' => '100500', 'message' => '系统繁忙', 'data' => [$exception->getMessage()]]); } } // 上传视频到aws s3 public function uploadVideo() { try { // 获取文件 $file = $this->request->file('file'); // 检测文件是否存在 if (!$file) { return json(['code' => 400, 'message' => 'No file uploaded']); } // 验证文件类型和大小 限制100M $maxSize = 100 * 1024 * 1024; if ($file->getSize() > $maxSize) { return json(['code' => 400, 'message' => 'The file size cannot exceed 1 GB']); } // 打开文件 $openFile = fopen($file->getRealPath(), 'r'); if (!$openFile) { return json(['code' => 400, 'message' => 'Failed to open the file']); } // 生成唯一的文件名 $fileName = bin2hex(random_bytes(16)) . '.' . $file->getOriginalExtension(); // 初始化s3客户端 $s3Config = Config::get('common.aws_s3'); $s3Client = new S3Client([ // 'version' => 'latest', 'version' => '2006-03-01', 'region' => $s3Config['aws_region'], 'credentials' => [ 'key' => $s3Config['aws_key'], 'secret' => $s3Config['aws_secret'], ], ]); // 上传文件到S3 $result = $s3Client->putObject([ 'Bucket' => $s3Config['aws_bucket'], 'Key' => 'bourse-video-node/' . $fileName, // s3中的存储路径 'Body' => $openFile, 'ContentType' => $file->getOriginalMime(), // 设置文件的MIME, 不然s3会以流式存储 // 'ACL' => 'public-read', // 设置文件为公开可读 ])->toArray(); fclose($openFile); Log::info("上传s3结果:". json_encode($result)); if (empty($result['ObjectURL'])) { return json(['code' => 400, 'message' => '上传失败']); } // 记录上传的文件 $resData = AwsS3Model::create([ 'name' => $fileName, 's3_url' => $result['ObjectURL'], 'size' => $file->getSize(), 'mime' => $file->getOriginalMime(), 'ext' => $file->getOriginalExtension(), ]); // 返回上传成功的地址 return json(['code' => '0', 'message' => '上传成功', 'data' => [ 'id' => $resData->id, 'url' => $result['ObjectURL'], 'name' => $fileName, 'size' => $file->getSize(), 'mime' => $file->getOriginalMime(), 'ext'=> $file->getOriginalExtension(), ]]); } catch (\Exception $exception) { if (isset($openFile)) { fclose($openFile); } return json(['code' => '100500', 'message' => '系统繁忙', 'data' => [$exception->getMessage()]]); } } // 上传文件至服务器本地 public function uploadToServer() { $file = $this->request->file('file'); if (!$file) { return json(['code' => 400, 'message' => 'No file uploaded233']); } if ($file->getSize() > 100 * 1024 * 1024) { return json(['code' => 400, 'message' => 'Upload file is too large']); } $name = Filesystem::disk('local')->putFile('topic', $file); $path = '/bs/image/'.$name; return json(['code'=>0, 'message'=>'ok', 'data'=>['path'=>$path]]); } // 创建分段上传,初始化一个新的上传任务,生成一个上传的唯一标识符 public function initiateUpload(){ try { $param = $this->request->post(); if (empty($param['mime'])) { return json(['code' => 400, 'message' => '缺少参数mime']); } $getMime = trim($param['mime']); // 获取文件扩展名 $mimeArr = explode('/', $getMime); $getExt = end($mimeArr); if (empty($getExt)) { return json(['code' => 400, 'message' => '提取文件扩展名错误']); } // 生成唯一的文件名 $fileName = bin2hex(random_bytes(16)) . '.' . $getExt; // 初始化s3客户端 $s3Config = Config::get('common.aws_s3'); $s3Client = new S3Client([ 'version' => 'latest', 'region' => $s3Config['aws_region'], 'credentials' => [ 'key' => $s3Config['aws_key'], 'secret' => $s3Config['aws_secret'], ], ]); // 初始化分段上传,获取上传Id $result = $s3Client->createMultipartUpload([ 'Bucket' => $s3Config['aws_bucket'], 'Key' => 'bourse-video-node/' . $fileName, 'ContentType' => $getMime, ])->toArray(); Log::info("初始化分段上传结果:".json_encode($result)); if (empty($result['UploadId'])) { return json(['code' => 500, 'message' => '初始化分片上传失败','data'=>$result]); } AwsS3Model::create([ 'upload_id' => $result['UploadId'], 'key' => 'bourse-video-node/' . $fileName, 'name' => $fileName, 'mime' => $getMime, 'ext' => $getExt, ]); return json([ 'code' => 0, 'message' => 'success', 'data' => [ 'uploadId' => $result['UploadId'], 'key' => $result['Key'] ] ]); } catch (\Exception $exception) { return json(['code' => '500', 'message' => '初始化分段上传失败', 'data' => [$exception->getMessage()]]); } } // 上传每个分段 public function uploadPart(){ try { $param = $this->request->param(); if (empty($param['uploadId']) || empty($param['partNumber'])) { return json(['code' => 400, 'message' => '缺少参数']); } $file = $this->request->file('file'); if (!$file) { return json(['code' => 400, 'message' => 'No file uploaded']); } // 每个分段大小限制 最大50M if ($file->getSize() > 100 * 1024 * 1024) { return json(['code' => 400, 'message' => 'File size is too large for multipart upload']); } // 打开文件 $openFile = fopen($file->getRealPath(), 'r'); if (!$openFile) { return json(['code' => 400, 'message' => 'Failed to open file']); } // 检查数据库中是否有对应上传记录 $awsS3 = AwsS3Model::where(['upload_id'=>$param['uploadId']])->find(); if (empty($awsS3) || empty($awsS3['key'])) { return json(['code' => 400, 'message' => 'uploadId对应的数据错误']); } // 初始化s3客户端 $s3Config = Config::get('common.aws_s3'); $s3Client = new S3Client([ 'version' => 'latest', 'region' => $s3Config['aws_region'], 'credentials' => [ 'key' => $s3Config['aws_key'], 'secret' => $s3Config['aws_secret'], ], ]); $result = $s3Client->uploadPart([ 'Bucket' => $s3Config['aws_bucket'], 'Key' => $awsS3['key'], 'PartNumber' => $param['partNumber'], 'UploadId' => $param['uploadId'], 'Body' => $openFile, ])->toArray(); fclose($openFile); Log::info("上传分段结果:".json_encode($result)); if (empty($result['partNumber']) || empty($result['ETag'])) { return json(['code' => 400, 'message' => '上传分片失败']); } // 更新上传分片记录 if (empty($awsS3->parts)) { $buildParts = json_encode([ ['PartNumber'=>trim($param['partNumber']), 'ETag'=>$result['ETag']] ]); $awsS3->parts = $buildParts; } else { $parsePart = json_decode($awsS3->parts, true); $parsePart[] = ['PartNumber'=>trim($param['partNumber']), 'ETag'=>$result['ETag']]; $awsS3->parts = json_encode($parsePart); } $awsS3->save(); return json([ 'code' => 200, 'message' => 'success', 'data' => [ 'ETag' => $result['ETag'], // 每个分段的ETag 'PartNumber' => $param['partNumber'], 'key' => $param['key'], // 存储在s3桶中的key ] ]); } catch (\Exception $exception) { if (isset($openFile)) { fclose($openFile); } return json(['code' => '100500', 'message' => '上传失败', 'data' => [$exception->getMessage()]]); } } // 完成分段上传 public function completeUpload(){ try { $param = $this->request->param(); if (empty($param['uploadId'])) { return json(['code' => 400, 'message' => '缺少参数']); } // 注意:$parts 是一个数组,里面需要有每个分段编号,以及每个分段对应的ETag // $parts = [ // ['PartNumber' => 1, 'ETag' => 'etag-for-part-1'], // ['PartNumber' => 2, 'ETag' => 'etag-for-part-2'], // ]; $awsS3 = AwsS3Model::where(['upload_id'=>trim($param['uploadId'])])->find(); if (empty($awsS3) || empty($awsS3['parts']) || empty($awsS3['key'])) { return json(['code' => 400, 'message' => 'uploadId对应的数据错误']); } $parts = json_decode($awsS3['parts']); // 初始化s3客户端 $s3Config = Config::get('common.aws_s3'); $s3Client = new S3Client([ 'version' => 'latest', 'region' => $s3Config['aws_region'], 'credentials' => [ 'key' => $s3Config['aws_key'], 'secret' => $s3Config['aws_secret'], ], ]); $result = $s3Client->completeMultipartUpload([ 'Bucket' => $s3Config['aws_bucket'], 'Key' => $awsS3['key'], 'UploadId' => $param['uploadId'], 'MultipartUpload' => [ 'Parts' => $parts ], ])->toArray(); Log::info("完成分段上传结果:".json_encode($result)); // 更新分片上传记录 $awsS3->is_complete = 1; $awsS3->parts = json_encode($param['parts']); $awsS3->s3_url = $result['Location']; $awsS3->save(); return json(['code' => 200, 'message' => '上传成功', 'data'=>[ 'id' => $awsS3->id, 'uploadId' => $param['uploadId'], 'location' => $result['Location'], ]]); } catch (\Exception $exception) { return json(['code' => '100500', 'message' => '完成上传失败', 'data' => [$exception->getMessage()]]); } } // 中止分段上传 public function abortUpload(){ try { $param = $this->request->param(); if (empty($param['uploadId']) || empty($param['key'])) { return json(['code' => 400, 'message' => '缺少参数']); } // 初始化s3客户端 $s3Config = Config::get('common.aws_s3'); $s3Client = new S3Client([ 'version' => 'latest', 'region' => $s3Config['aws_region'], 'credentials' => [ 'key' => $s3Config['aws_key'], 'secret' => $s3Config['aws_secret'], ], ]); $result = $s3Client->abortMultipartUpload([ 'Bucket' => $s3Config['aws_bucket'], 'Key' => $param['key'], 'UploadId' => $param['uploadId'], ]); Log::info('终止分段上传结果:'.json_encode($result)); return json(['code' => 200, 'message' => '上传已取消']); } catch (\Exception $exception) { return json(['code' => '100500', 'message' => '取消上传失败', 'data' => [$exception->getMessage()]]); } } }