javascript前台
<script src="http://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
layui.use(['layer'],function () {
var layer=layui.layer;
$('.goumai').click(function () {
var id="{$data.id}";
$.ajax({
url:'/index/video/order',
data:{id:id},
type:'post',
success: function (data) {
if(data.status=='success'){
$.ajax({
url:'/index/wxpay/pay',
data:{id:data.id},
type:'post',
success:function (res) {
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId": res.data.appId, //公众号名称,由商户传入
"timeStamp":res.data.timeStamp, //时间戳,自1970年以来的秒数
"nonceStr":res.data.nonceStr, //随机串
"package":res.data.package,
"signType":res.data.signType, //微信签名方式:
"paySign":res.data.paySign //微信签名
},
function(e){
if(e.err_msg=="get_brand_wcpay_request:ok" ){
$.ajax({
url: '/index/wxpay/gaiorder',
data: {id:data.id},
type: 'post',
success: function (resb) {
if(resb.status='success'){
location.href='/index/video/paysuccess';
}else{
location.href='/index/video/payerror';
}
}
})
}else if(e.err_msg=="get_brand_wcpay_request:cancel"){
layer.msg('<span style=color:#fff>您已取消支付</span>')
}else{
layer.msg('<span style=color:#fff>支付失败</span>')
}
}
)
}
})
}
}
})
});
生成订单
public function order(Request $request)
{
$user_id=session('userid');
$id=Request()->post('id');
$video=Db::name('video')->find($id);
$order_num=time().rand(111,999); //订单号
$data=[
'uid'=>$user_id, //用户id
'video_id'=>$id, //视频id
'price'=>$video['price'], //vip金额
'order_num'=>$order_num, //订单号
'create_time'=>time(), //购买时间
'status'=>0, //订单状态
'differ'=>1,
];
$id=Db::name('order')->insertGetId($data);
if($id) return json(['status'=>'success','id'=>$id]);
}
//微信支付
public function paysuccess(){
return view();
}
public function payerror(){
return view();
}
调起支付
class Wxpay extends Controller {
protected $appid;
protected $mch_id;//商户号
protected $key;
protected $openid; //用户id
protected $out_trade_no; //$out_trade_no;//订单号
protected $body;//自定义商品描述
protected $total_fee; //金额
protected $notify_url; //异步通知地址
protected $trade_type; //交易类型
protected $config;
function get_client_ip($type = 0, $adv = true) {
$type = $type ? 1 : 0;
static $ip = NULL;
if ($ip !== NULL) return $ip[$type];
if($adv){
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
$pos = array_search('unknown',$arr);
if(false !== $pos) unset($arr[$pos]);
$ip = trim($arr[0]);
}elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
}elseif (isset($_SERVER['REMOTE_ADDR'])) {
$ip = $_SERVER['REMOTE_ADDR'];
}
}elseif (isset($_SERVER['REMOTE_ADDR'])) {
$ip = $_SERVER['REMOTE_ADDR'];
}
// IP地址合法验证
$long = sprintf("%u",ip2long($ip));
$ip = $long ? array($ip, $long) : array('0.0.0.0', 0);
return $ip[$type];
}
public function pay(Request $re) {
$id=$re->param('id');
$order=Db('order')->where('id',$id)->find();
$openid=Db('user')->where('id',$order['uid'])->value('openid');
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
$config=Db('wxpay_config')->where('id',1)->find();
$price=$order['price'];
$str=$this->createNoncestr();
$parameters = array(
'appid' => $config['appid'], //小程序ID
'mch_id' => $config['mch_id'], //商户号
'nonce_str' => $str, //随机字符串
'body' => $config['body'], //商品描述
'out_trade_no'=> $order['order_num'],//订单号
'total_fee' =>$price*100,//$total_fee*100, //金额
'spbill_create_ip' => $this->get_client_ip(), //终端IP
'notify_url' => $config['notify_url'], //通知地址 确保外网能正常访问
'openid' => $openid, //用户id
'trade_type' => $config['trade_type'],//交易类型
);
//统一下单签名
$parameters['sign'] = $this->getSign($parameters,$config['key']); //生成签名
$xmlData = $this->arrayToXml($parameters);
$a=$this->postXmlCurl($xmlData, $url, 60);
$return = $this->xmlToArray($a);
if($return['return_msg']=='OK'){
$parameters = array(
'appId' => $config['appid'], //小程序ID
'timeStamp' => '"'.time().'"', //时间戳
'nonceStr' => $str, //随机串
'package' => 'prepay_id='.$return['prepay_id'], //数据包
'signType' => 'MD5'//签名方式
);
//签名
$parameters['paySign'] = $this->getSign($parameters,$config['key']);
return json(['status'=>'success','msg'=>'','data'=>$parameters]);
}else{
return json(['status'=>'error']);
}
}
//支付成功逻辑处理
public function gaiorder(){
$id=Request()->param('id');
$order=Db('order')->where('id',$id)->find();
if($order){
if($order['status'] == 0){
if($order['differ']==1){
$data=[
'payment_time'=>time(),
'status'=>1
];
$result=Db::name('order')->where('order_num',$order['order_num'])->update($data);
if($result){
//更新余额
$userid=Db::name('video')->where('id',$order['video_id'])->value('uid');
$balance=Db::name('user')->where('id',$userid)->value('balance');
$balance+=$order['price']*0.7;
Db::name('user')->where('id',$userid)->update(['balance'=>$balance]);
return json(['status'=>'success','msg'=>'支付成功']);
}else{
return json(['status'=>'error','msg'=>'支付失败']);
}
}
if($order['differ']==2){
$data=[
'payment_time'=>time(),
'status'=>1
];
$result=Db::name('order')->where('order_num',$order['order_num'])->update($data);
if($result){
//更新余额
$user_id=Db::name('order')->where('order_num',$order['order_num'])->value('user_id');
$balance=Db::name('user')->where('id',$user_id)->value('balance');
$balance+=$order['price'];
Db::name('user')->where('id',$user_id)->update(['balance'=>$balance]);
return json(['status'=>'success','msg'=>'支付成功']);
}else{
return json(['status'=>'error','msg'=>'支付失败']);
}
}
}
}
}
private static 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_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
curl_setopt($ch, CURLOPT_TIMEOUT, 40);
set_time_limit(0);
//运行curl
$data = curl_exec($ch);
//返回结果
if ($data) {
curl_close($ch);
return $data;
} else {
$error = curl_errno($ch);
curl_close($ch);
throw new WxPayException("curl出错,错误码:$error");
}
}
//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;
}
//数组转换成xml
private function arrayToXml($arr) {
$xml = "<root>";
foreach ($arr as $key => $val) {
if (is_array($val)) {
$xml .= "<" . $key . ">" . arrayToXml($val) . "</" . $key . ">";
} else {
$xml .= "<" . $key . ">" . $val . "</" . $key . ">";
}
}
$xml .= "</root>";
return $xml;
}
//作用:格式化参数,签名过程需要使用
private function formatBizQueryParaMap($paraMap, $urlencode) {
$buff = "";
ksort($paraMap);
foreach ($paraMap as $k => $v) {
if ($urlencode) {
$v = urlencode($v);
}
$buff .= $k . "=" . $v . "&";
}
$reqPar;
if (strlen($buff) > 0) {
$reqPar = substr($buff, 0, strlen($buff) - 1);
}
return $reqPar;
}
//作用:生成签名
private function getSign($Obj,$AppSecret) {
foreach ($Obj as $k => $v) {
$Parameters[$k] = $v;
}
//签名步骤一:按字典序排序参数
ksort($Parameters);
$String = $this->formatBizQueryParaMap($Parameters, false);
//签名步骤二:在string后加入KEY
$String = $String . "&key=" . $AppSecret;
//签名步骤三:MD5加密
$String = md5($String);
//签名步骤四:所有字符转为大写
$result_ = strtoupper($String);
return $result_;
}
//作用:产生随机字符串,不长于32位
private function createNoncestr($length = 32) {
$chars = "abcdefghijklmnopqrstuvwxyz0123456789";
$str = "";
for ($i = 0; $i < $length; $i++) {
$str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
}
return $str;
}
}