PHP之 微信APP支付类

<?php  defined('BASEPATH') OR exit('No direct script access allowed');


/**
 * 微信支付 - APP - 类
 * @author NangongYi
 * @time 2020-03-03
 */
class Wechat_payment_service extends FIT_Service
{
    /**
     * 构造函数,初始化成员变量
     * @param string $appid  商户的应用ID
     * @param int $mch_id 商户编号
     * @param string $key 秘钥
     * @param string $notify_url 回调地址
     */
    public function __construct($appid, $mch_id, $key, $notify_url)
    {
        if (is_string($appid) && is_string($mch_id)) {
            $this->appid = $appid;
            $this->mch_id = $mch_id;
            $this->key = $key;
            $this->notify_url = $notify_url;
        }
    }

    /**
     * 微信支付统一下单,生成预支付交易单
     * @param string $body
     * @param string $out_trade_no
     * @param float $total_fee
     * @param string $ip
     * @return mixed
     */
    public function weChat_pay($body, $out_trade_no, $total_fee, $ip)
    {
        $request_data = array(
            'appid' => $this->appid,               //应用APPID
            'mch_id' => $this->mch_id,             //商户号
            'trade_type' => 'APP',                 //支付类型
            'nonce_str' => $this->get_nonce_str(), //随机字符串 不长于32位
            'body' => $body,                       //商品名称
            'out_trade_no' => $out_trade_no,       //商户后台订单号
            'total_fee' => $total_fee * 100,       //商品价格
            'spbill_create_ip' => $ip,             //用户端实际ip
            'notify_url' => $this->notify_url,     //异步通知回调地址
        );
        // 获取签名
        $request_data['sign'] = $this->get_sign($request_data);
        // 发送请求
        $res = $this->send_prePay_curl($this->produce_xml_data($request_data));
        if($res['return_code'] == 'SUCCESS' && $res['result_code'] == 'SUCCESS'){
            $Secondary['appid'] = $this->appid;
            $Secondary['partnerid'] = $this->mch_id; //商户号
            $Secondary['prepayid'] = $res['prepay_id'];  //预支付交易会话标识
            $Secondary['noncestr'] = $res['nonce_str']; //$this->get_nonce_str();
            $Secondary['timestamp'] = time();
            $Secondary['package'] = "Sign=WXPay";
            $Secondary['sign'] = $this->get_second_sign($Secondary);
            return ['error_code'=>200,'error_msg'=>'支付成功!', 'data'=>$Secondary];
        }else{
            return ['error_code'=>201,'error_msg'=>$res['return_msg']];
        }
    }

    /**
     * 微信回调
     * @return mixed
     */
    public function wx_notify()
    {
        //允许从外部加载XML实体(防止XML注入攻击)
        libxml_disable_entity_loader(true);
        $postStr = $this->post_data();//接收post数据
        $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
        $arr = $this->object_to_array($postObj);//对象转成数组
        ksort($arr);// 对数据进行排序
        $str = $this->params_to_url($arr);//对数据拼接成字符串
        $user_sign = strtoupper(md5($str));
        if($user_sign == $arr['sign']){//验证签名
            return '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA['.json_encode($arr).']]></return_msg></xml>';
        }else{
            return '<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA['.json_encode($arr).']]></return_msg></xml>';
        }
    }

    /**
     * 调取支付接口,查询支付状态
     * @param string $out_trade_no
     * @param int $user_coins
     * @return mixed
     */
    public function order_query($out_trade_no, $user_coins)
    {
        $request_data = array(
            'appid' => $this->appid,               //应用APPID
            'mch_id' => $this->mch_id,             //商户号
            'nonce_str' => $this->get_nonce_str(), //随机字符串 不长于32位
            'out_trade_no' => $out_trade_no,       //商户后台订单号
        );
        // 获取签名
        $request_data['sign'] = $this->get_sign($request_data);
        // 发送请求
        $res = $this->send_oQuery_curl($this->produce_xml_data($request_data));
        if($res['return_code'] == 'SUCCESS' && $res['result_code'] == 'SUCCESS'){
            $data = $user_coins ? ['user_coins'=>$user_coins] : [];
            return ['error_code'=>200,'error_msg'=>'支付成功!', 'data'=>$data];
        }else{
            return ['error_code'=>201,'error_msg'=>$res['err_code_des']];
        }
    }

