PHP微信商户平台打款到银行卡

1 在商户平台开通企业打款到银行卡,添加服务器ip

2 获取公钥,格式为PKCS#1 转PKCS#8

PKCS#1 转 PKCS#8:
        openssl rsa -RSAPublicKey_in -in <filename> -pubout
        PKCS#8 转 PKCS#1:
        openssl rsa -pubin -in <filename> -RSAPublicKey_out 
     *  openssl rsa -RSAPublicKey_in -in /www/wwwroot/xx/extend/wxcert/apiclient_public_rsa.pem -pubout

3 拿到pkcs8的公钥放到public.pem文件

4 类文件

<?php

declare (strict_types = 1);

namespace app\services\tool;

use app\services\BaseServices;
use think\facade\Db;

/**
 * 微信零钱打款到银行卡
 * Class JobServices
 * @package app\services\tool
 */
class WxBankServices extends BaseServices {
    
    /**
     *  PKCS#1 转 PKCS#8:
        openssl rsa -RSAPublicKey_in -in <filename> -pubout
        PKCS#8 转 PKCS#1:
        openssl rsa -pubin -in <filename> -RSAPublicKey_out 
     *  openssl rsa -RSAPublicKey_in -in /www/wwwroot/xx/extend/wxcert/apiclient_public_rsa.pem -pubout
     */
    
    protected $publicKeyPath;  //  public key 路径
    protected $publicKeyRsaPath;  //  public rsa key 路径
    protected $apiKey;    //  密钥
    protected $apiclientCert;    //  公钥
    protected $apiclientKey;    //  私钥
    protected $mchId;    //  商户号
    
    public function __construct()
    {
        $this->publicKeyPath = "/www/wwwroot/xx/extend/wxcert/apiclient_public.pem";
        $this->publicKeyRsaPath = "/www/wwwroot/xx/extend/wxcert/apiclient_public_rsa.pem";
        $this->apiclientCert = "/www/wwwroot/xx/extend/wxcert/apiclient_cert.pem";
        $this->apiclientKey = "/www/wwwroot/xx/extend/wxcert/apiclient_key.pem";
        $this->mchId = sysconfig('pay','wx_mach_id');
        $this->apiKey = sysconfig('pay', 'wx_key');
        $this->accessKeyId = sysconfig('sms','alisms_access_key_id');
        $this->accessKeySecret = sysconfig('sms','alisms_access_key_secret');
    }

    
    /*
     * 企业付款到银行卡接口
     * @params string $out_trade_no : 商户订单号
     * @params int $amount : 付款金额,单位分 只能是整数
     * @params string $enc_bank_no : 收款方银行卡号
     * @params string $enc_true_name : 收款方用户名
     * @params string $bank_name : 收款方开户行,根据银行名称获取银行编号bank_code
     * @params string $desc : 付款备注
     * return string $payment_no :支付成功的订单号
     */
    public function payBank( $enc_bank_no , $amount , $out_trade_no , $bank_name , $enc_true_name , $desc="" ) {
        $amount = (int)$amount * 100; 
        $data['amount'] = $amount;
        $data['bank_code'] = $this->getBankCode($bank_name);
        $data['desc'] = $desc;
        $data['enc_bank_no'] = $this->publicEncrypt($enc_bank_no);
        $data['enc_true_name'] = $this->publicEncrypt($enc_true_name);
        $data['mch_id'] = $this->mchId;
        $data['nonce_str'] = md5( (string)time() );
        $data['partner_trade_no'] = $out_trade_no;
        $sign = $this->getParam( $data );
        $data['sign'] = $sign;

        $dataXML = $this->arraytoxml($data);
        
        $url = 'https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank';
        
        $ret = $this->httpsPost($url, $dataXML, true);

//        echo "<pre>";var_dump($ret);die;

        if ($ret['return_code'] == 'SUCCESS' && $ret['result_code'] == 'SUCCESS' && $ret['err_code'] == 'SUCCESS') {
            return array( "code"=>1 , "data"=>$ret['payment_no'] );
        } else {
            return array( "code"=>0 , "data"=>$ret );
        }
    }
    
