[更新]php微信支付类(含h5支付、APP二次签名、jsapi支付)

[更新]php微信支付类(含h5支付、APP二次签名、jsapi支付)

云青
2019-11-02 / 0 评论 / 898 阅读 / 正在检测是否收录...
温馨提示:
本文最后更新于2021年01月17日,已超过271天没有更新,若内容或图片失效,请留言反馈。

博主之封装过一个微信支付类 很长时间没有更新了 现在分享一下自用的微信支付类

该类含有微信app支付 h5支付 公众号支付(jsapi) 订单查询

native扫码支付后面会添加

异步主要商户订单号查询 并确定金额是否与数据库中一致以及判断该商户订单号是否处理过(谨记)

个人觉得验签并不重要 有订单查询以及数据库订单验证就行了

过多的就不介绍了 源码有注释

<?php
/**
 * @author anderyly
 * @email anderyly@sina.com
 * @link https://blog.aaayun.cc/
 * @copyright Copyright (c) 2018
 */

class WxPay
{

    // 微信分配的公众账号ID
    public $appId;
    // 微信支付分配的商户号
    public $mch_id;
    // 微信支付分配的商户密钥
    public $key;
    // 回调地址
    public $notify_url;
    // 随机字符串
    public $nonce_str;
    // 站点名称
    public $webName;
    // 站点url地址
    public $webUrl;
    // h5支付成功后跳转的地址
    public $redirect_url;

    /**
     * [__construct 初始化配置]
     */
    public function __construct($data)
    {

        $this->appId = $data['appId'];
        $this->mch_id = $data['mch_id'];
        $this->key = $data['key'];
        $this->notify_url = $data['notify_url'];
        if (isset($data['webName'])) $this->webName = $data['webName'];
        if (isset($data['webUrl'])) $this->webUrl = $data['webUrl'];
        if (isset($data['redirect_url'])) $this->redirect_url = $data['redirect_url'];
        $this->nonce_str = $this->rand_code();

    }

    /**
     * [h5 html5支付]
     * @param out_trade_no [订单号]
     * @param $body [商品描述]
     * @param $ip [ip地址]
     * @param $total_fee [订单总金额]
     * @return array|bool
     */
    public function h5($out_trade_no, $body, $ip, $total_fee)
    {
        $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        $data = [
            'appid' => $this->appId,
            'mch_id' => $this->mch_id,
            'body' => $body,
            'spbill_create_ip' => $ip,
            'total_fee' => $total_fee * 100,
            'out_trade_no' => $out_trade_no,
            'nonce_str' => $this->nonce_str,
            'notify_url' => $this->notify_url,
            'trade_type' => 'MWEB',
            'scene_info' => "{'h5_info':{'type': 'WAP','wap_url': $this->webUrl,'wap_name': $this->webName}}"
        ];
        $data['sign'] = $this->sign($data); //获取签名
        $data = $this->curlWx($url, $this->ToXml($data));
        if ($data) {
            $res = $this->FromXml($data);
            if (isset($res['return_code']) and $res['return_code'] != 'SUCCESS' and isset($res['return_msg']) and $res['return_msg'] == 'OK' and isset($res['result_code']) and $res['result_code'] == 'SUCCESS') {
                exit("签名失败!");
            } else {
                $url = $res['mweb_url'] . '&redirect_url=' . urlencode($this->redirect_url);
                 exit('<script src="https://open.mobile.qq.com/sdk/qqapi.js?_bid=152"></script><script type="text/javascript">mqq.ui.openUrl({ target: 2,url: "' . $url . '"});</script>');
            }
        }
    }

    /**
     * [app 移动端二次签名]
     * @param out_trade_no [订单号]
     * @param $body [商品描述]
     * @param $ip [ip地址]
     * @param $total_fee [订单总金额]
     * @return array|bool
     */
    public function app($out_trade_no, $body, $ip, $total_fee)
    {
        $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        $data = [
            'appid' => $this->appId,
            'mch_id' => $this->mch_id,
            'body' => $body,
            'spbill_create_ip' => $ip,
            'total_fee' => $total_fee * 100,
            'out_trade_no' => $out_trade_no,
            'nonce_str' => $this->nonce_str,
            'notify_url' => $this->notify_url,
            'trade_type' => 'APP',
        ];
        $data['sign'] = $this->Sign($data);
        $data = $this->curlWx($url, $this->ToXml($data));
        if ($data) {
            $res = $this->FromXml($data);
            if ($res['return_code'] != 'SUCCESS') {
                return false;
            } else {
                $arr = [
                    'prepayid' => $res['prepay_id'],
                    'appid' => $this->appId,
                    'partnerid' => $this->mch_id,
                    'package' => 'Sign=WXPay',
                    'noncestr' => $this->nonce_str,
                    'timestamp' => time(),
                ];
                $sign = $this->sign($arr, 1);
                $arr['out_trade_no'] = $out_trade_no;
                $arr['return_code'] = $res['return_code'];
                $arr['sign'] = $sign;
                return $arr;
            }
        } else {
            return false;
        }
    }
    
