<?php
/**
* Created by PhpStorm.
* User: mabao
* Date: 2018/6/13
* Time: 10:40
*/
namespace app\api\controller;
use think\Controller;
use think\Db;
class Weixin extends Base {
// 定义配置项
private $config=array(
'APPID' => 'wx79afdec9ad2e67a2', // 微信支付APPID.
'MCHID' => '1557327661', // 微信支付MCHID 商户收款账号
'KEY' => 'qAIpKcjJQrgQJMbzfNqYoBBgFj1STO31', // 微信支付KEY
'APPSECRET' => '81b17ac2628875727b2393c1bb285e05', // 公众帐号secert (公众号支付专用)
'NOTIFY_URL' => '', // 接收支付状态的连接
);
public $body;//描述
public $total_fee;//喵额
public $out_trade_no;//订单号
// 构造函数
public function __construct($config=null){
// 如果配置项为空 则直接返回
if (!empty($config)) {
$this->config=$config;
}
}
/**
* 对返回信息的统一处理
* @param $data 成功需要返回的信息
* @param $go 是否需要继续对信息进行处理
* @param $ext 扩展字段数组
*/
protected function apiSuccess($data = '',$extra = '')
{
$info['status'] = '200';
$info['msg']= '成功';
if ($data || is_array($data)) {
$info['data'] = $data;
}
if($extra){
foreach ($extra as $key=>$value){
$info[$key] = $value;
}
}
$returnInfo = json_encode($info, JSON_UNESCAPED_UNICODE);
echo $returnInfo;
exit;
}
/***
* @param $code
* @param string $msg
* 错误返回信息
*/
protected function apiError($code, $msg = '')
{
if (!$msg) {
$info['msg'] = $this->_error[$code]['msg'];
} else {
$info['msg'] = $msg;
}
$info['status'] = $code;
$returnInfo = json_encode($info, JSON_UNESCAPED_UNICODE);
echo $returnInfo;
exit();
}
/**
* 微信支付接口
* @return string
* classroom_id:课程ID,当type为1时,传此参数
* user_id:用户ID,
* type:1 课程购买 2 捐赠 3 打赏
* price:打赏或捐赠的价格,当type为2或者3时传
* activity_id:捐赠的活动ID,当type为2时,传此值
*/
public function FacePay(){
extract(input());
$params = input('param.');
// $params['money'] = 1;
// $params['device_info'] = 'FPATL1941010351TYA12606';
// $params['openid'] = 'o-tBouMFqu1xkWMF8qFlvBIQcG5E';
// $params['face_code'] = 'a0f8a6b9-a0f8-4098-a8c5-94a26447807c';
// $params['order_num'] = '1572342602815654210';
$order_number = $params['order_num'];//订单编号
if(empty($params['device_info'])){
return json_encode(['status'=>0,'msg'=>'设备号不能为空']);
}
$params['device_info'] = strtoupper($params['device_info']);
$have_order = Db::table('up_order')->where('order_num',$order_number)->find();
if($have_order){
return json_encode(['status'=>0,'msg'=>'订单号重复,请刷新重试']);
}
if($params['money'] <= 0){
return json_encode(['status'=>0,'msg'=>'金额为0,无需支付']);
}
//---添加分账
$shopdevice = Db::table('up_shop_device')->where('shop_device_id',$params['device_info'])->find();
if(empty($shopdevice)){
return json_encode(['status'=>0,'msg'=>'此设备不存在或已被清除,请联系相关人员']);
}
// $add_res = $this->addFen($shopdevice['shop_wx'],$shopdevice['shop_username']);
$add_res = $this->addFen();
if($add_res['status'] != 200){
return json_encode(['status'=>0,'msg'=>'分账方添加失败,请刷新重试']);
}
//---添加分账end
$data['order_num'] = $order_number;
$data['order_money'] = $params['money'];
$data['order_time'] = date('Y-m-d H:i:s');
$data['order_openid'] = $params['openid'];
$data['order_device_id'] = $params['device_info'];
$data['order_shi'] = $shopdevice['shop_shi'];
$order_id = Db::table('up_order')->insertGetId($data);
if(!$order_id){
return json_encode(['status'=>0,'msg'=>'订单生成失败,请刷新重试']);
}
$this->body = '刷脸支付';
$this->total_fee = $params['money'] * 100;
$this->out_trade_no = $order_number;
$order = array();
$order['body'] = $this->body;//描述
$order['total_fee'] = $this->total_fee;//订单喵额
$order['out_trade_no'] = $this->out_trade_no;//订单号
// $order['device_info'] = $params['device_info'];//产品ID
// $order['openid'] = $params['openid'];//类型
$order['auth_code'] = $params['face_code'];//类型
$order['profit_sharing'] = 'Y';//类型
$res_back = $this->WeChatPayReady($order);
if($res_back['status'] == 200){
//
//分账之前先改订单状态
Db::table('up_order')->where('order_num',$order_number)->update([
'order_status' => 2,
'order_wx_back_num' => $res_back['msg'],
'order_pay_time' => date('Y-m-d H:i:s')
]);
$config = Db::table('up_about')->where('id',1)->find();
$four_get = 0;
if($params['money'] >= 0.1){
$allmoney = $params['money'] - sprintf("%.2f",$params['money']*0.003);
$four_get = sprintf("%.2f",($allmoney * $config['shop'])/10000);
$shopmoney = $allmoney - $four_get;
if($four_get > 0){
//TODO:这四个等级去分钱
$this->fenxiao1_3($shopdevice['shop_fid'],$four_get,$order_id,$config);
}
}else{
$shopmoney = $params['money'];
}
$shopmoney = sprintf("%.2f",$shopmoney);
// $fen_res = $this->fenMoney($res_back['transaction_id'],$order_number,$shopdevice['shop_wx'],$shopmoney);
$fen_res = $this->fenMoney($res_back['msg'],$order_number,'1557327661',1);
if($fen_res['status'] == 200){
//分账成功之后再改这个
Db::table('up_order')->where('order_num',$order_number)->update([
'order_shopmoney' => $shopmoney, //店铺老板得到了多少
'order_fourmoney' => $four_get //分账了多少
]);
}else{
return json_encode($fen_res);
}
}else{
return json_encode($res_back);
}
return json_encode($res_back);
// return json_encode(['status'=>200,'msg'=>$respont]);
}
public function fenxiao1_3($fid,$money,$order_id,$config)
{
$today = date('Y-m-d H:i:s');
if($fid == 0){
$oi = array();
$oi['info_order_id'] = $order_id;
$oi['info_fen_id'] = 0;
$oi['info_level'] = 0;
$oi['info_money'] = $money;
$oi['info_time'] = $today;
Db::table('up_order_info')->insert($oi);
}else{
$top = sprintf("%.2f",($money * $config['top'])/100);
if($top > 0){
$oi = array();
$oi['info_order_id'] = $order_id;
$oi['info_fen_id'] = 0;
$oi['info_level'] = 0;
$oi['info_money'] = $top;
$oi['info_time'] = $today;
Db::table('up_order_info')->insert($oi);
Db::table('up_admin')->where('id',1)->setInc('money',$oi['info_money']);
}
$info = Db::table('up_fenxiao')->where('fen_id',$fid)->find();
if($info['fen_level'] == 1){
$oi = array();
$oi['info_order_id'] = $order_id;
$oi['info_fen_id'] = $fid;
$oi['info_level'] = 1;
$oi['info_money'] = $money - $top;
$oi['info_time'] = $today;
Db::table('up_order_info')->insert($oi);
Db::table('up_fenxiao')->where('fen_id',$fid)->setInc('fen_money',$oi['info_money']);
}else{
if($info['fen_fid'] > 0){
$oneinfo = Db::table('up_fenxiao')->where('fen_id',$info['fen_fid'])->find();
if($oneinfo['fen_fid'] > 0){ //三级
$one = sprintf("%.2f",($money * $config['one'])/100);
if($one > 0){
$oi = array();
$oi['info_order_id'] = $order_id;
$oi['info_fen_id'] = $oneinfo['fen_fid'];
$oi['info_level'] = 1;
$oi['info_money'] = $one;
$oi['info_time'] = $today;
Db::table('up_order_info')->insert($oi);
Db::table('up_fenxiao')->where('fen_id',$oneinfo['fen_fid'])->setInc('fen_money',$oi['info_money']);
}
$two = sprintf("%.2f",($money * $config['two'])/100);
if($two > 0){
$oi = array();
$oi['info_order_id'] = $order_id;
$oi['info_fen_id'] = $info['fen_fid'];
$oi['info_level'] = 2;
$oi['info_money'] = $two;
$oi['info_time'] = $today;
Db::table('up_order_info')->insert($oi);
Db::table('up_fenxiao')->where('fen_id',$info['fen_fid'])->setInc('fen_money',$oi['info_money']);
}
$oi = array();
$oi['info_order_id'] = $order_id;
$oi['info_fen_id'] = $fid;
$oi['info_level'] = 3;
$oi['info_money'] = $money - $top - $one - $two;
$oi['info_time'] = $today;
Db::table('up_order_info')->insert($oi);
Db::table('up_fenxiao')->where('fen_id',$fid)->setInc('fen_money',$oi['info_money']);
}else{ //二级
$one = sprintf("%.2f",($money * $config['one'])/100);
if($one > 0){
$oi = array();
$oi['info_order_id'] = $order_id;
$oi['info_fen_id'] = $info['fen_fid'];
$oi['info_level'] = $oneinfo['fen_level'];
$oi['info_money'] = $one;
$oi['info_time'] = $today;
Db::table('up_order_info')->insert($oi);
Db::table('up_fenxiao')->where('fen_id',$info['fen_fid'])->setInc('fen_money',$oi['info_money']);
}
$oi = array();
$oi['info_order_id'] = $order_id;
$oi['info_fen_id'] = $fid;
$oi['info_level'] = $info['fen_level'];
$oi['info_money'] = $money - $top - $one;
$oi['info_time'] = $today;
Db::table('up_order_info')->insert($oi);
Db::table('up_fenxiao')->where('fen_id',$fid)->setInc('fen_money',$oi['info_money']);
}
}else{
$oi = array();
$oi['info_order_id'] = $order_id;
$oi['info_fen_id'] = $fid;
$oi['info_level'] = $info['fen_level'];
$oi['info_money'] = $money - $top;
$oi['info_time'] = $today;
Db::table('up_order_info')->insert($oi);
Db::table('up_fenxiao')->where('fen_id',$fid)->setInc('fen_money',$oi['info_money']);
}
}
}
}
// public function fenxiao1_3($fid,$money,$order_id,$config)
// {
// if($fid == 0){
// $oi = array();
// $oi['info_order_id'] = $order_id;
// $oi['info_fen_id'] = 0;
// $oi['info_level'] = 0;
// $oi['info_money'] = $money;
// Db::table('up_order_info')->insert($oi);
// }else{
// $top = sprintf("%.2f",($money * $config['top'])/100);
// if($top > 0){
// $oi = array();
// $oi['info_order_id'] = $order_id;
// $oi['info_fen_id'] = 0;
// $oi['info_level'] = 0;
// $oi['info_money'] = $top;
// Db::table('up_order_info')->insert($oi);
// Db::table('up_admin')->where('id',1)->setInc('money',$oi['info_money']);
// }
// $info = Db::table('up_fenxiao')->where('fen_id',$fid)->find();
// if($info['fen_level'] == 1){
// $oi = array();
// $oi['info_order_id'] = $order_id;
// $oi['info_fen_id'] = $fid;
// $oi['info_level'] = 1;
// $oi['info_money'] = $money - $top;
// Db::table('up_order_info')->insert($oi);
// Db::table('up_fenxiao')->where('fen_id',$fid)->setInc('fen_money',$oi['info_money']);
// }
// if($info['fen_level'] == 2){
// $one = sprintf("%.2f",($money * $config['one'])/100);
// if($one > 0){
// $oi = array();
// $oi['info_order_id'] = $order_id;
// $oi['info_fen_id'] = $info['fen_fid'];
// $oi['info_level'] = 1;
// $oi['info_money'] = $one;
// Db::table('up_order_info')->insert($oi);
// Db::table('up_fenxiao')->where('fen_id',$info['fen_fid'])->setInc('fen_money',$oi['info_money']);
// }
// $oi = array();
// $oi['info_order_id'] = $order_id;
// $oi['info_fen_id'] = $fid;
// $oi['info_level'] = 2;
// $oi['info_money'] = $money - $top - $one;
// Db::table('up_order_info')->insert($oi);
// Db::table('up_fenxiao')->where('fen_id',$fid)->setInc('fen_money',$oi['info_money']);
// }
// if($info['fen_level'] == 3){
// $one = sprintf("%.2f",($money * $config['one'])/100);
// if($one > 0){
// $oneinfo = Db::table('up_fenxiao')->where('fen_id',$info['fen_fid'])->find();
// $oi = array();
// $oi['info_order_id'] = $order_id;
// $oi['info_fen_id'] = $oneinfo['fen_fid'];
// $oi['info_level'] = 1;
// $oi['info_money'] = $one;
// Db::table('up_order_info')->insert($oi);
// Db::table('up_fenxiao')->where('fen_id',$oneinfo['fen_fid'])->setInc('fen_money',$oi['info_money']);
// }
// $two = sprintf("%.2f",($money * $config['two'])/100);
// if($two > 0){
// $oi = array();
// $oi['info_order_id'] = $order_id;
// $oi['info_fen_id'] = $info['fen_fid'];
// $oi['info_level'] = 2;
// $oi['info_money'] = $two;
// Db::table('up_order_info')->insert($oi);
// Db::table('up_fenxiao')->where('fen_id',$info['fen_fid'])->setInc('fen_money',$oi['info_money']);
// }
// $oi = array();
// $oi['info_order_id'] = $order_id;
// $oi['info_fen_id'] = $fid;
// $oi['info_level'] = 3;
// $oi['info_money'] = $money - $top - $one - $two;
// Db::table('up_order_info')->insert($oi);
// Db::table('up_fenxiao')->where('fen_id',$fid)->setInc('fen_money',$oi['info_money']);
// }
// }
// }
/**
* 统一下单
* @param array $order 订单 必须包含支付所需要的参数 body(产品描述)、total_fee(订单喵额)、out_trade_no(订单号)、product_id(产品id)、trade_type(类型:JSAPI,NATIVE,APP)
*/
public function WeChatPayReady($order){
// 获取配置项
$weixinpay_config=$this->config;
$config=array(
'appid'=>$weixinpay_config['APPID'],
'mch_id'=>$weixinpay_config['MCHID'],
'nonce_str'=>$this->getRandChar(32),
'spbill_create_ip'=>$_SERVER['REMOTE_ADDR']
);
// 合并配置数据和订单数据
$data=array_merge($order,$config);
// 生成签名
$sign=$this->makeSign($data);
$data['sign']=$sign;
$xml=$this->toXml($data);
$url = 'https://api.mch.weixin.qq.com/pay/micropay';//接收xml数据的文件
$header[] = "Content-type: text/xml";//定义content-type为xml,注意是数组
$ch = curl_init ($url);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);//严格校验
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
$response = curl_exec($ch);
if(curl_errno($ch)){
print curl_error($ch);
}
curl_close($ch);
$result=$this->toArray($response);
if($result['return_code'] != 'SUCCESS'){
return ['status'=>0,'msg'=>$result['return_msg']];
// $this->apiError(0,$result['return_msg']);
}else{
if($result['return_code'] != 'SUCCESS'){
return ['status'=>0,'msg'=>$result['err_code']];
// $this->apiError(0,$result['err_code']);
}else{
return ['status'=>200,'msg'=>$result['transaction_id']];
// $this->apiSuccess();
}
}
}
/**
* 生成签名
* @return 签名,本函数不覆盖sign成员变量,如要设置签名需要调用SetSign方法赋值
*/
public function makeSign($data,$signty=false){
// 去空
$data=array_filter($data);
//签名步骤一:按字典序排序参数
ksort($data);
$string_a=http_build_query($data);
$string_a=urldecode($string_a);
//签名步骤二:在string后加入KEY
$config=$this->config;
$string_sign_temp=$string_a."&key=".$config['KEY'];
//签名步骤三:MD5加密
$sign = md5($string_sign_temp);
if($signty == true){
$sign = hash_hmac("sha256",$string_sign_temp ,$config['KEY']);
}
// 签名步骤四:所有字符转为大写
$result=strtoupper($sign);
return $result;
}
/**
* 将xml转为array
* @param string $xml xml字符串
* @return array 转换得到的数组
*/
public function toArray($xml){
//禁止引用外部xml实体
libxml_disable_entity_loader(true);
$result= json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $result;
}
/**
* 输出xml字符
* @throws WxPayException
**/
public function toXml($data){
//var_dump($data);
if(!is_array($data) || count($data) <= 0){
throw new WxPayException("数组数据异常!");
}
$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;
}
//数组转xml
function arrayToXml($arr)
{
$xml = "<xml>";
foreach ($arr as $key=>$val)
{
if (is_numeric($val))
{
$xml.="<".$key.">".$val."</".$key.">";
}
else
$xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
}
$xml.="</xml>";
return $xml;
}
//获取指定长度的随机字符串
function getRandChar($length){
$str = null;
$strPol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
$max = strlen($strPol)-1;
for($i=0;$i<$length;$i++){
$str.=$strPol[rand(0,$max)];//rand($min,$max)生成介于min和max两个数之间的一个随机整数
}
return $str;
}
//执行第二次签名,才能返回给客户端使用
public function getOrder($prepayId){
$data["appid"] = $this->config["APPID"];
$data["noncestr"] = $this->getRandChar(32);
$data["package"] = "Sign=WXPay";
$data["partnerid"] = $this->config['MCHID'];
$data["prepayid"] = $prepayId;
$data["timestamp"] = time();
$s = $this->makeSign($data, false);
$data["sign"] = $s;
return $data;
}
/**
* 获取当前服务器IP
* @return string
*/
public function get_client_ip()
{
if ($_SERVER['REMOTE_ADDR']) {
$cip = $_SERVER['REMOTE_ADDR'];
} elseif (getenv("REMOTE_ADDR")) {
$cip = getenv("REMOTE_ADDR");
} elseif (getenv("HTTP_CLIENT_IP")) {
$cip = getenv("HTTP_CLIENT_IP");
} else {
$cip = "unknown";
}
return $cip;
}
/**
* 提现
* 提现的这个如果是201也把状态改了
* 查询的那个如果是200说明已经提现过了,拒绝的时候也要查询一下,200就把状态改了,防止数据出错
*/
// public function addFen($account,$name){
public function addFen(){
$account="1557327661";
$name="商丘市新吾文化传媒有限公司";
$url = "https://api.mch.weixin.qq.com/pay/profitsharingaddreceiver";
$data["appid"] = $this->config['APPID'];//微信开放平台审核通过的应用APPID
$data["mch_id"] = $this->config['MCHID'];//商户号
$data["nonce_str"] = $this->getRandChar(32);//随机字符串
$data["sign_type"] = 'HMAC-SHA256';
$data["receiver"] = json_encode([
'type' => 'MERCHANT_ID',
'account' => $account,
'name' => $name,
'relation_type' => 'PARTNER',
],JSON_UNESCAPED_UNICODE);
$sign = $this->makeSign($data,true);
$data['sign'] = $sign;
$xml = $this->toXml($data);
$response = $this->postXmlCurl($xml, $url, '', false, '', '');
$responseArr = $this->toArray($response);
if (!is_array($responseArr) || count($responseArr) <= 0) {
$return['msg'] = '网络请求繁忙';
$return['status'] = 0;
} else if ($responseArr['return_code'] == 'FAIL') {
$return['msg'] = $responseArr['return_msg'];
$return['status'] = 0;
} else {
if ($responseArr['result_code'] == 'FAIL') {
$return['msg'] = $responseArr['err_code'];
$return['status'] = 0;
} else {
$return['text'] = $responseArr;
$return['status'] = 200;
}
}
return $return;
}
/**
* 提现查询
*/
public function fenMoney($transaction_id,$refundNo,$account,$amount){ //这个单号就是前端传回来的那个
// public function fenMoney(){ //这个单号就是前端传回来的那个
// $transaction_id = '4200000461201911123780673082';
// $refundNo = '1573549454228873027';
// $account = 'ningwy1314';
// $amount = 1;
$url = "https://api.mch.weixin.qq.com/secapi/pay/profitsharing";
$data["appid"] = $this->config['APPID'];//微信开放平台审核通过的应用APPID
$data["mch_id"] = $this->config['MCHID'];//商户号
$data["nonce_str"] = $this->getRandChar(32);//随机字符串
$data["sign_type"] = 'HMAC-SHA256';//随机字符串
$data["transaction_id"] = $transaction_id;
$data["out_order_no"] = $refundNo;
$data["receivers"] = json_encode([[
'type' => 'PERSONAL_WECHATID',
'account' => $account,
'amount' => $amount,
'description' => '分给商户',
]],JSON_UNESCAPED_UNICODE);
$sign=$this->makeSign($data,true);
$data['sign']=$sign;
$xml=$this->toXml($data);
$response = $this->postXmlCurl($xml, $url,'',true,'/appcert/apiclient_cert.pem','/appcert/apiclient_key.pem');
$responseArr=$this->toArray($response);
if(!is_array($responseArr) || count($responseArr)<=0){
$return['msg'] = '网络请求繁忙';
$return['status'] = 0;
}else if($responseArr['return_code'] == 'FAIL'){
$return['msg'] = $responseArr['return_msg'];
$return['status'] = 0;
}else{
if($responseArr['result_code'] == 'FAIL'){
$return['msg'] = $responseArr['err_code'];
$return['status'] = 0;
}else{
$return['text'] = $responseArr;
$return['status'] = 200;
}
}
return $return;
}
function postXmlCurl($xml, $url, $second=30, $useCert=false, $sslcert_path, $sslkey_path)
{
$ch = curl_init();
//设置超时
curl_setopt($ch, CURLOPT_TIMEOUT, $second);
curl_setopt($ch,CURLOPT_URL, $url);
//设置header
curl_setopt($ch, CURLOPT_HEADER, FALSE);
//要求结果为字符串且输出到屏幕上
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);
if($useCert == true){
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false);
// curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE);
// curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,1);//严格校验
//设置证书
$path = $_SERVER['DOCUMENT_ROOT'];
curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
curl_setopt($ch,CURLOPT_SSLCERT, $path.$sslcert_path);
curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
curl_setopt($ch,CURLOPT_SSLKEY, $path.$sslkey_path);
// curl_setopt($ch,CURLOPT_CAINFO, __DIR__.'/cert/rootca.pem');
}
//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);
return false;
}
}
}