• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

php 微信支付V3 APP支付

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

 

前言:微信支付现在分为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);
        }

    }

  


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
PHP.8-HTML+CSS(二)-HTML详解发布时间:2022-07-10
下一篇:
PHP memcache扩展模块安装发布时间:2022-07-10
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap