做过微信支付的小伙伴都知道,可以直接使用微信公众平台提供的支付demo,但是你会发现有很多没用的文件,而且demo写得异常复杂,文件太多,需要花比较多的时间去熟悉和调试。

这个对于新手小伙伴来说还是有一定的难度,在开发的过程中会遇到很多的坑,当初我第一次实现微信支付也是同样的啦!人生总会有很对第一次的不是,包括...嘿嘿,别想太多啦!

sdk对于有代码洁癖的资深php开发小伙伴来说就简直不能忍了,凭着高超的记忆怎么也要自己来封装一个吧,装逼必备啊有木有!

自己封装也是有很多好处的,能够更完美的嵌入到自身的框架内,能够更加方便的维护和修改,你看几十上百个文件和看一个文件实现同样的功能,那个更加容易些,答案显而易见了!

下面我们来研究一波:


image.png

看下请求的参数主要就是这个【签名和随机字符串】,其他字段的数据都能够很容易的得到,而这个签名和随机字符串需要做一个处理;

签名如何处理?我们写一个函数来搞定他,代码如下

1
2
3
4
5
6
//data就是所有必填参数值,key就是你的支付秘钥(商户中心设置那个32位那个)
function sign(array $data$key) {
    ksort($data);
    $sign strtoupper(md5(urldecode(http_build_query($data)).'&key='.$key));
    return $sign;
}

随机字符串如何处理?我们也写一个函数来搞定他

1
2
3
4
5
6
7
8
public 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;
    }

第二:微信支付请求数据类型位xml,因此我们还需要一个将数组转为xml的函数,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
 * @param $values
 * @return string
 * @throws \think\Exception
 * 数组转xml
 */
function ToXml($values){
    if(!is_array($values) || count($values) <= 0) {
        throw new \think\Exception('数组数据异常');
    }
 
    $xml "<xml>";
    foreach ($values as $key=>$val) {
        if (is_numeric($val)){
            $xml.="<".$key.">".$val."</".$key.">";
        }else{
            $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
        }
    }
    $xml.="</xml>";
    return $xml;
}

第三:组装完毕参数之后需要将参数发送到微信支付接口,因此需要一个curl请求函数代码如下(需要自己将参数配置到配置文件中,Config::get()为获取配置文件的微信支付配置信息)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
protected static function postXmlCurl($xml$url$useCert = false, $second = 30){
        $ch = curl_init();
        //设置超时
        curl_setopt($ch, CURLOPT_TIMEOUT, $second);
        //如果有配置代理这里就设置代理
        if(Config::get('wx.CURL_PROXY_HOST') != "0.0.0.0"
            && Config::get('wx.CURL_PROXY_PORT') != 0){
            curl_setopt($ch,CURLOPT_PROXY, Config::get('wx.CURL_PROXY_HOST'));
            curl_setopt($ch,CURLOPT_PROXYPORT, Config::get('wx.CURL_PROXY_PORT'));
        }
        curl_setopt($ch,CURLOPT_URL, $url);
        curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE);
        curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//严格校验
        //设置header
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        //要求结果为字符串且输出到屏幕上
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
 
        if($useCert == true){
            //设置证书
            //使用证书:cert 与 key 分别属于两个.pem文件
            curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
            curl_setopt($ch,CURLOPT_SSLCERT, Config::get('wx.SSLCERT_PATH'));
            curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
            curl_setopt($ch,CURLOPT_SSLKEY, Config::get('wx.SSLKEY_PATH'));
        }
        //post提交方式
        curl_setopt($ch, CURLOPT_POST, TRUE);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
        //运行curl
        $data = curl_exec($ch);
        //返回结果
        if($data){
            curl_close($ch);
            return $data;
        else {
            $error = curl_errno($ch);
            curl_close($ch);
            returnFailMsg('10018',"curl出错,错误码:$error");
        }
    }

微信支付需要的几个函数我们就写完了,剩下的就是如何传递参数和调用了。


