mchId = getSetting('pay_wechat_mch_id', ''); $this->apiKey = getSetting('pay_wechat_api_key', ''); $this->appId = getSetting('pay_wechat_appid', ''); } public function getName() { return '微信支付'; } /** * 创建微信 Native 支付订单(返回二维码链接)。 */ public function createOrder(array $order) { // 构建 V3 Native 下单请求 $url = $this->apiUrl . '/pay/transactions/native'; $body = [ 'mchid' => $this->mchId, 'out_trade_no' => $order['order_no'], 'appid' => $this->appId ?: '', 'description' => $order['subject'], 'notify_url' => $order['notify_url'], 'amount' => [ 'total' => (int)round($order['amount'] * 100), // 单位:分 'currency' => 'CNY', ], ]; $headers = [ 'Content-Type: application/json', 'Accept: application/json', 'Authorization: WECHATPAY2-SHA256-RSA2048 ' . $this->buildAuth($url, 'POST', json_encode($body)), ]; $result = $this->httpPost($url, json_encode($body), $headers); $data = json_decode($result, true); if (isset($data['code_url'])) { return [ 'url' => '', 'form' => '
请使用微信扫码支付
' . '支付创建失败: ' . h($data['message'] ?? '未知错误') . '
']; } public function verifyNotify(array $params) { // V3 回调验签 if (empty($_SERVER['HTTP_WECHATPAY_SIGNATURE'])) return false; $serial = $_SERVER['HTTP_WECHATPAY_SERIAL'] ?? ''; $signature = $_SERVER['HTTP_WECHATPAY_SIGNATURE'] ?? ''; $timestamp = $_SERVER['HTTP_WECHATPAY_TIMESTAMP'] ?? ''; $nonce = $_SERVER['HTTP_WECHATPAY_NONCE'] ?? ''; // TODO: 完整的 V3 验签实现需加载微信平台证书 // 这里做基础验证 return !empty($params['resource']['ciphertext']); } public function getTradeNo(array $params) { // V3 回调解密后获取 transaction_id $resource = $params['resource'] ?? []; return $resource['ciphertext'] ? $this->decryptResource($resource) : ''; } public function isPaid($params) { $resource = $params['resource'] ?? []; $decrypted = $resource['ciphertext'] ? json_decode($this->decryptResource($resource), true) : []; return ($decrypted['trade_state'] ?? '') === 'SUCCESS'; } public function respondSuccess() { header('Content-Type: application/json'); echo json_encode(['code' => 'SUCCESS', 'message' => '成功']); } // ─── V3 签名与请求 ─── private function buildAuth($url, $method, $body) { $timestamp = (string)time(); $nonce = bin2hex(random_bytes(16)); $signStr = "$method\n$url\n$timestamp\n$nonce\n$body\n"; // 使用 API Key 做 HMAC-SHA256 签名(简化版) $signature = hash_hmac('SHA256', $signStr, $this->apiKey); // 实际 V3 需要商户私钥签名,这里简化处理 return "mchid=\"{$this->mchId}\",nonce_str=\"{$nonce}\",timestamp=\"{$timestamp}\",serial_no=\"\",signature=\"$signature\""; } private function httpPost($url, $body, $headers = []) { $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => $url, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $body, CURLOPT_HTTPHEADER => $headers, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 30, CURLOPT_SSL_VERIFYPEER => false, ]); $result = curl_exec($ch); curl_close($ch); return $result; } /** * 解密 V3 回调资源。 */ private function decryptResource($resource) { $ciphertext = base64_decode($resource['ciphertext']); $nonce = $resource['nonce']; $associatedData = $resource['associated_data']; // AES-256-GCM 解密 $key = hash('sha256', $this->apiKey, true); // 用 API Key 派生密钥(简化) if (function_exists('openssl_decrypt') && defined('AES_256_GCM')) { $plain = openssl_decrypt($ciphertext, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $nonce, $associatedData); return $plain !== false ? $plain : ''; } return ''; } }