    /**
     * [h5 html5支付]
     * @param $out_trade_no [订单号]
     * @param $body [商品描述]
     * @param $ip [ip地址]
     * @param $total_fee [订单总金额]
     * @param $openid [授权用户的openid]
     * @return array|bool
     */
    public function jsapi($out_trade_no, $body, $ip, $total_fee, $openid)
    {
        $url = 'https://api2.mch.weixin.qq.com/pay/unifiedorder';
        $data = [
            'appid' => $this->appId,
            'mch_id' => $this->mch_id,
            'body' => $body,
            'spbill_create_ip' => $ip,
            'total_fee' => $total_fee * 100,
            'out_trade_no' => $out_trade_no,
            'nonce_str' => $this->nonce_str,
            'notify_url' => $this->notify_url,
            'trade_type' => 'JSAPI',
            'openid' => $openid
        ];
        $data['sign'] = $this->Sign($data, 1);
        $data = $this->curlWx($url, $this->ToXml($data));
        if ($data) {
            $res = $this->FromXml($data);
            if ($res['return_code'] != 'SUCCESS') {
                return false;
            } else {
                $arr = [
                    'appId' => $res['appid'],
                    'package' => 'prepay_id=' . $res['prepay_id'],
                    'nonceStr' => $this->nonce_str,
                    'timeStamp' => time(),
                    'signType' => 'MD5'
                ];
                $sign = $this->sign($arr);
                $as['nonceStr'] = $arr['nonceStr'];
                $as['package'] = $arr['package'];
                $as['sign'] = $sign;
                $as['timestamp'] = $arr['timeStamp'];
                $as['appid'] = $arr['appId'];
                return $as;
            }
        } else {
            return false;
        }
    }

    /**
     * [curlWx 发送curl请求]
     * @param $url [url地址]
     * @param $xml [xml]
     * @return mixed
     */
    protected function curlWx($url, $xml)
    {
        //header("Content-type:text/xml");
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        if (stripos($url, "https://") !== FALSE) {
            curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        } else {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, TRUE);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
        }
        curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        curl_setopt($ch, CURLOPT_POST, TRUE);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
        $data = curl_exec($ch);
        curl_close($ch);
        return $data;
    }

    /**
     * [sign 签名]
     * @param null $app [不为null开启二次签名]
     * @return string
     */
    protected function sign($params, $app = NULL)
    {
        ksort($params);
        foreach ($params as $key => $item) {
            if (!empty($item)) $newArr[] = $key . '=' . $item;
        }
        $stringA = implode("&", $newArr);
        $stringSignTemp = $stringA . "&key=" . $this->key;
        $sign = MD5($stringSignTemp);
        if (is_null($app)) $sign = strtoupper($sign);
        return $sign;
    }

    /**
     * [FromXml xml转数组]
     * @param $xml
     * @return bool|mixed
     */
    public function FromXml($xml)
    {
        if (!$xml) return false;
        libxml_disable_entity_loader(true);
        $data = @json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $data;
    }

    /**
     * [ToXml 参数组装成xml]
     * @param array $data
     * @return bool|string
     */
    public function ToXml($data = [])
    {
        if (!is_array($data) || count($data) <= 0) return false;
        $xml = "<xml>";
        foreach ($data as $key => $val) {
            if (is_numeric($val)) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            } else {
                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
            }
        }
        $xml .= "</xml>";
        return $xml;
    }

    /**
     * [rand_code 生成随机字符串]
     * @return bool|string
     */
    protected function rand_code()
    {
        $str = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';//62个字符
        $str = str_shuffle($str);
        $str = substr($str, 0, 32);
        return $str;
    }

    /**
     * [orderQuery 查询订单]
     * @param $order [商户订单号]
     * @param $money [订单金额]
     * @return bool [false | 成功返回流水号]
     */
    public function orderQuery($order, $money)
    {
        $url = 'https://api.mch.weixin.qq.com/pay/orderquery';
        $data = array(
            'appid' => $this->appId,
            'mch_id' => $this->mch_id,
            'nonce_str' => $this->nonce_str,
            'out_trade_no' => $order
        );
        $data['sign'] = $this->sign($data);
        $data = $this->curlWx($url, $this->ToXml($data));
        if ($data) {
            $res = $this->FromXml($data);
            if ($res['return_code'] == 'FAIL') {
                return false;
            } else {
                //
                if (isset($res['return_code']) and $res['return_code'] == 'SUCCESS' and isset($res['return_msg']) and $res['return_msg'] == 'OK' and isset($res['result_code']) and $res['result_code'] == 'SUCCESS' and isset($res['trade_state']) and $res['trade_state'] == 'SUCCESS') {
                    //
                    if ($res['total_fee'] == ($money * 100)) {
                        return $res['transaction_id'];
                    } else {
                        return false;
                    }
                    //
                } else {
                    return false;
                }
                //
            }
            //
        } else {
            return false;
        }
    }
}

该类含有微信app支付 h5支付 公众号支付(jsapi) 订单查询

native扫码支付后面会添加

异步主要商户订单号查询 并确定金额是否与数据库中一致以及判断该商户订单号是否处理过(谨记)

个人觉得验签并不重要 有订单查询以及数据库订单验证就行了

过多的就不介绍了 源码有注释

0

评论 (0)

取消
Title - Artist
0:00