/** * 發起支付 */ public function pay($user_id, $order_id) { // 查看用戶信息 $user_info = $this -> user_info($user_id); // 查看訂單信息 $order_info = $this -> order_info($order_id); // 基本信息 $money = $order_info['order_amount'] * 100; $openid = $user_info['mp_unionid']; // 用戶openid $order_code = $order_id; // 訂單號 $nonce_str = self::getNonceStr(); // 隨機字符串 $notify_url = "https://new.zhyin.net/index.php/mobile/pay/zhifu"; // 發送數據 $post_data = [ 'appid' => "", 'mch_id' => "", 'nonce_str' => $nonce_str, 'body' => '智慧印', 'out_trade_no' => $order_code, 'total_fee' => $money, 'spbill_create_ip' => $_SERVER['REMOTE_ADDR'], 'trade_type' => 'JSAPI', 'openid' => $openid, 'notify_url' => $notify_url ]; // 生成簽名 $post_data['sign'] = $this->MakeSign($post_data, ""); // 組合XML數據 $xmlData = $this->MakeXml($post_data); // 發送請求 $this->we_chat_url = 'https://api.mch.weixin.qq.com/pay/unifiedorder'; $result = $this->curl_post($this->we_chat_url,$xmlData,true); // 解析xml數據 $payment = $this->FromXml($result); // 是否請求成功 if($payment['return_code'] != 'SUCCESS'){ $this->jsonError($payment['return_msg']); } if ($payment['result_code'] == 'SUCCESS'){ $payment['timestamp'] = time(); // 建立統一訂單信息 $sign_data = [ 'appId'=>$payment['appid'], 'nonceStr'=>$payment['nonce_str'], 'package'=>'prepay_id=' . $payment['prepay_id'], 'signType'=>'MD5', 'timeStamp'=>'' . $payment['timestamp'] . '', ]; $sign_data['paySign'] = $this->MakeSign($sign_data , ""); return $sign_data; } else { return ['支付失敗']; } }
/** * 產生隨機字符串,不長於32位 * @param int $length * @return string */ protected static function getNonceStr($length = 32) { $chars = "abcdefghijklmnopqrstuvwxyz0123456789"; $str =""; for ( $i = 0; $i < $length; $i++ ) { $str .= substr($chars, mt_rand(0, strlen($chars)-1), 1); } return $str; } /** * 生成簽名 簽名,本函數不覆蓋sign成員變量,如要設置簽名須要調用SetSign方法賦值 * @param $sign * @param string $keys * @return string */ protected function MakeSign($sign, $keys = '') { ksort($sign); // 數組排序 $str = ''; foreach($sign as $key=>$val){ if($val != ''){ $str .= $key . "=" . $val . "&"; } } $str .= "key=" . $keys; $sign = strtoupper(md5($str)); return $sign; } /** * 生成XML數據 * @param $data * @return string */ protected function MakeXml($data) { $xmlData = "<xml>"; foreach($data as $key=>$val){ $xmlData.="<".$key.">".$val."</".$key.">"; } $xmlData.= "</xml>"; return $xmlData; } /** * POST請求數據 * @param $url * @param $xmlData * @param bool $useCert * @return mixed */ public function curl_post($url, $xmlData, $useCert = false) { $header[] = "Content-type: text/xml"; // POST發送數據 $ch = curl_init(); // 初始化CURL會話 curl_setopt($ch, CURLOPT_TIMEOUT, 30); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); if($useCert == true){ //設置證書 //使用證書:cert 與 key 分別屬於兩個.pem文件 //證書文件請放入服務器的非web目錄下 $sslCertPath = getcwd() . "/wx_cert/apiclient_cert.pem"; $sslKeyPath = getcwd() . "/wx_cert/apiclient_key.pem"; curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM'); curl_setopt($ch,CURLOPT_SSLCERT, $sslCertPath); curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM'); curl_setopt($ch,CURLOPT_SSLKEY, $sslKeyPath); } curl_setopt($ch, CURLOPT_HTTPHEADER, $header); curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlData); $result = curl_exec($ch); // 獲取結果 curl_close($ch);// 關閉會話 return $result; } /** * 將xml轉爲array * @param $xml * @return mixed */ protected function FromXml($xml) { if(!$xml){ $this->jsonReturn(0,'','XML解析錯誤!'); } libxml_disable_entity_loader(true); $values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); return $values; }
回調地址php
public function zhifu() { $postXml = file_get_contents('php://input'); libxml_disable_entity_loader(true); $data = json_decode(json_encode(simplexml_load_string($postXml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); $order_id = $data['out_trade_no']; // 訂單單號 // 查看有沒有這個訂單 $order_info_where['order_id'] = $order_id; $order_info_where['order_state'] = 10; $order_info = Db::name('order') -> where($order_info_where) -> find(); // 有這個訂單則執行操做 if ($order_info) { $update['order_state'] = '20'; $update['payment_time'] = time(); if (Db::name('order') -> where($order_info_where) -> update($update)) { // 減每一個商品的庫存 $order_common = Db::name('order_goods') -> where('order_id', $order_id) -> select(); foreach($order_common as $v) { $goods = Db::name('goods') -> where('goods_id', $v['goods_id']) -> field('goods_storage, goods_salenum, goods_id') -> find(); $update_goods['goods_storage'] = $goods['goods_storage'] - $v['goods_num']; $update_goods['goods_salenum'] = $goods['goods_salenum'] + $v['goods_num']; Db::name('goods') -> where('goods_id', $v['goods_id']) -> update($update_goods); } $str='<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>'; } else { $str='<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[簽名失敗]]></return_msg></xml>'; } } return $str; }