php小程序支付代码(微信公众平台,完整版)

1,wxpay.php 微信小程序支付(微信公众平台),微信公众号支付大同小异。希望对大家有所帮助,谢谢!内容如下:<?php
 
//微信小程序支付代码详解
 
//第一步,下单  支付前需要下单,调用了两个方法wxpay和wxapi
/**
*微信下单
*/
function wxorders(){
 
        ini_set("display_errors", "On");
        error_reporting(E_ALL | E_STRICT);
 
$kilometre = $_POST['kilometre'];
$km = $kilometre/1000;//米数转化成公里
//提交订单
$data = array(
'start_address'=>$_POST['startLoca'],//出发地址
'end_address'=>$_POST['destLoca'],//目的地
'start_time'=>strtotime(str_replace('.','-',$_POST['startTime'])),//开始时间
'end_time'=>strtotime(str_replace('.','-',$_POST['endTime'])),//结束时间
'km'=>$km,//公里数
'seat'=>$_POST['seat'],//座位
'borad_price'=>$_POST['basicPrice'],//上车价
'per_km'=>$_POST['perKiloPrice'],//每公里单价
'total_price'=>$_POST['cost'],//总价钱
'contact'=>$_POST['name'],//联系人名
'mobile'=>$_POST['phone'],//联系电话
'status'=>'1',//状态
'create_time'=>time(),//提交时间
'type'=>$_POST['type'],//租车类型  小bus 大巴等
'kelala'=>$_POST['session_key'],//标识符
);
$total_price = $_POST['cost'];//总价赋值
        //插入订单记录,此处状态为待付款
$res = $this->baseModel->add('orders',$data);
        //根据标识符查询当前账号的openid
        $kelala = $_POST['session_key'];//用户的唯一标识
        $user = $this->baseModel->getRow('user','*',array('kelala'=>$kelala));
    //调用下单接口  $res为新订单的id
$r = $this->wxpay($total_price,$user['openid']);
        //分别传总金额,用户openid,前面生成的订单id
        $a = $this->wxapi($total_price,$user['openid'],$r['prepay_id'],$res);
        //这里返回结果集合到前段,前段根据返回的参数调用微信支付界面,并且返回成功失败给后端,需要另外写接口接收
        echo $a;exit();
}
 
/**
*微信下单
*@param total_price 下单金额 单位为/元 
    *@return 这一步返回prepay_id
    *@param $id为新订单的id
*/
function wxpay($total_price,$openid){
//拼接商品订单号
$body = '测试商品';
$out_trade_no = date("YmdHis") . rand(100, 999);
        // //更新微信返回的订单号
        // $this->baseModel->updateById('orders',array('out_trade_no'=>$out_trade_no),$id);
  $order = [
            'appid'=>'',
            'mch_id'=>'',//商户id
            'openid'=>$openid,
            'nonce_str'=>$this->rand2(10),
            'body'=>'测试商品',
            'out_trade_no'=>$out_trade_no,//商户唯一订单号,可包含字母序
            'total_fee'=>$total_price*100,//订单金额,单位/分所以乘以100
            'spbill_create_ip'=>'123.12.12.123',//产生订单号的服务器IP
            'notify_url'=>'https://ww.baidu.com',//接受微信异步通知地址
            'trade_type'=>'JSAPI',//交易类型
        ];
        //MD5处理,默认支持MD5
        // $sign = md5($sign);
        $order['sign'] = $this->getSign($order);
        //转换成一维XML格式
        $xml = '<xml>';
        foreach($order as $k=>$v){
            $xml.='<'.$k.'><![CDATA['.$v.']]></'.$k.'>';
        }
        $xml.='</xml>';
 
        //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 );
        return $response;
}
 
//第二步,再次签名
/**
    *再次签名
    *@param $total_fee 下单金额
    *@param $openid 当前用户openid $order_id 下单时传来的id
    * @param $id为新订单的id
    */
