config = config('pay_list.ccpay') ?: []; $this->apiUrl = $this->config['api_url'] ?? ''; $this->mchNo = $this->config['mch_no'] ?? ''; $this->paySecret = $this->config['pay_secret'] ?? ''; } public function getConfigInfo() { return $this->config; } public function generateSign(array $params) { unset($params['sign']); ksort($params); $str = ''; foreach ($params as $k => $v) { if (is_string($v) && strlen($v) > 0) { $str .= "{$k}={$v}&"; } } $str = substr($str, 0, -1) . '&paySecret=' . $this->paySecret; return strtoupper(md5($str)); } public function verifySign(array $params) { $received = $params['sign'] ?? ''; if (!$received) return false; $calculated = $this->generateSign($params); return hash_equals($calculated, $received); } public function createOrder($orderNo, $amount, $notifyUrl, $memberId = 'og_user', $callbackUrl = '') { $extra = [ 'bankType' => 'OFFLINE', 'cardType' => '0', 'orderPeriod' => '30', 'memberId' => $memberId, 'merchantName' => 'OG', 'notifyUrl' => $notifyUrl, 'callbackUrl' => $callbackUrl, ]; $data = [ 'tradeType' => 'cs.pay.submit', 'version' => '2.0', 'channel' => 'union_pay', 'mchNo' => $this->mchNo, 'body' => 'online_pay', 'mchOrderNo' => $orderNo, 'amount' => strval(intval($amount)), 'currency' => 'VND', 'timePaid' => date('YmdHis'), 'remark' => 'online-pay', ]; $signParams = array_merge($data, $extra); $data['sign'] = $this->generateSign($signParams); $data['extra'] = json_encode($extra); addLogToFile('ccpay 下单请求: order=' . $orderNo . ' amount=' . $amount . ' params=' . json_encode($data, JSON_UNESCAPED_UNICODE), 'ccpay_request', 'ccpay'); $result = $this->postForm($this->apiUrl, $data); addLogToFile('ccpay 下单返回: ' . json_encode($result, JSON_UNESCAPED_UNICODE), 'ccpay_response', 'ccpay'); return $result; } public function queryOrder($orderNo) { $data = [ 'tradeType' => 'cs.order.query', 'version' => '2.0', 'mchNo' => $this->mchNo, 'mchOrderNo' => $orderNo, ]; $data['sign'] = $this->generateSign($data); return $this->postForm($this->apiUrl, $data); } private function postForm($url, $params) { $ch = curl_init($url); $body = ''; foreach ($params as $k => $v) { if (!is_string($v)) continue; $body .= $k . '=' . urlencode($v) . '&'; } $body = rtrim($body, '&'); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $body, CURLOPT_HTTPHEADER => ['Content-Type: application/x-www-form-urlencoded; charset=UTF-8'], CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 30, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYHOST => false, ]); $resp = curl_exec($ch); $err = curl_error($ch); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($resp === false) { addLogToFile("ccpay curl 失败: code={$code} err={$err}", 'ccpay_error', 'ccpay'); return null; } return json_decode($resp, true); } }