thinkphp微信支付配置怎么修改

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了thinkphp微信支付配置怎么修改相关的知识,希望对你有一定的参考价值。

参考技术A   Thinkphp整合微信支付功能的相关资料
  我要告诉你我这一篇文章写的是微信支付之中的(普通商户而非服务商商户的统一下单JSPI)微信支付:
  其实自己整合SDK失败了,用了一个博客博主整合的代码,在这里写一下笔记:
  前面准备:
  1、微信公众号:
  独特的appid、appscrect、接口权限之中设置可以获取用户ID信息权限的域名(每个用户对于不同公众都会有一个特有ID,通过这个ID获取用户微信账号基本信息、详情看微信开发者文档)、在微信支付按钮出设置微信支付授权目录(写到发起请求的控制器那一层)、设置开发者微信账号为测试白名单(用微信开发者工具的时候需要)2、微信支付平台:
  商户平台登陆账号、支付密钥(随时可以自行设置,只能有一个)、3、整合进去thinkphp之中逻辑:
  前端微信支付按钮设置点击调用支付发起控制器方法、控制器运行,引用微信支付类、获取用户openid、获取订单数据、拼接出所有普通商户预支付jsp需要的数据,display出那个自定义的支付页面、在支付页面点击支付、调用微信提供的jspi发起支付的scripet函数发起支付、支付完成以后页面会重定向到(在自定义支付页面的script函数里设置的跳转目录:U('controller/function)),并且异步(静默)设置的异步处理订单逻辑(记录支付时间啦、标记为已经支付啦、标记是微信支付啦)之类的、代码:
  我的订单页面的微信支付按钮:
  <a href=":U('Wxpay/js_api_start',array('order_key_num'=>$v['order_key_num]))"> 微信支付</a>
  发起支付控制器Wxpay:
  <?php
  namespace Home\Controller;
  use Think\Controller;
  //微信支付类
  class WxpayController extends Controller //获取access_token过程中的跳转uri,通过跳转将code传入jsapi支付页面public function js_api_start()if(!empty($_GET['order_key_num']))
  // session(array('pay_now_id'=>$_GET['order_key_num'],'expire'=>3600));S('pay_now_id',$_GET['order_key_num'],3600);
  vendor('Weixinpay.WxPayPubHelper');
  //使用jsapi接口
  $jsApi = new \JsApi_pub();
  //=========步骤1:网页授权获取用户openid============//通过code获得openidif($_GET['code'] == '')
  //跳转
  $redirect_uri = 'https://当前域名+模块+控制器+方法';$url = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid=公众号特有IDredirect_uri='.$redirect_uri.'&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect';header("Location: $url");exit();
  else
  //获取openid
  $url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=公众号ID&secret=公众号scrept&code='.$_GET['code'].'&grant_type=authorization_code';$openid_arr = json_decode(file_get_contents($url),true);
  $openid=$openid_arr['openid'];
  $pay_now_id = S('pay_now_id');
  if($pay_now_id)
  $id=$pay_now_id;
  $o = D('order_info');
  $order_info = $o->where('order_id = %d',$id)->find();if(empty($order_info['paycode']))$order_info['paycode'] = 'weixin';
  
  if($order_info['is_pay'])
  $this->error('当前订单已经支付');
  
  else
  $this->error("不存在当前订单编号!");
  
  $res = array(
  'order_sn' => $order_info['order_sn'],
  'order_amount' => $order_info['pay_money']
  );
  //=========步骤2:使用统一支付接口,获取prepay_id============//使用统一支付接口$unifiedOrder = new \UnifiedOrder_pub();
  //设置统一支付接口参数
  //设置必填参数
  //appid已填,商户无需重复填写
  //mch_id已填,商户无需重复填写
  //noncestr已填,商户无需重复填写
  //spbill_create_ip已填,商户无需重复填写
  //sign已填,商户无需重复填写
  $total_fee = $order_info['pay_money']*100;// $total_fee = $res['order_amount'];//$total_fee = 1;
  // var_dump($order_info['pay_money']);die;$body = "订单支付";$unifiedOrder->setParameter("openid", "$openid");//用户标识$unifiedOrder->setParameter("body", '商品采购');//商品描述//自定义订单号,此处仅作举例$unifiedOrder->setParameter("out_trade_no", $order_info['order_sn']);//商户订单号$unifiedOrder->setParameter("total_fee", $total_fee);//总金额//$unifiedOrder->setParameter("attach", "order_sn=$res['order_sn']");//附加数据$unifiedOrder->setParameter("notify_url", \WxPayConf_pub::NOTIFY_URL);//通知地址$unifiedOrder->setParameter("trade_type", "JSAPI");//交易类型//非必填参数,商户可根据实际情况选填//$unifiedOrder->setParameter("sub_mch_id","XXXX");//子商户号//$unifiedOrder->setParameter("device_info","XXXX");//设备号//$unifiedOrder->setParameter("attach","XXXX");//附加数据//$unifiedOrder->setParameter("time_start","XXXX");//交易起始时间//$unifiedOrder->setParameter("time_expire","XXXX");//交易结束时间//$unifiedOrder->setParameter("goods_tag","XXXX");//商品标记//$unifiedOrder->setParameter("openid","XXXX");//用户标识//$unifiedOrder->setParameter("product_id","XXXX");//商品ID$prepay_id = $unifiedOrder->getPrepayId();// var_dump($prepay_id);die;//=========步骤3:使用jsapi调起支付============$jsApi->setPrepayId($prepay_id);$jsApiParameters = $jsApi->getParameters();$wxconf = json_decode($jsApiParameters, true);if ($wxconf['package'] == 'prepay_id=') $this->error('当前订单存在异常!');
  $this->assign('res', $res);
  $this->assign('jsApiParameters', $jsApiParameters);$this->display('jsapi');
  //异步通知url,商户根据实际开发过程设定
  public function notify_url()
  vendor('Weixinpay.WxPayPubHelper');
  //使用通用通知接口
  $notify = new \Notify_pub();
  //存储微信的回调
  $xml = $GLOBALS['HTTP_RAW_POST_DATA'];
  $notify->saveData($xml);
  //验证签名,并回应微信。
  //对后台通知交互时,如果微信收到商户的应答不是成功或超时,微信认为通知失败,//微信会通过一定的策略(如30分钟共8次)定期重新发起通知,//尽可能提高通知的成功率,但微信不保证通知最终能成功。
  if($notify->checkSign() == FALSE)
  $notify->setReturnParameter("return_code", "FAIL");//返回状态码$notify->setReturnParameter("return_msg", "签名失败");//返回信息else$notify->setReturnParameter("return_code", "SUCCESS");//设置返回码
  $returnXml = $notify->returnXml();
  //==商户根据实际情况设置相应的处理流程,此处仅作举例=======//以log文件形式记录回调信息//$log_name = "notify_url.log";//log文件路径//$this->log_result($log_name, "【接收到的notify通知】:\n".$xml."\n");$parameter = $notify->xmlToArray($xml);//$this->log_result($log_name, "【接收到的notify通知】:\n".$parameter."\n");if($notify->checkSign() == TRUE)if ($notify->data["return_code"] == "FAIL") //此处应该更新一下订单状态,商户自行增删操作//$this->log_result($log_name, "【通信出错】:\n".$xml."\n");//更新订单数据【通信出错】设为无效订单echo 'error';
  
  else if($notify->data["result_code"] == "FAIL")//此处应该更新一下订单状态,商户自行增删操作//$this->log_result($log_name, "【业务出错】:\n".$xml."\n");//更新订单数据【通信出错】设为无效订单echo 'error';
  
  else
  //$this->log_result($log_name, "【支付成功】:\n".$xml."\n");//我这里用到一个process方法,成功返回数据后处理,返回地数据具体可以参考微信的文档if ($this->process($parameter)) //处理成功后输出success,微信就不会再下发请求了echo 'success';else
  //没有处理成功,微信会间隔的发送请求
  echo 'error';
  
  
  
  
  //订单处理
  private function process($parameter)
  //此处应该更新一下订单状态,商户自行增删操作/** 返回的数据最少有以下几个
  * $parameter = array(
  'out_trade_no' => xxx,//商户订单号
  'total_fee' => XXXX,//支付金额
  'openid' => XXxxx,//付款的用户ID
  );
  */
  $data = array(
  'order_sn'=>$parameter['out_trade_no'],
  'des'=>('订单交易:'.$parameter['out_trade_no']),'money'=>$parameter['total_fee'],);
  orderhandlestarysdgdss($data);//这是一个common方法,他会将该订单状态设置为已支付之类的return true;
  
  ?>
  发起支付后拼接预支付数据参数(参数列表看微信普通商户开发者文档——微信支付——统一下单)display的页面:
  <!DOCTYPE html>
  <html>
  <head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0;" name="viewport" />
  <meta name="format-detection" content="telephone=no"/>
  <title>下</title>
  <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
  <meta name="keyword" content="">
  <meta name="description" content="">
  <script type="text/javascript">
  var order_sn = "$res['order_sn']";
  //调用微信JS api 支付
  function jsApiCall()
  WeixinJSBridge.invoke(
  'getBrandWCPayRequest',
  <?php echo $jsApiParameters; ?>,
  function(res)
  //如果支付成功
  if (res.err_msg == 'get_brand_wcpay_request:ok') //支付成功后跳转的地址location.href = ":U('Home/User/my_order')";else if (res.err_msg == 'get_brand_wcpay_request:cancel') alert('请尽快完成支付哦!');else if (res.err_msg == 'get_brand_wcpay_request:fail') alert('支付失败');else
  alert('意外错误');
  
  //WeixinJSBridge.log(res.err_msg);
  //alert(res.err_code+res.err_desc+res.err_msg);/*if (res.err_msg == 'get_brand_wcpay_request:ok') alert('支付成功');else
  alert('取消支付');
  */
  
  );
  
  function callpay()
  if (typeof WeixinJSBridge == "undefined")if( document.addEventListener )document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);else if (document.attachEvent)document.attachEvent('WeixinJSBridgeReady', jsApiCall);document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
  else
  jsApiCall();
  
  
  </script>
  <style>
  *font-family:'微软雅黑','Microsoft YaHei';
  body #headposition:relative;z-index:99999999999999;padding:0 10px;
  body .zh-headpadding:0 0 0 0;height:auto;
  .zh-head-conterposition:relative;height:40px;
  .zh-logoposition:absolute;left:50%;top:0;margin:0 0 0 -60px;float:none;width:auto;
  .zh-logo adisplay:block;
  .zh-logo imgwidth:120px;height:40px;display:block;
  .heads_fix .zh-logo
  #headposition:fixed!important;left:0;top:0;right:0;z-index:99999;background:#fff;border-bottom:1px solid #ddd;
  .zh-logoheight:40px;
  .flowpaymargin-top:25%;
  .flowpay dttext-align:center;
  .flowpay strong.pricefont-size:40px;
  .wxLogotext-align:center;
  .wxLogo img
  .flowpay ddmargin:0;padding:20px 0 10px 0;
  .flowpay dd inputmargin:0 auto;padding:0;width:90%;height:45px;line-height:45px;border:0;border-radius:4px;background:#0CBC0A;color:#fff;font-size:17px;display:block;-webkit-appearance:none;-moz-appearance:none;appearance:none;outline:none;
  </style>
  </head>
  <body>
  <!--头部开始-->
  <div class="flowpay">
  <dl>
  <dt>
  <p class="wxLogo"><img src="__PUBLIC__/home/images/1479953699138120.png" alt=""></p>
  本次订单需支付:¥<strong class="price">$res['order_amount']</strong> 元</dt>
  <dd>
  <input type="button" id="hhhhhh" onclick="callpay()" value="立即支付" />
  </dd>
  </dl>
  </div>
  <!--尾结束-->
  </body>
  </html>
  然后就是类文件啦:

Thinkphp5.1微信小程序支付

参考技术A 研究了好几天,坑也遇到了,也百度了很久现在终于做完了,给大家分享出来,

我这个也是参考别人写的。有不明白的朋友可以问我

public function unifiedorder($order_no, $openid, $total_fee, $attach, $order_id, $user_id)

    // 当前时间

    $time = time();

    // 生成随机字符串

    $nonceStr = md5($time . $openid);

    // API参数

    $params = [

        'appid' => $this->appid,                                  //微信分配的小程序id

        'attach' => $attach,                                      //附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用。

        'body' => '会员卡',                                      //募捐描述

        'mch_id' => $this->mchid,                        //微信支付分配的商户号

        'nonce_str' => $nonceStr,                                  //随机字符串,32位以内

        'notify_url' => $this->notify_url,                    //            base_url() . 'notice.php?s=/task/notify/order/wxapp_id/'.$wxapp_id, // 异步通知地址

        'openid' => $openid,                                      //用户标识;trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识。

        'out_trade_no' => $order_no,                              //商户账单号

        'spbill_create_ip' => \request()->ip(),                    //终端IP;支持IPV4和IPV6两种格式的IP地址。调用微信支付API的机器IP

        'total_fee' => (int)$total_fee * 100, // 价格:单位分              // 价格:单位分

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

    ];

    // 生成签名

    $params['sign'] = $this->makeSign($params);  //这个地方最坑,需要的是配置 1、appid和商户号必须是绑定的状态

    // 请求API

    $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';

    $result = $this->post($url, $this->toXml($params));

    $prepay = $this->fromXml($result);

    //添加preapay_id

    $data = [

        'user_id' => $user_id,

        'order_id' => $order_id,

        'attach' => json_encode($attach),

        'prepay_id' => $prepay['prepay_id'],

    ];

    (new AppleWxPrepay())->addInfo($data);

    // 请求失败

    if ($prepay['return_code'] === 'FAIL')

        return [API_CODE_NAME => 2000004, API_MSG_NAME => $prepay['return_msg']];

   

    if ($prepay['result_code'] === 'FAIL')

        return [API_CODE_NAME => 2000004, API_MSG_NAME => $prepay['err_code_des']];

   

    // 生成 nonce_str 供前端使用

    $paySign = $this->makePaySign($params['nonce_str'], $prepay['prepay_id'], $time);

    return [

        'prepay_id' => $prepay['prepay_id'],

        'nonceStr' => $nonceStr,

        'timeStamp' => (string)$time,

        'paySign' => $paySign

    ];



/**

* 生成签名

* @param $values

* @return string 本函数不覆盖sign成员变量,如要设置签名需要调用SetSign方法赋值

*/

private function makeSign($values)



    //签名步骤一:按字典序排序参数

    ksort($values);

    $string = $this->toUrlParams($values);

    //签名步骤二:在string后加入KEY

    $string = $string . '&key=' . $this->apikey;

    //签名步骤三:MD5加密

    $string = md5($string);

    //签名步骤四:所有字符转为大写

    $result = strtoupper($string);

    return $result;



/**

* 格式化参数格式化成url参数

* @param $values

* @return string

*/

private function toUrlParams($values)



    $buff = '';

    foreach ($values as $k => $v)

        if ($k != 'sign' && $v != '' && !is_array($v))

            $buff .= $k . '=' . $v . '&';

       



    return trim($buff, '&');



/**

* 模拟POST请求

* @param $url

* @param array $data

* @param bool $useCert

* @param array $sslCert

* @return mixed

*/

public function post($url, $data = [], $useCert = false, $sslCert = [])



    $header = [

        'Content-type: application/json; charset=UTF8'

    ];

    $curl = curl_init();

    curl_setopt($curl, CURLOPT_URL, $url);

    curl_setopt($curl, CURLOPT_HTTPHEADER, $header);

    curl_setopt($curl, CURLOPT_HEADER, false);

    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);

    curl_setopt($curl, CURLOPT_POST, TRUE);

    curl_setopt($curl, CURLOPT_POSTFIELDS, $data);

    if ($useCert == true)

        // 设置证书:cert 与 key 分别属于两个.pem文件

        curl_setopt($curl, CURLOPT_SSLCERTTYPE, 'PEM');

        curl_setopt($curl, CURLOPT_SSLCERT, $sslCert['certPem']);

        curl_setopt($curl, CURLOPT_SSLKEYTYPE, 'PEM');

        curl_setopt($curl, CURLOPT_SSLKEY, $sslCert['keyPem']);

   

    $result = curl_exec($curl);

    curl_close($curl);

    return $result;



