微信支付demo

这里开发时使用的是thinkphp5.1

1.直接唤起微信支付

<?php
namespace appindexcontroller;

use wechatpaylibWxPayApi;
use wechatpaylibWxPayUnifiedOrder;
use wechatpayexampleJsApiPay;
use wechatpayexampleWxPayConfig;
use thinkfacadeEnv;

class Pay
{
    /*
    1、交易金额
    交易金额默认为人民币交易,接口中参数支付金额单位为【分】,参数值不能带小数。对账单中的交易金额单位为【元】。

    外币交易的支付金额精确到币种的最小单位,参数值不能带小数点。

    2、交易类型
    JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付,统一下单接口trade_type的传参可参考这里

    MICROPAY--刷卡支付,刷卡支付有单独的支付接口,不调用统一下单接口

    3、货币类型
    货币类型的取值列表:

    CNY:人民币

    4、时间
    标准北京时间,时区为东八区;如果商户的系统时间为非标准北京时间。参数值必须根据商户系统所在时区先换算成标准北京时间, 例如商户所在地为0时区的伦敦,当地时间为2014年11月11日0时0分0秒,换算成北京时间为2014年11月11日8时0分0秒。

    5、时间戳
    标准北京时间,时区为东八区,自1970年1月1日 0点0分0秒以来的秒数。注意:部分系统取到的值为毫秒级,需要转换成秒(10位数字)。

    6、商户订单号
    商户支付的订单号由商户自定义生成,仅支持使用字母、数字、中划线-、下划线_、竖线|、星号*这些英文半角字符的组合,请勿使用汉字或全角等特殊字符。微信支付要求商户订单号保持唯一性(建议根据当前系统时间加随机序列来生成订单号)。重新发起一笔支付要使用原订单号,避免重复支付;已支付过或已调用关单、撤销(请见后文的API列表)的订单号不能重新发起支付。
    */


    /**
     * 微信支付调用
     * @author ffx
     * @param int $userId 用户id
     * @param float $money 金额
     * @param int $type 支付类型(1充值,2订单支付)
     * @param string $body 显示title,提示头信息
     * @param string $backUrl 回调地址(/index/pay/wxPayBack)
     * @param string $addition 附加参数(微信回调时原样返回)
     * @return bool|mixed
     */
    public function wxPay($userId,$money,$type,$body,$backUrl,$addition = '')
    {
        $out_trade_no = self::getOrderNo();
        $wxchid = config('wechat.wxmchid');
        $wxAppId = config('wechat.paywxAppId');

        //微信支付sdk中的文件
        include_once EXTEND_PATH."wechatpay/lib/WxPay.Api.php";
        include_once EXTEND_PATH."wechatpay/example/WxPay.JsApiPay.php";

        $total_money = floor(sprintf("%0.3f",$money)*100);
        if(!$total_money || $total_money <= 0){
            return ['code'=>100001,'message'=>"支付金额小于0"];
        }
        if($_SERVER["REQUEST_SCHEME"] == "http"){
            $notify_url  = 'http://'.$_SERVER['HTTP_HOST'].$backUrl;
        }else{
            $notify_url  = 'https://'.$_SERVER['HTTP_HOST'].$backUrl;
        }

        //此处查询的是登录时存起来的openid
        $openid = Db::name('member')->where('id',$userId)->value('openid');
        $input = new WxPayUnifiedOrder();

        $input->SetAppid($wxAppId);
        $input->SetMch_id($wxchid); //商户号
        $input->SetAttach($addition); //附加参数
        $nonceStr = self::createNonceStr();
        $input->SetNonce_str($nonceStr);//自定义随机字符串
        $input->SetBody($body);//
        $input->SetOut_trade_no($out_trade_no);//订单号,自己建
        $input->SetTotal_fee($total_money);//金钱
        $input->SetSpbill_create_ip($this->getIP());//客户端ip
        $input->SetTime_start(date("YmdHis"));
        $input->SetTime_expire(date("YmdHis", time() + 600));//过期时间
        $input->SetNotify_url($notify_url);//回调的接口地址
        $input->SetTrade_type("JSAPI");//支付类型
        $input->SetOpenid($openid);

        //此处两个是微信支付的sdk的类
        $WxPayApi = new WxPayApi();
        $config = new WxPayConfig();

        $response = $WxPayApi->unifiedOrder($config,$input);//预创建订单

        //写入支付记录表(业务逻辑处理)
        $res = $this->insertWxPayLog($userId,$out_trade_no,$money,$type,0);
        if(!$res){
            return false;
        }

        if($response['result_code']=='SUCCESS' && $response['return_code']=='SUCCESS' && $response['return_msg']=='OK') {
            $tools = new JsApiPay();
            $response['nonce_str'] = $nonceStr;
            $jsApiParameters = $tools->GetJsApiParameters($response);
            return json_decode($jsApiParameters);

            //$jsApiParameters示例
            //{"appId":"wx194a1075c8bca3d9","nonceStr":"4tmc7nttscu5w6u6cqbxlgvum4qs6p8y","package":"prepay_id=wx05155440194924091e0efc912670185750","signType":"MD5","timeStamp":"1541404480","paySign":"CD4DE57A6B5B2B5418B5F07536C4DF10"}

            //输出直接唤起支付
//            $str = "<html><body></body></html>";
//
//            $str .='<html><head><meta http-equiv="content-type" content="text/html;charset=utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><title>微信支付</title></head><body>';
//
//            $str .= "<script>function onBridgeReady(){WeixinJSBridge.invoke('getBrandWCPayRequest',$jsApiParameters)}if(typeof WeixinJSBridge=='undefined'){if(document.addEventListener){document.addEventListener('WeixinJSBridgeReady',onBridgeReady,false)}else if(document.attachEvent){document.attachEvent('WeixinJSBridgeReady',onBridgeReady);document.attachEvent('onWeixinJSBridgeReady',onBridgeReady)}}else{onBridgeReady()}</script></body></html>";
//
//            echo $str;exit;

        }else{
            return false;
        }

    }

