php 微信支付V3 APP支付

 

前言:微信支付现在分为v2版和v3版,2014年9月10号之前申请的为v2版,之后申请的为v3版。V3版的微信支付没有paySignKey参数.

php 微信支付类

<?php

class Wechat {

    protected $wechat_config;

    //https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1
    public function __construct($wechat_config = [])
    {
        if(empty($wechat_config)){
            $wechat_config = [
                'appid'=>'',
                'mch_id'=>'',
                'api_key'=>'',
                'appsecret'=>'',
                'notify_url'=>'',
            ];
        }
        $this->wechat_config = $wechat_config;

    }


    //生成预支付订单
    public function wx_pay($body,$total_fee,$out_trade_no,$attach = 'charge_order') {
        $nonce_str = $this->rand_code();        //调用随机字符串生成方法获取随机字符串
        $data['appid'] = $this->wechat_config['appid'];   //appid
        $data['mch_id'] = $this->wechat_config['mch_id'] ;        //商户号
        $data['body'] = $body;
        $data['spbill_create_ip'] = $this->get_client_ip();   //ip地址
        $data['total_fee'] = $total_fee;                         //金额
        $data['out_trade_no'] = $out_trade_no;    //商户订单号,不能重复
        $data['nonce_str'] = $nonce_str;                   //随机字符串
        $data['notify_url'] = $this->wechat_config['notify_url'];   //回调地址,用户接收支付后的通知,必须为能直接访问的网址,不能跟参数
        $data['trade_type'] = 'APP';      //支付方式
        $data['attach'] = $attach;      //商户携带订单的自定义数据
        //将参与签名的数据保存到数组  注意:以上几个参数是追加到$data中的,$data中应该同时包含开发文档中要求必填的剔除sign以外的所有数据

        $data['sign'] = self::getSign($data,$this->wechat_config['api_key']);        //获取签名

        $xml = self::ToXml($data);            //数组转xml
        //curl 传递给微信方
        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        //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);//严格校验
        }
        //设置header
        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);
        //运行curl
        $data = curl_exec($ch);
        //返回结果
        if($data){

            curl_close($ch);
            //返回成功,将xml数据转换为数组.
            $re = self::FromXml($data);

            if($re['return_code'] != 'SUCCESS'){
                return [
                    'code'=>'201',
                    'msg'=>$re['return_msg']
                ];
            }
            else{
                //接收微信返回的数据,传给APP!
                $arr =array(
                    'prepayid' =>$re['prepay_id'],
                    'appid' => $this->wechat_config['appid'],
                    'partnerid' => $this->wechat_config['mch_id'],
                    'package' => 'Sign=WXPay',
                    'noncestr' => $nonce_str,
                    'timestamp' =>strval(time()),
                );
                //第二次生成签名
                $sign = self::getSign($arr,$this->wechat_config['api_key']);
                $arr['sign'] = $sign;
                $arr['code'] = '200';
                $arr['msg'] = '签名成功';
                return $arr;
            }
        } else {
            $error = curl_errno($ch);
            curl_close($ch);
            return [
                'code'=>'201',
                'msg'=>"curl出错,错误码:$error"
            ];

        }
    }




    //参数要组装成xml格式
    public static function ToXml($data = array()){
        if (!is_array($data) || count($data) <= 0) {
            return '数组异常';
        }

        $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;
    }



    public static function FromXml($xml)
    {
        if(!$xml){
            echo "xml数据异常!";
        }
        //将XML转为array
        //禁止引用外部xml实体
        libxml_disable_entity_loader(true);
        $data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $data;
    }

    //生成随机字符串
    private function rand_code(){
        $str = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';//62个字符
        $str = str_shuffle($str);
        $str = substr($str,0,32);
        return  $str;
    }

    /*
    获取当前服务器的IP
    */
    private function get_client_ip(){
        if ($_SERVER['REMOTE_ADDR']) {
            $cip = $_SERVER['REMOTE_ADDR'];
        } elseif (getenv("REMOTE_ADDR")) {
            $cip = getenv("REMOTE_ADDR");
        } elseif (getenv("HTTP_CLIENT_IP")) {
            $cip = getenv("HTTP_CLIENT_IP");
        } else {
            $cip = "unknown";
        }
        return $cip;
    }

    //生成签名
    public static function getSign($params,$api_key) {
        ksort($params);        //将参数数组按照参数名ASCII码从小到大排序
        foreach ($params as $key => $item) {
            if (!empty($item)) {         //剔除参数值为空的参数
                $newArr[] = $key.'='.$item;     // 整合新的参数数组
            }
        }

        $stringA = implode("&", $newArr);         //使用 & 符号连接参数
        $stringSignTemp = $stringA."&key=".$api_key;        //拼接key
        // key是在商户平台API安全里自己设置的
        $stringSignTemp = MD5($stringSignTemp);       //将字符串进行MD5加密
        $sign = strtoupper($stringSignTemp);      //将所有字符转换为大写
        return $sign;
    }

}