/**

* 输出xml字符

* @param $values

* @return bool|string

*/

private function toXml($values)



    if (!is_array($values) || count($values) <= 0)

        return false;

   

    $xml = "<xml>";

    foreach ($values as $key => $val)

        if (is_numeric($val))

            $xml .= "<" . $key . ">" . $val . "</" . $key . ">";

        else

            $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";

       



    $xml .= "</xml>";

    return $xml;



/**

* 将xml转为array

* @param $xml

* @return mixed

*/

private function fromXml($xml)



    // 禁止引用外部xml实体

    libxml_disable_entity_loader(true);

    return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);



/**

* 生成paySign

* @param $nonceStr

* @param $prepay_id

* @param $timeStamp

* @return string

*/

private function makePaySign($nonceStr, $prepay_id, $timeStamp)



    $data = [

        'appId' => $this->appid,

        'nonceStr' => $nonceStr,

        'package' => 'prepay_id=' . $prepay_id,

        'signType' => 'MD5',

        'timeStamp' => $timeStamp,

    ];

    // 签名步骤一:按字典序排序参数

    ksort($data);

    $string = $this->toUrlParams($data);

    // 签名步骤二:在string后加入KEY

    $string = $string . '&key=' . $this->apikey;

    // 签名步骤三:MD5加密

    $string = md5($string);

    // 签名步骤四:所有字符转为大写

    $result = strtoupper($string);

    return $result;



