您现在的位置是: 网站首页>文章详情 文章详情

微信企业付款到银行卡

Heartless Wolf 1560127924 php 13818 收藏

简介 PHP(外文名:PHP: Hypertext Preprocessor,中文名:“超文本预处理器”)是一种通用开源脚本语言。语法吸收了C语言、Java和Perl的特点,利于学习,使用广泛,主要适用于Web开发领域。PHP 独特的语法混合了C、Java、Perl以及PHP自创的语法。它可以比CGI或者Perl更快速地执行动态网页。用PHP做出的动态页面与其他的编程语言相比,PHP是将程序嵌入到HTML(标准通用标记语言下的一个应用)文档中去执行,执行效率比完全生成HTML标记的CGI要高许多;

<?php
defined('IN_IA') || exit('Access Denied');
class WxPay
{
   protected $wxpay;
   protected $cert;
   protected $mch_id;
   public function __construct($pay_type = '')
   {
       global $_W;
       $wechat = $_W['we7_wmall']['config']['payment']['wechat'];
       $wechat = $wechat[$wechat['type']];
       $pay_type = ((empty($pay_type) ? 'wap' : $pay_type));
       $this->mch_id = '123';
       if ($pay_type == 'h5app')
       {
           $wechat = $_W['we7_wmall']['config']['payment']['app_wechat'];
       }
       else if ($pay_type == 'wxapp')
       {
           $payment = get_plugin_config('wxapp.payment');
           $wechat = $payment['wechat'];
           $wechat = $wechat[$wechat['type']];
       }
       else if ($pay_type == 'H5')
       {
           $wechat = $_W['we7_wmall']['config']['payment']['h5_wechat'];
       }
       $this->pay_type = $pay_type;
       $this->wxpay = array('appid' => $wechat['appid'], 'mch_id' => $wechat['mchid'], 'sub_mch_id' => $wechat['sub_mch_id'], 'key' => $wechat['apikey']);
       $this->cert = array('apiclient_cert' => $wechat['apiclient_cert'], 'apiclient_key' => $wechat['apiclient_key'], 'rootca' => $wechat['rootca']);
   }
   public function array2url($params, $force = false)
   {
       $str = '';
       foreach ($params as $key => $val )
       {
           if ($force && empty($val))
           {
               continue;
           }
           $str .= $key . '=' . $val . '&';
       }
       $str = trim($str, '&');
       return $str;
   }
   public function bulidSign($params)
   {
       unset($params['sign']);
       ksort($params);
       $string = $this->array2url($params, true);
       $string = $string . '&key=' . $this->wxpay['key'];
       $string = md5($string);
       $result = strtoupper($string);
       return $result;
   }
   public function parseResult($result, $is_check_sign = false)
   {
       if (substr($result, 0, 5) != '<xml>')
       {
           return $result;
       }
       $result = json_decode(json_encode(isimplexml_load_string($result, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
       if (!(is_array($result)))
       {
           return error(-1, 'xml结构错误');
       }
       if (isset($result['return_code']) && ($result['return_code'] != 'SUCCESS'))
       {
           $msg = ((empty($result['return_msg']) ? $result['err_code_des'] : $result['return_msg']));
           return error(-1, $msg);
       }
       if ($is_check_sign && ($this->bulidsign($result) != $result['sign']))
       {
           return error(-1, '验证签名出错');
       }
       return $result;
   }
   public function httpWxurl($url, $params, $extra = array())
   {
       load()->func('communication');

       $xml = array2xml($params);


       $response = ihttp_request($url, $xml, $extra);
       if (is_error($response))
       {
           return $response;
       }
       $result = $this->parseResult($response['content']);
       return $result;
   }
   public function shortUrl($url)
   {
       $params = array('appid' => $this->wxpay['appid'], 'mch_id' => $this->wxpay['mch_id'], 'long_url' => $url, 'nonce_str' => random(32));
       $params['sign'] = $this->bulidSign($params);
       $result = $this->httpWxurl('https://api.mch.weixin.qq.com/tools/shorturl', $params);
       if (is_error($result))
       {
           return $result;
       }
       return $result['short_url'];
   }
   public function checkCert()
   {
       if (empty($this->cert['apiclient_key']) || empty($this->cert['apiclient_cert']))
       {
           return error(-1, '支付证书不完整');
       }
       return true;
   }
   public function mktTransfers($params, $check_type = 'FORCE_CHECK')
   {
       global $_W;
       $status = $this->checkCert();
       if (is_error($status))
       {
           return $status;
       }
       $params_origin = $params;
       $elements = array('openid', 'amount', 'partner_trade_no', 're_user_name', 'desc');
       $params = array_elements($elements, $params);
       if (empty($params['openid']))
       {
           return error(-1, '粉丝信息错误,你可以撤销本次提现,让体现人重新设置提现账户,再次申请提现来解决此问题');
       }
       if ((($check_type == 'FORCE_CHECK') || ($check_type == 'OPTION_CHECK')) && empty($params['re_user_name']))
       {
           return error(-1, '收款人真实姓名不能为空');
       }
       if (empty($params['amount']))
       {
           return error(-1, '打款金额不能为空');
       }
       if (empty($params['partner_trade_no']))
       {
           return error(-1, '商户订单号不能为空');
       }
       if (empty($params['desc']))
       {
           return error(-1, '付款描述信息不能为空');
       }
       $params['check_name'] = $check_type;
       $params['mch_appid'] = $this->wxpay['appid'];
       $params['mchid'] = $this->wxpay['mch_id'];
       $params['nonce_str'] = random(32);
       $params['spbill_create_ip'] = CLIENT_IP;
       $params['sign'] = $this->bulidSign($params);
       $extra = array(CURLOPT_SSLCERT => MODULE_ROOT . '/cert/' . $this->cert['apiclient_cert'] . '/apiclient_cert.pem', CURLOPT_SSLKEY => MODULE_ROOT . '/cert/' . $this->cert['apiclient_key'] . '/apiclient_key.pem', CURLOPT_CAINFO => MODULE_ROOT . '/cert/' . $this->cert['rootca'] . '/rootca.pem');
       $result = $this->httpWxurl('https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers', $params, $extra);



       if (is_error($result))
       {
           return $result;
       }
       if ($result['result_code'] != 'SUCCESS')
       {
           return error(-1, $result['err_code'] . ':' . $result['err_code_des']);
       }
       return true;
   }



   //数组转xml
   public function arrayToXml($arr){
       $xml = "<xml>";
       foreach ($arr as $key=>$val){
           if (is_numeric($val)){
               $xml.="<".$key.">".$val."</".$key.">";
           }else{
               $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
           }
       }
       $xml.="</xml>";
       return $xml;
   }






   public function mktTransfersRepeat($params)
   {
       $result = $this->mktTransfers($params);
       return $result;
   }
   public function check_bank_code($bank){
       $arr=array('1002'=>'工商银行','1005'=>'农业银行','1026'=>'中国银行','1003'=>'建设银行',
           '1001'=>'招商银行','1066'=>'邮政储蓄','1020'=>'交通银行','1004'=>'浦发银行','1006'=>'民生银行',
           '1009'=>'兴业银行','1010'=>'平安银行','1021'=>'中信银行', '1025'=>'华夏银行','1027'=>'广发银行',
           '1022'=>'光大银行','4836'=>'北京银行','1056'=>'宁波银行');
       if(in_array($bank,$arr)){
           return array_flip($arr)[$bank];
       }else{
           return false;
       }
   }



   /*获取公钥*/
   public function RasKey($datainfo="")
   {
       $data=[
           //商户号
           "mch_id"=>$this->mch_id,
           //随机字符串
           "nonce_str"=>random(32),
           //加密方式我是MD5
           "sign_type"=>"MD5",
       ];
       //微信签名
       $data["sign"]=$this->bulidSign($data);
       //提交到的URL
       $url="https://fraud.mch.weixin.qq.com/risk/getpublickey";
       //转换成XML格式POST到服务器
       $extra = array(CURLOPT_SSLCERT => MODULE_ROOT . '/cert/cert/apiclient_cert.pem',
           CURLOPT_SSLKEY => MODULE_ROOT . '/cert/cert/apiclient_key.pem');

       $backxml=$this->httpWxurl($url,$data,$extra);
       //保存成PEM文件
       file_put_contents(MODULE_ROOT . '/cert/cert/pub_key.pem',$backxml['pub_key']);
       return MODULE_ROOT . '/cert/cert/pub_key.pem';
   }

   /**
    * 公钥加密,银行卡号和姓名需要RSA算法加密
    * @param string $data    需要加密的字符串,银行卡/姓名
    * @return null|string    加密后的字符串
    */
   private function publicEncrypt($data,$pubkey)
   {
       // 进行加密
       $pubkey = openssl_pkey_get_public(file_get_contents($pubkey));
       $encrypt_data = '';
       $encrypted = '';
       $r = openssl_public_encrypt($data,$encrypt_data,$pubkey,OPENSSL_PKCS1_OAEP_PADDING);

       if($r){//加密成功,返回base64编码的字符串
           return base64_encode($encrypted.$encrypt_data);
       }else{
           return false;
       }
   }

   /**
    * 公钥解密
    *
    * @param $data 加密的数据
    * @param $b 加密的数据是否为符合url安全的字符串
    *
    */
   public function publicDecrypt($encrypted, $pu_key ){
       $crypto = '';
       foreach (str_split($this->urlsafe_b64decode($encrypted, true), 128) as $chunk) {
           openssl_public_decrypt($chunk,$decryptData,$pu_key,OPENSSL_PKCS1_PADDING);
           $crypto .= $decryptData;
       }
       return $crypto;
   }



   /**
    * base64解密
    *
    * @param $string 加密的数据
    * @param $b 加密的数据是否为符合url安全的字符串
    */
   public function urlsafe_b64decode($string, $b = true) {
       if (!$b) return base64_decode($string);
       $data = str_replace(array('-','_'),array('+','/'),$string);
       $mod4 = strlen($data) % 4;
       if ($mod4) {
           $data .= substr('====', $mod4);
       }
       return base64_decode($data);
   }




   //微信零钱提现到银行卡
   public function bankTransfers($params)
   {
       global $_W;
       $params_origin = $params;
       $bank_code=$this->check_bank_code($params['bank_code']);
       if (empty($params['enc_bank_no']))
       {
           return error(-1, '收款方银行卡号不能为空');
       }
       if ( empty($params['enc_true_name']))
       {
           return error(-1, '收款人姓名不能为空');
       }
       if ( empty($params['bank_code']))
       {
           return error(-1, '收款方开户行不能为空');
       }elseif(!$bank_code){
           return error(-1, '开户行不存在,请重新确定');
       }
       if (empty($params['amount']))
       {
           return error(-1, '打款金额不能为空');
       }
       if (empty($params['partner_trade_no']))
       {
           return error(-1, '商户订单号不能为空');
       }
       if (empty($params['desc']))
       {
           return error(-1, '付款描述信息不能为空');
       }
       //$miyao = $this->RasKey();

       $pubkey=MODULE_ROOT . '/cert/cert/pub_key.pem';

       $params['bank_code'] = $bank_code;
       $params['mch_id'] = $this->mch_id;
       $params['nonce_str'] = $this->random(32);

       $data['amount'] = $params['amount'];
       $data['bank_code'] = $params['bank_code'];
       $data['desc'] = $params['desc'];
       $data['enc_bank_no'] = $this->publicEncrypt($params['enc_bank_no'],$pubkey);
       $data['enc_true_name'] = $this->publicEncrypt($params['enc_true_name'],$pubkey);
       $data['mch_id'] = $this->mch_id;
       $data['nonce_str'] = $params['nonce_str'];
       $data['partner_trade_no'] = $params['partner_trade_no'];
       $sign = $this->bulidSign($data);

       $dataXML="<xml>
       <amount>".$data['amount']."</amount>
       <bank_code>".$data['bank_code']."</bank_code>
       <desc>".$data['desc']."</desc>
       <enc_bank_no>".$data['enc_bank_no']."</enc_bank_no>
       <enc_true_name>".$data['enc_true_name']."</enc_true_name>
       <mch_id>".$data['mch_id']."</mch_id>
       <nonce_str>".$data['nonce_str']."</nonce_str>
       <partner_trade_no>".$data['partner_trade_no']."</partner_trade_no>
       <sign>".$sign."</sign>
       </xml>";



       $url = 'https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank';
       $ret =  $this->httpsPost($url,$dataXML,true);
       if($ret['return_code'] == 'SUCCESS' && $ret['result_code'] == 'SUCCESS' && $ret['err_code'] == 'SUCCESS'){
           return $ret['payment_no'];
       }else{
           return error(-1, $ret['err_code_des']);
           //return error(-1, $ret['err_code'] . ':' . $ret['err_code_des']);
       }
   }

   /**
    * 发起POST网络请求
    * @params string $url : 请求的url链接地址
    * @params string $data : 数据包
    * @params bool $ssl : 是否加载证书
    * return array $result : 返回的数据结果
    */
   private function httpsPost($url,$data,$ssl = false)
   {
       $ch = curl_init ();
       curl_setopt ( $ch, CURLOPT_URL, $url );
       curl_setopt ( $ch, CURLOPT_CUSTOMREQUEST, "POST" );
       curl_setopt ( $ch, CURLOPT_SSL_VERIFYPEER, FALSE );
       curl_setopt ( $ch, CURLOPT_SSL_VERIFYHOST, FALSE );
       if($ssl) {
           curl_setopt ( $ch,CURLOPT_SSLCERT,MODULE_ROOT . '/cert/cert/apiclient_cert.pem');
           curl_setopt ( $ch,CURLOPT_SSLKEY,MODULE_ROOT . '/cert/cert/apiclient_key.pem');
       }
       curl_setopt ( $ch, CURLOPT_FOLLOWLOCATION, 1 );
       curl_setopt ( $ch, CURLOPT_AUTOREFERER, 1 );
       curl_setopt ( $ch, CURLOPT_POSTFIELDS, $data );
       curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true );
       $result = curl_exec($ch);
       if (curl_errno($ch)) {
           return 'Errno: '.curl_error($ch);
       }
       curl_close($ch);
       return $this->xmlToArray($result);
   }

   /*
   * 将xml转换成数组
   * @params xml $xml : xml数据
   * return array $data : 返回数组
   */
   private function xmlToArray($xml)
   {
       //禁止引用外部xml实体
       libxml_disable_entity_loader(true);
       $xmlstring = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
       $val = json_decode(json_encode($xmlstring),true);
       return $val;
   }

   //对参数排序,生成MD5加密签名
   private function getParam($paramArray, $isencode=false)
   {
       $paramStr = '';
       ksort($paramArray);
       $i = 0;
       foreach ($paramArray as $key => $value)
       {
           if ($key == 'Signature'){
               continue;
           }
           if ($i == 0){
               $paramStr .= '';
           }else{
               $paramStr .= '&';
           }
           $paramStr .= $key . '=' . ($isencode?urlencode($value):$value);
           ++$i;
       }
       $stringSignTemp=$paramStr."&key=".$this->key;
       $sign=strtoupper(md5($stringSignTemp));
       return $sign;
   }

   /**
    *  随机字符串
    *  @param int $length 长度
    *  @param string $type 类型
    *  @param int $convert 转换大小写 1大写 0小写
    *  @return string
    */
   private function random($length = 10, $type='letter', $convert=false)
   {
       $config = array(
           'number' => '1234567890',
           'letter'=>'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
           'string'=>'abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ23456789',
           'all'=>'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
       );

       if (!isset($config[$type])) $type = 'letter';
       $string  = $config[$type];

       $code = '';
       $strlen = strlen($string) -1;
       for ($i = 0; $i < $length; $i++ ){
           $code .= $string{mt_rand(0, $strlen)};
       }
       if (!empty($convert)) {
           $code = ($convert > 0)?strtoupper($code) : strtolower($code);
       }
       return $code;
   }


   public function payRefund_build($params)
   {
       global $_W;
       $status = $this->checkCert();
       if (is_error($status))
       {
           return $status;
       }
       $elements = array('total_fee', 'refund_fee', 'out_trade_no', 'out_refund_no');
       $params = array_elements($elements, $params);
       if (empty($params['total_fee']))
       {
           return error(-1, '订单总金额不能为空');
       }
       if (empty($params['refund_fee']))
       {
           return error(-1, '退款金额不能为空');
       }
       if (empty($params['out_trade_no']))
       {
           return error(-1, '商户订单号不能为空');
       }
       if (empty($params['out_refund_no']))
       {
           return error(-1, '商户退款单号不能为空');
       }
       $params['appid'] = $this->wxpay['appid'];
       $params['mch_id'] = $this->wxpay['mch_id'];
       $params['sub_mch_id'] = $this->wxpay['sub_mch_id'];
       $params['op_user_id'] = $this->wxpay['mch_id'];
       $params['nonce_str'] = random(32);
       $params['sign'] = $this->bulidSign($params);
       $extra = array(CURLOPT_SSLCERT => MODULE_ROOT . '/cert/' . $this->cert['apiclient_cert'] . '/apiclient_cert.pem', CURLOPT_SSLKEY => MODULE_ROOT . '/cert/' . $this->cert['apiclient_key'] . '/apiclient_key.pem', CURLOPT_CAINFO => MODULE_ROOT . '/cert/' . $this->cert['rootca'] . '/rootca.pem');
       $result = $this->httpWxurl('https://api.mch.weixin.qq.com/secapi/pay/refund', $params, $extra);
       if (is_error($result))
       {
           if ($result['message'] == 'certificate not match')
           {
               $order_channel = order_channel($this->pay_type);
               return error(-1, '发起退款申请失败:证书文件不匹配。该订单下单渠道为' . $order_channel . ',请检查' . $order_channel . '支付证书是否正确配置。');
           }
           return error(-1, '发起退款申请失败:' . $result['message']);
       }
       if ($result['result_code'] != 'SUCCESS')
       {
           return error(-10, '发起退款申请失败.' . $result['err_code'] . ':' . $result['err_code_des']);
       }
       return $result;
   }



   public function payRefund_query($params)
   {
       $elements = array('out_refund_no');
       $params = array_elements($elements, $params);
       if (empty($params['out_refund_no']))
       {
           return error(-1, '商户退款单号不能为空');
       }
       $params['appid'] = $this->wxpay['appid'];
       $params['mch_id'] = $this->wxpay['mch_id'];
       $params['sub_mch_id'] = $this->wxpay['sub_mch_id'];
       $params['nonce_str'] = random(32);
       $params['sign'] = $this->bulidSign($params);
       $result = $this->httpWxurl('https://api.mch.weixin.qq.com/pay/refundquery', $params);
       if (is_error($result))
       {
           return error(-1, '查询微信退款进度失败.' . $result['message']);
       }
       if ($result['result_code'] != 'SUCCESS')
       {
           return error(-1, '查询微信退款进度失败.' . $result['err_code'] . ':' . $result['err_code_des']);
       }
       return $result;
   }
   public function payRefund_status()
   {
       $wechat_status = array( 'SUCCESS' => array('text' => '成功', 'value' => 3), 'FAIL' => array('text' => '失败', 'value' => 4), 'PROCESSING' => array('text' => '处理中', 'value' => 2), 'NOTSURE' => array('text' => '未确定,需要商户原退款单号重新发起', 'value' => 5) );
       return $wechat_status;
   }
}
?>


文章评论

    点击加载更多评论

我的名片

网名:Hello World

职业:PHP开发

现居:福建省-福州市

Email:565554856@qq.com

  • 图片信息

站点信息

  • 建站时间:2019-04-20
  • 文章总计:69条
  • 笔记总计:4条
  • 文章评论:0条
  • 笔记评论:0条
  • 当前访问IP:3.144.91.90