首先从小程序端接收订单号、金额等参数,然后后台进行统一下单,把微信支付的订单号返回,在把订单号发送给前台,前台拉起支付,返回参数后更改支付状态。。。
回调
public function notify() {
$wechat=Db::name('wechat')->where('status',1)->find();
//$post = $GLOBALS['HTTP_RAW_POST_DATA'];
$post = file_get_contents("php://input"); //接受POST数据XML个数
// $order_over_test['openid']=$post;
// Db::name('order_over')->insert($order_over_test);
$post_data = $this->xml_to_array($post);
//输出订单号
$order_sn = $post_data['out_trade_no'];
$order_over['order_sn']=$order_sn;
$order_over['money']=$post_data['total_fee'];
$order_over['openid']=$post_data['openid'];
$order_over['time_end']=$post_data['time_end'];
$order_update['status']='1';
// Db::name('order_over')->insert($order_over);
$order_info=Db::name('order')->where('order_id',$order_sn)->find();
if ($post_data['return_code'] == 'SUCCESS') {
//判断证书是否正确
// if ($postSign != $user_sign) {
// Log::write('签名不匹配');
// exit;
// }
if ($order_info['status'] != '1') {
Db::name('order_over')->insert($order_over);
$result=Db::name('order')->where('order_id', $order_sn)->update($order_update);
}
return 'success';
} else {
return 'error';
//$this->error('error!');
}
}
public function xmlToArray($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;
}
public function xml_to_array($xml){
if(!$xml){
return false;
}
//将XML转为array
//禁止引用外部xml实体
libxml_disable_entity_loader(true);
$data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $data;
}
public static function ToUrlParams($data)
{
$buff = "";
foreach ($data as $k => $v)
{
if($k != "sign" && $v != "" && !is_array($v)){
$buff .= $k . "=" . $v . "&";
}
}
$buff = trim($buff, "&");
return $buff;
}
统一下单
public function getwxpay($orderSn,$money)
{
// $orderSn=$orderSn;
$body='广告投放';
//$orderSn='HB14257311281654';
//$money= '1';
$money=$money*100;
$wechat=Db::name('wechat')->where('status',1)->find();
$order_id=$orderSn;
// $money= $money; //充值金额 微信支付单位为分
$appid = $wechat['appid']; //应用APPID
$mch_id =$wechat['mch_id']; //微信支付商户号
$KEY = $wechat['key']; //微信商户API密钥
$out_trade_no = $orderSn ;//平台内部订单号
$nonce_str = $this->rand_code();//随机字符串
// $openid='oM0TH0nyMtlyrP_J8cOL70oLYaCw';
$openid=session('openid');
//获取系统的配置
//$nonce_str = $this->rand_str(12);//随机字符串
$notify_url = "http://**********************t/Wxnotify/notify"; //支付完成回调地址url,不能带参数
$spbill_create_ip = get_client_ip();
$trade_type = 'JSAPI';//交易类型 默认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'] = intval($money); //总金额 最低为一分钱 必须是整数
$post['trade_type'] = $trade_type;
$sign = $this->MakeSign($post, $KEY); //签名
$this->sign = $sign;
$post_xml = "
<xml>
<appid>$appid</appid>
<mch_id>$mch_id</mch_id>
<nonce_str>$nonce_str</nonce_str>
<body>$body</body>
<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>{$post["total_fee"]}</total_fee>
<trade_type>$trade_type</trade_type>
<sign>$sign</sign>
</xml>";
//统一下单接口prepay_id
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
$xml = $this->http_request($url, $post_xml); //POST方式请求http
$array = $this->xml2array($xml); //将【统一下单】api返回xml数据转换成数组,全要大写
$array['my_sign'] = $sign;
$array['post_xml'] = $post_xml;
$array['source_xml'] = $xml;
if ($array['RETURN_CODE'] == 'SUCCESS' && $array['RESULT_CODE'] == 'SUCCESS') {
$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'] = 1;
$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->MakeSign($tmp, $KEY); //签名,具体签名方案参见微信公众号支付帮助文档;
$data['prepay_id'] = $array['PREPAY_ID'];
$data['out_trade_no'] = $out_trade_no;
$data['order_id'] = $order_id;
} else {
// $data['statusCode'] = ;
$data['statusMsg'] = "请求错误";
$data['data']['RETURN_CODE'] = $array['RETURN_CODE'];
$data['data']['RETURN_MSG'] = $array['RETURN_MSG'];
}
return $data;
}
public function postXmlCurl($xml,$url,$second = 30){
$ch = curl_init();
//设置超时
curl_setopt($ch, CURLOPT_TIMEOUT, $second);
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);
//设置header
curl_setopt($ch, CURLOPT_HEADER, FALSE);
//要求结果为字符串且输出到屏幕上
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
//post提交方式
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
//运行curl
$data = curl_exec($ch);
//返回结果
if($data){
curl_close($ch);
return $data;
}else{
$error = curl_errno($ch);
curl_close($ch);
echo "curl出错,错误码:$error"."<br>";
}
}
//生成签名
public function MakeSign($params, $KEY)
{
//签名步骤一:按字典序排序数组参数
ksort($params);
$string = $this->ToUrlParams($params); //参数进行拼接key=value&k=v
//签名步骤二:在string后加入KEY
$string = $string . "&key=" . $KEY;
//签名步骤三:MD5加密
$string = md5($string);
//签名步骤四:所有字符转为大写
$result = strtoupper($string);
return $result;
}
/**
* 格式化参数格式化成url参数
*/
public static function ToUrlParams($data)
{
$buff = "";
foreach ($data as $k => $v)
{
if($k != "sign" && $v != "" && !is_array($v)){
$buff .= $k . "=" . $v . "&";
}
}
$buff = trim($buff, "&");
return $buff;
}
//发送http请求
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);
//
$zs1 = CMF_ROOT . "cert/apiclient_cert.pem";
$zs2 = CMF_ROOT . "cert/apiclient_key.pem";
// curl_setopt ( $curl, CURLOPT_SSLCERT, $zs1 );
// curl_setopt ( $curl, CURLOPT_SSLKEY, $zs2 );
//设置证书
//使用证书:cert 与 key 分别属于两个.pem文件
curl_setopt($curl, CURLOPT_SSLCERTTYPE, 'PEM');
curl_setopt($curl, CURLOPT_SSLCERT, $zs1);
curl_setopt($curl, CURLOPT_SSLKEYTYPE, 'PEM');
curl_setopt($curl, CURLOPT_SSLKEY, $zs2);
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里面数据,转换成array
public function xml2array($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;
}
//随机字符串
public function rand_code($length = 16) {
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
$str = "";
for ($i = 0; $i < $length; $i++) {
$str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
}
return $str;
}
public function ToXml($data=array())
{
if(!is_array($data) || count($data) <= 0)
{
return '数组异常';
}
$xml = "<xml>";
foreach ($data as $key=>$val)
{
if (is_numeric($val)){
$xml.="<".$key.">".$val."</".$key.">";
}else{
$xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
}
}
$xml.="</xml>";
return $xml;
}
前台页面拉起微信支付
<!DOCTYPE html>
<html>
<head>
<title>订单支付 {$site_info.site_name|default=''}</title>
<meta name="keywords" content="{$site_info.site_seo_keywords|default=''}"/>
<meta name="description" content="{$site_info.site_seo_description|default=''}">
<include file="public@head"/>
</head>
<body >
<include file="public@top"/>
<hook name="before_head_end"/>
<!-- top -->
<div class="zt">
<div class="am-container">
<div>
<div class="order_info">
<h3 class="am-text-center">核实订单</h3>
</div>
<div class="order_money am-text-center">
<table class="am-table ">
<tr>
<td>订单号</td>
<td class="am-text-right">{$order_info['order_id']}</td>
</tr>
<tr>
<td>金额</td>
<td class="am-text-right">{$order_info['money']}¥</td>
<input type="hidden" name="money" id="money_input" value="">
</tr>
</table>
</div>
<div class="am-form-group">
<button style="width:210px; height:50px; border-radius: 15px;background-color:#FE6714; border:0px #FE6714 solid; cursor: pointer; color:white; font-size:16px;" type="button" onclick="callpay()" >立即支付</button>
</div>
</div>
</div>
</div>
<include file="public@footer"/>
<!-- <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script> -->
<script type="text/javascript">
//调用微信JS api 支付
function jsApiCall()
{
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId":'{$wechat['appid']}', //公众号名称,由商户传入
"timeStamp":'{$wxpay_status['timeStamp']}', //时间戳,自1970年以来的秒数
"nonceStr":'{$wxpay_status['nonceStr']}', //随机串
"package":'{$wxpay_status['package']}',
"signType":"MD5", //微信签名方式:
"paySign":'{$wxpay_status['paySign']}'//微信签名
},
function(res){
console.log(res);
WeixinJSBridge.log(res.err_msg);
//alert('err_code:'+res.err_code+'err_desc:'+res.err_desc+'err_msg:'+res.err_msg);
//alert(res.err_code+res.err_desc+res.err_msg);
//alert(res);
if(res.err_msg == "get_brand_wcpay_request:ok"){
alert("支付成功!");
window.location.href="http://m.sxcrcm.com";
}else if(res.err_msg == "get_brand_wcpay_request:cancel"){
alert("用户取消支付!");
}else{
alert("支付失败!");
}
}
);
}
function callpay()
{
if (typeof WeixinJSBridge == "undefined"){
if( document.addEventListener ){
document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);
}else if (document.attachEvent){
document.attachEvent('WeixinJSBridgeReady', jsApiCall);
document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
}
}else{
jsApiCall();
}
}
</script>
</body>