PHP实现微信商户平台打款到银行卡功能
时间:2023-11-01 23:02:07浏览:3709
这种对接功能最重要和最基础的东西是什么?官方接口!
https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay_yhk.php?chapter=25_2
1、在微信商户平台开通企业打款到银行卡,添加服务器IP
2、在微信商户平台下载软件生成证书,得到apiclient_cert.pem和apiclient_key.pem,本处为了方便区别,假定商户号为:1600112233
证书文件分别改名为1600112233_apiclient_cert.pem和1600112233_apiclient_key.pem,都放到/www/wwwroot/Demo/data/Cert/目录下面
3、下面的类保存到Pay.php
class WxPayToBank {
/*
使用说明:
第一步:调用
$obj = new WxPayToBank();
$Re = $obj->get_pub_key();
print_r($Re);
生成1600112233_apiclient_public_rsa.pem
第二步:
openssl rsa -RSAPublicKey_in -in /www/wwwroot/Demo/data/Cert/1600112233_apiclient_public_rsa.pem -pubout
生成1600112233_apiclient_public.pem
*/
/**
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/Demo/data/Cert/1600112233_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/Demo/data/Cert/1600112233_apiclient_public.pem";
$this->publicKeyRsaPath = "/www/wwwroot/Demo/data/Cert/1600112233_apiclient_public_rsa.pem";
$this->apiclientCert = "/www/wwwroot/Demo/data/Cert/1600112233_apiclient_cert.pem";
$this->apiclientKey = "/www/wwwroot/Demo/data/Cert/1600112233_apiclient_key.pem";
$this->mchId = '1600112233';
$this->apiKey = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
}
/*
* 企业付款到银行卡接口
* @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 = floatval($amount) * 100;
$data['amount'] = $amount;
$data['bank_code'] = $this->getBankCode($bank_name);
if($desc!=""){
$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);
//print_r($dataXML);
$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 );
} 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;
}
}
}
4、调用上面的类,然后用这点代码先生成1600112233_apiclient_public_rsa.pem
$obj = new WxPayToBank();
$Re = $obj->get_pub_key();
print_r($Re);
5、在linux的ssh下用下面的命令生成出1600112233_apiclient_public.pem,需要手动复制去保存到/www/wwwroot/Demo/data/Cert/1600112233_apiclient_public.pem,或加上 > 1600112233_apiclient_public.pem
openssl rsa -RSAPublicKey_in -in /www/wwwroot/Demo/data/Cert/1600112233_apiclient_public_rsa.pem -pubout
6、调用类文件之后用下面的代码就可以发起向银行卡付款
//支付到银行卡
$obj = new WxPayToBank();
$out_trade_no = "OToB".date('YmdHis'); //商户付款单号
$enc_bank_no = "62220231000XXXXXXXX"; //收款方银行卡号
$enc_true_name = "XXX"; //收款方用户名
$bank_name = "工商银行"; //收款方开户行
$amount = 2; //付款金额
$desc = ''; //付款说明
$res = $obj->payBank( $enc_bank_no , $amount , $out_trade_no , $bank_name , $enc_true_name , $desc);
print_r($res);
7、实测这个执行比较慢,几个小时都没有结果,调用类后用下面的代码就可以查询到结果
$obj = new WxPayToBank();
$res = $obj->queryBank("OToB202311011xxx"); //之前发起付款到银行卡的订单号
print_r($res);
来源连接:https://blog.csdn.net/lorraine_40t/article/details/125102174
https://www.cnblogs.com/bluealine/p/11015081.html
上一篇:长图切割后前端显示有空行的解决办法
下一篇:mysql的expire_logs_days不重启怎么设置有效
- Linux文章
- PHP文章
- 随机文章
- Linux中的find(-atime...
- mysql的expire_logs_...
- PHP 扩展 libsodium s...
- Linux下利用find和cp实现筛...
- 使用mysqldump命令导出备份m...
- Linux系统如何设置开机自动运行脚...
- Linux上实现秒级执行的定时任务
- shell echo -e 颜色输出
- Linux下通过grep查找指定的进...
- 解决执行脚本报syntax erro...
发表评论
昵称: 验证码: