1 <?php 2 /* 3 微信支付類 4 */ 5 class Wx { 6 const APPID = 'xxxx'; //公眾賬號ID 7 const MCHID = 'xxxx'; //商戶號 8 const APPPWD = 'xxxx'; //APP秘鑰 9 const URL = 'https://api.mch.weixin.qq.com/pay/unifiedorder'; 10 private $_config = array(); 11 12 public function __construct($info) { 13 //生成配置參數 14 $this->_makeConfig($info); 15 } 16 17 /* 18 運行方法 19 */ 20 public function run() { 21 22 //將config 轉換為xml格式數據 23 $xml_str = ''; 24 $xml_str = '<xml>'; 25 foreach ($this->_config as $k => $v) { 26 $xml_str .= '<'.$k.'>' . $v . '</'.$k.'>'; 27 } 28 $xml_str .= '</xml>'; 29 30 return $this->_postXmlCurl($xml_str,self::URL); 31 } 32 33 /* 34 生成配置文件 35 */ 36 private function _makeConfig($info) { 37 if(!is_array($info)) 38 exit('非法傳參'); 39 40 //固定參數 41 $fix_config = array( 42 'appid' => strtolower(self::APPID), 43 'mch_id' => strtolower(self::MCHID), 44 'nonce_str' => strtolower($this->_makeRandom()), 45 'spbill_create_ip' => strtolower(get_client_ip()), 46 'trade_type' => 'APP', 47 ); 48 49 $tmp_config = array_merge($fix_config,$info); 50 51 $this->_config = $this->_sortConfig($tmp_config); 52 53 $this->_makeSign(); 54 } 55 56 /* 57 生成隨機字符串 58 */ 59 private function _makeRandom() { 60 return md5(uniqid()); 61 } 62 63 /* 64 對配置文件進行排序 65 */ 66 private function _sortConfig($arr) { 67 $new_arr = array(); 68 foreach ($arr as $key => $value) { 69 if(empty($value)) 70 continue; 71 72 $new_arr[$key] = $value; 73 } 74 ksort($new_arr); 75 return $new_arr; 76 } 77 78 /* 79 生成簽名 80 */ 81 private function _makeSign() { 82 //第一步,將config參數生成 & 分割的字符串 83 $str_config = ''; 84 foreach ($this->_config as $key => $value) { 85 if(empty($value)) 86 continue; 87 88 $str_config .= $key . '=' . $value . '&'; 89 } 90 91 //拼接API密鑰 92 $str_config .= 'key=' . self::APPPWD; 93 94 //md5 加密,並轉為大寫 95 $sign_info = strtoupper(md5($str_config)); 96 97 $this->_config['sign'] = $sign_info; 98 } 99 100 101 /** 102 * 以post方式提交xml到對應的接口url 103 * 104 * @param string $xml 需要post的xml數據 105 * @param string $url url 106 * @param bool $useCert 是否需要證書,默認不需要 107 * @param int $second url執行超時時間,默認30s 108 * @throws WxPayException 109 */ 110 private function _postXmlCurl($xml, $url, $useCert = false, $second = 30){ 111 $ch = curl_init(); 112 //設置超時 113 curl_setopt($ch, CURLOPT_TIMEOUT, $second); 114 curl_setopt($ch,CURLOPT_URL, $url); 115 curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE); 116 curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//嚴格校驗 117 //設置header 118 curl_setopt($ch, CURLOPT_HEADER, FALSE); 119 //要求結果為字符串且輸出到屏幕上 120 curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); 121 122 if($useCert == true){ 123 //設置證書 124 //使用證書:cert 與 key 分別屬於兩個.pem文件 125 curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM'); 126 curl_setopt($ch,CURLOPT_SSLCERT, WxPayConfig::SSLCERT_PATH); 127 curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM'); 128 curl_setopt($ch,CURLOPT_SSLKEY, WxPayConfig::SSLKEY_PATH); 129 } 130 //post提交方式 131 curl_setopt($ch, CURLOPT_POST, TRUE); 132 curl_setopt($ch, CURLOPT_POSTFIELDS, $xml); 133 //運行curl 134 $data = curl_exec($ch); 135 136 //返回結果 137 if($data){ 138 curl_close($ch); 139 return $data; 140 141 } else { 142 $error = curl_errno($ch); 143 curl_close($ch); 144 145 return false; 146 } 147 } 148 149 }
調用:
1 /* 2 微信支付總方法 3 */ 4 private function _wxPayAction($need_info) { 5 if(empty($need_info)) 6 $this->myreturn(array(),'109802','程序內部初始化失敗',-1); 7 8 9 //引入微信支付 10 Vendor('Wx.Wx'); 11 $wx_obj = new Wx(array( 12 'body' => $need_info['goods_name'],//商品名 13 'out_trade_no' => $need_info['order_index'],//訂單號 14 // 'total_fee' => $need_info['price_total'] * 100,//價格,分 15 'total_fee' => 1, 16 'attach' => $need_info['goods_name'], 17 'notify_url' => 'http://' . $_SERVER['HTTP_HOST'] . U('Leasegoods/wx_notify_url_new'),//異步通知頁面url 18 )); 19 20 $wx_return_data = $wx_obj->run(); 21 22 //日志記錄 23 $wx_log_path = RUNTIME_PATH . '/Wx_log/'; 24 25 if(!is_dir($wx_log_path)) 26 mkdir($wx_log_path,0777,true); 27 28 $wx_log_dir = $wx_log_path .date('Y-m-d'). '.log'; 29 Log::write('訂單編號為 ' . $need_info['order_index'] . '的訂單,請求微信prepay_id支付,返回xml為:' . $wx_return_data,Log::DEBUG,Log::FILE,$wx_log_dir); 30 31 32 33 //獲取需要的值 34 if($wx_return_data === false) 35 $this->myreturn(array(),'109803','請求微信支付接口失敗',-1); 36 37 //匹配出return_code 38 $pattern = '/<return_code><!\[CDATA\[([A-Z]{7})\]\]><\/return_code>/iU'; 39 $info = preg_match_all($pattern,$wx_return_data, $matches_code); 40 41 if($info) { 42 if($matches_code[1][0] == 'SUCCESS') { 43 $pattern = '/<prepay_id><!\[CDATA\[([\w]+)\]\]><\/prepay_id>/iU'; 44 $info_id = preg_match_all($pattern, $wx_return_data, $matches_id); 45 if($info_id) { 46 $this->myreturn(array('result' => array('prepay_id' => $matches_id[1][0])),'','獲取成功',0); 47 }else 48 $this->myreturn(array(),'109804','匹配prepay_id失敗',-1); 49 50 }else 51 $this->myreturn(array(),'109805','微信同一訂單請求失敗',-1); 52 53 }else 54 $this->myreturn(array(),'109806','匹配狀態碼失敗',-1); 55 56 }
通知處理
/* 微信支付后回調頁面 */ public function wx_notify_url_new() { $return_info = file_get_contents('php://input','r'); if(!$return_info) echo $this->_wxReturnDataFormat(array('code' => 'FILE','mes' => '無返回值')); //log目錄 $wx_log_path = RUNTIME_PATH . '/Wx_log/'; if(!is_dir($wx_log_path)) mkdir($wx_log_path,0777,true); $wx_log_dir = $wx_log_path .date('Y-m-d'). '.log'; Log::write('服務器獲取到的總參數:' . $return_info, Log::DEBUG, Log::FILE, $wx_log_dir); //匹配return_code $return_code = $this->_wxGetOneInfo('return_code',$return_info); if($return_code == 'SUCCESS'){ //獲取訂單號 $order_index = $this->_wxGetOneInfo('out_trade_no',$return_info); //業務處理。。。。 echo $this->_wxReturnDataFormat(array('code' => 'SUCCESS','mes' => 'OK')); }else { //暫放 echo $this->_wxReturnDataFormat(array('code' => 'FILE','mes' => 'code錯誤')); } } /* 匹配某一項內容 @param pat 要匹配的內容正則表達式 info 內容 */ private function _wxGetOneInfo($pat,$info) { if($pat == 'total_fee') $pattern = '/<total_fee>([\d]+)<\/total_fee>/iU'; else $pattern = '/<'.$pat.'><!\[CDATA\[([\s\S]+)\]\]><\/'.$pat.'>/uiU'; $mat_int = preg_match_all($pattern, $info, $matches); if(!$mat_int) return '匹配異常'; return $matches[1][0]; } /* 拼接微信返回值信息 */ private function _wxReturnDataFormat($arr) { $str = '<xml>'; $str .= '<return_code><![CDATA['.$arr['code'].']]></return_code>'; $str .= '<return_msg><![CDATA['.$arr['mes'].']]></return_msg>'; $str .= '</xml>'; return $str; }