function wxapi($total_fee,$openid,$order_id,$id){
         ini_set("display_errors", "On");
        error_reporting(E_ALL | E_STRICT);
        $out_trade_no = date("YmdHis") . rand(100, 999);
        //更新订单状态 此处状态更新为1
        $this->baseModel->updateById('orders',array('out_trade_no'=>$out_trade_no),$id);
 
        if(empty($total_fee)){
            echo json_encode(array('state'=>0,'Msg'=>'金额有误'));exit;
        }
        if(empty($openid)){
            echo json_encode(array('state'=>0,'Msg'=>'登录失效,请重新登录(openid参数有误)'));exit;
        }
        if(empty($order_id)){
            echo json_encode(array('state'=>0,'Msg'=>'自定义订单有误'));exit;
        }
        $appid =        '';//如果是公众号 就是公众号的appid;小程序就是小程序的appid
        $body =         '测试数据';
        $mch_id =       '';//商户id
        $KEY = '12ed7bd47d66f4ef7865f79b2194a94b';//加密的字符串  在公众号平台设置
        $nonce_str =    $this->rand2(10);//随机字符串
        $notify_url =   'https://www.baidu.com/';  //支付完成回调地址url,不能带参数
        $out_trade_no = $out_trade_no;//商户订单号
        // $spbill_create_ip = '123.12.12.123';
        $spbill_create_ip = $_SERVER['SERVER_ADDR'];
        $trade_type = 'JSAPI';//交易类型 默认JSAPI
    
        //这里是按照顺序的 因为下面的签名是按照(字典序)顺序 排序错误 肯定出错
        $post['appid'] = $appid;
        $post['body'] = $body;
        $post['mch_id'] = $mch_id;
        $post['nonce_str'] = $nonce_str;//随机字符串
        $post['notify_url'] = $notify_url;
        $post['openid'] = $openid;
        $post['out_trade_no'] = $out_trade_no;
        $post['spbill_create_ip'] = $spbill_create_ip;//服务器终端的ip
        $post['total_fee'] = intval($total_fee);        //总金额 最低为一分钱 必须是整数
        $post['trade_type'] = $trade_type;
        $sign = $this->MakeSign($post,$KEY);              //签名
        $this->sign = $sign;
    
        $post_xml = '<xml>
               <appid>'.$appid.'</appid>
               <body>'.$body.'</body>
               <mch_id>'.$mch_id.'</mch_id>
               <nonce_str>'.$nonce_str.'</nonce_str>
               <notify_url>'.$notify_url.'</notify_url>
               <openid>'.$openid.'</openid>
               <out_trade_no>'.$out_trade_no.'</out_trade_no>
               <spbill_create_ip>'.$spbill_create_ip.'</spbill_create_ip>
               <total_fee>'.$total_fee.'</total_fee>
               <trade_type>'.$trade_type.'</trade_type>
               <sign>'.$sign.'</sign>
            </xml> ';
    
        //统一下单接口prepay_id
        $xml = $this->http_request($url,$post_xml);     //POST方式请求http
        $array = $this->xml2array($xml);               //将【统一下单】api返回xml数据转换成数组,全要大写
        if($array['RETURN_CODE'] == 'SUCCESS' && $array['RESULT_CODE'] == 'SUCCESS'){
            $time = time();   
            $tmp='';                            //临时数组用于签名
            $tmp['appId'] = $appid;
            $tmp['nonceStr'] = $nonce_str;
            $tmp['package'] = 'prepay_id='.$order_id;
            $tmp['signType'] = 'MD5';
            $tmp['timeStamp'] = (string)$time;
    
            $data['state'] = 1;
            $data['timeStamp'] = (string)$time;           //时间戳
            $data['nonceStr'] = $nonce_str;         //随机字符串
            $data['signType'] = 'MD5';              //签名算法,暂支持 MD5
            $data['package'] = 'prepay_id='.$order_id;
            // = 'prepay_id='.'wx20180314162441c9c0b517a40292406177';   //统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=*
            $data['paySign'] = $this->MakeSign($tmp,$KEY);       //签名,具体签名方案参见微信公众号支付帮助文档;
            $data['out_trade_no'] = $out_trade_no;
    
        }else{
            $data['state'] = 0;
            $data['text'] = "错误";
            $data['RETURN_CODE'] = $array['RETURN_CODE'];
            $data['RETURN_MSG'] = $array['RETURN_MSG'];
        }
        //此处返回结果集合
        return json_encode($data);
    }
//第三部,上面三个fuction为核心代码,下面的全部是封装的方法,可直接复制使用
/**
*生成签名算法
*/
function getSign($array)
{
    $pay_key = "12ed7bd47d66f4ef7865f79b2194a94b";
    unset($array['sign']);
    ksort($array);
    $stringA = urldecode(http_build_query($array));
    $stringSignTemp="$stringA&key=".$pay_key;
    return strtoupper(md5($stringSignTemp));
}
 
 
/**
*生成不重复的字符串
*@param $len 字符串长度
*@return 随机字符串
*/
function rand2($len)
   {
      $chars='ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';
      $string=time();
      for(;$len>=1;$len--)
      {
          $position=rand()%strlen($chars);
          $position2=rand()%strlen($string);
          $string=substr_replace($string,substr($chars,$position,1),$position2,0);
     }
     return $string;
}
 
 
 
    /**
     * 生成签名, $KEY就是支付key
     * @return 签名
     */
    function MakeSign( $params,$KEY){
        //签名步骤一:按字典序排序数组参数
        ksort($params);
        $string = $this->ToUrlParams($params);  //参数进行拼接key=value&k=v
        //签名步骤二:在string后加入KEY
        $string = $string . "&key=".$KEY;
        //签名步骤三:MD5加密
        $string = md5($string);
        //签名步骤四:所有字符转为大写
        $result = strtoupper($string);
        return $result;
    }
 
 
     function ToUrlParams( $params ){
        $string = '';
        if( !empty($params) ){
            $array = array();
            foreach( $params as $key => $value ){
                $array[] = $key.'='.$value;
            }
            $string = implode("&",$array);
        }
        return $string;
    }
 
     function xml2array($xml){
        $p = xml_parser_create();
        xml_parse_into_struct($p, $xml, $vals, $index);
        xml_parser_free($p);
        $data = "";
        foreach ($index as $key=>$value) {
            if($key == 'xml' || $key == 'XML') continue;
            $tag = $vals[$value[0]]['tag'];
            $value = $vals[$value[0]]['value'];
            $data[$tag] = $value;
        }
        return $data;
    }
 
    function http_request($url,$data = null,$headers=array())
    {
        $curl = curl_init();
        if( count($headers) >= 1 ){
            curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        }
        curl_setopt($curl, CURLOPT_URL, $url);
    
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
    
        if (!empty($data)){
            curl_setopt($curl, CURLOPT_POST, 1);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        }
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($curl);
        curl_close($curl);
        return $output;
    }
原文地址:https://www.cnblogs.com/ayanboke/p/8574349.html