微信支付-APP支付

7 篇文章 1 订阅
4 篇文章 0 订阅

1. 登陆商户平台 查看APPID , https://pay.weixin.qq.com

在产品中心->我的产品 中查看当前商户开的支付类型。

 然后在appID授权里边查看APPID。

然后在  产品中心>api安全  中设置API密钥

微信APP支付接口文档    https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1

<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2018/10/20
 * Time: 18:48
 */

namespace app\v1\controller;
use app\common\controller\Checking;
use think\console\Command;
use think\Controller;
use think\Db;

class WechatPay extends Controller
{
    protected $values;
    const APPID='';
    const MCHID='';
    const KEY='tv0ov06vgvavh1ml5enx9dgocetsvbyg';//自己设置的微信商家key

    public function wx_apppay(){
        $data=Db::name('account_recharge_orders')->where(['pay_order_num'=>$_GET['orderId']])->find();
//        $data['pay_order_num']=time();
        $notify_url = "http://api.chachuanqi.cn/v1/pay/wechatNotify"; //回调地址
        $out_trade_no=$data['pay_order_num'];
        $nonce_str=MD5($out_trade_no);//随机字符串
        $userip =$this->get_client_ip();
        $appid = self::APPID;//微信
        $mch_id = self::MCHID;//微信官方的
//        $key = self::KEY;//自己设置的微信商家key
        $setAttr = [
            'body' => '充值',
            'appid' => $appid,
            'out_trade_no' => $data['pay_order_num'],
            'total_fee' => $data['money']*100,
            'notify_url' => $notify_url,
            'mch_id' => $mch_id,
            'spbill_create_ip' => $userip,
            'nonce_str' => $nonce_str,
            'trade_type' => 'APP'
        ];
        $this->values = $setAttr;   //配置赋给values属性
        $sign = $this->MakeSign();  //获取签名
        $this->values['sign'] = $sign;
        $xmlstr = $this->ToXml();   //生成微信请求xml数据格式
        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";    //请求url参数
        $dataxml = self::postXmlCurl( $xmlstr, $url );//传参调用curl请求
        $objectxml = $this->xmlToArray( $dataxml );
        if ( $objectxml['return_code'] == 'FAIL' && $objectxml['result_code'] == 'FAIL' ) {
            Checking::response( -200, '获取签名失败' );
        } else {
            $time = time();
            //如果上一次请求成功,那么我们将返回的数据重新拼装,进行第二次签名
            $resignData = array(
                'appid' => $appid,
                'noncestr' => $setAttr['nonce_str'],
                'package' => 'Sign=WXPay',
                'partnerid' => $mch_id,
                'prepayid' => $objectxml['prepay_id'],
                'timestamp' => "$time"
            );
            $this->values = $resignData;
            $secondSign = $this->MakeSign( $resignData );
            $this->values['sign'] = $secondSign;
//            $this->values['notify_url'] = $notify_url;
            Checking::response( 200, 'ok', $this->values );
        }
    }