    /**
     * 余额支付回调
     * @author ffx
     *
     */
    function amountPayBack()
    {
        $xml = file_get_contents('php://input');
        $xmlJson = json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA));
        $arr = json_decode($xmlJson, true);

        //此处注释暂未用到
        /* //用户http_build_query()将数据转成URL键值对形式
         $sign = http_build_query($arr);
         //md5处理
         $sign = md5($sign);
         //转大写
         $sign = strtoupper($sign);
         //验签名。默认支持MD5
         if($sign === $arr['sign']) {
             // 校验返回的订单金额是否与商户侧的订单金额一致。修改订单表中的支付状态。
         }
         $return = ['return_code'=>'SUCCESS','return_msg'=>'OK'];
         $xml = '<xml>';
         foreach($return as $k=>$v){
             $xml.='<'.$k.'><![CDATA['.$v.']]></'.$k.'>';
         }
         $xml.='</xml>';*/

        $out_trade_no=$arr['out_trade_no']; //订单号

        //判断金额
        $total_fee=$arr['total_fee']/100*10000; //回调回来的xml文件中金额是以分为单位的
        $money = Db::name('recharge_log')->where('out_trade_no',$out_trade_no)->value('money');
        if($money != $total_fee){
            return;
        }

        $result_code=$arr['result_code']; //状态
        if($result_code=='SUCCESS'){
            //处理数据库操作
            $post = [
                'out_trade_no'=>$out_trade_no,
                'total_fee'=>$arr['total_fee'] //微信实际收到金额(分为单位)
            ];
            //处理业务逻辑
            $res = $this->amountPayBackLogic($xmlJson,$post,1,$money);
            if($res['code'] == 0){
                echo 'SUCCESS'; //返回成功给微信端 一定要带上不然微信会一直回调8次
                exit;
            }
        }else{
            //失败
            return;
        }
    }

    /**
     * 获取随机字符串
     * @author ffx
     * @param int $length 长度
     * @return string
     */
    public static function createNonceStr($length = 16)
    {
        $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        $str = '';
        for ($i = 0; $i < $length; $i++) {
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }

    /**
     * 获取订单号
     * @author ffx
     * @return string
     */
    public static function getOrderNo()
    {
        $outTradeNo = time() . rand(1000, 9999);
        return $outTradeNo;
    }

    /**
     * @purpose 获取请求来源的ip
     * @author ffx
     * @return mixed
     */
    function getIp()
    {
        if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
        } elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
            $ip = $_SERVER['HTTP_CLIENT_IP'];
        } else {
            $ip = $_SERVER['REMOTE_ADDR'];
        }
        $ip_arr = explode(',', $ip);
        return $ip_arr[0];
    }


}