    /**
     * 通过curl发送数据给微信接口 - 下单支付并返回调起数据
     * @param array $xmlData
     * @return mixed
     */
    private function send_prePay_curl($xmlData)
    {
        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        return $this->send_data_curl($url, $xmlData);
    }

    /**
     * 通过curl发送数据给微信接口 - 查询订单支付状态
     * @param array $xmlData
     * @return mixed
     */
    private function send_oQuery_curl($xmlData)
    {
        $url = "https://api.mch.weixin.qq.com/pay/orderquery";
        return $this->send_data_curl($url, $xmlData);
    }

    /**
     * 通过curl发送数据给微信接口的函数
     * @param string $url
     * @param array $xmlData
     * @return mixed
     */
    private function send_data_curl($url, $xmlData)
    {
        $header[] = "Content-type: text/xml";
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_POST, 1);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $xmlData);
        $data = curl_exec($curl);
        if (curl_errno($curl)) {
            print curl_error($curl);
        }
        curl_close($curl);
        return $this->xml_to_array($data);
    }

    /**
     * 生成随机数并返回
     * @return string 32位字符
     */
    private function get_nonce_str()
    {
        $code = "";
        for ($i=0; $i > 10; $i++) {
            $code .= mt_rand(1000); //获取随机数
        }
        $nonceStrTemp = md5($code);
        $nonce_str = mb_substr($nonceStrTemp, 5,37); //MD5加密后截取32位字符
        return $nonce_str;
    }


    /**
     * 将xml转为array
     *
     * @param $xml
     * @return mixed
     */
    private function xml_to_array($xml)
    {
        //将XML转为array
        return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), TRUE);
    }

    /**
     * 生成xml格式的数据
     * @param array $data
     * @return mixed
     */
    private function produce_xml_data($data)
    {
        $xmlData = "<xml>";
        foreach ($data as $key => $value) {
            $xmlData.="<".$key."><![CDATA[".$value."]]></".$key.">";
        }
        $xmlData = $xmlData."</xml>";
        return $xmlData;
    }

    /**
     * 一次签名的函数
     * @param array $data
     * @return mixed
     */
    private function get_sign($data)
    {
        ksort($data);
        $str = '';
        foreach ($data as $key => $value) {
            $str .= !$str ? $key . '=' . $value : '&' . $key . '=' . $value;
        }
        $str.='&key='.$this->key;
        $sign = strtoupper(md5($str));
        return $sign;
    }

    /**
     * 二次签名的函数
     * @param array $data
     * @return mixed
     */
    private function get_second_sign($data)
    {
        $sign_data = array(
            "appid"=>$data['appid'],
            "partnerid"=>$data['partnerid'],
            "prepayid"=>$data['prepayid'],
            "noncestr"=>$data['noncestr'],
            "timestamp"=>$data['timestamp'],
            "package"=>$data['package'],
        );
        return $this->get_sign($sign_data);
    }

    /**
     * 接收post数据
     * @return array
     */
    private function post_data()
    {
        $receipt = file_get_contents("php://input");
        if($receipt == null){
            $receipt = $GLOBALS['HTTP_RAW_POST_DATA'];
        }
        return $receipt;
    }

    /**
     * 把对象转成数组
     * @param array $arr
     * @return array
     */
    private function object_to_array($arr)
    {
        if(is_object($arr)) {
            $arr = (array)$arr;
        } if(is_array($arr)) {
        foreach($arr as $key=>$value) {
            $arr[$key] = $this->object_to_array($value);
        }
    }
        return $arr;
    }

    /**
     * 格式化参数格式化成url参数
     * @param array $arr
     * @return string
     */
    private function params_to_url($arr)
    {
        $weChat_pay_key = $this->key; 
        $buff = "";
        foreach ($arr as $k => $v)
        {
            if($k != "sign" && $v != "" && !is_array($v)){
                $buff .= $k . "=" . $v . "&";
            }
        }
        $buff = trim($buff, "&");
        return $buff.'&key='.$weChat_pay_key;
    }
}
发布了74 篇原创文章 · 获赞 2 · 访问量 7380

猜你喜欢

转载自blog.csdn.net/LDR1109/article/details/105492650