    /**
     * 获取客户端ip
     * @return string
     */
    public function get_client_ip() {
        if(getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) {
            $ip = getenv('HTTP_CLIENT_IP');
        } elseif(getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) {
            $ip = getenv('HTTP_X_FORWARDED_FOR');
        } elseif(getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) {
            $ip = getenv('REMOTE_ADDR');
        } elseif(isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
            $ip = $_SERVER['REMOTE_ADDR'];
        }
        return preg_match ( '/[\d\.]{7,15}/', $ip, $matches ) ? $matches [0] : '';
    }
    /**
     * 订单查询
     *
     */
    public function orderQuery( $out_trade_no = '' )
    {
        $config = [
            'out_trade_no' => $out_trade_no,
            'appid' => self::APPID,
            'mch_id' => self::MCHID,
            'nonce_str' => self::getNonceStr()
        ];
        $this->values = $config;
        $sign = $this->MakeSign();      //生成sign签名
        $this->values['sign'] = $sign;
        $xmlstr = $this->ToXml();   //生成微信请求xml数据格式
        $url = "https://api.mch.weixin.qq.com/pay/orderquery";  //查询订单url
        $dataxml = self::postXmlCurl( $xmlstr, $url, false );//传参调用curl请求
        $objectxml = $this->xmlToArray( $dataxml );
        if ( $objectxml['return_code'] == 'SUCCESS' && $objectxml['result_code'] == 'SUCCESS' && $objectxml['trade_state'] == 'SUCCESS' ) {
            return true;
        } else {
            return false;
        }
    }
    /**
     *  作用:将xml转为array
     */
    public function xmlToArray( $xml )
    {
        //将XML转为array
        $array_data = json_decode( json_encode( simplexml_load_string( $xml, 'SimpleXMLElement', LIBXML_NOCDATA ) ), true );
        return $array_data;
    }
    /**
     * 以post方式提交xml到对应的接口url
     *
     * @param string $xml 需要post的xml数据
     * @param string $url url
     * @param bool $useCert 是否需要证书,默认不需要
     * @param int $second url执行超时时间,默认30s
     * @throws WxPayException
     */
    private static function postXmlCurl( $xml, $url, $useCert = false, $second = 30 )
    {
        $ch = curl_init();
        //设置超时
        curl_setopt( $ch, CURLOPT_TIMEOUT, $second );

        curl_setopt( $ch, CURLOPT_URL, $url );
        curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, TRUE );
        curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 2 );//严格校验
        //设置header
        curl_setopt( $ch, CURLOPT_HEADER, FALSE );
        //要求结果为字符串且输出到屏幕上
        curl_setopt( $ch, CURLOPT_RETURNTRANSFER, TRUE );

        if ( $useCert == true ) {
            //设置证书
            //使用证书:cert 与 key 分别属于两个.pem文件
            curl_setopt( $ch, CURLOPT_SSLCERTTYPE, 'PEM' );
            curl_setopt( $ch, CURLOPT_SSLCERT, self::SSLCERT_PATH );
            curl_setopt( $ch, CURLOPT_SSLKEYTYPE, 'PEM' );
            curl_setopt( $ch, CURLOPT_SSLKEY, self::SSLKEY_PATH );
        }
        //post提交方式
        curl_setopt( $ch, CURLOPT_POST, TRUE );
        curl_setopt( $ch, CURLOPT_POSTFIELDS, $xml );
        //运行curl
        $data = curl_exec( $ch );
        //返回结果
        if ( $data ) {
            curl_close( $ch );
            return $data;
        } else {
            $error = curl_errno( $ch );
            curl_close( $ch );
            throw new \Exception( "curl出错,错误码:$error" );
        }
    }
    /**
     * 输出xml字符
     **/
    public function ToXml()
    {
        if ( !is_array( $this->values )
            || count( $this->values ) <= 0 ) {
            throw new Exception( '数组异常', 1 );
        }

        $xml = "<xml>";
        foreach ( $this->values as $key => $val ) {
            if ( is_numeric( $val ) ) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            } else {
                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
            }
        }
        $xml .= "</xml>";
        return $xml;
    }
    /**
     *
     * 产生随机字符串,不长于32位
     * @param int $length
     * @return 产生的随机字符串
     */
    public static function getNonceStr( $length = 32 )
    {
        $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
        $str = "";
        for ( $i = 0; $i < $length; $i++ ) {
            $str .= substr( $chars, mt_rand( 0, strlen( $chars ) - 1 ), 1 );
        }
        return $str;
    }
    /**
     * 生成签名
     * @return 签名,本函数不覆盖sign成员变量,如要设置签名需要调用SetSign方法赋值
     */
    protected function MakeSign(){
        //签名步骤一:按字典序排序参数
        ksort( $this->values );
        $string = $this->ToUrlParams( ksort( $this->values ) );
        //签名步骤二:在string后加入KEY
        $string = $string . "&key=" . self::KEY;
        //签名步骤三:MD5加密
        $string = md5( $string );
        //签名步骤四:所有字符转为大写
        $result = strtoupper( $string );
        return $result;
    }

    /**
     * 格式化参数格式化成url参数
     */
    public function ToUrlParams()
    {
        $buff = "";
        foreach ( $this->values as $k => $v ) {
            if ( $k != "sign" && $v != "" && !is_array( $v ) ) {
                $buff .= $k . "=" . $v . "&";
            }
        }

        $buff = trim( $buff, "&" );
        return $buff;
    }
}

客户确认商品点击支付—>后台提供前端调用的加签接口---->前端拿到后台加签的参数调起支付-->微信支付--->微信回调后台提供的回调接口   

这样微信支付就完成了,总体看起来,后台只需要做两件事

      1.给前端提供接口把订单进行加签在返还给前端

      2.给微信提供回调接口确认支付信息。

 

到此支付验签成功,然后结束回调数据

/**
     * 微信回调
     */
    public function wechatNotify()
    {

        Checking::writeLog('回调开始','回调','wx_cz.txt');
        $xml = file_get_contents('php://input');
        $arr = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        //用户http_build_query()将数据转成URL键值对形式
        $sign = http_build_query($arr);
        //md5处理
        $sign = md5($sign);
        //转大写
        $sign = strtoupper($sign);
        Checking::writeLog(json_encode($arr),'回调开始','wx_cz.txt');
        //验签名。默认支持MD5
        Checking::writeLog('开始验签','开始验签','wx_cz.txt');
//        if ( $sign === $arr['sign']) {
            //校验返回的订单金额是否与商户侧的订单金额一致。修改订单表中的支付状态。
            //逻辑
            Checking::writeLog('开始验签','验签成功'.$arr['return_code'],'wx_cz.txt');
//          $arr=json_decode();
            if ( $arr['return_code'] == 'SUCCESS' ) {
                $orderCode = htmlspecialchars( $arr['out_trade_no'] );
                $money = htmlspecialchars( $arr['total_fee'] );   //微信回调过来的支付金额
                $where = [
                    'pay_order_num' => $orderCode,
                    'status' => '1'
                ];
                Checking::writeLog($orderCode.'>>'.'','查询订单','wx_cz.txt');
                $info = Db::name('account_recharge_orders')->where( $where )->find();
                if (!empty($info)){
                    Db::startTrans();
                    try{
                        #处理逻辑
                        
                        
                        $return = ['return_code'=>'SUCCESS','return_msg'=>'OK'];
                        $xml = '<xml>';
                        foreach($return as $k=>$v){
                            $xml.='<'.$k.'><![CDATA['.$v.']]></'.$k.'>';
                        }
                        $xml.='</xml>';
                        echo $xml;
                    }catch (Exception $exception){
                        Db::rollback();
                        Checking::writeLog($exception->getMessage(),'程序出错','wx_cz.txt');
                        echo $exception->getMessage();
                    }
                }
            } else {
                echo 'fail';
            }
//        }


    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梦夏夜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值