// +---------------------------------------------------------------------- declare (strict_types=1); namespace app\store\model; use think\facade\Filesystem; use cores\exception\BaseException; use app\common\library\helper; use app\store\model\Payment as PaymentModel; use app\common\enum\payment\Method as PaymentMethodEnum; use app\common\model\PaymentTemplate as PaymentTemplateModel; use app\common\library\wechat\payment\PlatformCertDown; /** * 模型类:支付方式记录 * Class PaymentTemplate * @package app\store\model */ class PaymentTemplate extends PaymentTemplateModel { /** * 获取列表 * @return \think\Paginator * @throws \think\db\exception\DbException */ public function getList(): \think\Paginator { return $this->where('is_delete', '=', 0) ->order(['sort' => 'asc', $this->getPk()]) ->paginate(15); } /** * 新增记录 * @param array $data * @return bool|false * @throws BaseException */ public function add(array $data): bool { // 整理保存的数据 $config = helper::jsonDecode(htmlspecialchars_decode($data['config'])); $methodConfig = $config[$data['method']]; $data['store_id'] = self::$storeId; // 写入证书文件 $data['config'] = [$data['method'] => $this->certFileName($data['method'], $methodConfig)]; // 写入到数据库 return $this->save($data); } /** * 更新记录 * @param array $data * @return bool * @throws BaseException */ public function edit(array $data): bool { // 整理保存的数据 $config = helper::jsonDecode(htmlspecialchars_decode($data['config'])); $methodConfig = $config[$data['method']]; $data['store_id'] = self::$storeId; // 记录证书文件名 $data['config'] = [ $data['method'] => array_merge($methodConfig, $this->certFileName($data['method'], $methodConfig)) ]; // 记录微信支付v3平台证书序号 if ($data['method'] === 'wechat' && $data['config']['wechat']['version'] === 'v3') { $data['wechatpay_serial'] = $data['config']['wechat'][$data['config']['wechat']['mchType']]['platformCertSerial']; } // 更新到数据库 return $this->save($data) !== false; } /** * 记录证书文件名 * @param string $method 支付方式类型 * @param array $config 支付配置 * @return array * @throws BaseException */ private function certFileName(string $method, array $config): array { if ($method === PaymentMethodEnum::WECHAT) { $config['normal'] = $this->saveCertFileNames($config['normal'], $method, [ 'apiclientCert', 'apiclientKey' ], 'pem'); $config['provider'] = $this->saveCertFileNames($config['provider'], $method, [ 'spApiclientCert', 'spApiclientKey' ], 'pem'); // 微信支付v3下载 [微信平台证书] $config['version'] === 'v3' && $this->downloadPlatformCert($config); } if ($method === PaymentMethodEnum::ALIPAY && $config['signMode'] == 10) { $config = $this->saveCertFileNames($config, $method, [ 'appCertPublicKey', 'alipayCertPublicKey', 'alipayRootCert' ], 'crt'); } return $config; } /** * 微信支付v3下载 [微信平台证书] * @param array $config * @return void * @throws BaseException */ private function downloadPlatformCert(array &$config): void { // 配置项的字段(用于区分普通商户和子商户) $field = $config['mchType'] === 'normal' ? ['normal', 'apiclientCert', 'apiclientKey', 'apiKey', 'mchId'] : ['provider', 'spApiclientCert', 'spApiclientKey', 'spApiKey', 'spMchId']; // 微信商户API证书 [公钥] $publicKey = parent::realPathCertFile(PaymentMethodEnum::WECHAT, $config[$field[0]][$field[1]], self::$storeId); // 微信商户API证书 [私钥] $privatekey = parent::realPathCertFile(PaymentMethodEnum::WECHAT, $config[$field[0]][$field[2]], self::$storeId); // 生成平台证书文件名 $platformCertName = $this->buildCertFileName('platformCert', 'pem'); // 证书保存的目录 $certFolder = parent::certFolder(PaymentMethodEnum::WECHAT, self::$storeId); // 下载平台证书 $downloader = new PlatformCertDown([ 'key' => $config[$field[0]][$field[3]], 'mchid' => $config[$field[0]][$field[4]], 'privatekey' => $privatekey, 'publicKey' => $publicKey, 'output' => $certFolder, 'fileName' => $platformCertName ]); $downloader->run(); // 记录平台证书 $config[$field[0]]['platformCert'] = $platformCertName; $config[$field[0]]['platformCertSerial'] = $downloader->getPlatformCertSerial(); } /** * 批量设置证书文件名 * @param array $config 配置项 * @param string $method 支付方式类型 * @param array $certNames * @param string $ext 文件后缀 * @return array */ private function saveCertFileNames(array $config, string $method, array $certNames, string $ext): array { foreach ($certNames as $name) { $config[$name] = $this->writeFile($method, $name, $ext) ?: $config[$name]; } return $config; } /** * 写入证书文件 * @param string $method 支付方式类型 * @param string $name 证书名称 * @param string $ext 文件后缀 * @return string|false */ private function writeFile(string $method, string $name, string $ext) { // 接收上传的文件 $file = request()->file($name); if (empty($file)) { return false; } // 证书文件夹路径 $dirPath = "payment/{$method}/" . self::$storeId; // 证书文件名 $fileName = $this->buildCertFileName($name, $ext); // 写入到本地服务器 Filesystem::disk('data')->putFileAs($dirPath, $file, $fileName); return $fileName; } /** * 生成证书文件名 * @param string $name * @param string $ext * @return string */ private function buildCertFileName(string $name, string $ext): string { $hash = str_substr(md5(get_guid_v4()), 8); return "{$name}-{$hash}.{$ext}"; } /** * 删除记录 * @return bool */ public function setDelete(): bool { // 验证模板是否被引用 if (PaymentModel::existsTemplateId($this['template_id'])) { $this->error = '当前支付模板已被引用,需解除后才可删除'; return false; } // 标记为已删除 return $this->save(['is_delete' => 1]); } }