1、首先找银行申请,按照他那边的规定把所有资料给到他,然后他会帮我们申请(我这次联系的是邮政的)
2、申请完成之后,商户后台的登录地址、账号、密码、开发者秘钥,会以邮箱形式发送我们的邮箱
3、进入商户后台做微信配置(搜不到的话找银行那边人对接,可能出现的问题很多,信息错一个都会导致匹配不上)。根据商户编号搜到之后进到配置页:
4、进到配置页后,先添加appid。注意:公众号主体一定要和银行那边开户主体一致,公司的一定做企业认证,在我们信息没有问题的前提下,配置不上找银行那边对接人员处理。
5、配置合法域名,和公众号的配置一样有,(vue的有一个问题,vue是单页面,前端跳转到支付页的时候记得使用<a></a>标签跳,不然合法域名的验证会不通过)
6、发起支付的时候可能会出现下图问题这个也是找银行那边做一个实名认证,步骤挺多的,申请完等审核通过就可以了。
【微信】公众号支付demo
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2019-04-22
* Time: 14:20
*/
namespace app\common\logic;
/**
* 云闪付
* Class Wap
* @auth Alan
* @time 2019-04-22
* @package app\common\logic
*/
class Wap extends Base
{
var $data;
var $responseCode;
/** 网关url地址 */
var $gateUrl;
var $getKey = '';
/** 密钥 */
var $key='075914978dcf6aa65c5765a28799a06c';
var $url ='https://qra.95516.com/pay/gateway';
/* RSA私钥*/
var $private_rsa_key;
var $signtype='MD5';
/** 请求的参数 */
var $parameters;
//原始内容
var $content;
/** debug信息 */
var $debugInfo;
//应答内容
var $resContent;
public function createOrder($openid,$pay_money,$order_number,$body='下单',$notify_url){
$post_data = [
'out_trade_no'=>$order_number,
'mch_create_ip'=>getClientIp(),
'total_fee'=>$pay_money*100,
'body'=>$body,
];
$this->setReqParams($post_data);
$this->setParameter('service','pay.weixin.jspay');
$this->setParameter('mch_id','QRA513541210FFL');//必填项,商户号,由平台分配
$this->setParameter('version','2.0');
$this->setParameter('sign_type','MD5');
$this->setParameter('notify_url',$notify_url);//通知地址,必填项,接收平台通知的URL,保证外网能正常访问到
$this->setParameter('sub_appid','wx4e51002cd8b4dd09');//对应公众号appid,必填
$this->setParameter('sub_openid',$openid);//对应公众号获取到的用户openid,必填(使用微信官方网页授权接口获取地址: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842&token=&lang=zh_CN )
$this->setParameter('is_raw','1');
$this->setParameter('nonce_str',mt_rand());//随机字符串,必填项,不长于 32 位
$this->createSign();//创建签名
//dump($this->parameters);
$this->data = $this->toXml($this->parameters);
$res = $this->call();
$res_data = $this->parseXML($this->resContent);
$res_data['pay_info'] = json_decode($res_data['pay_info'],true);
return $res_data['pay_info'];
}
/**
* 申请退款
*/
public function applyRefund($order_number,$refund_number,$total_fee,$refund_fee){
$post_data = [
'out_trade_no'=>$order_number,
'out_refund_no'=>$refund_number,
'total_fee'=>$total_fee*100,
'refund_fee'=>$refund_fee*100,
'refund_channel'=>'ORIGINAL'
];
$this->setReqParams($post_data);
$this->setParameter('service','unified.trade.refund');
$this->setParameter('mch_id','QRA513541210FFL');//必填项,商户号,由平台分配
$this->setParameter('op_user_id','QRA513541210FFL');//必填项,商户号,由平台分配
$this->setParameter('version','2.0');
$this->setParameter('sign_type','MD5');
$this->setParameter('nonce_str',mt_rand());//随机字符串,必填项,不长于 32 位
$this->createSign();//创建签名
//dump($this->parameters);
$this->data = $this->toXml($this->parameters);
$res = $this->call();
$res_data = $this->parseXML($this->resContent);
return $res_data;
}
/**
*是否平台签名,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
*true:是
*false:否
*/
function isTenpaySign() {
$swiftpassSign = strtolower($this->getParameter("sign"));
if ($this->signtype == 'MD5') {
return $this->getMD5Sign() == $swiftpassSign;
} else if ($this->getParameter('sign_type') == 'RSA_1_1' || $this->getParameter('sign_type') == 'RSA_1_256') {
return $this->verifyRSASign();
}
}
//设置原始内容
function setContent($content) {
$this->content = $content;
libxml_disable_entity_loader(true);
$xml = simplexml_load_string($this->content);
$encode = $this->getXmlEncode($this->content);
if($xml && $xml->children()) {
foreach ($xml->children() as $node){
//有子节点
if($node->children()) {
$k = $node->getName();
$nodeXml = $node->asXML();
$v = substr($nodeXml, strlen($k)+2, strlen($nodeXml)-2*strlen($k)-5);
} else {
$k = $node->getName();
$v = (string)$node;
}
if($encode!="" && $encode != "UTF-8") {
$k = iconv("UTF-8", $encode, $k);
$v = iconv("UTF-8", $encode, $v);
}
$this->setParameter($k, $v);
}
}
}
function verifyRSASign() {
$signPars = "";
ksort($this->parameters);
foreach($this->parameters as $k => $v) {
if("sign" != $k && "" != $v) {
$signPars .= $k . "=" . $v . "&";
}
}
$signPars = substr($signPars, 0, strlen($signPars) - 1);
$res = openssl_get_publickey($this->public_rsa_key);
if ($this->getParameter('sign_type') == 'RSA_1_1') {
$result = (bool)openssl_verify($signPars, base64_decode($this->getParameter("sign")), $res);
openssl_free_key($res);
return $result;
} else if($this->getParameter('sign_type') == 'RSA_1_256') {
$result = (bool)openssl_verify($signPars, base64_decode($this->getParameter("sign")), $res, OPENSSL_ALGO_SHA256);
openssl_free_key($res);
return $result;
}
}
function getMD5Sign() {
$signPars = "";
ksort($this->parameters);
foreach($this->parameters as $k => $v) {
if("sign" != $k && "" != $v) {
$signPars .= $k . "=" . $v . "&";
}
}
$signPars .= "key=" . $this->key;
return strtolower(md5($signPars));
}
/**
*获取参数值
*/
function getParameter($parameter) {
return isset($this->parameters[$parameter])?$this->parameters[$parameter] : '';
}
function call() {
//启动一个CURL会话
$ch = curl_init();
// 设置curl允许执行的最长秒数
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false);
// 获取的信息以文件流的形式返回,而不是直接输出。
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
//发送一个常规的POST请求。
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_URL, $this->url);
//要传送的所有数据
curl_setopt($ch, CURLOPT_POSTFIELDS, $this->data);
// 执行操作
$res = curl_exec($ch);
$this->responseCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($res == NULL) {
$this->errInfo = "call http err :" . curl_errno($ch) . " - " . curl_error($ch) ;
curl_close($ch);
return false;
} else if($this->responseCode != "200") {
$this->errInfo = "call http err httpcode=" . $this->responseCode ;
curl_close($ch);
return false;
}
//var_dump($this->data);
curl_close($ch);
$this->resContent = $res;
return true;
}
/**
*创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
*/
function createSign() {
if($this->signtype == 'MD5') {
$this->createMD5Sign();
} else {
$this->createRSASign();
}
}
function createMD5Sign() {
$signPars = "";
ksort($this->parameters);
foreach($this->parameters as $k => $v) {
if("" != $v && "sign" != $k) {
$signPars .= $k . "=" . $v . "&";
}
}
$signPars .= "key=" . $this->key;
$sign = strtoupper(md5($signPars));
$this->setParameter("sign", $sign);
//debug信息
$this->_setDebugInfo($signPars . " => sign:" . $sign);
}
function createRSASign() {
$signPars = "";
ksort($this->parameters);
foreach($this->parameters as $k => $v) {
if("" != $v && "sign" != $k) {
$signPars .= $k . "=" . $v . "&";
}
}
$signPars = substr($signPars, 0, strlen($signPars) - 1);
$res = openssl_get_privatekey($this->private_rsa_key);
if ($this->signtype == 'RSA_1_1') {
openssl_sign($signPars, $sign, $res);
} else if ($this->signtype == 'RSA_1_256') {
openssl_sign($signPars, $sign, $res, OPENSSL_ALGO_SHA256);
}
openssl_free_key($res);
$sign = base64_encode($sign);
$this->setParameter("sign", $sign);
//debug信息
$this->_setDebugInfo($signPars . " => sign:" . $sign);
}
/**
*设置参数值
*/
function setParameter($parameter, $parameterValue) {
$this->parameters[$parameter] = $parameterValue;
}
/**
* 一次性设置参数
*/
function setReqParams($post,$filterField=null){
if($filterField !== null){
forEach($filterField as $k=>$v){
unset($post[$v]);
}
}
//判断是否存在空值,空值不提交
forEach($post as $k=>$v){
if(empty($v)){
unset($post[$k]);
}
}
$this->parameters = $post;
}
/**
*设置debug信息
*/
function _setDebugInfo($debugInfo) {
$this->debugInfo = $debugInfo;
}
/**
* 将数据转为XML
*/
public function toXml($array){
$xml = '<xml>';
forEach($array as $k=>$v){
$xml.='<'.$k.'><![CDATA['.$v.']]></'.$k.'>';
}
$xml.='</xml>';
return $xml;
}
public function dataRecodes($title,$data){
$handler = fopen('result.txt','a+');
$content = "================".$title."===================\n";
if(is_string($data) === true){
$content .= $data."\n";
}
if(is_array($data) === true){
forEach($data as $k=>$v){
$content .= "key: ".$k." value: ".$v."\n";
}
}
$flag = fwrite($handler,$content);
fclose($handler);
return $flag;
}
public function parseXML($xmlSrc){
if(empty($xmlSrc)){
return false;
}
$array = array();
libxml_disable_entity_loader(true);
$xml = simplexml_load_string($xmlSrc);
$encode = $this->getXmlEncode($xmlSrc);
if($xml && $xml->children()) {
foreach ($xml->children() as $node){
//有子节点
if($node->children()) {
$k = $node->getName();
$nodeXml = $node->asXML();
$v = substr($nodeXml, strlen($k)+2, strlen($nodeXml)-2*strlen($k)-5);
} else {
$k = $node->getName();
$v = (string)$node;
}
if($encode!="" && $encode != "UTF-8") {
$k = iconv("UTF-8", $encode, $k);
$v = iconv("UTF-8", $encode, $v);
}
$array[$k] = $v;
}
}
return $array;
}
//获取xml编码
public function getXmlEncode($xml) {
$ret = preg_match ("/<?xml[^>]* encoding=\"(.*)\"[^>]* ?>/i", $xml, $arr);
if($ret) {
return strtoupper ( $arr[1] );
} else {
return "";
}
}
}
<?php
namespace app\wechat\controller;
use app\common\logic\Wap;
class Vip extends Basic
{
public function ceshi(){
$wap_logic = new Wap();
$res_data = $wap_logic->createOrder('*****',0.01,'ceshi8','xiadan','********/vip/wapcallback');
//dump($res_data);
return sendSuccessMessage($res_data);
}
public function refund(){
$wap_logic = new Wap();
$res = $wap_logic->applyRefund('ceshi8','ceshi8',0.01,0.01);
if($res['result_code']&&$res['status']==0){
//申请退款成功
}
dump($res);
return 0;
}
/**
* 支付回调
*/
public function wapcallback(){
$xml = file_get_contents('php://input');
$wap_logic = new Wap();
$wap_logic->setContent($xml);
apilog('home','1','home/wapcallback',[],$wap_logic->parameters);
if($wap_logic->isTenpaySign()){
if($wap_logic->getParameter('status') == 0 && $wap_logic->getParameter('result_code') == 0){
//echo $this->resHandler->getParameter('status');
// 11;
//更改订单状态
$order_number = $wap_logic->getParameter('out_trade_no');
apilog('home','2','home/wapcallback',[],$wap_logic->parameters);
echo 'success';
exit();
}else{
echo 'failure';
exit();
}
}else{
echo 'failure';
}
}
}