微信转账到零钱有额度上限,而且受风控影响很可能每日付款上限都会有较大影响。
因此,考虑打款到银行卡。
类型/对比 | 优势 | 缺点 |
---|---|---|
付款到零钱 | 速度快,免手续费 | 每日额度较低 |
付款到银行卡 | 转账额度较高 | 收取手续费,最低1元,25块封顶。转账周期T+1到T+3,需要用API查询最新进度 |
官方文档
开通条件:
① 满足官方基本要求
② 进入商户中心开通 【付款到个人银行卡】 功能,需要启动API接口功能,另外需要取消转账银行卡限制,否则无法转账给其他银行卡。
步骤:
① 获取 商户ID、密钥,通过接口获取公钥证书,PHP端需要证书公钥格式转换为PKCS8的
② POST请求附带证书,敏感字段公钥加密
③ 请求转账后需要用接口请求获取付款状态
核心代码
// 根据商户订单号查询银行卡转账状态 PROCESSING 处理中 SUCCESS 付款成功 FAILED 付款失败,需要替换付款单号 (partner_trade_no) 重新发起付款 BANK_FAIL 银行退票,订单状态由付款成功流转至退票,退票时付款金额和手续费会自动退还
public function queryBank($partner_trade_no) {
$url = 'https://api.mch.weixin.qq.com/mmpaysptrans/query_bank';
$str = '<xml>
<mch_id>%s</mch_id>
<partner_trade_no>%s</partner_trade_no>
<nonce_str>%s</nonce_str>
<sign>%s</sign>
</xml>';
$params['mch_id'] = $this->mchid;
$params['partner_trade_no'] = $partner_trade_no;
$params['nonce_str'] = random(32);
ksort($params);
$string = $this->ToUrlParams($params);
$string .= "&key={$this->mchkey}";
$sign = strtoupper(md5($string));
$params['sign'] = $sign;
$data = sprintf(
$str,
$params['mch_id'],
$params['partner_trade_no'],
$params['nonce_str'],
$params['sign']
);
$flag = $this->curl_post_ssl($url, $data, $msg, 30, <span style="font-family: "Helvetica Neue", Helvetica, "PingFang SC", 微软雅黑, Tahoma, Arial, sans-serif;">MY_ROOT . '/include/auth/'</span><span style="font-family: "Helvetica Neue", Helvetica, "PingFang SC", 微软雅黑, Tahoma, Arial, sans-serif;">);</span>
if (!$flag) {
$this->msg = $msg;
return false;
}
$return = $this->xmltoArray($msg);
if (!$return) {
$this->msg = '无法获取转账信息';
return false;
}
if ($return['result_code'] != 'SUCCESS') {
$this->msg = $this->errs[$return['return_msg']] ?: $return['return_msg'];
if ($return['err_code_des']) {
$this->msg = $this->msg . ':' . $return['err_code_des'];
}
return false;
}
$params = array_merge($params, $return);
return $params;
}
// 保存公钥文件到本地
public function savePublicKey($path) {
$content = $this->getPublicKey();
if (!$content) {
return false;
}
// 保存文件
if (!file_put_contents($path, $content)) {
$this->msg = '保存文件失败';
return false;
}
return true;
}
// 获取RSA 加密公钥
protected function getPublicKey() {
$url = 'https://fraud.mch.weixin.qq.com/risk/getpublickey';
$str = '<xml>
<mch_id>%s</mch_id>
<nonce_str>%s</nonce_str>
<sign>%s</sign>
</xml>';
$params['mch_id'] = $this->mchid;
$params['nonce_str'] = random(32);
ksort($params);
$string = $this->ToUrlParams($params);
$string .= "&key={$this->mchkey}";
$sign = strtoupper(md5($string));
$params['sign'] = $sign;
$data = sprintf(
$str,
$params['mch_id'],
$params['nonce_str'],
$params['sign']
);
$flag = $this->curl_post_ssl($url, $data, $msg, 30, MY_ROOT . '/include/auth/');
if (!$flag) {
$this->msg = $msg;
return false;
}
$return = $this->xmltoArray($msg);
if (!$return) {
$this->msg = '无法获取返回信息';
return false;
}
if ($return['result_code'] != 'SUCCESS') {
$this->msg = $return['err_code_des'];
return false;
}
// 返回公钥信息
return $this->convertPKCS1toPKCS8($return['pub_key']);
}
// RSA 加密 微信返回来的 公钥文件需要 从1转成8 PHP 支持 8 不支持 1
protected function rsaencrypt($data) {
$encrypted = '';
$pkeyid = openssl_pkey_get_public(file_get_contents($this->bank_public_file));
if (!$pkeyid) {
$this->msg = '公钥不可用';
return false;
}
if (!openssl_public_encrypt($data, $encrypted, $pkeyid, OPENSSL_PKCS1_OAEP_PADDING)) {
$this->msg = '加密失败,请检查RSA秘钥';
return false;
}
openssl_free_key($pkeyid);
return base64_encode($encrypted);
}
// 将返回来的 cs1 转成cs8
protected function convertPKCS1toPKCS8($pkcs1) {
$start_key = $pkcs1;
$start_key = str_replace('-----BEGIN RSA PUBLIC KEY-----', '', $start_key);
$start_key = trim(str_replace('-----END RSA PUBLIC KEY-----', '', $start_key));
$key = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A' . str_replace("\n", '', $start_key);
$key = "-----BEGIN PUBLIC KEY-----\n" . wordwrap($key, 64, "\n", true) . "\n-----END PUBLIC KEY-----";
return $key;
}
转账需要输入银行卡代码 具体可看 https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=24_4
整理后的映射数组
$code2Name = [
"SRCB" => "深圳农村商业银行",
"BGB" => "广西北部湾银行",
"SHRCB" => "上海农村商业银行",
"BJBANK" => "北京银行",
"WHCCB" => "威海市商业银行",
"BOZK" => "周口银行",
"KORLABANK" => "库尔勒市商业银行",
"SPABANK" => "平安银行",
"SDEB" => "顺德农商银行",
"HURCB" => "湖北省农村信用社",
"WRCB" => "无锡农村商业银行",
"BOCY" => "朝阳银行",
"CZBANK" => "浙商银行",
"HDBANK" => "邯郸银行",
"BOC" => "中国银行",
"BOD" => "东莞银行",
"CCB" => "中国建设银行",
"ZYCBANK" => "遵义市商业银行",
"SXCB" => "绍兴银行",
"GZRCU" => "贵州省农村信用社",
"ZJKCCB" => "张家口市商业银行",
"BOJZ" => "锦州银行",
"BOP" => "平顶山银行",
"HKB" => "汉口银行",
"SPDB" => "上海浦东发展银行",
"NXRCU" => "宁夏黄河农村商业银行",
"NYNB" => "广东南粤银行",
"GRCB" => "广州农商银行",
"BOSZ" => "苏州银行",
"HZCB" => "杭州银行",
"HSBK" => "衡水银行",
"HBC" => "湖北银行",
"JXBANK" => "嘉兴银行",
"HRXJB" => "华融湘江银行",
"BODD" => "丹东银行",
"AYCB" => "安阳银行",
"EGBANK" => "恒丰银行",
"CDB" => "国家开发银行",
"TCRCB" => "江苏太仓农村商业银行",
"NJCB" => "南京银行",
"ZZBANK" => "郑州银行",
"DYCB" => "德阳商业银行",
"YBCCB" => "宜宾市商业银行",
"SCRCU" => "四川省农村信用",
"KLB" => "昆仑银行",
"LSBANK" => "莱商银行",
"YDRCB" => "尧都农商行",
"CCQTGB" => "重庆三峡银行",
"FDB" => "富滇银行",
"JSRCU" => "江苏省农村信用联合社",
"JNBANK" => "济宁银行",
"CMB" => "招商银行",
"JINCHB" => "晋城银行JCBANK",
"FXCB" => "阜新银行",
"WHRCB" => "武汉农村商业银行",
"HBYCBANK" => "湖北银行宜昌分行",
"TZCB" => "台州银行",
"TACCB" => "泰安市商业银行",
"XCYH" => "许昌银行",
"CEB" => "中国光大银行",
"NXBANK" => "宁夏银行",
"HSBANK" => "徽商银行",
"JJBANK" => "九江银行",
"NHQS" => "农信银清算中心",
"MTBANK" => "浙江民泰商业银行",
"LANGFB" => "廊坊银行",
"ASCB" => "鞍山银行",
"KSRB" => "昆山农村商业银行",
"YXCCB" => "玉溪市商业银行",
"DLB" => "大连银行",
"DRCBCL" => "东莞农村商业银行",
"GCB" => "广州银行",
"NBBANK" => "宁波银行",
"BOYK" => "营口银行",
"SXRCCU" => "陕西信合",
"GLBANK" => "桂林银行",
"BOQH" => "青海银行",
"CDRCB" => "成都农商银行",
"QDCCB" => "青岛银行",
"HKBEA" => "东亚银行",
"HBHSBANK" => "湖北银行黄石分行",
"WZCB" => "温州银行",
"TRCB" => "天津农商银行",
"QLBANK" => "齐鲁银行",
"GDRCC" => "广东省农村信用社联合社",
"ZJTLCB" => "浙江泰隆商业银行",
"GZB" => "赣州银行",
"GYCB" => "贵阳市商业银行",
"CQBANK" => "重庆银行",
"DAQINGB" => "龙江银行",
"CGNB" => "南充市商业银行",
"SCCB" => "三门峡银行",
"CSRCB" => "常熟农村商业银行",
"SHBANK" => "上海银行",
"JLBANK" => "吉林银行",
"CZRCB" => "常州农村信用联社",
"BANKWF" => "潍坊银行",
"ZRCBANK" => "张家港农村商业银行",
"FJHXBC" => "福建海峡银行",
"ZJNX" => "浙江省农村信用社联合社",
"LZYH" => "兰州银行",
"JSB" => "晋商银行",
"BOHAIB" => "渤海银行",
"CZCB" => "浙江稠州商业银行",
"YQCCB" => "阳泉银行",
"SJBANK" => "盛京银行",
"XABANK" => "西安银行",
"BSB" => "包商银行",
"JSBANK" => "江苏银行",
"FSCB" => "抚顺银行",
"HNRCU" => "河南省农村信用",
"COMM" => "交通银行",
"XTB" => "邢台银行",
"CITIC" => "中信银行",
"HXBANK" => "华夏银行",
"HNRCC" => "湖南省农村信用社",
"DYCCB" => "东营市商业银行",
"ORBANK" => "鄂尔多斯银行",
"BJRCB" => "北京农村商业银行",
"XYBANK" => "信阳银行",
"ZGCCB" => "自贡市商业银行",
"CDCB" => "成都银行",
"HANABANK" => "韩亚银行",
"CMBC" => "中国民生银行",
"LYBANK" => "洛阳银行",
"GDB" => "广东发展银行",
"ZBCB" => "齐商银行",
"CBKF" => "开封市商业银行",
"H3CB" => "内蒙古银行",
"CIB" => "兴业银行",
"CRCBANK" => "重庆农村商业银行",
"SZSBK" => "石嘴山银行",
"DZBANK" => "德州银行",
"SRBANK" => "上饶银行",
"LSCCB" => "乐山市商业银行",
"JXRCU" => "江西省农村信用",
"ICBC" => "中国工商银行",
"JZBANK" => "晋中市商业银行",
"HZCCB" => "湖州市商业银行",
"NHB" => "南海农村信用联社",
"XXBANK" => "新乡银行",
"JRCB" => "江苏江阴农村商业银行",
"YNRCC" => "云南省农村信用社",
"ABC" => "中国农业银行",
"GXRCU" => "广西省农村信用",
"PSBC" => "中国邮政储蓄银行",
"BZMD" => "驻马店银行",
"ARCU" => "安徽省农村信用社",
"GSRCU" => "甘肃省农村信用",
"LYCB" => "辽阳市商业银行",
"JLRCU" => "吉林农信",
"URMQCCB" => "乌鲁木齐市商业银行",
"XLBANK" => "中山小榄村镇银行",
"CSCB" => "长沙银行",
"JHBANK" => "金华银行",
"BHB" => "河北银行",
"NBYZ" => "鄞州银行",
"LSBC" => "临商银行",
"BOCD" => "承德银行",
"SDRCU" => "山东农信",
"NCB" => "南昌银行",
"TCCB" => "天津银行",
"WJRCB" => "吴江农商银行",
"CBBQS" => "城市商业银行资金清算中心",
"HBRCU" => "河北省农村信用社",
];
整理入库
$names = array_flip($code2Name);
if (preg_match_all("/<tr[\s\S]+?>([\s\S]+?)<\/tr>/", $content, $data)) {
foreach ($data[1] as $k => $v) {
if (strpos($v, 'strong') !== false) {
continue;
}
$v = trim(preg_replace("/\r|\n/", '', strip_tags($v)));
$rs = explode(" ", $v);
$rs = array_values(array_filter($rs, function (&$v) {
$v = trim(str_replace(" ", "", $v));
return $v ? true : false;
}
));
if (preg_match('/(\d+)/', $rs[1], $result)) {
$rs[1] = $result[1];
}
//入库
$row = fetch_first("SELECT * FROM banks WHERE name='{$rs[0]}'");
if (!$row) {
$record = ['name'=>$rs[0],'identify'=>$names[$rs[0]]?:$names['中国'.$rs[0]],'bank_number'=>$rs[1]];
DB::insert('banks',$record);
}
}
}