diff --git a/app/Constants/ErrorCode.php b/app/Constants/ErrorCode.php index a7fee16..f6dde1c 100644 --- a/app/Constants/ErrorCode.php +++ b/app/Constants/ErrorCode.php @@ -33,4 +33,8 @@ class ErrorCode extends AbstractConstants * @Message("Save failure!"); */ const SAVE_FAILURE = 100; -} + + /** + * @Message("Upload failure!") + */ + const UPLOAD_INVALID = 200;} diff --git a/app/Controller/AttachmentController.php b/app/Controller/AttachmentController.php new file mode 100644 index 0000000..efbf45d --- /dev/null +++ b/app/Controller/AttachmentController.php @@ -0,0 +1,68 @@ +request->file('upload'); + $type = $this->request->input('type', ''); + + $fileName = $this->attachmentService->formUpload($file, $type, $filesystem, 'file'); + + return $this->success(['file_path' => $fileName]); + } + + /** + * 单图表单上传 + * @param ImageRequest $request + * @param Filesystem $filesystem + * @return \Psr\Http\Message\ResponseInterface + */ + public function uploadImage(ImageRequest $request, Filesystem $filesystem) + { + $file = $this->request->file('upload'); + $type = $this->request->input('type', ''); + + $fileName = $this->attachmentService->formUpload($file, $type, $filesystem); + + return $this->success(['file_path' => $fileName]); + } + + /** + * 单图base64上传 + * @param ImageBase64Request $request + * @param Filesystem $filesystem + * @return \Psr\Http\Message\ResponseInterface + */ + public function uploadImageByBase64(ImageBase64Request $request, Filesystem $filesystem) + { + $base64Code = $this->request->input('upload'); + $type = $this->request->input('type', ''); + + $fileName = $this->attachmentService->base64Upload($base64Code, $type, $filesystem); + + return $this->success(['file_path' => $fileName]); + } + +} \ No newline at end of file diff --git a/app/Exception/Handler/FilesystemExceptionHandler.php b/app/Exception/Handler/FilesystemExceptionHandler.php new file mode 100644 index 0000000..f5f1b1c --- /dev/null +++ b/app/Exception/Handler/FilesystemExceptionHandler.php @@ -0,0 +1,35 @@ +stopPropagation(); + + $content = json_encode([ + "status" => 'error', + "code" => ErrorCode::UPLOAD_INVALID, + "result" => [], + "message" => $throwable->getMessage() + ]); + + return $response->withHeader('Content-Type', 'application/json') + ->withStatus($throwable->status) + ->withBody(new SwooleStream($content)); + } + + public function isValid(Throwable $throwable): bool + { + return $throwable instanceof FilesystemException; + } +} \ No newline at end of file diff --git a/app/Listener/ValidatorFactoryResolvedListener.php b/app/Listener/ValidatorFactoryResolvedListener.php index 74f4f20..d725d26 100644 --- a/app/Listener/ValidatorFactoryResolvedListener.php +++ b/app/Listener/ValidatorFactoryResolvedListener.php @@ -42,5 +42,35 @@ class ValidatorFactoryResolvedListener implements ListenerInterface return strlen($value)>=$parameters[0] && strlen($value)<=$parameters[1]; }); + // 注册了 base64 验证器规则 + $validatorFactory->extend('base64', function ($attribute, $value, $parameters, $validator) { + + preg_match('/^(data:\s*image\/(\w+);base64,)/', $value, $result); + + if (empty($result)) { + return false; + } + + if ( + in_array('image', $parameters) + && !in_array($result[2], ['jpg','jpeg','png','gif','svg','bmp']) + ) { + return false; + } + + return true; + + }); + + // 注册了 ext_not_in 验证器规则 + $validatorFactory->extend('ext_not_in', function ($attribute, $value, $parameters, $validator) { + + if (empty($parameters)) { + $parameters = ['', 'php', 'exe', 'sql', 'sh', 'bat', 'py', 'go', 'c', 'cpp']; + } + return !in_array($value->getExtension(), $parameters); + + }); + } } \ No newline at end of file diff --git a/app/Request/AttachmentRequest.php b/app/Request/AttachmentRequest.php new file mode 100644 index 0000000..da2e1f0 --- /dev/null +++ b/app/Request/AttachmentRequest.php @@ -0,0 +1,47 @@ + 'required|nonempty|file|ext_not_in', + 'type' => 'nonempty|alpha' + ]; + } + + public function messages(): array + { + return [ + 'upload.required' => '未选择上传的文件', + 'upload.nonempty' => '文件异常', + 'upload.file' => '文件上传不成功', + 'upload.ext_not_in' => '文件不允许上传', + 'type.nonempty' => '文件类型参数异常', + ]; + } + + public function attributes(): array + { + return [ + 'upload' => '文件' + ]; + } +} diff --git a/app/Request/ImageBase64Request.php b/app/Request/ImageBase64Request.php new file mode 100644 index 0000000..88a752a --- /dev/null +++ b/app/Request/ImageBase64Request.php @@ -0,0 +1,46 @@ + 'required|nonempty|base64:image', + 'type' => 'nonempty|alpha' + ]; + } + + public function messages(): array + { + return [ + 'upload.required' => '未选择上传的文件', + 'upload.base64' => '文件不是正常的图片', + 'upload.nonempty' => '文件异常', + 'type.nonempty' => '图片类型参数异常', + ]; + } + + public function attributes(): array + { + return [ + 'upload' => '图片' + ]; + } +} diff --git a/app/Request/ImageRequest.php b/app/Request/ImageRequest.php new file mode 100644 index 0000000..85bad47 --- /dev/null +++ b/app/Request/ImageRequest.php @@ -0,0 +1,46 @@ + 'required|nonempty|file|image', + 'type' => 'nonempty|alpha' + ]; + } + + public function messages(): array + { + return [ + 'upload.required' => '未选择上传的文件', + 'upload.image' => '文件不是正常的图片', + 'upload.nonempty' => '文件异常', + 'type.nonempty' => '图片类型参数异常', + ]; + } + + public function attributes(): array + { + return [ + 'upload' => '图片' + ]; + } +} diff --git a/app/Service/AttachmentService.php b/app/Service/AttachmentService.php new file mode 100644 index 0000000..65ab9a4 --- /dev/null +++ b/app/Service/AttachmentService.php @@ -0,0 +1,73 @@ +getRealPath(); + $fileHash = md5_file($fileRealPath); + + $path = $this->getBasePath($path, $attachmenttype); + $fileName = $path . '/' . $fileHash . '.' . $file->getExtension(); + + $stream = fopen($fileRealPath, 'r+'); + $filesystem->writeStream($fileName, $stream); + fclose($stream); + + return $fileName; + } + + /** + * @inheritDoc + */ + public function base64Upload($contents, $path, $filesystem) + { + + preg_match('/^(data:\s*image\/(\w+);base64,)/', $contents, $result); + if (empty($result)) { + throw new FilesystemNotFoundException(ErrorCode::getMessage(ErrorCode::UPLOAD_INVALID),ErrorCode::UPLOAD_INVALID); + } + + $contents = base64_decode(str_replace($result[1], '', $contents)); + + $fileHash = md5($contents); + $path = $this->getBasePath($path); + $fileName = $path . '/' . $fileHash . '.' . $result[2]; + + $filesystem->write($fileName, $contents); + + return $fileName; + } + + protected function getBasePath($path, $attachmenttype = 'image') + { + switch ($attachmenttype) { + case 'image': + $baseDir = env('IMAGE_BASE', '/attachment/images'); + break; + + case 'file': + $baseDir = env('FILES_BASE', '/attachment/files'); + break; + + default: + $baseDir = env('FILES_BASE', '/attachment'); + break; + } + + $path = $path ? '/'.$path : ''; + $path .= '/'.date('Y').'/'.date('m').'/'.date('d'); + return $baseDir.$path; + } +} \ No newline at end of file diff --git a/app/Service/AttachmentServiceInterface.php b/app/Service/AttachmentServiceInterface.php new file mode 100644 index 0000000..28439b2 --- /dev/null +++ b/app/Service/AttachmentServiceInterface.php @@ -0,0 +1,23 @@ + \App\Service\ServiceEvaluateService::class + \App\Service\ServiceEvaluateServiceInterface::class => \App\Service\ServiceEvaluateService::class, + \App\Service\AttachmentServiceInterface::class => \App\Service\AttachmentService::class, ]; diff --git a/config/autoload/exceptions.php b/config/autoload/exceptions.php index cca06d6..1776a7c 100644 --- a/config/autoload/exceptions.php +++ b/config/autoload/exceptions.php @@ -15,6 +15,7 @@ return [ Hyperf\HttpServer\Exception\Handler\HttpExceptionHandler::class, App\Exception\Handler\AppExceptionHandler::class, \App\Exception\Handler\ValidationExceptionHandler::class, + \App\Exception\Handler\FilesystemExceptionHandler::class, ], ], ]; diff --git a/config/autoload/file.php b/config/autoload/file.php index 59cd236..6744d66 100644 --- a/config/autoload/file.php +++ b/config/autoload/file.php @@ -10,11 +10,11 @@ declare(strict_types=1); * @license https://github.com/hyperf/hyperf/blob/master/LICENSE */ return [ - 'default' => 'local', + 'default' => 'oss', 'storage' => [ 'local' => [ 'driver' => \Hyperf\Filesystem\Adapter\LocalAdapterFactory::class, - 'root' => __DIR__ . '/../../runtime', + 'root' => BASE_PATH . '/attachment', ], 'ftp' => [ 'driver' => \Hyperf\Filesystem\Adapter\FtpAdapterFactory::class, diff --git a/config/routes.php b/config/routes.php index 01b4681..4e17da6 100644 --- a/config/routes.php +++ b/config/routes.php @@ -24,6 +24,9 @@ Router::addGroup('/v1/',function (){ Router::post('ServiceEvaluate/getPersonnelInfo', 'App\Controller\ServiceEvaluateController@getPersonnelInfo'); Router::post('ServiceEvaluate/getEvaluateList', 'App\Controller\ServiceEvaluateController@getEvaluateList'); Router::get('test/index1', 'App\Controller\TestController@index1'); + Router::post('Attachment/uploadImage', 'App\Controller\AttachmentController@uploadImage'); + Router::post('Attachment/uploadImageByBase64', 'App\Controller\AttachmentController@uploadImageByBase64'); + Router::post('Attachment/upload', 'App\Controller\AttachmentController@upload'); }); \ No newline at end of file