工作中经常用到微信支付或小程序支付,特此整理一下基础代码,方便以后重复造轮子的时候用得上……本文代码不可直接放入生产环境使用,需要根须自身产品需求进行代码封装。
事先准备工作
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 = '<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> ';
//统一接口接口
$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.本代码需要根据自身业务需求进行封装使用。
gg修改器http://www.guiyangtax.com/
地铁跑酷破解版https://www.n012.cn/
王者荣耀点券修改器http://www.wzryzx.cn/
要认证号才行对吗
认证过的服务号或小程序,并且开通微信支付。如果有认证的服务号并且开通了支付,可以使用服务号快速开通小程序,这样小程序也同样认证+开通微信支付了(需要微信商户授权)。
学习了,技术博客啊,收藏了!
程序倒是好搞,认证麻烦得要死
路过赞一个|´・ω・)ノ