调起微信支付

        //生成微信支付预订单信息
        $wechat_config = [
            'appid'=>$this->config->openWeixin->appid,
            'mch_id'=>$this->config->openWeixin->mch_id,
            'api_key'=>$this->config->openWeixin->api_key,
            'appsecret'=>$this->config->openWeixin->appsecret,
            'notify_url'=>$this->config->openWeixin->notify_url,
        ];
        $order_no = date('YmdHis').rand(1000,9999);
        $money = 1;
        $wechat = new Wechat($wechat_config);
        $wechat_data = $wechat->wx_pay('test',$money,$order_no,'aid_order');

        if($wechat_data['code'] != 200){
        echo $wechat_data['msg'];die;
        } 
        $result = [ 'order_no'=>$order_no , 'money'=>$money, 'wechat_data'=>$wechat_data, ]; 
        print_r($result);die;

微信支付回调

 // 微信支付回调
    public function wx_notifyAction(){
        defined('BASE_PATH') || define('BASE_PATH', getenv('BASE_PATH') ?: realpath(dirname(__FILE__) . '/../..'));
        //接收微信返回的数据数据,返回的xml格式
        $xmlData = file_get_contents('php://input');
        //将xml格式转换为数组
        $data = Wechat::FromXml($xmlData);
        //用日志记录检查数据是否接受成功,验证成功一次之后,可删除。
        $file_name = BASE_PATH.'/log'.date('Ymd').'.txt';
        //$file = fopen($file_name, 'a+') or die("Unable to open file!");;
        //fwrite($file,'test:'.json_encode($data));die;
        //为了防止假数据,验证签名是否和返回的一样。
        //记录一下,返回回来的签名,生成签名的时候,必须剔除sign字段。
        $sign = $data['sign'];
        unset($data['sign']);
        if($sign == Wechat::getSign($data,$this->config->openWeixin->api_key)){
            //签名验证成功后,判断返回微信返回的
            if ($data['result_code'] == 'SUCCESS') {
                //根据返回的订单号做业务逻辑
                $res = false;
                if($data['attach'] == 'aid_order'){
                    $model = new PetAidOrder();
                    //宠物援助
                    $PetAidOrderData = $model::findFirst([
                        'order_no = :out_trade_no: AND pay_type = 2 AND status = 2',
                        'bind'=>[
                            'out_trade_no'=>$data['out_trade_no'],
                        ]
                    ]);
                    $getPetAidData = PetAid::findFirst([
                        'id = :pet_aid_id:',
                        'bind'=>[
                            'pet_aid_id'=>$PetAidOrderData->pet_aid_id
                        ]
                    ]);
                    if($PetAidOrderData && $getPetAidData){
                        /*===================事务开启================================*/
                        $connection = $model->getWriteConnection();
                        $connection->begin();
                        //更新订单数据
                        $PetAidOrderData->status = 1;
                        $PetAidOrderData->pay_time = time();
                        //更新项目数据
                        $getPetAidData->get_money += $PetAidOrderData->money;
                        if($PetAidOrderData->update() && $a = $getPetAidData->update()){$connection->commit();
                            $res = true;
                        }

                    }

                }elseif($data['attach'] == 'rescue_order'){
                    $model = new UserRescueOrder();
                    //爱心捐献
                    $UserRescueOrderData = $model::findFirst([
                        'order_no = :out_trade_no: AND pay_type = 2 AND status = 2',
                        'bind'=>[
                            'out_trade_no'=>$data['out_trade_no'],
                        ]
                    ]);

                    $getUserRescueAuthData = UserRescueAuth::findFirst([
                        'id = :user_resuce_auth_id:',
                        'bind'=>[
                            'user_resuce_auth_id'=>$UserRescueOrderData->user_resuce_auth_id
                        ]
                    ]);

                    if($UserRescueOrderData && $getUserRescueAuthData){
                        /*===================事务开启================================*/
                        $connection = $model->getWriteConnection();
                        $connection->begin();
                        //更新订单数据
                        $UserRescueOrderData->status = 1;
                        $UserRescueOrderData->pay_time = time();
                        //更新救助中心数据
                        $getUserRescueAuthData->donation_money += $UserRescueOrderData->money;

                        if($UserRescueOrderData->update() && $getUserRescueAuthData->update()){
                            $connection->commit();
                            $res = true;
                        }
                    }

                }

                //处理完成之后,告诉微信成功结果!
                if($res == true){
                    echo '<xml>
                      <return_code><![CDATA[SUCCESS]]></return_code>
                      <return_msg><![CDATA[OK]]></return_msg>
                      </xml>';
                    exit();
                }else{
                    $file = fopen($file_name, 'a+');
                    fwrite($file,date("Y-m-d H:i:s")."错误信息:数据修改失败,".json_encode($data).PHP_EOL);
                }
            }
            //支付失败,输出错误信息
            else{
                $file = fopen($file_name, 'a+');
                fwrite($file,date("Y-m-d H:i:s")."错误信息:支付失败,".json_encode($data).PHP_EOL);
            }
        }
        else{
            $file = fopen($file_name, 'a+');
            fwrite($file,date("Y-m-d H:i:s")."错误信息:签名验证失败,".json_encode($data).PHP_EOL);
        }

    }

  

转载于:https://www.cnblogs.com/-mrl/p/8392735.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值