网站首页 文章专栏 微信支付流程(H5);退款
以下是几年前写的,原生写法,现已改进,融合了微信和支付宝的各种支付方式,调用方便。详见:《常用微信和支付宝支付方法》
function wxpayfromh5($name, $orderNo, $money) {
$ip = '用户IP';//真实IP
$nonce_str = $this->makePassword(32);//随机数
$return_url = '同步回调地址';
$notify_url = '异步回调地址';
$scene_info = array(
'h5_info' => array(
'type' => 'Wap',
'wap_url' => $_SERVER['HTTP_REFERER'],
'wap_name' => $name,//描述
),
);
$arr = array(
'nonce_str' => $nonce_str,
'out_trade_no' => $orderNo,//订单号,微信的订单号只能一次性使用,不管支付成功与否均不允许第二次支付,建议每次生成新的订单号
'total_fee' => $money,//支付金额,单位分
'body' => $name,
'ip' => $ip,
'notify_url' => $notify_url,
'trade_type' => 'MWEB',
'scene_info' => json_encode($scene_info),
);
vendor('WxPay.WxPay#Api');
vendor('WxPay.WxPay#NativePay');
$notify = new \WxPayApi();
$input = new \WxPayUnifiedOrder();
$input->SetNonce_str($nonce_str); //随机字符串,不长于32位
$input->SetBody($name); //设置商品或支付单简要描述
$input->SetOut_trade_no($orderNo); //设置商户系统内部的订单号,32个字符内、可包含字母,
$input->SetTotal_fee($money); //设置订单总金额,只能为整数,单位为分
$input->SetSpbill_create_ip($ip); //必须传正确的用户端IP
$input->SetNotify_url($notify_url); //设置接收微信支付异步通知回调地址
$input->SetTrade_type("MWEB"); //设置trade_type H5支付的交易类型为MWEB
$input->SetScene_info(json_encode($scene_info)); //场景信息
$input->SetSign($arr); //签名
$result = $notify->unifiedOrder($input);
$this->siteLogsPay('微信H5支付处理结果:' . $orderNo . ':' . json_encode($result, JSON_UNESCAPED_UNICODE), date('Ymd', strtotime('now')), 'wxpay');//建议记录日志
if ($result['result_code'] == 'SUCCESS') {
//成功处理
$url = $result['mweb_url'] . '&redirect_url=' . urldecode($return_url . '?token=' . $token);
$this->assign('url', $url);
$this->display('wxpayfromh5');//微信H5不会自动唤醒微信APP,需要用户前台确认,用返回的$result['mweb_url']去唤醒
} else {
//失败
echo $result['err_code_des'];
return false;
}
}
wxpayfromh5 页面如下:
<a href="{$url}" class="btn btn-black-b">打开微信支付</a>
/**
* h5微信支付完成页面 同步返回不会显示支付的交易单号,需要用户前台确认,用订单号去查询交易信息
*
*/
function h5wxreturn() {
$token = I('get.token', '');//token是中间参数,一般加密传递一些交易信息
if (!$token) {
return false;
}
$this->assign('token', $token);
$this->display('h5wxreturn');
}
h5wxreturn 页面如下:
<a href="支付成功地址h5wxsuccess.cgi?token={$token}">支付完成</a>
<br>
<a href="再次支付地址h5payagain.cgi?token={$token}">支付遇到问题,重新支付</a>
/**
* H5微信支付完成 微信H5支付完毕不会返回任何的支付信息,需要重新用订单号去查,而且还必须是前台提交
*
*/
function h5wxsuccess() {
$token = I('get.token', '');
$info = $token;//从token中解密出交易信息
$orderno = $info['orderno'];
if (!$orderno) {
return false;
}
$old_orderno = $this->redis->get('wxoldorderno_' . trim($orderno));//从缓存中取出老的订单号 这步可省略(建议保留新老订单号数据)
$this->h5wxorderquery($orderno, $old_orderno);//用订单号查询微信支付状态 $old_orderno可省略 建议将老订单号能够回传
}
/**
* h5微信查询 提供所有微信支付订单的查询
*/
private function h5wxorderquery($orderNo, $old_orderno = '') {
$nonce_str = $this->makePassword(32);
$arr = array(
'nonce_str' => $nonce_str,
'out_trade_no' => $orderNo,
);
vendor('WxPay.WxPay#Api');
vendor('WxPay.WxPay#NativePay');
$notify = new \WxPayApi();
$input = new \WxPayOrderQuery();
$input->SetNonce_str($nonce_str); //随机字符串,不长于32位
$input->SetOut_trade_no($orderNo); //设置商户系统内部的订单号,32个字符内、可包含字母,
$input->SetSign($arr); //签名
$result = $notify->orderQuery($input);
$this->siteLogsPay('微信H5支付查询结果:' . $orderNo . ':' . json_encode($result, JSON_UNESCAPED_UNICODE), date('Ymd', strtotime('now')), 'wxpay');//建议记录日志
if ($result['result_code'] == 'SUCCESS' && $result['trade_state'] == 'SUCCESS') {
//确认支付成功处理 可直接处理,建议将数据传到其他地方处理保证方法的可利用性
$this->redis->rm('wxoldorderno_' . trim($orderNo));
header("Location:" . $backurl .= "?token=" . $token);//
} else {
return false;
}
}
/**
* H5微信再次提交
*/
public function h5payagain() {
$token = I('get.token', '');
$info =$token;//从token中解密出交易信息
$orderno = $info['orderno'];
$old_orderno = $this->redis->get('data_pay_wxoldorderno_' . trim($orderno));
if (!$old_orderno) {
return false;
}
$this->wxpayfromh5($info['name'], $orderno, $info['money']);//再次去支付
}
/**
*微信异步
*/
public function h5wxnotify() {
ob_clean();
$data = @file_get_contents('php://input');
if ($data) {
$data = $this->_xmldataparse($data);
}
$old_orderno = $this->redis->get('wxoldorderno_' . trim($data['out_trade_no']));
$backurl = $this->redis->get('backurl_' . $old_orderno);
if ($data['return_code'] == "SUCCESS" && $data['result_code'] == "SUCCESS") {
//支付成功处理 建议在其他地方处理 如下,也可在这里直接处理
$this->siteLogsPay('微信H5支付成功异步参数:' . json_encode($d, JSON_UNESCAPED_UNICODE), date('Ymd', strtotime('now')), 'wxpay');
$d['selling'] = $data['total_fee'] / 100;
$d['payno'] = $data['transaction_id'];
$d['orderno'] = $data['out_trade_no'];
$d['old_orderno'] = $old_orderno;
//将接收到的数据加密token
$url = $backurl . "?token=" . $token;
$result = curlPost($url, $d);//建议在其他地方处理
$status = json_decode($result)->status;//处理完毕后的响应
if ($status != 200) {
$return['return_code'] = "FAIL";
} else {
$return['return_code'] = "SUCCESS";
$return['return_msg'] = "OK";
$this->redis->rm('wxoldorderno_' . trim($data['out_trade_no']));
}
} else {
//支付失败处理
$this->siteLogsPay('微信回调支付失败!!', date('Ymd', strtotime('now')), 'wxpay');
$return['return_code'] = "FAIL";
}
echo $this->ToXml($return);
}
//xml格式数据解析函数
private function _xmldataparse($data) {
$msg = array();
$msg = (array) simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOCDATA);
return $msg;
}
/**
*随机字符串
*
*/
private function makePassword($length = 32) {
// 密码字符集,可任意添加你需要的字符
$chars = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '!', '@', '*');
// 在 $chars 中随机取 $length 个数组元素键名
$keys = array_rand($chars, $length);
$password = '';
for ($i = 0; $i < $length; $i++) {
// 将 $length 个数组元素连接成字符串
$password .= $chars[$keys[$i]];
}
return $password;
}
特别注意:同步和异步的返回均要验证数据库信息是否更改,避免重复处理操作
/**
*微信退款
*/
private function wxrefund($orderNo, $refund_no, $money, $refund_money) {
$nonce_str = $this->makePassword(32);
$arr = array(
'nonce_str' => $nonce_str,
'out_trade_no' => $orderNo,
'out_refund_no' => $refund_no,
'total_fee' => $money,
'refund_fee' => $refund_money,
);
vendor('WxPay.WxPay#Api');
vendor('WxPay.WxPay#NativePay');
Vendor('phpqrcode.phpqrcode');
//vendor('WxPay.WxPay#WxPay#Config');
$notify = new \WxPayApi();
$input = new \WxPayRefund();
$input->SetOut_trade_no($orderNo); //设置商户系统内部的订单号,32个字符内、可包含字母,
$input->SetTotal_fee($money); //设置订单总金额,只能为整数,单位为分
$input->SetNonce_str($nonce_str); //随机字符串,不长于32位
$input->SetOut_refund_no($refund_no); //商户退款单号
$input->SetRefund_fee($refund_money); //退款总金额,订单总金额,单位为分,只能为整数
$input->SetSign($arr);
$input->SetOp_user_id('微信授权ID');
$result = $notify->refund($input);
$this->siteLogsPay('微信退款处理结果:' . $orderNo . ':' . json_encode($result, JSON_UNESCAPED_UNICODE), date('Ymd', strtotime('now')), 'userrefund');
if ($result['result_code'] == 'SUCCESS') {
$this->ajaxReturn(array('status' => 200));
} else {
$this->ajaxReturn(array('status' => -200));
}
}
转载请注明出处