• 0
  • 0

微信商户API付款到银行卡流程

2020-07-21 832 0 admin 所属分类:PHP 记录

微信转账到零钱有额度上限,而且受风控影响很可能每日付款上限都会有较大影响。

因此,考虑打款到银行卡。

类型/对比 优势  缺点
 付款到零钱 速度快,免手续费 每日额度较低
 付款到银行卡 转账额度较高 收取手续费,最低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);
		}
	}
}



返回顶部