直接上代码,只需要填写自己的参数就行
thinkphp 后台程序
<?php
/**
* 小程序支付
*/
namespace Salesapi\Controller;
use Think\Controller;
class PayController extends Controller
{
/*
* 充值功能
*/
public function recharge()
{
$uid = I("post.txt_uid", '');//用户id
!$uid && $this->ajax_common_return(4, "用户id不能为空", array(), 1);
$amount = I("post.txt_amount");
!$amount && $this->ajax_common_return(4, "金额不能为空", array(), 1);
$txt_mcoupon = I("post.txt_mcoupon");
!$txt_mcoupon && $this->ajax_common_return(4, "金额不能为空", array(), 1);
if (!is_numeric($amount)) {
$this->ajax_common_return(4, "请输入正确的金额", array(), 1);
}
$data = M("system_set")->field("mcoupon_edinfo,recharge_status,recharge_radio")->find();
if ($data['recharge_status'] == 0) {
$this->ajax_common_return(4, "请先开启充值功能", array(), 1);
}
if (empty($data['recharge_radio']) || ($data['recharge_radio'] <= 0)) {
$this->ajax_common_return(4, '请先设置比例', array(), 1);
}
$rechargeArr = M("system_set")->field("recharge_radio")->find();
$saveData['ratio'] = $rechargeArr['recharge_radio'];
$mcoupon = $txt_mcoupon;
$ini['uid'] = $uid;
$ini['status'] = 1;
$result = M('order_recharge')->where($ini)->getField('recharge_id');
if (empty($result)) {
$saveData['uid'] = $uid;
$saveData['amount'] = $amount;
$saveData['mcoupon'] = $mcoupon;
$saveData['status'] = 1;
$saveData['out_trade_no'] = $this->createOrderNo();
$saveData['add_time'] = time();
M('order_recharge')->add($saveData);
} else {
$saveData['amount'] = $amount;
$saveData['mcoupon'] = $mcoupon;
$saveData['out_trade_no'] = $this->createOrderNo();
$saveData['add_time'] = time();
M('order_recharge')->where(array('recharge_id' => $result))->save($saveData);
}
$openid = M('users_sales')->where(array('sales_id' => $uid))->getField('openids');
if (empty($openid)) {
$this->ajax_common_return(4, "未获取到用户的openid", array(), 1);
}
$payData = $this->pay($amount, $openid, $saveData['out_trade_no']);
$this->ajax_common_return(0, '请求成功', $payData);
}
/*
*回调地址
*/
public function notify()
{
//获取接口数据,如果$_REQUEST拿不到数据,则使用file_get_contents函数获取
$post = $_REQUEST;
if ($post == null) {
$post = file_get_contents("php://input");
}
if ($post == null) {
$post = isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : '';
}
if (empty($post) || $post == null || $post == '') {
//阻止微信接口反复回调接口
// 文档地址 https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_7&index=7,
//下面这句非常重要!!!
$str = '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
echo $str;
exit('Notify 非法回调');
}
libxml_disable_entity_loader(true); //禁止引用外部xml实体
$xml = simplexml_load_string($post, 'SimpleXMLElement', LIBXML_NOCDATA);//XML转数组
$post_data = (array)$xml;
//此时你就可以进行修改订单状态以及其他的操作了...
$out_trade_no = $post_data['out_trade_no']; //微信支付订单号
$transaction_id = $post_data['transaction_id']; //商户订单号
$ini['out_trade_no'] = $out_trade_no;
$res = M('order_recharge')->where($ini)->find();
if ($res['status'] == 1) {
//更新状态
$saveData['status'] = 2;
$saveData['transaction_id'] = $transaction_id;
M('order_recharge')->where($ini)->save($saveData);
$this->salesData($res['uid'],$res['mcoupon'],$res['amount']);
}
//阻止微信接口反复回调接口
//文档地址 https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_7&index=7,
//下面这句非常重要!!!
$str = '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
echo $str;
}
/*
* 业务员的操作
*/
public function salesData($salesId,$mcoupon,$amount)
{
$ini['sales_id'] = $salesId;
$res = M('users_sales')->where($ini)->getField('mcoupon_available');
$saveData['mcoupon_available'] = $res + $mcoupon;
$saveData['recharge_time'] = time();
M('users_sales')->where($ini)->save($saveData);
//记录
mcoupon_store_record(1,12,'充值优惠券额度',$salesId,$mcoupon,$saveData['mcoupon_available'],$amount);
}
/*
* 生成唯一的订单号
* @return string
*/
function createOrderNo()
{
$order_no = date('Ymd') . substr(time(), -5) . substr(microtime(), 2, 5) . sprintf('%02d', rand(1000, 9999));
return $order_no;
}
/*
* $openid 支付用户的openid
* $out_trade_no 商户订单号
* @return mixed
*/
public function pay($fee, $openid, $out_trade_no)
{
$appid = "";//appid.如果是公众号 就是公众号的appid
$body = "充值余额";
$mch_id = '';//商户号
$notify_url = '';
//回调的url【自己填写】,注:此处url必须是外网可访问地址才可以,如果是自己内网服务器不行。
$spbill_create_ip = '';//服务器的ip【自己填写】;
$total_fee = $fee * 100;// 微信支付单位是分,所以这里需要*100
$nonce_str = $this->nonceStr();//随机字符串
$trade_type = 'JSAPI';//交易类型 默认
//这里是按照顺序的 因为下面的签名是按照顺序 排序错误 肯定出错
$post['appid'] = $appid;
$post['body'] = $body;
$post['mch_id'] = $mch_id;
$post['nonce_str'] = $nonce_str;//随机字符串
$post['notify_url'] = $notify_url;
$post['openid'] = $openid;
$post['out_trade_no'] = $out_trade_no;
$post['spbill_create_ip'] = $spbill_create_ip;//终端的ip
$post['total_fee'] = $total_fee;//总金额
$post['trade_type'] = $trade_type;
$sign = $this->sign($post);//签名
$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> ';
// print_r($post_xml);die;
//统一接口prepay_id
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
$xml = $this->http_request($url, $post_xml);
$array = $this->xmlToArray($xml);
// print_r($xml);die;
if ($array['return_code'] == 'SUCCESS' && $array['result_code'] == 'SUCCESS') {
$time = time();
$tempArr = array(
'appId' => $appid,
'nonceStr' => $nonce_str,
'package' => 'prepay_id=' . $array['prepay_id'],
'signType' => 'MD5',
'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'] = $this->sign($tempArr);//签名,具体签名方案参见微信公众号支付帮助文档;
$data['out_trade_no'] = $out_trade_no;
} else {
$data['state'] = 0;
$data['text'] = "错误";
$data['returnArr'] = $array;
}
//将此处的$data返回给小程序即可,小程序端发起支付需要用到:timeStamp、nonceStr、package、signType、paySign等参数,我们此处并没有发起真正的支付,仅是向微信发起了统一下单拿到微信返回的相关参数返回给小程序,然后由小程序发起支付
return $data;
}
//随机32位字符串
private function nonceStr()
{
$result = '';
$str = 'QWERTYUIOPASDFGHJKLZXVBNMqwertyuioplkjhgfdsamnbvcxz';
for ($i = 0; $i < 32; $i++) {
$result .= $str[rand(0, 48)];
}
return $result;
}
//签名 $data要先排好顺序
private function sign($data)
{
$stringA = '';
foreach ($data as $key => $value) {
if (!$value) continue;
if ($stringA) $stringA .= '&' . $key . "=" . $value;
else $stringA = $key . "=" . $value;
}
$wx_key = '商户key';//申请支付后有给予一个商户账号和密码,登陆后自己设置的key
$stringSignTemp = $stringA . '&key=' . $wx_key;
return strtoupper(md5($stringSignTemp));
}
//curl请求
public function http_request($url, $data = null, $headers = array())
{
$curl = curl_init();
if (count($headers) >= 1) {
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
}
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
if (!empty($data)) {
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($curl);
curl_close($curl);
return $output;
}
//xml转换成数组
private function xmlToArray($xml)
{
//禁止引用外部xml实体
libxml_disable_entity_loader(true);
$xmlstring = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
$val = json_decode(json_encode($xmlstring), true);
return $val;
}
function ajax_common_return($code = "0", $other = "请求成功", $arr = array(), $save = "0")
{
if (empty($arr)) {
$arr = array();
}
if ($save) {
$returnarr = array("txt_code" => $code, "txt_other" => $other);
} else {
$returnarr = array("txt_code" => $code, "txt_other" => $other, "txt_mydata" => $arr);
}
return $this->ajaxReturn($returnarr);
}
}
微信小程序代码部分:
此处发起支付所用到的timeStamp、nonceStr、package、signType、paySign等相关参数是由后端pay方法返回而来。
wx.requestPayment({
timeStamp: results.data['timeStamp'],
nonceStr: results.data['nonceStr'],
package: results.data['package'],
signType: results.data['signType'],
paySign: results.data['paySign'],
success: function(res) {
//支付完成:此时可以执行跳转页面等操作
},
fail: function(res) {
//此时用户取消支付
}
})