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[([sS]+)]]></'.$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; }