//微信支付
public function pay(){
$fee = 1;//举例支付0.01,单位是分
$appid = "你的小程序appid";//appid.如果是公众号 就是公众号的appid
$body = "你的商品名称";
$mch_id = '你的商户号';//商户号
$nonce_str = $this->nonce_str();//随机字符串
$notify_url = '你的支付成功回调url'; //回调的url【自己填写】,注:此处url必须是外网可访问地址才可以,如果是自己内网服务器不行。
$openid = "支付用户的openid"; //支付用户的openid
$out_trade_no = "此处是你生成的订单号";//商户订单号:需要保证随机生成不重复,建议生成20位
$spbill_create_ip = '127.0.0.1';//服务器的ip【自己填写】;
$total_fee = $fee*100;// 微信支付单位是分,所以这里需要*100
$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;
$data['orderNumber'] = $orderNumber;
$data['sumPrice'] = $sumPrice;
}else{
$data['state'] = 0;
$data['text'] = "错误";
$data['returnArr'] = $array;
}
//将此处的$data返回给小程序即可,小程序端发起支付需要用到:timeStamp、nonceStr、package、signType、paySign等参数,我们此处并没有发起真正的支付,仅是向微信发起了统一下单拿到微信返回的相关参数返回给小程序,然后由小程序发起支付
return $data;
}
//随机32位字符串
private function nonce_str(){
$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;
}//小程序支付成功回调函数
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 非法回调');
}
/*****************微信回调返回数据样例*******************
$post = '<xml><appid><![CDATA[wx42e35e9cba15a5fc]]></appid>
<bank_type><![CDATA[CFT]]></bank_type>
<cash_fee><![CDATA[1]]></cash_fee>
<fee_type><![CDATA[CNY]]></fee_type>
<is_subscribe><![CDATA[N]]></is_subscribe>
<mch_id><![CDATA[1509441511]]></mch_id>
<nonce_str><![CDATA[UtpvtBhXIqpROhTXNpJSafbcFuPXTprt]]></nonce_str>
<openid><![CDATA[oYlJJ5Fs8VzKYE3xOKvKn-IuuMLM]]></openid>
<out_trade_no><![CDATA[20190516155797735964]]></out_trade_no>
<result_code><![CDATA[SUCCESS]]></result_code>
<return_code><![CDATA[SUCCESS]]></return_code>
<sign><![CDATA[8DBFF1A0922A35B081CD09E59FB21EDF]]></sign>
<time_end><![CDATA[20190516112925]]></time_end>
<total_fee>1</total_fee>
<trade_type><![CDATA[JSAPI]]></trade_type>
<transaction_id><![CDATA[4200000296201905161862992531]]></transaction_id>
</xml>';
*************************微信回调返回*****************/
libxml_disable_entity_loader(true); //禁止引用外部xml实体
$xml = simplexml_load_string($post, 'SimpleXMLElement', LIBXML_NOCDATA);//XML转数组
$post_data = (array)$xml;
//将用户支付信息记录日志文件
\Think\Log::record("用户openid:".$post_data['openid']);
\Think\Log::record("appId:".$post_data['appid']);
\Think\Log::record("订单编号:".$post_data['out_trade_no']);
\Think\Log::record("支付金额:".$post_data['total_fee']/100);
//此时你就可以进行修改订单状态以及其他的操作了...
$out_trade_no=$post_data['out_trade_no']; //订单编号
//阻止微信接口反复回调接口 文档地址 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;
}// pages/pay/pay.js
Page({
data: {
orderId: '', // 订单ID
},
onLoad: function (options) {
// 从页面参数中获取订单ID
this.setData({
orderId: options.orderId
});
},
initiatePayment: function () {
const that = this;
wx.request({
url: 'https://your-backend.com/api/getPayParams', // 后端接口地址
method: 'POST',
data: {
orderId: that.data.orderId,
},
success: function (res) {
const payParams = res.data;
that.wxPay(payParams);
},
fail: function (error) {
console.error('Failed to get payment parameters:', error);
}
});
},
wxPay: function (payParams) {
wx.requestPayment({
timeStamp: payParams.timeStamp,
nonceStr: payParams.nonceStr,
package: payParams.package,
signType: payParams.signType,
paySign: payParams.paySign,
success: function (res) {
console.log('Payment success:', res);
// 处理支付成功的逻辑
},
fail: function (error) {
console.error('Payment failed:', error);
// 处理支付失败的逻辑
}
});
}
});<!-- pages/pay/pay.wxml --> <view class="container"> <button bindtap="initiatePayment">支付</button> </view>
<?php // config/wechat.php return [ 'appid' => 'your_appid', // 公众号ID 'appsecret' => 'your_appsecret', // 公众号秘钥 'mch_id' => 'your_mch_id', // 商户ID 'key' => 'your_pay_key', // 支付密钥 'notify_url' => 'https://your-backend.com/api/payNotify', // 支付结果通知地址 ];
composer require overtrue/easywechat:~4.0
<?php
// application/controller/WechatPayController.php
namespace app\controller;
use think\Controller;
use EasyWeChat\Factory;
use think\facade\Config;
class WechatPayController extends Controller
{
public function pay()
{
$config = Config::get('wechat');
$app = Factory::payment($config);
$params = [
'body' => '订单描述', // 商品描述
'out_trade_no' => '订单号', // 自定义的订单号
'total_fee' => '订单金额(单位:分)',
'notify_url' => $config['notify_url'],
'trade_type' => 'JSAPI',
'openid' => '用户的openid', // 用户的openid
];
$result = $app->order->unify($params);
if ($result['return_code'] === 'SUCCESS' && $result['result_code'] === 'SUCCESS') {
$prepay_id = $result['prepay_id'];
$data = [
'timeStamp' => strval(time()),
'nonceStr' => $app->utils->createNonceStr(),
'package' => "prepay_id={$prepay_id}",
'signType' => 'MD5',
'paySign' => $app->utils->getPaySign([
'timeStamp' => $data['timeStamp'],
'nonceStr' => $data['nonceStr'],
'package' => $data['package'],
'signType' => $data['signType'],
], $config['key']),
];
return json($data);
} else {
return json(['error' => '支付参数生成失败']);
}
}
public function notify()
{
$config = Config::get('wechat');
$app = Factory::payment($config);
$response = $app->handlePaidNotify(function ($message, $fail) {
// 根据$message中的参数进行验证和处理
// 验证通过后,处理订单状态等业务逻辑
return true; // 返回true表示处理成功
});
return $response;
}
}<?php
// route/route.php
use think\facade\Route;
Route::post('pay', 'WechatPayController/pay'); // 发起支付
Route::any('notify', 'WechatPayController/notify'); // 支付回调参考原文:https://blog.csdn.net/weixin_42028285/article/details/93483574