    /*
     * 获取公钥,格式为PKCS#1 转PKCS#8
     * openssl rsa -RSAPublicKey_in -in pubkey.pem -pubout > newpubkey.pem
     * */
    public function get_pub_key() {

        $data['mch_id'] = $this->mchId;
        $data['nonce_str'] = md5( (string)time() );
        $sign = $this->getParam($data);
        $data['sign'] = $sign;
        
        $dataXML = $this->arraytoxml($data);
       
        $url = 'https://fraud.mch.weixin.qq.com/risk/getpublickey';
        $ret = $this->httpsPost($url, $dataXML, true);
        
        if ($ret['return_code'] == 'SUCCESS' && isset($ret['pub_key'])) {
            file_put_contents( $this->publicKeyRsaPath , $ret['pub_key']);
            return $ret['pub_key'];
        } else {
            return null;
        }
    }
    
    /**
     * 公钥加密,银行卡号和姓名需要RSA算法加密
     * @param string $data  需要加密的字符串,银行卡/姓名
     * @return null|string  加密后的字符串
     */
    public function publicEncrypt($data) {
        $public_key = file_get_contents( $this->publicKeyPath );
        $encrypt_data = '';
        
        $r = openssl_public_encrypt($data, $encrypted, $public_key, OPENSSL_PKCS1_OAEP_PADDING);
        $encrypted = base64_encode($encrypted);
        return $encrypted;
        
//        $public_key = "-----BEGIN PUBLIC KEY-----\n" . wordwrap($public_key, 64, "\n", true) . "\n-----END PUBLIC KEY-----";
//        $public_key = "-----BEGIN PUBLIC KEY-----\n" . $public_key . "\n-----END PUBLIC KEY-----";
//        $public_key = openssl_pkey_get_public( $public_key );
//        $r = openssl_public_encrypt( $data, $encrypted, $public_key );
//        echo "<pre>";var_dump(  $r , $encrypted  );die;
    }

    /**
     * [arraytoxml 将数组转换成xml格式(简单方法):]
     * @param [type] $data [数组]
     * @return [type]  [array 转 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;
    }

    /*
     * 发起POST网络请求
     * @params string $url : 请求的url链接地址
     * @params string $data : 数据包
     * @params bool $ssl : 是否加载证书
     * return array $result : 返回的数据结果
     */

    public 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, $this->apiclientCert );
            curl_setopt($ch, CURLOPT_SSLKEY, $this->apiclientKey );
        }
        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);
    }

    public 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->apiKey;
        $sign = strtoupper(md5($stringSignTemp));
        return $sign;
    }

    /*
     * 将xml转换成数组
     * @params xml $xml : xml数据
     * return array $data : 返回数组
     */
    public 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;
    }

    /*
     * 查询付款到银行卡状态
     * @params string $out_trade_no : 商户订单号
     * return array $ret:查询状态
     */
    public function queryBank($out_trade_no) {
        $data['mch_id'] = $this->mchId;
        $data['nonce_str'] = md5( (string)time() );
        $data['partner_trade_no'] = $out_trade_no;
        $sign = $this->getParam($data);
        $data['sign'] = $sign;
        
        $dataXML = $this->arraytoxml($data);
        
        $url = 'https://api.mch.weixin.qq.com/mmpaysptrans/query_bank';
        $ret = $this->httpsPost($url, $dataXML, true);

//        echo "<pre>";var_dump($ret);die;
        
        if ($ret['return_code'] == 'SUCCESS' && $ret['result_code'] == 'SUCCESS' && $ret['err_code'] == 'SUCCESS') {
            return $ret;
            return array( "code"=>1 , "data"=>$ret );
        } else {
            return array( "code"=>0 , "data"=>$ret );
        }
    }
    
    
    /**
     * @param $string
     * @return string|string[]
     * url安全解码
     */
    public static function url_safe_decode($string)
    {
        $data = str_replace(['-','_'], ['+','/'], $string);
        $mod4 = strlen($data) % 4;
        if ($mod4)
        {
            $data .= substr('====', $mod4);
        }
        return $data;
    }

    /**
     * @param $string
     * @return string|string[]
     * url安全转码
     */
    public static function url_safe_encode($string)
    {
        return str_replace(['+','/','='], ['-','_',''], $string);
    }
    
    
    /*
     * 银行编号列表,详情参考:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=25_4
     * @params string $bank_name : 银行名称,4个汉字
     * return int $bank_code : 银行编码
     */
    public function getBankCode( $bank_name ) {
        
        $BankArr = [];
        $BankArr["工商银行"] = 1002;
        $BankArr["农业银行"] = 1005;
        $BankArr["建设银行"] = 1003;
        $BankArr["中国银行"] = 1026;
        $BankArr["交通银行"] = 1020;
        $BankArr["招商银行"] = 1001;
        $BankArr["邮储银行"] = 1066;
        $BankArr["民生银行"] = 1006;
        $BankArr["平安银行"] = 1010;
        $BankArr["中信银行"] = 1021;
        $BankArr["浦发银行"] = 1004;
        $BankArr["兴业银行"] = 1009;
        $BankArr["光大银行"] = 1022;
        $BankArr["广发银行"] = 1027;
        $BankArr["华夏银行"] = 1025;
        $BankArr["上海银行"] = 1024;
        $BankArr["宁波银行"] = 1056;
        $BankArr["北京银行"] = 4836;
        $BankArr["南京银行"] = 1054;
        $BankArr["长子县融汇村镇银行"] = 4755;
        $BankArr["长沙银行"] = 4216;
        $BankArr["浙江泰隆商业银行"] = 4051;
        $BankArr["中原银行"] = 4753;
        $BankArr["企业银行(中国)"] = 4761;
        $BankArr["顺德农商银行"] = 4036;
        $BankArr["衡水银行"] = 4752;
        $BankArr["长治银行"] = 4756;
        $BankArr["大同银行"] =  4767;
        $BankArr["河南省农村信用社"] = 4115;
        $BankArr["宁夏黄河农村商业银行"] = 4150;
        $BankArr["山西省农村信用社"] = 4156;
        $BankArr["安徽省农村信用社"] = 4166;
        $BankArr["甘肃省农村信用社"] = 4157;
        $BankArr["天津农村商业银行"] = 4153;
        $BankArr["广西壮族自治区农村信用社"] = 4113;
        $BankArr["陕西省农村信用社"] = 4108;
        $BankArr["深圳农村商业银行"] = 4076;
        $BankArr["宁波鄞州农村商业银行"] = 4052;
        $BankArr["浙江省农村信用社联合社"] = 4764;
        $BankArr["江苏省农村信用社联合社"] = 4217;
        $BankArr["江苏紫金农村商业银行股份有限公司"] = 4072;
        $BankArr["北京中关村银行股份有限公司"] = 4769;
        $BankArr["星展银行(中国)有限公司"] = 4778;
        $BankArr["枣庄银行股份有限公司"] = 4766;
        $BankArr["海口联合农村商业银行股份有限公司"] = 4758;
        $BankArr["南洋商业银行(中国)有限公司"] = 4763;
        
        if( isset( $BankArr[ $bank_name ] ) ) {
            return $BankArr[ $bank_name ];
        }else{
            return 0;
        }
    }
    

}

