$value) { $parts[] = $name . '=' . $value; } $parts[] = 'key=' . ($key ?? self::getSecret()); return strtoupper(md5(implode('&', $parts))); } public static function pay($amount, string $orderNo, string $member): array { $data = self::signedData([ 'appId' => self::getAppId(), 'mchOrderNo' => $orderNo, 'amount' => self::amount($amount), 'member' => $member, 'notifyUrl' => self::getPayNotifyUrl(), 'timestamp' => self::timestamp(), 'nonce' => self::nonce(), ]); return self::post((string)config('app.zimu_pay_gateway'), $data); } public static function queryPayOrder(string $orderNo): array { return self::post((string)config('app.zimu_pay_query_gateway'), self::queryData($orderNo)); } public static function withdraw($amount, string $orderNo, string $member, string $receiveAccount, string $realName = ''): array { $data = self::signedData([ 'appId' => self::getAppId(), 'member' => $member, 'realName' => $realName, 'mchOrderNo' => $orderNo, 'amount' => self::amount($amount), 'notifyUrl' => self::getPayoutNotifyUrl(), 'timestamp' => self::timestamp(), 'nonce' => self::nonce(), 'receiveAccount' => $receiveAccount, ]); return self::post((string)config('app.zimu_withdraw_gateway'), $data); } public static function queryWithdrawOrder(string $orderNo): array { return self::post((string)config('app.zimu_withdraw_query_gateway'), self::queryData($orderNo)); } public static function cash($amount, string $orderNo, string $accountName, string $accountNo, string $bank, string $payMethod = ''): array { $data = self::signedData([ 'appId' => self::getAppId(), 'mchOrderNo' => $orderNo, 'amount' => self::amount($amount), 'notifyUrl' => self::getPayoutNotifyUrl(), 'accountName' => $accountName, 'accountNo' => $accountNo, 'bank' => $bank, 'payMethod' => $payMethod, 'timestamp' => self::timestamp(), 'nonce' => self::nonce(), ]); return self::post((string)config('app.zimu_cash_gateway'), $data); } public static function queryCashOrder(string $orderNo): array { return self::post((string)config('app.zimu_cash_query_gateway'), self::queryData($orderNo)); } public static function balance(): array { $data = self::signedData([ 'appId' => self::getAppId(), 'timestamp' => self::timestamp(), 'nonce' => self::nonce(), ]); return self::post((string)config('app.zimu_balance_gateway'), $data); } public static function verifyNotify(array $params): bool { if (self::getAppId() === '' || ($params['appId'] ?? '') !== self::getAppId() || empty($params['sign'])) { return false; } return hash_equals(self::signature($params), strtoupper((string)$params['sign'])); } public static function notifySignatureDiagnostics(array $params): array { $fields = $params; unset($fields['sign']); return [ 'received_sign' => strtoupper((string)($params['sign'] ?? '')), 'calculated_sign' => self::signature($params), 'signing_fields' => array_keys(array_filter($fields, static function ($value) { return $value !== null && $value !== ''; })), ]; } public static function cashPayMethod(string $bankName): string { if (str_contains($bankName, '微信')) { return '2'; } if (str_contains($bankName, '支付宝')) { return '3'; } if (str_contains($bankName, '数字')) { return '4'; } return '1'; } private static function queryData(string $orderNo): array { return self::signedData([ 'appId' => self::getAppId(), 'mchOrderNo' => $orderNo, 'timestamp' => self::timestamp(), 'nonce' => self::nonce(), ]); } private static function signedData(array $data): array { $data['sign'] = self::signature($data); return $data; } private static function timestamp(): string { return (string)round(microtime(true) * 1000); } private static function nonce(): string { return substr(str_replace('.', '', uniqid('', true)), 0, 15); } private static function post(string $url, array $data): array { $logData = $data; unset($logData['sign']); Log::info('ZIMU支付接口请求', [ 'url' => $url, 'app_id' => self::getAppId(), 'data' => $logData, ]); try { $response = (new Client(['timeout' => 10.0]))->post($url, [ 'json' => $data, 'headers' => [ 'Accept' => 'application/json', 'Content-Type' => 'application/json', ], ]); $body = $response->getBody()->getContents(); Log::info('ZIMU支付接口响应', [ 'url' => $url, 'app_id' => self::getAppId(), 'http_status' => $response->getStatusCode(), 'body' => $body, ]); return json_decode($body, true) ?: []; } catch (RequestException $e) { $response = $e->getResponse(); $body = $response ? $response->getBody()->getContents() : ''; Log::error('ZIMU支付接口请求失败', [ 'url' => $url, 'app_id' => self::getAppId(), 'http_status' => $response ? $response->getStatusCode() : null, 'body' => $body, 'error' => $e->getMessage(), ]); throw $e; } catch (\Throwable $e) { Log::error('ZIMU支付接口异常', [ 'url' => $url, 'app_id' => self::getAppId(), 'error' => $e->getMessage(), ]); throw $e; } } public static function getWhere(array $search = []): array { return []; } }