2.生成二维码支付

回调和唤起支付一样

/**
     * 微信支付调用
     * @author ffx
     * @param int $userId 用户id
     * @param float $money 金额
     * @param string $body 显示title,提示头信息
     * @param string $backUrl 回调地址(/v1/pay/wxPayBack)
     * @param string $addition 附加参数(微信回调时原样返回)
     * @return bool
     */
    public function wxPayErWeiMa($userId,$money,$body,$backUrl,$addition = '')
    {
        $out_trade_no = self::getOrderNo();
        $total_money = $money;

        include_once EXTEND_PATH."wxpay/lib/WxPay.Api.php";
        include_once EXTEND_PATH."wxpay/example/WxPay.JsApiPay.php";
        include_once EXTEND_PATH."wxpay/example/WxPay.NativePay.php";

        $total_money = floor(sprintf("%0.3f",$total_money)*100);
        if(!$total_money || $total_money <= 0){
            return ['code'=>100001,'message'=>"支付金额小于0"];
        }
        $notify_url  = 'http://'.$_SERVER['HTTP_HOST'].$backUrl;

        $wxPayConfig = Db::name('user_wxpay_config')
            ->alias('c')
            ->join('member m','m.admin_user=c.admin_user')
            ->where('m.id', $userId)
            ->where('c.status', 1)
            ->field('c.*')
            ->order('update_time','desc')
            ->find();
        if(empty($wxPayConfig)){
            return false;
        }

        if(empty($body)){
            $body = $wxPayConfig['body'];
        }

        $wxchid = $wxPayConfig['mac_id'];
        $wxAppId = $wxPayConfig['appid'];
        $wxAppSecret = $wxPayConfig['app_secret'];
        $wxKey = $wxPayConfig['key'];

        $config = new WxPayConfig();
        $config->SetAppSecret($wxAppSecret);
        $config->SetKey($wxKey);
        $config->SetAppId1($wxAppId);
        $config->SetMerchantId1($wxchid);

        $input = new WxPayUnifiedOrder();
        $input->SetBody($body);
        $input->SetAttach($addition); //附加参数
        $input->SetOut_trade_no($out_trade_no); //订单号,自己建
        $input->SetTotal_fee($total_money);//金钱
        $input->SetTime_start(date("YmdHis"));
        $input->SetTime_expire(date("YmdHis", time() + 600)); //过期时间
        $input->SetGoods_tag("test");
        $input->SetNotify_url($notify_url); //回调的接口地址
        $input->SetTrade_type("NATIVE"); //支付类型(二维码)
        $input->SetProduct_id("123456789");

        //写入支付记录表
        $res = $this->insertRechargeLog($userId,$out_trade_no,$money,0,'wxpay');
        if(!$res){
            return false;
        }
        $notify = new NativePay();
        $result = $notify->GetPayUrl($input);

        if(isset($result["code_url"]) && !empty($result["code_url"])){
            require_once './../extend/wxpay/example/phpqrcode/phpqrcode.php';
            $url = urldecode($result['code_url']);
            if(substr($url, 0, 6) == "weixin"){
                QRcode::png($url);
            }else{
                header('HTTP/1.1 404 Not Found');
            }
        }else{
            return false;
        }
    }
原文地址:https://www.cnblogs.com/yangjiayu/p/11176698.html