php 微信公众号支付(小程序也是这么支付的)

网上查看了很多微信支付程序,大多数是调用很多类,十分繁杂,出错概率很高。于是自己写的尽量简单一些,代码如下:

//$appid和$appsecret 两个是在微信公众号设置的账号密码,记得appsecret要 保存好哦!$mch_id是微信商户id,要和微信开发公众平台绑定的商户id一致(我因为不这个不一致,当时没注意查看了两天代码)

protected $appid = 'wx29c65112380c560';
protected $AppSecret = 'f7241b0b8dc21j2sxe4215bc78c24d1';
protected $mch_id = '150335221';

 /**

*微信下单

*@param total_price 下单金额 单位为/元 

    *@return 这一步返回prepay_id

    *@param $id为新订单的id

*/

function wxpay($total_price='',$id=''){

// header("Content-type:text/xml;charset=utf-8");

if(empty($total_price)){

//加个测试金额

$total_price = 110;

}

$total_price = 0.01;

$openid = $_SESSION['openid'];

if(empty($openid)){

//加个测试的openid

$openid = 'opFig0knA1xDiGFGlZ9hpxq1aIXE';

}

//拼接商品订单号

$body = '测试商品';

$out_trade_no = date("YmdHis") . rand(100, 999);

//更新支付宝订单号到数据表

$this->ORDER->updateById(array('out_trade_no'=>$out_trade_no),

$id);

        $noncestr = $this->rand2(10);

  $order = [

            'appid'=>$this->appid,

            'mch_id'=>$this->mch_id,

            'openid'=>$openid,

            'nonce_str'=>$noncestr,

            'body'=>'测试商品',

            'out_trade_no'=>$out_trade_no,//商户唯一订单号,可包含字母序

            'total_fee'=>(string)$total_price*100,//订单金额,单位/分所以乘以100

            'spbill_create_ip'=>$_SERVER['REMOTE_ADDR'],

            //产生订单号的服务器IP

            'notify_url' => \App_Const::Domain_INDEX . 'notice',//接受微信异步通知地址

            'trade_type'=>'JSAPI',//交易类型

        ];

        //MD5处理,默认支持MD5

        $order['sign'] = $this->getSign($order);

        //转换成一维XML格式

        $xml = '<xml>';

        foreach($order as $k=>$v){

            $xml.='<'.$k.'><![CDATA['.$v.']]></'.$k.'>';

        }

        $xml.='</xml>';

//这个key是商户平台加密的字符串,在商户平台一定要复制出来保存好,不要写成appsecret,容易混淆

        $KEY = '96e79218965eb72c92a549dd5ax112';//加密的字符串

        //CURL会话

        $ch = curl_init();

        // 设置curl允许执行的最长秒数

        curl_setopt($ch, CURLOPT_TIMEOUT, 3);

        curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);

        curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false);

        // 获取的信息以文件流的形式返回,而不是直接输出。

        curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);

        //发送一个常规的POST请求。

        curl_setopt($ch, CURLOPT_POST, 1);

        curl_setopt($ch, CURLOPT_URL, 'https://api.mch.weixin.qq.com/pay/unifiedorder');

        //要传送的所有数据

        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);

        // 执行操作

        $response = curl_exec($ch);

        //将xml格式的$response 转成数组

        $response = json_decode( json_encode( simplexml_load_string($response, 'SimpleXMLElement', LIBXML_NOCDATA) ), true );

        // if($response['return_code'] == "SUCCESS" && $response['result_code'] == "SUCCESS"){

            //根据微信支付返回的结果进行二次签名

            //二次签名所需的随机字符串

            $order["nonceStr"] = $noncestr;//随机字符串

            //二次签名所需的时间戳

            $order['timeStamp'] = time()."";

            //二次签名剩余参数的补充

            $secondSignArray = array(

                    "appId"=>$order['appid'],

                    "nonceStr"=>$order['nonceStr'],

                    //"package"=>"Sign=WXPay",

                    "package"=>"prepay_id=".$response['prepay_id'],

                    "signType"=>"MD5",

                    "timeStamp"=>$order['timeStamp'],

            );

            $data = $secondSignArray;

            $recharge_num = $order["out_trade_no"];

            $data['paySign'] =  $this->getSign($secondSignArray,$KEY);

            $data['prepay_id'] = $response['prepay_id'];

            $data['out_trade_no'] = $out_trade_no;

            // $output = array('data'=>$data ,'info'=>"success" ,'code'=>"200" ,'order_number'=>$recharge_num);

        $msg['status'] = 'success';

//这个参数的data是前端调起微信支付窗口的数据,之所以写到msg里面,是因为我们公司前端这么要求,平时用单独 把data写出来就可以

        $msg['data'] = array(

        'timeStamp'=>time(),

        'nonceStr'=>$noncestr,

        'package'=>"prepay_id=".$response['prepay_id'],

        'signType'=>'MD5',

        'paySign'=> $data['paySign'],

        );

        echo json_encode($msg);die();

}

以上方法传输一个金额,一个订单id即可,完成上面的方法调用就算完成了,但是里面用到的封装function我需要列一下,代码如下:

//这些直接复制就可以 了,不需要做任何修改

function rand2($length = 16) {

        $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

        $str = "";

        for ($i = 0; $i < $length; $i++) {

            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);

        }

        return $str;

    }

//这个是生成sign的方法,直接复制就可以

     function getSign($params) {

ksort($params); //将参数数组按照参数名ASCII码从小到大排序

foreach ($params as $key => $item) {

  if (!empty($item)) {  //剔除参数值为空的参数

  $newArr[] = $key.'='.$item; // 整合新的参数数组

  }

}

$stringA = implode("&", $newArr);  //使用 & 符号连接参数

$stringSignTemp = $stringA."&key="."96e79218965eb72c92a549d222a330112"; //拼接key

// key是在商户平台API安全里自己设置的

$stringSignTemp = MD5($stringSignTemp); //将字符串进行MD5加密

$sign = strtoupper($stringSignTemp); //将所有字符转换为大写

return $sign;

 }

以上微信下单的方法,记得打印prepay_id,这个值非常关键,如果没有的话,即使调用返回值成功,下单也是没成功的。上面代码复制完了,数据返回给前端,前端调用支付窗口,然后付钱,微信会根据上面的回调地址返回成功或者失败。按照时间戳生成的那个订单号,也会在结果里返回,可以搞个 唯一的订单号作为标识,用来更新订单id。回调方法如下:

    /**

    *支付异步通知

    */

    function notice(){

        //获取微信的数据流

        $testxml = file_get_contents("php://input");

        $jsonxml = json_encode(simplexml_load_string($testxml,'SimpleXMLElement', LIBXML_NOCDATA));

        $result = json_decode($jsonxml,true);//转换成数组

        if($result){

            //如果成功了

            $out_tarde_no = $result['out_tarde_no'];

           if($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS'){

                //支付状态 订单发货状态status  都修改掉

                 $this->ORDER->update(array('pay_status'=>2,'status'=>2),array('out_trade_no'=>$result['out_trade_no']));

            }else{

                $this->ORDER->update(array('pay_status'=>3),array('out_trade_no'=>$result['out_trade_no']));

            }

        }else{

          //加一条测试,如果调用接口但是没有成功

           $this->ORDER->update(array('pay_status'=>22),array('id'=>10));

        }

    }

注意回调结果是返回数据流,处理数据流然后根据out_trade_no字段来更新状态的,写到这里,整个微信支付代码就算结束了,谢谢大家观看!

猜你喜欢

转载自www.cnblogs.com/ayanboke/p/9335383.html
今日推荐