微信APP支付,服务器端生成prepay_id,及后续处理

  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;
        }
原文地址:https://www.cnblogs.com/lxdd/p/4708140.html