/*********************************微信回调**********************/

public function getNotify()



    if (!$xml = file_get_contents('php://input'))

        $this->returnCode(50000001, 'Not found DATA');

   

    // 将服务器返回的XML数据转化为数组

    $data = $this->fromXml($xml);

    $payLog = new ApplePayLog();

    // 记录日志

    $payLog->addInfo(['content'=>json_encode($xml)]);

    $payLog->addInfo(['content'=>json_encode($data)]);

    // 实例化账单模型

    $OrderModel = new AppleOrder();

    // 账单信息

    $orderInfo = $OrderModel->getInfo(['id'=>$data['attach']],'*');

    if (empty($orderInfo))

        $this->returnCode(50000001, '账单不存在');

   

    if($orderInfo['pay_status'] != 1 || !empty($orderInfo['pay_time']))

        $this->returnCode(50000001,'订单已支付,请勿再次支付');

   

    // 保存微信服务器返回的签名sign

    $dataSign = $data['sign'];

    $return_code = $data['return_code'];

    $result_code = $data['result_code'];

    $data['body'] = '会员卡';

    $data['spbill_create_ip'] = \request()->ip();

    $data['notify_url'] = $this->notify_url;

    // sign 与 s 参数 不参与签名算法

    unset($data['sign']);

    unset($data['transaction_id']);

    unset($data['coupon_id']);

    unset($data['coupon_type']);

    unset($data['coupon_count']);

    unset($data['coupon_fee']);

    unset($data['time_end']);

    unset($data['return_code']);

    unset($data['result_code']);

    unset($data['is_subscribe']);

    unset($data['fee_type']);

    unset($data['bank_type']);

    unset($data['bank_type']);

    // 生成签名

    $sign = $this->makeSign($data);

    // 判断签名是否正确  判断支付状态

    if (($sign === $dataSign) && ($return_code == 'SUCCESS') && ($result_code == 'SUCCESS'))

        $OrderModel->startTrans();

        try

            // 账单支付成功业务处理

            $appleOrderInfo = $OrderModel->where(['id'=>$orderInfo['id']])->lock(true)->find();

            $result = $appleOrderInfo->addInfo(['pay_status'=>2,'pay_time'=>time()],['id'=>$orderInfo['id']]);

            if(!$result)

                $OrderModel->rollback();

                $this->returnCode(5000003, '修改订单失败,失败原因:'.$OrderModel->getError());

           

            $appleUserModel = new AppleUser();

            $appleUserInfo =  $appleUserModel->where(['openid'=>$orderInfo['openid']])->lock(true)->find();

            $appleUser = $appleUserInfo->where(['openid'=>$orderInfo['openid']])->setInc('moxibustion',$orderInfo['moxibustion']);

            if(!$appleUser)

                $OrderModel->rollback();

                $this->returnCode(5000003, '添加会员针灸次数失败,失败原因:'.$appleUserModel->getError());

           

        catch (\Exception $exception)

            $OrderModel->rollback();

            $this->returnCode(5000003, '操作失败,失败原因:'.$exception->getMessage());

       

            $OrderModel->commit();

        // 返回状态

        die(json(['code'=>0,'支付成功']));

   

    // 返回状态

    $this->returnCode(2000003, '签名失败');

以上是关于thinkphp微信支付配置怎么修改的主要内容,如果未能解决你的问题,请参考以下文章

微信小程序怎么修改支付方式

thinkphp 微信支付 thinkphp 微信企业付款

Thinkphp5.1微信小程序支付

thinkphp微信支付回调是啥意思

微信的jsapi支付能整合到thinkphp吗

认证服务号Thinkphp微信支付