php 对接微信小程序支付完整代码
程序员文章站
2022-07-13 17:08:45
...
php 微信支付
一、准备工作
- 小程序注册,要以公司的以身份去注册一个小程序,才有微信支付权限;
- 绑定商户号。
- 在小程序填写合法域
二、完成以上条件,你可以得到
- 小程序appid 小程序秘钥 这两个用于获取用户openid;
- 商户号id ,商户号秘钥 支付接口必须的;
三、开始开发
<?php
/**
* 生成微信签名
* Date: 2020-09-21
* Time: 10:41
*/
namespace app\model;
class Dev
{
//作用:生成签名
public static function get_sign($params, $secret) {
foreach ($params as $k => $v) {
$Parameters[$k] = $v;
}
//签名步骤一:按字典序排序参数
ksort($Parameters);
$String = self::formatBizQueryParaMap($Parameters, false);
//签名步骤二:在string后加入KEY
$String = $String . "&key=" . $secret;
//签名步骤三:MD5加密
$String = md5($String);
//签名步骤四:所有字符转为大写
$result_ = strtoupper($String);
return $result_;
}
///作用:格式化参数,签名过程需要使用
public static function formatBizQueryParaMap($paraMap, $urlencode) {
$buff = "";
ksort($paraMap);
foreach ($paraMap as $k => $v) {
if ($urlencode) {
$v = urlencode($v);
}
$buff .= $k . "=" . $v . "&";
}
$reqPar="";
if (strlen($buff) > 0) {
$reqPar = substr($buff, 0, strlen($buff) - 1);
}
return $reqPar;
}
}
在这里插入代码片
<?php
/**
* 微信支付
* Date: 2020-09-21
* Time: 10:41
*/
namespace app\model;
use think\Db;
use app\model\Dev;
use think\Cache;
class Wxpay
{
/**
* 微信支付
* @param string $order_sn 订单号
* @param string $fee 金额 如 0.01
* @param $openid openid
* @param string $body 标题
* @param string $notify_url 成功回掉路径
*/
public static function pay($order_sn = '', $fee = '', $code, $body = '', $notify_url = '')
{
$ip = $_SERVER['SERVER_ADDR'];
$appid = config('wx_payment.appid');//appid.如果是公众号 就是公众号的appid
$mch_id = config('wx_payment.wx_mch_id'); //商户号
$nonce_str = nonce_str();//随机字符串
$out_trade_no = $order_sn;//订单号
$spbill_create_ip = $ip;//服务器的ip【自己填写】;
$total_fee = $fee * 100;// 微信支付单位是分,所以这里需要*100
$trade_type = 'JSAPI';//交易类型 默认
$get_code = Cache::get($code);
if ($get_code) {
$openid = $get_code;
} else {
$WX_SECRET = config('wx_payment.appsecret');//AppSecret
$url = "https://api.weixin.qq.com/sns/jscode2session?appid=" . $appid . "&secret=" . $WX_SECRET . "&js_code=" . $code . "&grant_type=authorization_code";
$infos = json_decode(file_get_contents($url));
$openid = $infos->openid ?? '';
if (empty($openid)) {
$data['state'] = 0;
$data['text'] = "支付失败";
$data['RETURN_CODE'] = "";
$data['RETURN_MSG'] = "";
return json_encode($data);
}
$set_code = Cache::set($code, $openid);
}
//这里是按照顺序的 因为下面的签名是按照顺序 排序错误 肯定出错
$post['appid'] = trim($appid);
$post['mch_id'] = trim($mch_id);//商户号
$post['nonce_str'] = trim($nonce_str);//随机字符串
$post['notify_url'] = trim($notify_url);
$post['body'] = $body;
$post['openid'] = trim($openid);
$post['out_trade_no'] = trim($out_trade_no);
$post['spbill_create_ip'] = $spbill_create_ip;//终端的ip
$post['total_fee'] = intval($total_fee); //总金额 最低为一分钱 必须是整数
$post['trade_type'] = $trade_type;
$sign = Dev::get_sign($post, config('wx_payment.wx_key'));
$post_xml = '<xml> <appid>' . $appid . '</appid><body>' . $body . '</body><mch_id>' . $mch_id . '</mch_id>
<nonce_str>' . $nonce_str . '</nonce_str>
<notify_url>' . $notify_url . '</notify_url>
<openid>' . $openid . '</openid>
<out_trade_no>' . $out_trade_no . '</out_trade_no>
<spbill_create_ip>' . $spbill_create_ip . '</spbill_create_ip>
<total_fee>' . $total_fee . '</total_fee>
<trade_type>' . $trade_type . '</trade_type>
<sign>' . $sign . '</sign></xml> ';;
// $post_xml = self::arrayToXml($post);
//统一接口prepay_id
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
$xml = http_request($url, $post_xml);
write_log('Res:xml' . $xml, 'pay');
$array = self::xml($xml);//全要大写
write_log('Res:xml 转大写' . json_encode($array, JSON_UNESCAPED_UNICODE), 'pay');
if ($array['RETURN_CODE'] == 'SUCCESS' && $array['RESULT_CODE'] == 'SUCCESS') {
write_log('Res:状态成功', 'pay');
$time = time();
$tmp = [];//临时数组用于签名
$tmp['appId'] = $appid;
$tmp['nonceStr'] = $nonce_str;
$tmp['package'] = 'prepay_id=' . $array['PREPAY_ID'];
$tmp['signType'] = 'MD5';
$tmp['timeStamp'] = "$time";
$data['state'] = 200;
$data['timeStamp'] = "$time";//时间戳
$data['nonceStr'] = $nonce_str;//随机字符串
$data['signType'] = 'MD5';//签名算法,暂支持 MD5
$data['package'] = 'prepay_id=' . $array['PREPAY_ID'];//统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=*
$data['paySign'] = Dev::get_sign($tmp, config('wx_payment.wx_key'));
$data['out_trade_no'] = $out_trade_no;
} else {
write_log('Res:失败', 'pay');
$data['state'] = 0;
$data['text'] = "支付失败";
$data['RETURN_CODE'] = $array['RETURN_CODE'];
$data['RETURN_MSG'] = $array['RETURN_MSG'];
}
return json_encode($data);
}
//获取xml
private static function xml($xml)
{
$p = xml_parser_create();
xml_parse_into_struct($p, $xml, $vals, $index);
xml_parser_free($p);
$data = [];
foreach ($index as $key => $value) {
if ($key == 'xml' || $key == 'XML') continue;
$tag = $vals[$value[0]]['tag'];
$value = $vals[$value[0]]['value'];
$data[$tag] = $value;
}
return $data;
}
}
在这里插入代码片
<?php
/**
* 微信支付配置文件
* Date: 2020-09-21
* Time: 16:40
*/
// 微信支付
return [
'appid' => '', //小程序appid,如果是公众号 就是公众号的appid
'appsecret' => '', //小程序appid
'wx_mch_id' => '',// 商户号
'wx_key' => '',// 商户支付**
];
在这里插入代码片
最后调用 微信获取 code 获取openid
$cash = 0.01;
$body = "礼包支付";
$host = $this->request->domain();
$notify_url = $host . '/order/notify/opay_notify';
$res = Wxpay::pay($order_sn, $cash, $code, $body, $notify_url);
if (empty($res)) {
return json(['code' => '2002', 'msg' => '请求支付失败', 'data' => []]);
}
$send_res = json_decode($res, true);
if (!is_array($send_res) || empty($send_res)) {
return json(['code' => '2002', 'msg' => '请求支付失败', 'data' => []]);
}
if ($send_res['state'] != '200') {
return json(['code' => '2002', 'msg' => '请求支付失败', 'data' => []]);
}
return json(['code' => '0000', 'msg' => '支付成功', 'data' => []]);
有问题留言,随时查看
上一篇: NIO在客户端并发访问多个站点
下一篇: 完整微信小程序支付代码+支付工具