微信小程序 统一支付 php,微信/微信小程序统一下单(PHP版)

工作中经常用到微信支付或小程序支付,特此整理一下基础代码,方便以后重复造轮子的时候用得上……本文代码不可直接放入生产环境使用,需要根须自身产品需求进行代码封装。

事先准备工作

1.开通公众号/小程序支付

2.商户号后台设置支付目录、回调目录、白名单等设置。

3.记录商户号ID(mchid)和生成支付key

需要准备辅助函数//-----------------支付相关-----------------

//随机32位字符串

public function nonce_str(){

$result = '';

$str = 'QWERTYUIOPASDFGHJKLZXVBNMqwertyuioplkjhgfdsamnbvcxz';

for ($i=0;$i<32;$i++){

$result .= $str[rand(0,48)];

}

return $result;

}

//生成订单号

public function order_number(){

return date('Ymd',time()).time().rand(10,99);//18位

}

//签名 $data要先排好顺序

public function sign($data, $mch_key){

$stringA = '';

ksort($data);

foreach ($data as $key=>$value){

if(!$value) continue;

if($stringA) $stringA .= '&'.$key."=".$value;

else $stringA = $key."=".$value;

}

$wx_key = $mch_key;

$stringSignTemp = $stringA.'&key='.$wx_key;//申请支付后有给予一个商户账号和密码,登陆后自己设置key

return strtoupper(md5($stringSignTemp));

}

/**

* [http_request CURL请求函数版本1 发送数组或字符串]

* @param [type] $url [description]

* @param [type] $data [description]

* @param array $headers [description]

* @return [type] [description]

*/

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;

}

/**

* [curl_post CURL请求函数 版本2 发送json]

* @param [String] $url [请求URL]

* @param [Array] $post_data [请求数组]

* @return [Array] [返回请求结果数组]

*/

public function curl_post($url, $post_data = ''){

$requestUrl = $url;

if ($post_data == '') {

$data_string = '{}';

}else{

$data = $post_data;

$data_string = json_encode($data, JSON_UNESCAPED_UNICODE);

}

$ch = curl_init($requestUrl);

curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");

curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);

curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);

curl_setopt($ch, CURLOPT_HTTPHEADER, array(

'Content-Type: application/json',

'Content-Length: ' . strlen($data_string)

));

$result = curl_exec($ch);

if (curl_errno($ch)) {

curl_close($ch);

print curl_error($ch);

}else{

$result = json_decode($result, true);

curl_close($ch);

return $result;

}

}

/**

* [xml xml转数组]

* @param [type] $xml [description]

* @return [type] [description]

*/

public function xml($xml){

//禁止引用外部xml实体

libxml_disable_entity_loader(true);

$values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);

return $values;

}

支付核心/**

* [Pay 支付]

* @return [type] [description]

*/

public function Pay() {

//支付金额

$fee = 0.01;

//公众号或小程序appid

$appid = '';

//商品描述

$body = 'XX服务购买';

//商户ID

$mch_id = '';

//商户key

$mch_key = '';

//随机字符串

$nonce_str = $this->nonce_str();

//异步回调URL(需在商户平台添加白名单)

$notify_url = '';

//用户openid

$openid = '';

//商户订单号

$out_trade_no = $this->order_number();

//用户openid

$openid = '';

//终端IP(服务器IP)

$spbill_create_ip = '';

//单位为分

$total_fee = $fee*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;

$post['total_fee'] = $total_fee;

$post['trade_type'] = $trade_type;

//生成签名

$sign = $this->sign($post, $mch_key);

//统一下单XML数据包生成

$post_xml = '

'.$appid.'

'.$mch_id.'

'.$nonce_str.'

'.$notify_url.'

'.$openid.'

'.$out_trade_no.'

'.$spbill_create_ip.'

'.$total_fee.'

'.$trade_type.'

'.$sign.'

';

//统一接口接口

$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';

//下单

$xml = $this->http_request($url,$post_xml);

//对下单结果解包(XML)

$array = $this->xml($xml);

if($array['return_code'] == 'SUCCESS' && $array['result_code'] == 'SUCCESS'){

$time = time();

$tmp = array();//临时数组用于签名

$tmp['appId'] = $appid;

$tmp['nonceStr'] = $nonce_str;

$tmp['package'] = 'prepay_id='.$array['prepay_id'];

$tmp['signType'] = 'MD5';

$tmp['timeStamp'] = "$time";

$data['state'] = 1;

$data['timeStamp'] = "$time"; //时间戳

$data['nonceStr'] = $nonce_str;//随机字符串

$data['signType'] = 'MD5'; //签名算法,暂支持 MD5

$data['package'] = 'prepay_id='.$array['prepay_id'];//统一下单接口返回的 prepay_id 参数值

$data['paySign'] = $this->sign($tmp);//签名,具体签名方案参见微信公众号支付帮助文档;

$data['out_trade_no'] = $out_trade_no;

}else{

$data['state'] = 0;

$data['text'] = "错误";

$data['RETURN_CODE'] = $array['RETURN_CODE'];

$data['RETURN_MSG'] = $array['RETURN_MSG'];

}

//订单储存到本地

$pay_data = array(

'order_id' => $out_trade_no,

'total_pay' => $fee,

'pay_status' => '未支付',

'pay_time' => time()

);

//输出订单数据到前端,调用支付SDK

echo json_encode($data, true);

}

异步回调

xml转数组函数function xmlToArray($xml)

{

//禁止引用外部xml实体

libxml_disable_entity_loader(true);

$values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);

return $values;

}

异步回调验证$pay_data = file_get_contents('php://input');

$pay_data = xmlToArray($pay_data);

if ($pay_data['result_code'] == 'SUCCESS' && $pay_data['return_code'] == 'SUCCESS') {

//此处为订单成功回调后的业务逻辑

//注:要验证订单真实性

}else{

//支付失败的业务逻辑,记录异常

}

备注

1.订单数据返回到前端之前,将订单信息插入到订单表,用来异步回调时核对账单。

2.异步回调要做好订单验证,相关验证SDK可以去微信支付开发文档查看。

3.本代码支持微信公众号和小程序的JSAPI支付。

4.本代码需要根据自身业务需求进行封装使用。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值