$value) { if ($value === null || $value === '' || $key === 'sign') { continue; } if ($signStr) { $signStr .= '&'; } $signStr .= $key.'='.$value; } $signStr .= '&key='.$secretKey; $sign = md5($signStr); return strtoupper($sign); } /** * 时间戳偏差校验 * @throws AppException */ private function checkRequestTime(int $requestTime): void { if (abs(time() - $requestTime / 1000) > 300) { throw new AppException('时间戳相差大于300秒'); } } /** * 渠道编码校验 * @throws AppException */ private function checkIfCode(string $ifCode): void { if ($ifCode !== 'alipay') { throw new AppException('渠道编码固定为:alipay'); } } /** * 接口版本号校验 * @throws AppException */ private function checkVersion(string $version): void { if ($version !== '1.0') { throw new AppException('接口版本号固定为:1.0'); } } /** * 签名类型校验 * @throws AppException */ private function checkSignType(string $signType): void { if ($signType !== 'MD5') { throw new AppException('签名类型固定为:MD5'); } } /** * 校验签名 * @throws AppException */ private function checkSign(array $params, string $secretKey): void { if (empty($params['sign'])) { throw new AppException('签名缺失'); } $checkSign = $this->makeSign($params, $secretKey); if ($checkSign !== $params['sign']) { throw new AppException('签名不匹配'); } } /** * 根据商户号和应用ID获取应用 * @throws AppException */ private function getMchApp(string $mchNo, string $appId): MchApp { $app = MchApp::query() ->where('mch_no', $mchNo) ->where('app_id', $appId) ->first(); if (empty($app)) { throw new AppException('应用不存在'); } if (empty($app->account_book_id)) { throw new AppException('还未开通记账本'); } return $app; } /** * 查询记账本余额 * @param array $params * @return array * @throws AppException */ public function queryBalance(array $params): array { $this->checkRequestTime($params['reqTime']); $this->checkIfCode($params['ifCode']); $this->checkVersion($params['version']); $this->checkSignType($params['signType']); $mchApp = $this->getMchApp($params['mchNo'], $params['appId']); $this->checkSign($params, $mchApp->secret_key); // TODO mock $data = [ 'availableAmount' => 700, ]; $sign = $this->makeSign($data, $mchApp->secret_key); return [$data, $sign]; } /** * 单笔转账 * @param array $params * @return array * @throws AppException */ public function transferOrder(array $params): array { $this->checkRequestTime($params['reqTime']); $this->checkIfCode($params['ifCode']); $this->checkVersion($params['version']); $this->checkSignType($params['signType']); $mchApp = $this->getMchApp($params['mchNo'], $params['appId']); $this->checkSign($params, $mchApp->secret_key); // TODO mock $data = [ 'accountName' => '广西拉米信息科技有限公司', 'accountNo' => '3858074971@qq.com', 'amount' => 300, 'channelOrderNo' => '20250825020070011530820074021763', 'mchOrderNo' => 'P00000000000000000010', 'state' => 1, 'transferId' => 'T1708316875559008' ]; $sign = $this->makeSign($data, $mchApp->secret_key); return [$data, $sign]; } /** * 转账查询 * @param array $params * @return array * @throws AppException */ public function transferQuery(array $params): array { $this->checkRequestTime($params['reqTime']); $this->checkVersion($params['version']); $this->checkSignType($params['signType']); $mchApp = $this->getMchApp($params['mchNo'], $params['appId']); $this->checkSign($params, $mchApp->secret_key); // TODO mock $data = [ 'accountName' => '广西拉米信息科技有限公司', 'accountNo' => '3858074971@qq.com', 'amount' => 300, 'appId' => '664714f9e4b078d6ee5d0007', 'channelOrderNo' => '20250825020070011530820074021763', 'createdAt' => 1756092887724, 'currency' => 'cny', 'entryType' => 'ALIPAY_CASH', 'ifCode' => 'alipay', 'mchNo' => 'M1715934457', 'mchOrderNo' => 'P00000000000000000010', 'state' => 2, 'successTime' => 1756092888000, 'transferDesc' => '提现到账3.00元', 'transferId' => 'T1708316875559008' ]; $sign = $this->makeSign($data, $mchApp->secret_key); return [$data, $sign]; } }