diff --git a/app/Controller/Api/V1/DownloadController.php b/app/Controller/Api/V1/DownloadController.php deleted file mode 100644 index 9fc0c15..0000000 --- a/app/Controller/Api/V1/DownloadController.php +++ /dev/null @@ -1,73 +0,0 @@ -get(Filesystem::class)->getConfig()->get('root') . '/' . $path; - } - - /** - * 下载用户聊天文件 - * @RequestMapping(path="user-chat-file", methods="get") - * - * @param ResponseInterface $response - * @param Filesystem $filesystem - * @return \Psr\Http\Message\ResponseInterface - */ - public function userChatFile(ResponseInterface $response, Filesystem $filesystem) - { - $params = $this->request->inputs(['cr_id']); - $this->validate($params, [ - 'cr_id' => 'required|integer' - ]); - - $recordsInfo = TalkRecords::select(['msg_type', 'talk_type', 'user_id', 'receiver_id'])->where('id', $params['cr_id'])->first(); - if (!$recordsInfo) { - return $this->response->fail('文件不存在!'); - } - - $user_id = $this->uid(); - - // 判断消息是否是当前用户发送(如果是则跳过权限验证) - if ($recordsInfo->user_id != $user_id) { - if ($recordsInfo->talk_type == 1) { - if ($recordsInfo->receiver_id != $user_id) { - return $this->response->fail('非法请求!'); - } - } else { - if (!di()->get(GroupMemberService::class)->isMember($recordsInfo->receiver_id, $user_id)) { - return $this->response->fail('非法请求!'); - } - } - } - - $info = TalkRecordsFile::select(['save_dir', 'original_name'])->where('record_id', $params['cr_id'])->first(); - if (!$info || !$filesystem->has($info->save_dir)) { - return $this->response->fail('文件不存在或没有下载权限!'); - } - - return $response->download($this->getFilePath($info->save_dir), $info->original_name); - } -} diff --git a/app/Controller/Api/V1/Talk/MessageController.php b/app/Controller/Api/V1/Talk/MessageController.php index 4e98938..df7f9dd 100644 --- a/app/Controller/Api/V1/Talk/MessageController.php +++ b/app/Controller/Api/V1/Talk/MessageController.php @@ -9,7 +9,7 @@ use App\Constants\TalkModeConstant; use App\Controller\Api\V1\CController; use App\Event\TalkEvent; use App\Model\EmoticonItem; -use App\Model\FileSplitUpload; +use App\Model\SplitUpload; use App\Service\TalkForwardService; use App\Service\TalkMessageService; use App\Support\UserRelation; @@ -149,9 +149,9 @@ class MessageController extends CController 'receiver_id' => $params['receiver_id'], ], [ 'user_id' => $user_id, - 'file_suffix' => $ext, - 'file_size' => $file->getSize(), - 'save_dir' => $path, + 'suffix' => $ext, + 'size' => $file->getSize(), + 'path' => $path, 'original_name' => $file->getClientFilename(), ]); @@ -180,14 +180,14 @@ class MessageController extends CController return $this->response->fail('暂不属于好友关系或群聊成员,无法发送聊天消息!'); } - $file = FileSplitUpload::where('user_id', $user_id)->where('hash_name', $params['hash_name'])->where('file_type', 1)->first(); - if (!$file || empty($file->save_dir)) { + $file = SplitUpload::where('user_id', $user_id)->where('upload_id', $params['hash_name'])->where('type', 1)->first(); + if (!$file || empty($file->path)) { return $this->response->fail('文件不存在...'); } + $save_dir = "private/files/talks/" . date('Ymd') . '/' . create_random_filename($file->file_ext); try { - $save_dir = "files/talks/" . date('Ymd') . '/' . create_random_filename($file->file_ext); - $filesystem->copy($file->save_dir, $save_dir); + $filesystem->copy($file->path, $save_dir); } catch (\Exception $e) { return $this->response->fail('文件不存在...'); } @@ -198,14 +198,14 @@ class MessageController extends CController 'receiver_id' => $params['receiver_id'] ], [ 'user_id' => $user_id, - 'file_source' => 1, + 'source' => 1, 'original_name' => $file->original_name, - 'file_suffix' => $file->file_ext, - 'file_size' => $file->file_size, - 'save_dir' => $save_dir, + 'suffix' => $file->file_ext, + 'size' => $file->file_size, + 'path' => $save_dir, ]); - if (!$isTrue) return $this->response->fail('表情发送失败!'); + if (!$isTrue) return $this->response->fail('文件发送失败!'); return $this->response->success(); } @@ -275,9 +275,9 @@ class MessageController extends CController 'receiver_id' => $params['receiver_id'], ], [ 'user_id' => $user_id, - 'file_suffix' => $emoticon->file_suffix, - 'file_size' => $emoticon->file_size, - 'save_dir' => $emoticon->url, + 'suffix' => $emoticon->file_suffix, + 'size' => $emoticon->file_size, + 'url' => $emoticon->url, 'original_name' => '图片表情', ]); diff --git a/app/Controller/Api/V1/Talk/RecordsController.php b/app/Controller/Api/V1/Talk/RecordsController.php index 556edd1..c6ee349 100644 --- a/app/Controller/Api/V1/Talk/RecordsController.php +++ b/app/Controller/Api/V1/Talk/RecordsController.php @@ -3,9 +3,12 @@ declare(strict_types=1); namespace App\Controller\Api\V1\Talk; +use App\Constants\FileDriveConstant; use App\Constants\TalkMessageType; use App\Constants\TalkModeConstant; use App\Controller\Api\V1\CController; +use App\Model\Talk\TalkRecords; +use App\Model\Talk\TalkRecordsFile; use App\Service\Group\GroupMemberService; use App\Service\TalkListService; use App\Service\TalkService; @@ -14,6 +17,7 @@ use Hyperf\HttpServer\Annotation\Controller; use Hyperf\HttpServer\Annotation\RequestMapping; use Hyperf\HttpServer\Annotation\Middleware; use App\Middleware\JWTAuthMiddleware; +use League\Flysystem\Filesystem; use Psr\Http\Message\ResponseInterface; /** @@ -145,4 +149,58 @@ class RecordsController extends CController return $this->response->success(['rows' => $rows]); } + + /** + * 获取转发记录详情 + * + * @RequestMapping(path="file/download", methods="get") + */ + public function download(\Hyperf\HttpServer\Contract\ResponseInterface $response, Filesystem $filesystem) + { + $params = $this->request->inputs(['cr_id']); + $this->validate($params, [ + 'cr_id' => 'required|integer' + ]); + + $recordsInfo = TalkRecords::select(['msg_type', 'talk_type', 'user_id', 'receiver_id'])->where('id', $params['cr_id'])->first(); + if (!$recordsInfo) { + return $this->response->fail('文件不存在!'); + } + + $user_id = $this->uid(); + + // 判断消息是否是当前用户发送(如果是则跳过权限验证) + if ($recordsInfo->user_id != $user_id) { + if ($recordsInfo->talk_type == 1) { + if ($recordsInfo->receiver_id != $user_id) { + return $this->response->fail('非法请求!'); + } + } else { + if (!di()->get(GroupMemberService::class)->isMember($recordsInfo->receiver_id, $user_id)) { + return $this->response->fail('非法请求!'); + } + } + } + + $info = TalkRecordsFile::select(['path', 'original_name', "drive"])->where('record_id', $params['cr_id'])->first(); + + switch ($info->drive) { + case FileDriveConstant::Local: + if (!$info || !$filesystem->has($info->path)) { + return $this->response->fail('文件不存在或没有下载权限!'); + } + + return $response->download($this->getFilePath($info->path), $info->original_name); + case FileDriveConstant::Cos: + // 后期添加 + break; + default: + break; + } + } + + private function getFilePath(string $path) + { + return di()->get(Filesystem::class)->getConfig()->get('root') . '/' . $path; + } } diff --git a/app/Controller/Api/V1/UploadController.php b/app/Controller/Api/V1/UploadController.php index 32c7aba..df2ef73 100644 --- a/app/Controller/Api/V1/UploadController.php +++ b/app/Controller/Api/V1/UploadController.php @@ -30,20 +30,21 @@ class UploadController extends CController /** * 图片文件流上传接口 * - * @RequestMapping(path="file-stream", methods="post") + * @RequestMapping(path="avatar", methods="post") * @param Filesystem $filesystem * @return ResponseInterface */ public function fileStream(Filesystem $filesystem): ResponseInterface { - $fileStream = $this->request->post('fileStream', ''); - if (empty($fileStream)) { + $file = $this->request->file("file"); + + if (!$file->isValid()) { return $this->response->fail(); } - $path = 'media/images/avatar/' . date('Ymd') . '/' . create_random_filename('png'); + $path = 'public/media/images/avatar/' . date('Ymd') . '/' . create_random_filename('png'); try { - $filesystem->write($path, base64_decode(str_replace(['data:image/png;base64,', ' '], ['', '+'], $fileStream))); + $filesystem->write($path, file_get_contents($file->getRealPath())); } catch (\Exception $e) { return $this->response->fail(); } @@ -54,9 +55,9 @@ class UploadController extends CController /** * 获取拆分文件信息 * - * @RequestMapping(path="get-file-split-info", methods="get") + * @RequestMapping(path="multipart/initiate", methods="post") */ - public function getFileSplitInfo(): ResponseInterface + public function initiateMultipart(): ResponseInterface { $params = $this->request->inputs(['file_name', 'file_size']); $this->validate($params, [ @@ -66,23 +67,23 @@ class UploadController extends CController $data = $this->splitUploadService->create($this->uid(), $params['file_name'], $params['file_size']); + + $data['hash_name'] = $data["upload_id"]; + return $data ? $this->response->success($data) : $this->response->fail('获取文件拆分信息失败!'); } /** * 文件拆分上传接口 * - * @RequestMapping(path="file-subarea-upload", methods="post") + * @RequestMapping(path="multipart", methods="post") */ public function fileSubareaUpload(): ResponseInterface { $file = $this->request->file('file'); - $params = $this->request->inputs(['name', 'hash', 'ext', 'size', 'split_index', 'split_num']); + $params = $this->request->inputs(['upload_id', 'split_index', 'split_num']); $this->validate($params, [ - 'name' => "required", - 'hash' => 'required', - 'ext' => 'required', - 'size' => 'required', + 'upload_id' => 'required', 'split_index' => 'required', 'split_num' => 'required' ]); @@ -92,20 +93,20 @@ class UploadController extends CController } $user_id = $this->uid(); - $uploadRes = $this->splitUploadService->upload($user_id, $file, $params['hash'], intval($params['split_index']), intval($params['size'])); + $uploadRes = $this->splitUploadService->upload($user_id, $file, $params['upload_id'], intval($params['split_index'])); if (!$uploadRes) { return $this->response->fail('上传文件失败!'); } if (($params['split_index'] + 1) == $params['split_num']) { - $fileInfo = $this->splitUploadService->merge($user_id, $params['hash']); + $fileInfo = $this->splitUploadService->merge($user_id, $params['upload_id']); if (!$fileInfo) { return $this->response->fail('上传文件失败!'); } return $this->response->success([ 'is_file_merge' => true, - 'hash' => $params['hash'] + 'hash' => $params['upload_id'] ]); } diff --git a/app/Model/FileSplitUpload.php b/app/Model/FileSplitUpload.php deleted file mode 100644 index 16f2838..0000000 --- a/app/Model/FileSplitUpload.php +++ /dev/null @@ -1,51 +0,0 @@ - 'integer', - 'user_id' => 'integer', - 'split_index' => 'integer', - 'split_num' => 'integer', - 'file_size' => 'integer', - 'is_delete' => 'integer', - 'upload_at' => 'integer' - ]; -} diff --git a/app/Model/SplitUpload.php b/app/Model/SplitUpload.php new file mode 100644 index 0000000..1c06fd0 --- /dev/null +++ b/app/Model/SplitUpload.php @@ -0,0 +1,60 @@ + 'integer', + 'drive' => 'integer', + 'user_id' => 'integer', + 'split_index' => 'integer', + 'split_num' => 'integer', + 'file_size' => 'integer', + 'is_delete' => 'integer', + 'attr' => 'json', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', + ]; +} diff --git a/app/Model/Talk/TalkRecordsLocation.php b/app/Model/Talk/TalkRecordsLocation.php new file mode 100644 index 0000000..ca2289b --- /dev/null +++ b/app/Model/Talk/TalkRecordsLocation.php @@ -0,0 +1,29 @@ + 'integer', + 'user_id' => 'integer', + ]; +} diff --git a/app/Service/SplitUploadService.php b/app/Service/SplitUploadService.php index cfd8b8d..cc91eff 100644 --- a/app/Service/SplitUploadService.php +++ b/app/Service/SplitUploadService.php @@ -3,8 +3,8 @@ declare(strict_types=1); namespace App\Service; -use App\Model\FileSplitUpload; -use Hyperf\Utils\Str; +use App\Constants\FileDriveConstant; +use App\Model\SplitUpload; use Hyperf\HttpMessage\Upload\UploadedFile; use League\Flysystem\Filesystem; @@ -24,29 +24,33 @@ class SplitUploadService * 创建文件拆分相关信息 * * @param int $user_id 用户ID - * @param string $fileName 上传的文件名 - * @param string $fileSize 上传文件大小 + * @param string $fileName 文件名 + * @param int $fileSize 文件大小 * @return array|bool */ - public function create(int $user_id, string $fileName, string $fileSize) + public function create(int $user_id, string $fileName, int $fileSize) { - $hash_name = implode('-', [uniqid(), rand(10000000, 99999999), Str::random(6)]); $split_num = intval(ceil($fileSize / self::SPLIT_SIZE)); $data = []; - $data['file_type'] = 1; + $data['type'] = 1; + $data['drive'] = FileDriveConstant::Local; + $data['upload_id'] = uniqid(strval(time())); $data['user_id'] = $user_id; $data['original_name'] = $fileName; - $data['hash_name'] = $hash_name; $data['file_ext'] = pathinfo($fileName, PATHINFO_EXTENSION); $data['file_size'] = $fileSize; - $data['upload_at'] = time(); + $data['attr'] = new \stdClass(); + $data['created_at'] = date("Y-m-d H:i:s"); + $data['updated_at'] = date("Y-m-d H:i:s"); + + $data['path'] = sprintf("private/tmp/multipart/%s/%s.tmp", date("Ymd"), md5($data['upload_id'])); // 文件拆分数量 $data['split_num'] = $split_num; $data['split_index'] = $split_num; - return FileSplitUpload::create($data) ? array_merge($data, ['split_size' => self::SPLIT_SIZE]) : false; + return SplitUpload::create($data) ? array_merge($data, ['split_size' => self::SPLIT_SIZE]) : false; } /** @@ -54,39 +58,43 @@ class SplitUploadService * * @param int $user_id 用户ID * @param UploadedFile $file 文件信息 - * @param string $hashName 上传临时问价hash名 + * @param string $upload_id 上传临时问价hash名 * @param int $split_index 当前拆分文件索引 - * @param int $fileSize 文件大小 * @return bool */ - public function upload(int $user_id, UploadedFile $file, string $hashName, int $split_index, int $fileSize) + public function upload(int $user_id, UploadedFile $file, string $upload_id, int $split_index) { - $fileInfo = FileSplitUpload::select(['id', 'original_name', 'split_num', 'file_ext']) - ->where([['user_id', '=', $user_id], ['hash_name', '=', $hashName], ['file_type', '=', 1]]) + $fileInfo = SplitUpload::select(['id', 'original_name', 'split_num', 'file_ext']) + ->where([['user_id', '=', $user_id], ['upload_id', '=', $upload_id], ['type', '=', 1]]) ->first(); if (!$fileInfo) return false; - $save_path = "tmp/{$hashName}/" . "{$hashName}_{$split_index}_{$fileInfo->file_ext}.tmp"; + $path = sprintf("private/tmp/%s/%s/%d-%s.tmp", date("Ymd"), md5($upload_id), $split_index, $upload_id); + try { - di()->get(Filesystem::class)->write($save_path, file_get_contents($file->getRealPath())); + di()->get(Filesystem::class)->write($path, file_get_contents($file->getRealPath())); } catch (\Exception $e) { return false; } - $info = FileSplitUpload::where('user_id', $user_id)->where('hash_name', $hashName)->where('split_index', $split_index)->first(); + $info = SplitUpload::where('user_id', $user_id)->where('upload_id', $upload_id)->where('split_index', $split_index)->first(); + if (!$info) { - return (bool)FileSplitUpload::create([ + return (bool)SplitUpload::create([ 'user_id' => $user_id, - 'file_type' => 2, - 'hash_name' => $hashName, + 'type' => 2, + 'drive' => FileDriveConstant::Local, + 'upload_id' => $upload_id, 'original_name' => $fileInfo->original_name, 'split_index' => $split_index, 'split_num' => $fileInfo->split_num, - 'save_dir' => $save_path, + 'path' => $path, + 'attr' => new \stdClass(), 'file_ext' => $fileInfo->file_ext, - 'file_size' => $fileSize, - 'upload_at' => time(), + 'file_size' => $file->getSize(), + 'created_at' => date("Y-m-d H:i:s"), + 'updated_at' => date("Y-m-d H:i:s"), ]); } @@ -97,46 +105,38 @@ class SplitUploadService * 文件合并 * * @param int $user_id 用户ID - * @param string $hash_name 上传临时问价hash名 + * @param string $upload_id 上传临时问价hash名 * @return array|bool */ - public function merge(int $user_id, string $hash_name) + public function merge(int $user_id, string $upload_id) { - $fileInfo = FileSplitUpload::select(['id', 'original_name', 'split_num', 'file_ext', 'file_size']) + $fileInfo = SplitUpload::select(['id', 'original_name', 'split_num', 'file_ext', 'file_size', 'path']) ->where('user_id', $user_id) - ->where('hash_name', $hash_name) - ->where('file_type', 1) + ->where('upload_id', $upload_id) + ->where('type', 1) ->first(); if (!$fileInfo) return false; - $files = FileSplitUpload::where('user_id', $user_id) - ->where('hash_name', $hash_name) - ->where('file_type', 2) - ->orderBy('split_index', 'asc') - ->get(['split_index', 'save_dir'])->toArray(); + $files = SplitUpload::where('user_id', $user_id) + ->where('upload_id', $upload_id) + ->where('type', 2) + ->orderBy('split_index') + ->get(['split_index', 'path'])->toArray(); if (!$files || count($files) != $fileInfo->split_num) return false; - $file_merge = "tmp/{$hash_name}/{$fileInfo->original_name}.tmp"; - $filesystem = di()->get(Filesystem::class); $root_path = $filesystem->getConfig()->get('root'); + + @mkdir(pathinfo("{$root_path}/{$fileInfo->path}", PATHINFO_DIRNAME)); + foreach ($files as $file) { - file_put_contents( - "{$root_path}/{$file_merge}", - $filesystem->read($file['save_dir']), - FILE_APPEND - ); + file_put_contents("{$root_path}/{$fileInfo->path}", $filesystem->read($file['path']), FILE_APPEND); } - FileSplitUpload::select(['id', 'original_name', 'split_num', 'file_ext', 'file_size']) - ->where('user_id', $user_id)->where('hash_name', $hash_name) - ->where('file_type', 1) - ->update(['save_dir' => $file_merge]); - return [ - 'path' => $file_merge, + 'path' => $fileInfo->path, 'tmp_file_name' => "{$fileInfo->original_name}.tmp", 'original_name' => $fileInfo->original_name, 'file_size' => $fileInfo->file_size @@ -152,10 +152,11 @@ class SplitUploadService // 24小时前 $time = time() - 60 * 60 * 24 * 1; - FileSplitUpload::where('file_type', 1)->where('upload_at', '<', $time)->select('hash_name')->chunk(100, function ($rows) { + SplitUpload::where('file_type', 1)->where('upload_at', '<', $time)->select('upload_id')->chunk(100, function ($rows) { foreach ($rows as $row) { - @di()->get(Filesystem::class)->deleteDir("tmp/{$row->hash_name}"); - @FileSplitUpload::where('hash_name', $row->hash_name)->delete(); + @di()->get(Filesystem::class)->deleteDir(pathinfo($row->path, PATHINFO_DIRNAME)); + + @SplitUpload::where('upload_id', $row->upload_id)->delete(); } }); } diff --git a/app/Service/TalkMessageService.php b/app/Service/TalkMessageService.php index d593216..9694c90 100644 --- a/app/Service/TalkMessageService.php +++ b/app/Service/TalkMessageService.php @@ -105,8 +105,9 @@ class TalkMessageService } $file['record_id'] = $insert->id; - $file['file_type'] = MediaTypeConstant::getMediaType($file['file_suffix']); + $file['type'] = MediaTypeConstant::getMediaType($file['suffix']); $file['created_at'] = date('Y-m-d H:i:s'); + if (!TalkRecordsFile::create($file)) { throw new Exception('插入聊天记录(代码消息)失败...'); } @@ -114,6 +115,7 @@ class TalkMessageService Db::commit(); } catch (Exception $e) { Db::rollBack(); + logger()->error($e->getMessage()); return false; }