微信支付

<?php
namespace WxPay;
/**
  • 微信支付
    */
    class wxpay{
    private $pay_url = ‘https://api.mch.weixin.qq.com/pay/unifiedorder‘; // 统一支付地址
    private $h5_pay_url = ‘https://api.mch.weixin.qq.com/pay/unifiedorder‘; // H5支付地址
    private $h5_order = ‘https://api.mch.weixin.qq.com/pay/orderquery‘; // H5支付订单查询地址
    private $refund_url = ‘https://api.mch.weixin.qq.com/secapi/pay/refund‘; // 退款地址
    private $transfers = ‘https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers‘; // 企业付款到零钱 需支付证书
    // 证书文件放在与入口文件同级的cert目录下
    private $SSLCERT_PATH = ‘cert/apiclient_cert.pem‘; // api证书路径
    private $SSLKEY_PATH = ‘cert/apiclient_key.pem‘; // 密钥证书路径

    /**

    • H5网页支付
    • [web_pay description]
    • @Author 念天地之悠悠
    • @DateTime 2019-05-28
    • @param [type] $appid [description] 微信分配的公众账号ID(企业号corpid即为此appId)
    • @param [type] $mch_id [description] 微信支付分配的商户号
    • @param [type] $body [description] 商品描述 如 购买商品
    • @param [type] $out_trade_no [description] 商户系统内部的订单号
    • @param [type] $total_fee [description] 订单金额 金额 单位分
    • @param [type] $notify_url [description] 异步回调地址
    • @param [type] $scene_info [description] 场景信息
    • @param [type] $wx_key [description] 微信支付秘钥
    • @return [type] [description]
      */
      public function web_pay($appid,$mch_id,$body,$out_trade_no,$total_fee,$notify_url,$scene_info,$wx_key){
      $nonce_str = $this->nonce_str(); // 随机字符串
      $spbill_create_ip = request()->ip(); // 终端ip
      $trade_type = ‘MWEB‘; // 交易类型
      $device_info = ‘WEB‘; // 设备号
      $attach = "yidun"; // 附加数据
      $post[‘appid‘] = $appid;
      $post[‘attach‘] = $attach;
      $post[‘body‘] = $body;
      $post[‘device_info‘] = $device_info;
      $post[‘mch_id‘] = $mch_id;
      $post[‘nonce_str‘] = $nonce_str;
      $post[‘notify_url‘] = $notify_url;
      $post[‘out_trade_no‘] = $out_trade_no;
      $post[‘scene_info‘] = $scene_info;
      $post[‘spbill_create_ip‘] = $spbill_create_ip;
      $post[‘total_fee‘] = $total_fee;
      $post[‘trade_type‘] = $trade_type;
      $sign = $this->sign($post,$wx_key);
      $post_xml = ‘<xml>
      <appid>‘.$appid.‘</appid>
      <attach>‘.$attach.‘</attach>
      <body>‘.$body.‘</body>
      <device_info>‘.$device_info.‘</device_info>
      <mch_id>‘.$mch_id.‘</mch_id>
      <nonce_str>‘.$nonce_str.‘</nonce_str>
      <notify_url>‘.$notify_url.‘</notify_url>
      <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>
      <scene_info>‘.$scene_info.‘</scene_info>
      <sign>‘.$sign.‘</sign>
      </xml>‘;
      $xml = $this->http_request($this->h5_pay_url,$post_xml);
      // 将xml转数组
      $arr = simplexml_load_string($xml, ‘SimpleXMLElement‘, LIBXML_NOCDATA);
      $xmljson = json_encode($arr);
      $array = json_decode($xmljson,true);
      if ($array[‘return_code‘] == ‘SUCCESS‘ && $array[‘return_msg‘] == ‘OK‘ && $array[‘result_code‘] == ‘SUCCESS‘) {
      // $data[‘return_code‘] = 1;
      // $data[‘mweb_url‘] = $array[‘mweb_url‘];
      $ret = [‘code‘=>1,‘data‘=>$array[‘mweb_url‘],‘msg‘=>‘调用成功!‘];
      }else{
      // $data[‘return_code‘] = 0;
      // $data[‘return_msg‘] = $array[‘err_code_des‘];
      $ret = [‘code‘=>0,‘data‘=>‘‘,‘msg‘=>$array[‘err_code_des‘]];
      }
      return $ret;
      }
      /**
    • APP支付
    • [app_pay description]
    • @Author 念天地之悠悠
    • @DateTime 2019-05-28
    • @param [type] $appid [description] 微信开放平台审核通过的应用APPID
    • @param [type] $mch_id [description] 微信支付分配的商户号
    • @param [type] $body [description] 商品描述 如 购买商品
    • @param [type] $out_trade_no [description] 商户系统内部的订单号
    • @param [type] $total_fee [description] 订单金额 单位分
    • @param [type] $notify_url [description] 异步回调地址
    • @param [type] $wx_key [description] 微信支付秘钥
    • @return [type] [description]
      */
      public function app_pay($appid,$mch_id,$body,$out_trade_no,$total_fee,$notify_url,$wx_key){
      $nonce_str = $this->nonce_str(); // 随机字符串
      $spbill_create_ip = request()->ip(); // 终端ip
      $trade_type = ‘APP‘; // 交易类型
      $post[‘appid‘] = $appid;
      $post[‘body‘] = $body;
      $post[‘mch_id‘] = $mch_id;
      $post[‘nonce_str‘] = $nonce_str;
      $post[‘notify_url‘] = $notify_url;
      $post[‘out_trade_no‘] = $out_trade_no;
      $post[‘spbill_create_ip‘] = $spbill_create_ip;
      $post[‘total_fee‘] = $total_fee;
      $post[‘trade_type‘] = $trade_type;
      $sign = $this->sign($post,$wx_key);
      $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>
      <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>‘;
      $xml = $this->http_request($this->pay_url,$post_xml);
      // 将xml转数组
      $arr = simplexml_load_string($xml, ‘SimpleXMLElement‘, LIBXML_NOCDATA);
      $xmljson = json_encode($arr);
      $array = json_decode($xmljson,true);
      if ($array[‘return_code‘] == ‘SUCCESS‘ && $array[‘result_code‘] == ‘SUCCESS‘) {
      // 进行二签
      $data[‘appid‘] = $appid; // appid
      $data[‘noncestr‘] = $this->nonce_str(); // 随机字符串
      $data[‘package‘] = ‘Sign=WXPay‘; // 固定值
      $data[‘partnerid‘] = $mch_id; // 商户号
      $data[‘prepayid‘] = $array[‘prepay_id‘]; // 支付交易会话ID
      $data[‘timestamp‘] = (string)time(); // 时间戳
      $data[‘sign‘] = $this->sign($data,$wx_key); // 签名
      $ret = [‘code‘=>1,‘data‘=>$data,‘msg‘=>‘调用成功!‘];
      }else{
      $ret = [‘code‘=>0,‘data‘=>‘‘,‘msg‘=>$array[‘return_msg‘]];
      // $data[‘return_code‘] = 0;
      // $data[‘return_msg‘] = $array[‘return_msg‘];
      }
      return $ret;
      }
      /**
    • H5支付订单查询
    • [get_H5_order description]
    • @Author 念天地之悠悠
    • @DateTime 2019-06-04
    • @param [type] $appid [description] 微信支付分配的公众账号ID(企业号corpid即为此appId)
    • @param [type] $mch_id [description] 商户号
    • @param [type] $out_trade_no [description] 自定义单号
    • @param [type] $wx_key [description] 支付秘钥
    • @return [type] [description]
      */
      public function get_H5_order($appid,$mch_id,$out_trade_no,$wx_key){
      $nonce_str = $this->nonce_str(); // 随机字符串
      $post[‘appid‘] = $appid;
      $post[‘mch_id‘] = $mch_id;
      $post[‘nonce_str‘] = $nonce_str;
      $post[‘out_trade_no‘] = $out_trade_no;
      $sign = $this->sign($post,$wx_key);
      $post_xml = ‘<xml>
      <appid>‘.$appid.‘</appid>
      <mch_id>‘.$mch_id.‘</mch_id>
      <nonce_str>‘.$nonce_str.‘</nonce_str>
      <out_trade_no>‘.$out_trade_no.‘</out_trade_no>
      <sign>‘.$sign.‘</sign>
      </xml>‘;
      $xml = $this->http_request($this->h5_order,$post_xml);
      // 将xml转数组
      $arr = simplexml_load_string($xml, ‘SimpleXMLElement‘, LIBXML_NOCDATA);
      $xmljson = json_encode($arr);
      $array = json_decode($xmljson,true);
      $data = [];
      if ($array[‘return_code‘] == ‘SUCCESS‘ && $array[‘result_code‘] == ‘SUCCESS‘ && $array[‘trade_state‘] == ‘SUCCESS‘) {
      $data[‘code‘] = 1;
      $data[‘transaction_id‘] = $array[‘transaction_id‘];
      }else{
      $data[‘code‘] = 0;
      }
      return $data;
      }
      /**
    • 微信小程序支付
    • [pay description]
    • @Author 念天地之悠悠
    • @DateTime 2019-03-11
    • @param [type] $appid [description] 小程序APPid
    • @param [type] $body [description] 商品描述
    • @param [type] $mch_id [description] 商户id
    • @param [type] $notify_url [description] 异步通知地址
    • @param [type] $openid [description] 微信用户唯一标识符
    • @param [type] $order_no [description] 商户自定义订单号
    • @param [type] $total_fee [description] 总金额 单位分
    • @param [type] $trade_type [description] 交易类型
    • @param [type] $spbill_create_ip [description] 终端的ip地址
    • @param [type] $wx_key [description] 申请支付后设置的key
    • @return [type] [description]
      */
      public function pay($appid,$body,$mch_id,$notify_url,$openid,$order_no,$total_fee,$trade_type,$spbill_create_ip,$wx_key){
      $post = [];
      $nonce_str = $this->nonce_str();
      //这里是按照顺序的 因为下面的签名是按照顺序 排序错误 肯定出错
      $post[‘appid‘] = $appid; // 小程序APPid
      $post[‘body‘] = $body; // 商品描述
      $post[‘mch_id‘] = $mch_id; // 商户id
      $post[‘nonce_str‘] = $nonce_str; // 随机字符串
      $post[‘notify_url‘] = $notify_url; // 异步通知地址
      $post[‘openid‘] = $openid; // 微信用户唯一标识符
      $post[‘out_trade_no‘] = $order_no; // 商户自定义订单号
      $post[‘spbill_create_ip‘] = $spbill_create_ip; // 终端的ip
      $post[‘total_fee‘] = (int)$total_fee; // 总金额
      $post[‘trade_type‘] = $trade_type; // 交易类型
      $sign = $this->sign($post,$wx_key); //签名
      $post_xml = ‘<xml>
      <appid>‘.$appid.‘</appid>
      <body>‘.$post[‘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>‘.$order_no.‘</out_trade_no>
      <spbill_create_ip>‘.$spbill_create_ip.‘</spbill_create_ip>
      <total_fee>‘.(int)$total_fee.‘</total_fee>
      <trade_type>‘.$trade_type.‘</trade_type>
      <sign>‘.$sign.‘</sign>
      </xml> ‘;
      $xml = $this->http_request($this->pay_url,$post_xml);
      // 将xml转数组
      $arr = simplexml_load_string($xml, ‘SimpleXMLElement‘, LIBXML_NOCDATA);
      $xmljson = json_encode($arr);
      $array = json_decode($xmljson,true);
      if ($array[‘return_code‘] == ‘SUCCESS‘ && $array[‘result_code‘] == ‘SUCCESS‘) {
      $time = time();
      $tmp = ‘‘;//临时数组用于签名
      $tmp[‘appId‘] = $appid;
      $tmp[‘nonceStr‘] = $nonce_str;
      $tmp[‘package‘] = ‘prepay_id=‘.$array[‘prepay_id‘];
      $tmp[‘signType‘] = ‘MD5‘;
      $tmp[‘timeStamp‘] = "$time";

      $data[‘code‘]                 = 1;
      $data[‘msg‘]                  = ‘成功!‘;
      $data[‘data‘][‘timeStamp‘]    = "$time";                            // 时间戳
      $data[‘data‘][‘nonceStr‘]     = $nonce_str;                         // 随机字符串
      $data[‘data‘][‘signType‘]     = ‘MD5‘;                              // 签名算法,暂支持 MD5
      $data[‘data‘][‘package‘]      = ‘prepay_id=‘.$array[‘prepay_id‘];   // 统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=*
      $data[‘data‘][‘paySign‘]      = $this->sign($tmp,$wx_key);          // 签名,具体签名方案参见微信公众号支付帮助文档;
      $data[‘data‘][‘out_trade_no‘] = $order_no;

      }else{
      $data[‘code‘] = 0;
      $data[‘msg‘] = $array[‘err_code_des‘];
      $data[‘data‘][‘return_code‘] = $array[‘return_code‘]; // 微信支付返回码
      $data[‘data‘][‘return_msg‘] = $array[‘err_code_des‘]; // 微信支付返回消息
      }
      return $data;
      }
      /**

    • 微信退款
    • [wx_refund description]
    • @Author 念天地之悠悠
    • @DateTime 2019-03-11
    • @param [type] $appid [description] APPID
    • @param [type] $mch_id [description] 商户号
    • @param [type] $order_no [description] 商户退款单号
    • @param [type] $notify_url [description] 异步通知地址
    • @param [type] $total_fee [description] 订单金额
    • @param [type] $refund_fee [description] 退款金额 单位分
    • @param [type] $transaction_id [description] 微信单号
    • @param [type] $wx_key [description] 申请支付后设置的key
    • @return [type] [description]
      */
      public function wx_refund($appid,$mch_id,$order_no,$notify_url,$total_fee,$refund_fee,$transaction_id,$wx_key){
      $post_data = [];
      $nonce_str = $this->nonce_str();
      $post_data[‘appid‘] = $appid; // APPID
      $post_data[‘mch_id‘] = $mch_id; // 商户号
      $post_data[‘nonce_str‘] = $nonce_str; // 随机码
      $post_data[‘out_refund_no‘] = $order_no; // 商户退款单号
      $post_data[‘refund_fee‘] = (int)$refund_fee; // 退款金额
      $post_data[‘total_fee‘] = (int)$total_fee; // 订单金额
      $post_data[‘transaction_id‘] = $transaction_id; // 微信单号
      $sign = $this->sign($post_data,$wx_key); // 签名
      $post_xml = ‘<xml>
      <appid>‘.$appid.‘</appid>
      <mch_id>‘.$mch_id.‘</mch_id>
      <nonce_str>‘.$nonce_str.‘</nonce_str>
      <out_refund_no>‘.$order_no.‘</out_refund_no>
      <refund_fee>‘.$refund_fee.‘</refund_fee>
      <total_fee>‘.$total_fee.‘</total_fee>
      <transaction_id>‘.$transaction_id.‘</transaction_id>
      <sign>‘.$sign.‘</sign>
      </xml>‘;
      $xml = $this->postXmlSSLCurl($this->refund_url,$post_xml);
      // 将xml转数组
      $arr = simplexml_load_string($xml, ‘SimpleXMLElement‘, LIBXML_NOCDATA);
      $xmljson = json_encode($arr);
      $array = json_decode($xmljson,true);
      $data = [];
      if ($array[‘return_code‘] == ‘SUCCESS‘ && $array[‘result_code‘] == ‘SUCCESS‘) {
      $data[‘code‘] = 1;
      $data[‘data‘] = ‘‘;
      $data[‘msg‘] = ‘调用成功!‘;
      }else{
      $data[‘code‘] = 0;
      $data[‘data‘] = ‘‘;
      $data[‘msg‘] = $array[‘err_code_des‘];
      }
      return $data;
      }
      /**
    • 企业向微信用户个人付款(用作提现) 需要支付证书 付款到零钱包
    • 使用条件
    • 1、商户号(或同主体其他非服务商商户号)已入驻90日
    • 2、截止今日回推30天,商户号(或同主体其他非服务商商户号)连续不间断保持有交易
    • 3、登录微信支付商户平台-产品中心,开通企业付款。
    • [wx_transfers description]
    • @Author 念天地之悠悠
    • @DateTime 2019-07-09
    • @param [type] $mch_appid [description] 申请商户号的appid或商户号绑定的appid
    • @param [type] $mchid [description] 微信支付分配的商户号
    • @param [type] $partner_trade_no [description] 商户订单号,需保持唯一性(只能是字母或者数字,不能包含有其他字符)
    • @param [type] $openid [description] 商户appid下,某用户的openid
    • @param string $check_name [description] NO_CHECK:不校验真实姓名 FORCE_CHECK:强校验真实姓名
    • @param [type] $amount [description] 企业付款金额,单位为分
    • @param string $desc [description] 企业付款备注,必填。
    • @param [type] $wx_key [description] 支付秘钥
    • @return [type] [description]
      */
      public function wx_transfers($mch_appid,$mchid,$partner_trade_no,$openid,$check_name=‘NO_CHECK‘,$amount,$desc=‘提现‘,$wx_key){
      $nonce_str = $this->nonce_str(); // 32位随机字符串
      $spbill_create_ip = request()->ip(); // 终端ip
      $post_data[‘amount‘] = $amount;
      $post_data[‘check_name‘] = $check_name;
      $post_data[‘desc‘] = $desc;
      $post_data[‘mch_appid‘] = $mch_appid;
      $post_data[‘mchid‘] = $mchid;
      $post_data[‘nonce_str‘] = $nonce_str;
      $post_data[‘openid‘] = $openid;
      $post_data[‘partner_trade_no‘] = $partner_trade_no;
      $post_data[‘spbill_create_ip‘] = $spbill_create_ip;
      $sign = $this->sign($post_data,$wx_key);
      $post_xml = ‘<xml>
      <mch_appid>‘.$mch_appid.‘</mch_appid>
      <mchid>‘.$mchid.‘</mchid>
      <nonce_str>‘.$nonce_str.‘</nonce_str>
      <partner_trade_no>‘.$partner_trade_no.‘</partner_trade_no>
      <openid>‘.$openid.‘</openid>
      <check_name>‘.$check_name.‘</check_name>
      <amount>‘.$amount.‘</amount>
      <desc>‘.$desc.‘</desc>
      <spbill_create_ip>‘.$spbill_create_ip.‘</spbill_create_ip>
      <sign>‘.$sign.‘</sign>
      </xml>‘;
      $xml = $this->postXmlSSLCurl($this->transfers,$post_xml);
      // 将xml转数组
      $arr = simplexml_load_string($xml, ‘SimpleXMLElement‘, LIBXML_NOCDATA);
      $xmljson = json_encode($arr);
      $arr = json_decode($xmljson,true);
      return $arr;
      }
      /**
    • 签名
    • [sign description]
    • @Author 念天地之悠悠
    • @DateTime 2019-03-11
    • @param [type] $data [description] 数据集
    • @param [type] $wx_key [description] 微信支付key
    • @return [type] [description]
      */
      private function sign($data,$wx_key = ‘‘){
      $stringA = ‘‘;
      foreach ($data as $key => $value) {
      if (!$value) continue;
      if ($stringA) $stringA .= ‘&‘.$key."=".$value;
      else $stringA = $key."=".$value;
      }
      if ($wx_key == ‘‘) {
      $stringSignTemp = $stringA;
      }else{
      $stringSignTemp = $stringA.‘&key=‘.$wx_key;
      }
      return strtoupper(md5($stringSignTemp));
      }
      /**
    • 随机32位字符串
    • [nonce_str description]
    • @Author 念天地之悠悠
    • @DateTime 2019-02-21
    • @return [type] [description]
      */
      private function nonce_str(){
      $result = ‘‘;
      $str = ‘QWERTYUIOPASDFGHJKLZXVBNMqwertyuioplkjhgfdsamnbvcxz‘;
      for ($i = 0; $i < 32; $i++) {
      $result .= $str[rand(0,48)];
      }
      return $result;
      }
      /**
    • curl请求
    • [http_request description]
    • @Author 念天地之悠悠
    • @DateTime 2019-02-21
    • @param [type] $url [description]
    • @param [type] $data [description]
    • @param array $headers [description]
    • @return [type] [description]
      */
      public 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;
      }
      /**
    • 需要证书的curl请求
    • [postXmlSSLCurl description]
    • @Author 念天地之悠悠
    • @DateTime 2019-03-12
    • @param [type] $url [description] 访问地址
    • @param [type] $xml [description] mxl数据体
    • @param integer $second [description] 超时时间
    • @return [type] [description]
      */
      public function postXmlSSLCurl($url,$xml,$second=30){
      $ch = curl_init();
      //超时时间
      curl_setopt($ch,CURLOPT_TIMEOUT,$second);
      //这里设置代理,如果有的话
      //curl_setopt($ch,CURLOPT_PROXY, ‘8.8.8.8‘);
      //curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
      curl_setopt($ch,CURLOPT_URL, $url);
      curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
      curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);
      //设置header
      curl_setopt($ch,CURLOPT_HEADER,FALSE);
      //要求结果为字符串且输出到屏幕上
      curl_setopt($ch,CURLOPT_RETURNTRANSFER,TRUE);
      //设置证书
      //使用证书:cert 与 key 分别属于两个.pem文件
      //默认格式为PEM,可以注释
      curl_setopt($ch,CURLOPT_SSLCERTTYPE,‘PEM‘);
      curl_setopt($ch,CURLOPT_SSLCERT, $this->SSLCERT_PATH);
      //默认格式为PEM,可以注释
      curl_setopt($ch,CURLOPT_SSLKEYTYPE,‘PEM‘);
      curl_setopt($ch,CURLOPT_SSLKEY, $this->SSLKEY_PATH);
      //post提交方式
      curl_setopt($ch,CURLOPT_POST, true);
      curl_setopt($ch,CURLOPT_POSTFIELDS,$xml);
      $data = curl_exec($ch);
      //返回结果
      if($data){
      curl_close($ch);
      return $data;
      } else {
      $error = curl_errno($ch);
      echo "curl出错,错误码:$error"."<br>";
      curl_close($ch);
      return false;
      }
      }
      }

微信支付

上一篇:Redis开发运维实践开发设计规范之数据异常处理


下一篇:关于微信扫码登录的2种解决办法thinkphp5