5 调用

public function t1() {
        $WxBankServices = app()->make( WxBankServices::class );
        
        //  先生成证书
//        $ret = $WxBankServices->get_pub_key();
//        echo "<pre>";var_dump(   $ret   );die;
        
        //  查询
        $out_trade_no1 = "202206";
        $out_trade_no2 = "202206";
        $ret1 = $WxBankServices->queryBank( $out_trade_no1 );
        $ret2 = $WxBankServices->queryBank( $out_trade_no2 );
        echo "<pre>";var_dump(   $ret1,$ret2   );die;
        
        //  转账
        $enc_bank_no = "622";
        $bank_name = "建设银行";
        $enc_true_name = "aa";
        $desc = "测试微信商户打款到银行卡";
        $amount = 20;
        $out_trade_no = date('Ymdhis', time()) . rand(100000, 999999);
        $ret = $WxBankServices->payBank( $enc_bank_no , $amount , $out_trade_no , $bank_name , $enc_true_name , $desc );
        
        echo "<pre>";var_dump(   $ret   );die;
    }

6 查询案例

<pre>array(16) {
  ["return_code"]=>
  string(7) "SUCCESS"
  ["return_msg"]=>
  string(12) "查询成功"
  ["result_code"]=>
  string(7) "SUCCESS"
  ["err_code"]=>
  string(7) "SUCCESS"
  ["err_code_des"]=>
  string(12) "查询成功"
  ["mch_id"]=>
  string(10) "1618"
  ["partner_trade_no"]=>
  string(20) "20220"
  ["payment_no"]=>
  string(35) "1000138826773"
  ["bank_no_md5"]=>
  string(32) "24745DC562E013"
  ["true_name_md5"]=>
  string(32) "68EC6B22123C0E"
  ["amount"]=>
  string(4) "2000"
  ["status"]=>
  string(10) "PROCESSING"
  ["cmms_amt"]=>
  string(3) "100"
  ["create_time"]=>
  string(19) "2022-06-02 15:42:16"
  ["pay_succ_time"]=>
  array(0) {
  }
  ["reason"]=>
  array(0) {
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值