最后大概是这样,需要自己调调了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
class Wechat {
    public $values = [];
    /**
     * @return \think\response\Json
     * 支付
     */
    public function wxPay(){
        //通用参数
        $this->values['appid']  = Config::get('wx.APPID');
        $this->values['mch_id'] = Config::get('wx.MCHID');
        $this->values['nonce_str'] = $this->getNonceStr();
        $this->values['goods_tag'] = 'test';
        $this->values['out_trade_no'] = time().rand(1000,9999); //平台订单号
        $this->values['total_fee'] = 1 * 100; //单位为分*100为元
        $this->values['time_start'] = date("YmdHis");
        $this->values['time_expire'] = date("YmdHis", time() + 600);
        $this->values['notify_url']       = Config::get('wx.NOTIFY');
        if('JSAPI' === $this->values['trade_type']){
            if(empty($this->values['openid']) || !isset($this->values['openid']))
                die('jsAPI支付openid为必传项')
        }
        if('NATIVE' === $this->values['trade_type']){
            $this->values['spbill_create_ip'] = $_SERVER['REMOTE_ADDR']; //获取机器的IP
            if(empty($this->values['product_id'] || !isset($this->values['product_id']))){
                die('NATIVE支付商品id为必传项')
            }
        }
        $sign $this->sign($this->values,Config::get('wx.KEY')); //签名
        $this->values['sign'] = $sign;
        $xml $this->ToXml($this->values);//转xml对象
        $response =$this->postXmlCurl($xml, Config::get('wx.PAYURL'), false, 6);//发起post请求
        $this->values = $this->FromXml($response);
        if($this->sign($this->values,Config::get('wx.KEY')) !== $this->values['sign']){
           die('签名错误')
        }
        var_dump($this->values);
    }
     
    public function sign($data$key) {
        //sign不参与签名
        if($data['sign']){
            unset($data['sign']);
        }
        ksort($data);
        $sign strtoupper(md5(urldecode(http_build_query($data)).'&key='.$key));
        return $sign;
    }
     
    /**
     * @param $values
     * @return string
     * @throws \think\Exception
     * 数组转xml
     */
    function ToXml($values){
        if(!is_array($values) || count($values) <= 0) {
            throw new \think\Exception('数组数据异常');
        }
 
        $xml "<xml>";
        foreach ($values as $key=>$val) {
            if (is_numeric($val)){
                $xml.="<".$key.">".$val."</".$key.">";
            }else{
                $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
            }
        }
        $xml.="</xml>";
        return $xml;
    }
     
     public 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;
    }
    /**
     * @param $xml
     * @param $url
     * @param bool $useCert
     * @param int $second
     * @return mixed
     * post方式请求
     */
    protected static function postXmlCurl($xml$url$useCert = false, $second = 30){
        $ch = curl_init();
        //设置超时
        curl_setopt($ch, CURLOPT_TIMEOUT, $second);
        //如果有配置代理这里就设置代理
        if(Config::get('wx.CURL_PROXY_HOST') != "0.0.0.0"
            && Config::get('wx.CURL_PROXY_PORT') != 0){
            curl_setopt($ch,CURLOPT_PROXY, Config::get('wx.CURL_PROXY_HOST'));
            curl_setopt($ch,CURLOPT_PROXYPORT, Config::get('wx.CURL_PROXY_PORT'));
        }
        curl_setopt($ch,CURLOPT_URL, $url);
        curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE);
        curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//严格校验
        //设置header
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        //要求结果为字符串且输出到屏幕上
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
 
        if($useCert == true){
            //设置证书
            //使用证书:cert 与 key 分别属于两个.pem文件
            curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
            curl_setopt($ch,CURLOPT_SSLCERT, Config::get('wx.SSLCERT_PATH'));
            curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
            curl_setopt($ch,CURLOPT_SSLKEY, Config::get('wx.SSLKEY_PATH'));
        }
        //post提交方式
        curl_setopt($ch, CURLOPT_POST, TRUE);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
        //运行curl
        $data = curl_exec($ch);
        //返回结果
        if($data){
            curl_close($ch);
            return $data;
        else {
            $error = curl_errno($ch);
            curl_close($ch);
            returnFailMsg('10018',"curl出错,错误码:$error");
        }
    }
 
 
    /**
     * 回调
     */
    public function notify(){
        //接受回调参数
        $xml file_get_contents('php://input');
  
    }

相关评论(0)
您是不是忘了说点什么?

友情提示:垃圾评论一律封号...

还没有评论,快来抢沙发吧!