From dadb0cb7243bba55434faccd6fa8b17014e8bf0c Mon Sep 17 00:00:00 2001 From: manghe Date: Wed, 19 Mar 2025 13:09:41 +0000 Subject: [PATCH] =?UTF-8?q?=20=E4=BF=AE=E6=94=B9=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E5=A4=B4=E5=83=8F=EF=BC=8C=E5=A2=9E=E5=8A=A0=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E5=A4=B4=E5=83=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/admin/controller/Upload.php | 48 ++----- app/api/controller/Login.php | 25 ++-- app/api/controller/Upload.php | 101 ++++++------- app/common/server/TencentCosUploader.php | 172 +++++++++++++++++++++++ composer.json | 3 +- composer.lock | 59 +++++++- 6 files changed, 311 insertions(+), 97 deletions(-) create mode 100644 app/common/server/TencentCosUploader.php diff --git a/app/admin/controller/Upload.php b/app/admin/controller/Upload.php index dedcb45..db97155 100755 --- a/app/admin/controller/Upload.php +++ b/app/admin/controller/Upload.php @@ -7,25 +7,22 @@ namespace app\admin\controller; use app\admin\controller\Base; use OSS\Core\OssException; use OSS\OssClient; +use app\common\server\TencentCosUploader; use think\facade\Db; use think\facade\Filesystem; use think\facade\Request; use Qcloud\Cos\Client; class Upload extends Base { - private $secretId; // 腾讯云 API 密钥 SecretId - private $secretKey; // 腾讯云 API 密钥 SecretKey - private $bucket; // 存储桶名称 - private $region; // 存储桶所在地域 - private $domain; // 存储桶所在地域 + + private $uploader; + public function initialize() { + $config = getConfig('uploads'); - $this->secretId = $config['AccessKeyId']; - $this->secretKey = $config['AccessKeySecret']; - $this->bucket = $config['Bucket']; - $this->region = $config['Region']; - $this->domain = $config['Domain']; + + $this->uploader = new TencentCosUploader($config); } @@ -61,32 +58,10 @@ class Upload extends Base $data['imgurl'] = $info['imgurl']; return $this->renderSuccess('上传成功', $data); } else { - // 初始化腾讯云 COS 客户端 - $cosClient = new Client([ - 'region' => $this->region, - 'schema' => 'https', // 协议 - 'credentials' => [ - 'secretId' => $this->secretId, - 'secretKey' => $this->secretKey, - ], - ]); - - // 生成唯一文件名 - $date = date('Ymd'); - $uniqueFileName = md5(uniqid(rand(), true)) . '.' . $type; - $cosKey = 'topic/' . $date . '/' . $uniqueFileName; // COS 中的文件路径 - try { // 上传文件到腾讯云 COS - $result = $cosClient->putObject([ - 'Bucket' => $this->bucket, - 'Key' => $cosKey, - 'Body' => fopen($_FILES['file']['tmp_name'], 'rb'), // 文件内容 - ]); - - // 获取文件访问 URL - $cosUrl = $result['Location']; - $imgurl = $this->domain . $cosKey; + $uploadResult = $this->uploader->uploadFilePath($_FILES['file']['tmp_name'], $type); + $imgurl = $uploadResult['full_url']; // 新增数据到数据库 $save_data['token'] = $hash; $save_data['imgurl'] = $imgurl; // 保存 COS 中的文件路径 @@ -96,7 +71,7 @@ class Upload extends Base if ($res) { $data['id'] = $res; $data['path'] = $imgurl; // 返回文件的完整访问 URL - $data['imgurl'] = $imgurl ; + $data['imgurl'] = $imgurl; return $this->renderSuccess('上传成功', $data); } else { return $this->renderError('上传失败'); @@ -169,7 +144,8 @@ class Upload extends Base } } - public function uploadimage(){ + public function uploadimage() + { // return diff --git a/app/api/controller/Login.php b/app/api/controller/Login.php index 7180a8c..fa4d96c 100755 --- a/app/api/controller/Login.php +++ b/app/api/controller/Login.php @@ -11,10 +11,17 @@ use think\facade\Db; use app\common\model\ProfitDraw; use app\common\model\UserLoginIp; use think\facade\Log; - +use app\common\server\TencentCosUploader; class Login extends Base { + private $uploader; + public function initialize() + { + + $config = getConfig('uploads'); + $this->uploader = new TencentCosUploader($config); + } /** * 微信授权 */ @@ -67,17 +74,13 @@ class Login extends Base $ip_city = ''; $ip_adcode = ''; if ($result) { - $ip_province = $result['province']; $ip_city = $result['city']; $ip_adcode = $result['adcode']; } else { - } - - $res[] = UserAccount::where(['user_id' => $user['id']])->update([ 'account_token' => $account_token, 'token_num' => $token_num, @@ -95,19 +98,24 @@ class Login extends Base } else { $nickname = request()->param('nickname', ''); $headimg = request()->param('headimg', ''); - if (!$nickname || !$headimg) { + if (!$nickname) { return $this->renderError('请求参数错误!'); } + $pid = 0; $pid_pid = request()->param('pid', 0); if ($pid_pid > 0) { $pid_pid = $pid_pid - 1260; log::info("获取推荐人id" . $pid_pid); } + $randx = rand(1000, 9999); if ($nickname == "微信用户") { - $nickname =$nickname . rand(1000, 9999); + $nickname = $nickname . $randx; } - + $identicon = new \Identicon\Identicon(); + $imageData = $identicon->getImageData($openid . $nickname); + $uploadResult = $this->uploader->uploadFile($imageData, "storage/users/icon/default/" . $randx . ".png"); + $headimg = $uploadResult['full_url']; if ($pid_pid) { $pid_info = User::where('id', '=', $pid_pid)->value("id"); if ($pid_info) { @@ -115,7 +123,6 @@ class Login extends Base $pid = $pid_info; } } - Db::startTrans(); $res[] = $user_id = User::insertGetId([ diff --git a/app/api/controller/Upload.php b/app/api/controller/Upload.php index aaebd48..35155d3 100755 --- a/app/api/controller/Upload.php +++ b/app/api/controller/Upload.php @@ -3,6 +3,7 @@ namespace app\api\controller; use app\common\server\Upload as uploadss; + use \think\facade\Db; use OSS\Core\OssException; use OSS\OssClient; @@ -49,7 +50,7 @@ class Upload extends Base return $this->renderError("上传失败"); } #新增数据 - $object = '/'.$object; + $object = '/' . $object; $save_data['token'] = $hash; $save_data['imgurl'] = $object; $save_data['addtime'] = time(); @@ -64,7 +65,7 @@ class Upload extends Base } } } - + public function picture1() { #获取表单上传文件 @@ -90,55 +91,55 @@ class Upload extends Base // return $this->renderSuccess('上传成功', $data); // } else { - // 保存图片 - $date = date('Ymd'); - $uniqueFileName = md5(uniqid(rand(), true)) . '.' . $type; - $saveDir = './storage/topic/' . $date; - if (!is_dir($saveDir)) { - mkdir($saveDir, 0777, true); - } - $savename = $saveDir . '/' . $uniqueFileName; - - // 移动文件到目标目录 - if (move_uploaded_file($_FILES['file']['tmp_name'], $savename)) { - $savename = str_replace('\\', '/', $savename); - $savename = substr($savename, 1); // 去掉开头的 “.” - - // 新增数据 - $save_data['token'] = $hash; - $save_data['imgurl'] = $savename; - $save_data['addtime'] = time(); - $res = Db::name('picture')->insertGetId($save_data); - if ($res) { - $data['id'] = $res; - $data['path'] = imageUrl($savename); - $data['imgurl'] = $savename; - return $this->renderSuccess('上传成功', $data); - } else { - return $this->renderError('上传失败'); - } - } else { - return $this->renderError('文件保存失败'); - } + // 保存图片 + $date = date('Ymd'); + $uniqueFileName = md5(uniqid(rand(), true)) . '.' . $type; + $saveDir = './storage/topic/' . $date; + if (!is_dir($saveDir)) { + mkdir($saveDir, 0777, true); + } + $savename = $saveDir . '/' . $uniqueFileName; - // #保存图片 - // $savename = \think\facade\Filesystem::disk('public')->putFile('topic', $files); - // $hash = $files->hash('sha1'); - // $savename = '/storage/' . $savename; - // $savename = str_replace('\\', '/', $savename); - // #新增数据 - // $save_data['token'] = $hash; - // $save_data['imgurl'] = $savename; - // $save_data['addtime'] = time(); - // $res = Db::name('picture')->insertGetId($save_data); - // if ($res) { - // $data['id'] = $res; - // $data['path'] = imageUrl($savename); - // $data['imgurl'] = $savename; - // return $this->renderSuccess('上传成功', $data); - // } else { - // return $this->renderError('上传失败'); - // } + // 移动文件到目标目录 + if (move_uploaded_file($_FILES['file']['tmp_name'], $savename)) { + $savename = str_replace('\\', '/', $savename); + $savename = substr($savename, 1); // 去掉开头的 “.” + + // 新增数据 + $save_data['token'] = $hash; + $save_data['imgurl'] = $savename; + $save_data['addtime'] = time(); + $res = Db::name('picture')->insertGetId($save_data); + if ($res) { + $data['id'] = $res; + $data['path'] = imageUrl($savename); + $data['imgurl'] = $savename; + return $this->renderSuccess('上传成功', $data); + } else { + return $this->renderError('上传失败'); + } + } else { + return $this->renderError('文件保存失败'); + } + + // #保存图片 + // $savename = \think\facade\Filesystem::disk('public')->putFile('topic', $files); + // $hash = $files->hash('sha1'); + // $savename = '/storage/' . $savename; + // $savename = str_replace('\\', '/', $savename); + // #新增数据 + // $save_data['token'] = $hash; + // $save_data['imgurl'] = $savename; + // $save_data['addtime'] = time(); + // $res = Db::name('picture')->insertGetId($save_data); + // if ($res) { + // $data['id'] = $res; + // $data['path'] = imageUrl($savename); + // $data['imgurl'] = $savename; + // return $this->renderSuccess('上传成功', $data); + // } else { + // return $this->renderError('上传失败'); + // } // } } /** diff --git a/app/common/server/TencentCosUploader.php b/app/common/server/TencentCosUploader.php new file mode 100644 index 0000000..264785a --- /dev/null +++ b/app/common/server/TencentCosUploader.php @@ -0,0 +1,172 @@ + '您的SecretId', + * 'AccessKeySecret' => '您的SecretKey', + * 'Bucket' => '存储桶名称', + * 'Region' => '存储桶地域', + * 'Domain' => '自定义域名' + * ] + */ + public function __construct(array $config) + { + // 初始化基础配置 + $this->bucket = $config['Bucket']; + $this->region = $config['Region']; + $this->domain = $config['Domain']; + + // 创建COS客户端实例 + $this->cosClient = new Client([ + 'region' => $this->region, // 地域 + 'schema' => 'https', // 使用HTTPS协议 + 'credentials' => [ // 鉴权凭证 + 'secretId' => $config['AccessKeyId'], + 'secretKey' => $config['AccessKeySecret'], + ], + ]); + } + + /** + * 通过文件路径上传到COS(适合表单上传场景) + * + * @param string $tempPath 本地临时文件路径(如:/tmp/upload_xxxx.jpg) + * @param string $fileType 文件扩展名(如:jpg) + * @param string $prefix 存储路径前缀(默认:topic) + * + * @return array [ + * 'cos_key' => 'COS存储路径', + * 'full_url' => '完整访问URL', + * 'location' => 'COS返回的Location' + * ] + * + * @throws \Exception 上传失败时抛出异常 + */ + public function uploadFilePath(string $tempPath, string $fileType, string $prefix = 'topic'): array + { + try { + // 生成唯一存储路径(自动包含日期目录) + $cosKey = $this->generateUniqueKey($fileType, $prefix); + + // 执行文件上传 + $result = $this->cosClient->putObject([ + 'Bucket' => $this->bucket, // 存储桶 + 'Key' => $cosKey, // COS存储路径 + 'Body' => fopen($tempPath, 'rb'), // 以二进制只读方式打开文件 + ]); + + return [ + 'cos_key' => $cosKey, + 'full_url' => $this->domain . $cosKey, // 拼接完整访问地址 + 'location' => $result['Location'] // COS返回的访问地址 + ]; + } catch (ServiceResponseException $e) { + // 记录详细错误日志 + Log::error("COS文件上传失败 | {$e->getStatusCode()} | {$e->getErrorCode()} | {$e->getMessage()}"); + throw new \Exception('文件上传失败: ' . $e->getMessage()); + } + } + + /** + * 直接上传二进制内容到COS(适合Base64或内存文件场景) + * + * @param mixed $content 二进制内容(支持字符串或资源类型) + * @param string $filePath 指定在COS中的存储路径(如:images/20230101/abc.jpg) + * + * @return array [ + * 'cos_key' => 'COS存储路径', + * 'full_url' => '完整访问URL', + * 'location' => 'COS返回的Location' + * ] + * + * @throws \Exception 上传失败时抛出异常 + */ + public function uploadFile($content, string $filePath): array + { + try { + // 执行二进制内容上传 + $result = $this->cosClient->putObject([ + 'Bucket' => $this->bucket, // 存储桶 + 'Key' => $filePath, // 指定存储路径 + 'Body' => $content, // 直接传入二进制内容 + ]); + + return [ + 'cos_key' => $filePath, + 'full_url' => $this->domain . $filePath, // 拼接完整访问地址 + 'location' => $result['Location'] // COS返回的访问地址 + ]; + } catch (ServiceResponseException $e) { + // 记录详细错误日志 + Log::error("COS二进制上传失败 | {$e->getStatusCode()} | {$e->getErrorCode()} | {$e->getMessage()}"); + throw new \Exception('二进制上传失败: ' . $e->getMessage()); + } + } + + /** + * 生成唯一存储路径(私有方法) + * + * 格式:{prefix}/YYYYMMDD/{32位随机字符串}.{ext} + * 示例:topic/20230101/7a97e8f7d6e5f4c3b2a1987654321abc.jpg + * + * @param string $fileType 文件扩展名 + * @param string $prefix 路径前缀 + * + * @return string COS存储路径 + */ + private function generateUniqueKey(string $fileType, string $prefix): string + { + $dateSegment = date('Ymd'); // 日期目录 + $uniqueName = md5(uniqid(rand(), true)) . '.' . $fileType; // 唯一文件名 + return sprintf( + '%s/%s/%s', + trim($prefix, '/'), // 去除前后斜线 + $dateSegment, + $uniqueName + ); + } + + /** + * 获取完整访问URL + * + * @param string $cosKey COS存储路径 + * @return string 完整的HTTP访问地址 + */ + public function getFullUrl(string $cosKey): string + { + // 示例:https://cdn.example.com/topic/20230101/abc.jpg + return $this->domain . $cosKey; + } +} \ No newline at end of file diff --git a/composer.json b/composer.json index cb1da9f..cae2409 100755 --- a/composer.json +++ b/composer.json @@ -28,7 +28,8 @@ "topthink/think-captcha": "^3.0", "endroid/qr-code": "^4.6", "phpoffice/phpspreadsheet": "^1.29", - "qcloud/cos-sdk-v5": "^2.6" + "qcloud/cos-sdk-v5": "^2.6", + "yzalis/identicon": "^2.0" }, "require-dev": { "symfony/var-dumper": "^4.2", diff --git a/composer.lock b/composer.lock index ecf5db0..96591e4 100755 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "810d3950b90680e91d2b03690286abf6", + "content-hash": "50099350288722431f222e8410e3c5b4", "packages": [ { "name": "bacon/bacon-qr-code", @@ -2173,6 +2173,63 @@ ], "description": "thinkphp template driver", "time": "2019-11-06T11:40:13+00:00" + }, + { + "name": "yzalis/identicon", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/yzalis/Identicon.git", + "reference": "ff5ed090129cab9bfa2a322857d4a01d107aa0ae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/yzalis/Identicon/zipball/ff5ed090129cab9bfa2a322857d4a01d107aa0ae", + "reference": "ff5ed090129cab9bfa2a322857d4a01d107aa0ae", + "shasum": "" + }, + "require": { + "php": ">=5.5.0" + }, + "require-dev": { + "ext-imagick": "*", + "fzaninotto/faker": "^1.2.0", + "phpunit/phpunit": "^4.0 || ^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "Identicon\\": "src/Identicon/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Benjamin Laugueux", + "email": "benjamin@yzalis.com" + } + ], + "description": "Create awesome unique avatar.", + "homepage": "http://identicon-php.org", + "keywords": [ + "avatar", + "identicon", + "image" + ], + "support": { + "issues": "https://github.com/yzalis/Identicon/issues", + "source": "https://github.com/yzalis/Identicon/tree/master" + }, + "abandoned": true, + "time": "2019-10-14T09:30:57+00:00" } ], "packages-dev": [