class Payment extends Apiclass
{
public $config;
function __construct()
{
//查询小程序配置信息
$this->config=Db::name('payinfo')->where('type',1)->find();
}
//支付
public function pay()
{
//接收小程序端传的参数
$id = input('id');
$user_id = input('user_id');
$goods_name = input('goods_name');
//查询订单信息
$order=Db::name('order')->where(['id'=>$id,'user_id'=>$user_id])->find();
//获取openid
$user=Db::name('users')->where('id',$user_id)->find();
if (empty($user['open_id'])) {
return $this->msg(false,'openid不存在');
}
$openid=$user['open_id'];
$param=[
'appid'=>$this->config['appid'], //小程序appid
'mch_id'=>$this->config['mch_id'], //商户id
'nonce_str'=>$this->getRand(20,true), //随机字符串
'body'=>$goods_name, //商品名称
'out_trade_no'=>$order['order_no'], //订单号
'total_fee'=> 100, //支付金额(分)
'spbill_create_ip'=>$this->get_client_ip(), //用户ip
'notify_url'=>$this->config['notify_url'], //支付回调地址
'trade_type'=>'JSAPI', //
'openid'=>$openid //用户的openid
];
//生成签名
$sign=$this->makeSign($param,$this->config['mchkey']);
$param['sign']=$sign;
try{
//将数组转换成xml数据
$xml=$this->ToXml($param);
}catch (\Exception $e){
return $this->msg('false',$e->getMessage());
}
//微信小程序支付接口地址
$url="https://api.mch.weixin.qq.com/pay/unifiedorder";
//请求微信支付接口
$getXml=$this->curl_post($url,$xml,false);
//将微信返回值转换成数组
$getArr=$this->FromXml($getXml);
if ($getArr['return_code']=='SUCCESS'&&$getArr['result_code']=='SUCCESS') {
//请求成功
$prepay_id=$getArr['prepay_id'];
$data['appId']=$this->config['appid'];
$time = time();
$data['timeStamp']="{$time}";
$data['nonceStr']=$this->getRand(20,true);
$data['package']="prepay_id=".$prepay_id;
$data['signType']='MD5';
$data['paySign']=$this->makeSign($data,$this->config['mchkey']);
} else if($getArr['return_code']=='SUCCESS'&&$getArr['result_code']=='FAIL') {
$data['code']=$getArr['err_code'];
$data['msg']=$getArr['err_code_des'];
} else {
$data['code']=$getArr['return_code'];
$data['msg']=$getArr['return_msg'];
}
return $this->msg('true','请求结果',$data);
}
//支付成功回调
public function paysuccess()
{
//接收微信返回的数据数据,返回的xml格式
$xmlData = file_get_contents('php://input');
//下面四行代码可以将支付返回的xml数据写入一个文件,从文件中复制xml代码,赋值给 $xmlData 变量,就可以重复测试此接口,不用每次测试都执行支付接口
// $myfile = fopen(__DIR__."newfile.txt", "w") or die("Unable to open file!");
// $txt = $xmlData;
// fwrite($myfile, $txt);
// fclose($myfile);
//将xml格式转换为数组
$data = $this->FromXmls($xmlData);
if ($data[0] == 'false') {
return;
}
//记录一下,返回回来的签名,生成签名的时候,必须剔除sign字段。
$data = $data[1];
if (!isset($data['sign'])) {
return;
}
$sign = $data['sign'];
unset($data['sign']);
if($sign == $this->makeSign($data,$this->config['mchkey'])){
//签名验证成功后
if ($data['result_code'] == 'SUCCESS') {
//支付成功
$orderId = $data['out_trade_no'];
Db::startTrans();
try {
//在这里执行支付成功后的逻辑
Db::commit();
} catch (\Exception $e) {
Db::rollback();
}
}else {
//支付失败,输出错误信息
return json_encode(['false',$data['return_msg']]);
}
} else {
return json_encode(['true','签名失败!']);
}
}
//将xml转换成数组
private function FromXmls($xml)
{
if(!$xml){
return ['false','xml数据异常!'];
}
//将XML转为array
//禁止引用外部xml实体
libxml_disable_entity_loader(true);
$data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return ['true',$data];
}
//将数组转换成xml数据
public function ToXml($data)
{
if(!is_array($data)
|| count($data) <= 0)
{
throw new Exception("数组数据异常!");
}
$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;
}
//获取随机字符串
protected function getRand( $length = 6,$isAll = false)
{
if ($isAll) {
$chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
} else {
$chars = '0123456789';
}
$randStr = '';
for ( $i = 0; $i < $length; $i++ )
{
$randStr .= $chars[ mt_rand(0, strlen($chars) - 1) ];
}
return $randStr;
}
//生成签名
protected function makeSign($param,$key)
{
ksort($param);
$string=$this->toUrlParams($param);
$string=$string.'&key='.$key;
$string=md5($string);
$result=strtoupper($string);
return $result;
}
//拼接字符串
protected function toUrlParams($param)
{
$string='';
if (!empty($param)) {
$array=array();
foreach ($param as $key=>$v) {
$array[]=$key.'='.$v;
}
$string=implode('&',$array);
}
return $string;
}
//获取哦用户的ip地址
protected function get_client_ip(){
if(!empty($_SERVER["HTTP_CLIENT_IP"]))
{
$cip = $_SERVER["HTTP_CLIENT_IP"];
}
else if(!empty($_SERVER["HTTP_X_FORWARDED_FOR"]))
{
$cip = $_SERVER["HTTP_X_FORWARDED_FOR"];
}
else if(!empty($_SERVER["REMOTE_ADDR"]))
{
$cip = $_SERVER["REMOTE_ADDR"];
}
else
{
$cip = '';
}
preg_match("/[\d\.]{7,15}/", $cip, $cips);
$cip = isset($cips[0]) ? $cips[0] : '127.0.0.1';
unset($cips);
return $cip;
}
//curl请求模块
protected function curl_post($url,$post_data,$isTrue = true)
{
if (is_array($post_data)) {
$postData = http_build_query($post_data);
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
$data = curl_exec($ch);
curl_close($ch);
return $data;
}
//统一返回
public function msg($code,$msg,$data = [])
{
return ['code'=>$code,'msg'=>$msg,'data'=>$data];
}
小程序端
wx.requestPayment(
{
"timeStamp":res.data.data.timeStamp,
"nonceStr": res.data.data.nonceStr,
"package": res.data.data.package,
"signType": res.data.data.signType,
"paySign": res.data.data.paySign,
"success":function(res){
wx.showModal({
title: '提示',
content: '支付成功',
confirmText:'立即查看',
success: function (res) {
if (res.confirm) {
wx.navigateTo({
url: '/pages/wode/quan'
})
}
}
})
},
"fail":function(res){},
"complete":function(res){}
})