diff --git a/.env b/.env index f0a1a12..d6326f0 100755 --- a/.env +++ b/.env @@ -1 +1 @@ -APP_DEBUG = false [APP] DEFAULT_TIMEZONE = Asia/Shanghai [DATABASE] TYPE = mysql HOSTNAME = 124.71.161.49 DATABASE = cxhxy USERNAME = cxhxy PASSWORD = FmfbjEeHfYKZHHK7 HOSTPORT = 3306 CHARSET = utf8 DEBUG = false \ No newline at end of file +APP_DEBUG = false [APP] DEFAULT_TIMEZONE = Asia/Shanghai [DATABASE] TYPE = mysql HOSTNAME = 124.71.161.49 DATABASE = cxhxy USERNAME = cxhxy PASSWORD = FmfbjEeHfYKZHHK7 HOSTPORT = 3306 CHARSET = utf8 DEBUG = true \ No newline at end of file diff --git a/extend/hema/wechat/Pay.php b/extend/hema/wechat/Pay.php index 5b377b0..b18fcde 100755 --- a/extend/hema/wechat/Pay.php +++ b/extend/hema/wechat/Pay.php @@ -1,1164 +1,1181 @@ -isp_config = Setting::getItem('wxpayisp',0); - $this->config = $config; - } - - /********** V3接口 **********/ - - /** - * H5下单API - * $out_trade_no=订单号, $total=支付金额,,$attach=订单描述 - * $profit_sharing=是否分账(有配送费要分账时传递) - */ - public function h5($out_trade_no,$total,$notify_url,$attach='订单支付',$profit_sharing = false) - { - $params = [ - 'description' => $attach,//商品描述 - 'out_trade_no' => $out_trade_no,//商户订单号 - 'attach' => $attach,//附加数据 - 'notify_url' => base_url() . $notify_url, //通知地址 - 'amount' => [ - 'total' => intval($total * 100),//订单总金额,单位为分 - ], - 'scene_info' => [ - 'payer_client_ip' => \request()->ip(),//用户终端IP - ], - 'h5_info' => [ - 'type' => 'Wap' - ] - ]; - if($this->config['is_sub'] == 1){ - //服务商 - $params['sp_appid'] = $this->isp_config['app_id'];//服务商应用ID - $params['sp_mchid'] = $this->isp_config['mch_id'];//服务商商户号 - $params['sub_appid'] = $this->config['app_id'];//子商户应用ID - $params['sub_mchid'] = $this->config['mch_id'];//子商户号 - $url = $this->getUrl('pay/partner/transactions/h5');//服务商 - $is_isp = true; - }else{ - //直连商户 - $params['appid'] = $this->config['app_id'];//小程序ID - $params['mchid'] = $this->config['mch_id'];//商户号 - $url = $this->getUrl('pay/transactions/h5');//直连商户 - $is_isp = false; - } - //判断是否开启分账 - $divide = Setting::getItem('divide',0); - if($profit_sharing or $divide['extract'] > 0){ - $params['settle_info']['profit_sharing'] = true; //开启分账 - } - $params = hema_json($params); - $headers = [ - 'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $this->sign($url,'POST',$params,$is_isp), - 'Content-Type:application/json', - 'Accept:application/json', - 'User-Agent:' . $is_isp?$this->isp_config['mch_id']:$this->config['mch_id'], - ]; - $result = json_decode(Http::post($url, $params,[],$headers),true); - if(isset($result['code'])){ - $this->error = 'code:' . $result['code'] . ',msg:' . $result['message']; - return false; - } - return $result['h5_url']; - } - //扣取手续费 按照0.6%计算 - private function serviceFee($fee) - { - return intval(($fee - ($fee * 6 / 1000)) * 100); - } - /** - * 分账 - * $data:数组 =分账数据 - * [ - * out_order_no:第三方订单号 - * transaction_id:微信订单号 - * total:分账总金额 - * ] - * $applet_id=小程序编号 - * $delivery_fee=配送费分账金额 - */ - public function divide($data,$applet_id='',$delivery_fee=0) - { - $is_divide = false;//是否分账 - $total = $data['total'];//分账总金额 - $service_fee = 0;//平台分账金额(单位分) - $agent_fee = 0;//代理分账金额(单位分) - $agent_openid = '';//代理收款账号 - //判断外卖订单是否分账配送费 - if($delivery_fee > 0){ - $total = $total - $delivery_fee; - $delivery_fee = $this->serviceFee($delivery_fee);//去掉手续费 - $is_divide = true; //配送费大于0 开启分账 - } - $divide = Setting::getItem('divide',0); //分佣参数 - $applet = Applet::get($applet_id);//获取商家应用 - //如果开启分佣 - if($divide['extract'] > 0){ - $extract = $total * $divide['extract'] / 100;//抽取金额 - $service_fee = $this->serviceFee($extract);//去掉手续费 - if($divide['agent_extract'] > 0){ - //判断商家是否有代理商 - if($applet['agent_id'] > 0){ - if($account = DivideAccount::withoutGlobalScope()->where('applet_id',$applet_id)->find()){ - if(!empty($account['open_id'])){ - $agent_openid = $account['open_id']; - $agent_fee = $this->serviceFee($extract * $divide['agent_extract'] / 100);//去掉手续费 - $service_fee = $service_fee - $agent_fee; - } - } - } - } - $is_divide = true; //开启分账 - } - //判断是否要进行分账 - if(!$is_divide){ - $this->error = '不用分账'; - return false; - } - //***************** 添加分账接收方 *********************// - $receivers = [];//收款方账号列表 - //添加平台收佣账号 - if(($service_fee + $delivery_fee) > 0){ - if(!$this->addReceivers($applet_id)) { - $this->error = '添加平台分账接收方失败'; - return false; - } - $webpay = Setting::getItem('webpay',0)['wx']; //平台微信支付参数 - $receivers[] = [ - 'type' => 'MERCHANT_ID',//分账接收方类型 MERCHANT_ID=商户号 PERSONAL_OPENID=个人openid - 'account' => $webpay['mch_id'],//分账接收方账号 - 'amount' => $service_fee + $delivery_fee,//分账金额 - 'description' => '分佣给平台',//分账描述 - ]; - } - //添加代理收佣账号 - if($agent_fee > 0 and !empty($agent_openid)){ - if(!$this->addReceivers($applet_id,false,$agent_openid)) { - $this->error = '添加代理分账接收方失败'; - return false; - } - $receivers[] = [ - 'type' => $this->config['is_sub'] == 1 ? 'PERSONAL_SUB_OPENID':'PERSONAL_OPENID',//分账接收方类型 - 'account' => $agent_openid,//分账接收方账号 - 'amount' => $agent_fee,//分账金额 - 'description' => '分佣给代理',//分账描述 - ]; - } - //***************** 请求分账 *********************// - if(sizeof($receivers) == 0){ - $this->error = '收款方账号列表为空'; - return false; - } - if(!$this->profitSharing($data['transaction_id'],$data['out_order_no'],$receivers)) { - $this->error = '请求分账失败'; - return false; - } - //***************** 添加交易记录 *********************// - $record_log = [];//交易流水记录 - //是否增加平台分红记录(分佣) - if(($service_fee - $agent_fee) > 0){ - $money = sprintf("%.2f",$service_fee / 100);//计算金额 - //平台分红(分佣)记录 - array_push($record_log,[ - 'mode' => 40, //赠送 - 'type' => 30, //微信 - 'order_no' => $data['out_order_no'], - 'money' => $money, - 'remark' => '交易分佣' - ]); - //商户扣费记录 - array_push($record_log,[ - 'mode' => 50, //扣减 - 'type' => 30, //微信 - 'order_no' => $data['out_order_no'], - 'money' => $money, - 'user_id' => $applet['user_id'], - 'remark' => '交易服务费' - ]); - } - //是否增加配送费记录 - if($delivery_fee > 0){ - $money = sprintf("%.2f",$delivery_fee / 100);//计算金额 - //平台收取记录 - array_push($record_log,[ - 'mode' => 40, //赠送 - 'type' => 30, //微信 - 'order_no' => $data['out_order_no'], - 'money' => $money, - 'remark' => '第三方配送费' - ]); - //商户扣费记录 - array_push($record_log,[ - 'mode' => 50, //扣减 - 'type' => 30, //微信 - 'order_no' => $data['out_order_no'], - 'money' => $money, - 'user_id' => $applet['user_id'], - 'remark' => '第三方配送费' - ]); - } - //是否增加代理分佣记录 - if($agent_fee > 0){ - $money = sprintf("%.2f",$agent_fee / 100);//计算金额 - //平台收取记录 - array_push($record_log,[ - 'mode' => 40, //赠送 - 'type' => 30, //微信 - 'order_no' => $data['out_order_no'], - 'money' => $money, - 'user_id' => $applet['agent_id'], - 'remark' => '交易分佣' - ]); - } - //批量增加交易记录 - $model = new Record; - if(!$model->saveAll($record_log)){ - $this->error = '添加交易记录失败'; - return false; - } - return true; - } - /** - * 请求分账API - */ - private function profitSharing($transaction_id,$out_order_no,$receivers) - { - //服务商 - $params = [ - 'transaction_id' => $transaction_id,//微信订单号 - 'out_order_no' => $out_order_no,//商户分账单号 - 'receivers' => $receivers, - 'unfreeze_unsplit' => true,//是否解冻剩余未分资金 - ]; - if($this->config['is_sub'] == 1){ - //服务商 - $params['appid'] = $this->isp_config['app_id'];//服务商应用ID - $params['sub_appid'] = $this->config['app_id'];//子商户应用ID - $params['sub_mchid'] = $this->config['mch_id'];//子商户号 - $is_isp = true; - }else{ - //直连商户 - $params['appid'] = $this->config['app_id'];//小程序ID - $is_isp = false; - } - $params = hema_json($params); - $url = $this->getUrl('profitsharing/orders'); - $headers = [ - 'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $this->sign($url,'POST',$params,$is_isp), - 'Content-Type:application/json', - 'Accept:application/json', - 'User-Agent:' . $is_isp?$this->isp_config['mch_id']:$this->config['mch_id'], - 'Wechatpay-Serial:' . $this->isp_config['serial_no'], - ]; - return $this->result(json_decode(Http::post($url, $params,[],$headers),true)); - } - /** - * 添加分账接收方API - * $is_mchid = 接收方是否是商户 $account = 接收账号 - */ - private function addReceivers($applet_id,$is_mchid=true,$account='') - { - if($this->config['is_sub'] == 1){ - //服务商 - $params['appid'] = $this->isp_config['app_id'];//服务商应用ID - $params['sub_appid'] = $this->config['app_id'];//子商户应用ID - $params['sub_mchid'] = $this->config['mch_id'];//子商户号 - if($is_mchid){ - $webpay = Setting::getItem('webpay',0)['wx']; - $params['type'] = 'MERCHANT_ID';//分账接收方类型 - $params['account'] = $webpay['mch_id'];//分账接收方账号 - $params['name'] = $this->getEncrypt($webpay['name']); //(加密)分账个人接收方姓名 分账接收方类型是MERCHANT_ID时,是商户全称(必传) - }else{ - $params['type'] = 'PERSONAL_SUB_OPENID';//分账接收方类型 - $params['account'] = $account;//分账接收方账号 - } - $params['relation_type'] = 'SERVICE_PROVIDER'; //与分账方的关系类型 服务商 - $is_isp = true; - $serial_no = $this->isp_config['serial_no']; - }else{ - //直连商户 - $params['appid'] = $this->config['app_id'];//小程序ID - if($is_mchid){ - $webpay = Setting::getItem('webpay',0)['wx']; - $params['type'] = 'MERCHANT_ID';//分账接收方类型 - $params['account'] = $webpay['mch_id'];//分账接收方账号 - $params['name'] = $this->getEncrypt($webpay['name'],false,$applet_id); //(加密)分账个人接收方姓名 分账接收方类型是MERCHANT_ID时,是商户全称(必传) - }else{ - $params['type'] = 'PERSONAL_OPENID';//分账接收方类型 - $params['account'] = $account;//分账接收方账号 - } - $params['relation_type'] = 'PARTNER'; ////与分账方的关系类型 合作伙伴 - $is_isp = false; - $serial_no = $this->config['serial_no']; - } - $params = hema_json($params); - $url = $this->getUrl('profitsharing/receivers/add'); - $headers = [ - 'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $this->sign($url,'POST',$params,$is_isp), - 'Content-Type:application/json', - 'Accept:application/json', - 'User-Agent:' . $is_isp?$this->isp_config['mch_id']:$this->config['mch_id'], - 'Wechatpay-Serial:' . $serial_no, - ]; - return $this->result(json_decode(Http::post($url, $params,[],$headers),true)); - } - /** - * 申请退款API - */ - public function refunds($transaction_id,$out_refund_no,$refund_fee,$total_fee,$notify_url='',$reason='') - { - $params = [ - 'transaction_id' => $transaction_id,//微信支付订单号 - 'out_refund_no' => $out_refund_no,//退款订单号 - 'amount' => [ - 'refund' => intval($refund_fee * 100), // 退款金额,价格:单位分 - 'total' => intval($total_fee * 100), // 订单金额,价格:单位分 - 'currency' => 'CNY', //退款币种 只支持人民币:CNY - ], - ]; - if($this->config['is_sub'] == 1){ - //服务商 - $params['sub_mchid'] = $this->config['mch_id'];//子商户号 - $is_isp = true; - }else{ - $is_isp = false; - } - !empty($reason) && $params['reason'] = $reason;//退款原因 - !empty($notify_url) && $params['notify_url'] = base_url() . $notify_url; // 异步通知地址 - - $params = hema_json($params); - $url = $this->getUrl('refund/domestic/refunds'); - $headers = [ - 'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $this->sign($url,'POST',$params,$is_isp), - 'Content-Type:application/json', - 'Accept:application/json', - 'User-Agent:' . $is_isp?$this->isp_config['mch_id']:$this->config['mch_id'], - ]; - return $this->result(json_decode(Http::post($url, $params,[],$headers),true)); - - } - /** - * 退款成功异步通知 - */ - public function refundsNotify($Model,$applet_id='') - { - //接收微信服务器回调的数据流 - if (!$json = file_get_contents('php://input')) { - $this->returnHttpCode(false); - } - // 将服务器返回的json数据转化为数组 - $result = json_decode($json,true); - if(empty($applet_id)){ - $this->config = Setting::getItem('webpay',0)['wx'];//平台商户支付参数 - }else{ - $this->config = Setting::getItem('wxpay',$applet_id);//商家商户支付参数 - } - if($this->config['is_sub'] == 1){ - //服务商 - $api_key = $this->isp_config['api_key']; - //判断平台证书是否过期 - if($this->isp_config['expire_time'] < time()){ - //更新平台证书 - if(!$this->certificates()){ - $this->returnHttpCode(false,$this->error);//更新失败 - } - } - }else{ - //直连商户 - $api_key = $this->config['api_key']; - //判断平台证书是否过期 - if($this->config['expire_time'] < time()){ - //更新平台证书 - if(!$this->certificates(false,$applet_id)){ - $this->returnHttpCode(false,$this->error);//更新失败 - } - } - } - if(!$decrypt = new AesUtil($api_key)){ - $this->returnHttpCode(false,$decrypt->getError()); - } - if(!$res = $decrypt->decryptToString($result['resource']['associated_data'], $result['resource']['nonce'], $result['resource']['ciphertext'])){ - $this->returnHttpCode(false,$decrypt->getError()); - } - $data = json_decode($res,true); - // 订单信息 - if(!$order = $Model->refundDetail($data['out_refund_no'])){ - $this->returnHttpCode(false,'订单不存在'); - } - - if($data['refund_status'] == 'SUCCESS') { - // 更新订单状态 - $order->updateRefundStatus($data['refund_id']); - $this->returnHttpCode(true);// 返回状态 - } - $this->returnHttpCode(false, '退款失败'); - } - /** - * Native下单API - * $out_trade_no=订单号, $total=支付金额,$attach=订单描述 $profit_sharing=是否分账 - */ - public function native($out_trade_no,$total,$notify_url,$attach='订单支付',$profit_sharing = false) - { - $params = [ - 'description' => $attach,//商品描述 - 'out_trade_no' => $out_trade_no,//商户订单号 - 'attach' => $attach,//附加数据 - 'notify_url' => base_url() . $notify_url, //通知地址 - 'amount' => [ - 'total' => intval($total * 100),//订单总金额,单位为分 - ], - 'scene_info' => [ - 'payer_client_ip' => \request()->ip(),//用户终端IP - ], - ]; - if($this->config['is_sub'] == 1){ - //服务商 - $params['sp_appid'] = $this->isp_config['app_id'];//服务商应用ID - $params['sp_mchid'] = $this->isp_config['mch_id'];//服务商商户号 - //$params['sub_appid'] = $this->config['app_id'];//子商户应用ID - $params['sub_mchid'] = $this->config['mch_id'];//子商户号 - //$params['payer']['sub_openid'] = $openid; //子用户标识Openid - $url = $this->getUrl('pay/partner/transactions/native');//服务商 - $is_isp = true; - }else{ - //直连商户 - $params['appid'] = $this->config['app_id'];//小程序ID - $params['mchid'] = $this->config['mch_id'];//商户号 - $url = $this->getUrl('pay/transactions/native');//直连商户 - $is_isp = false; - } - //判断是否开启分账 - $divide = Setting::getItem('divide',0); - if($profit_sharing or $divide['extract'] > 0){ - $params['settle_info']['profit_sharing'] = true; //开启分账 - } - $params = hema_json($params); - $headers = [ - 'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $this->sign($url,'POST',$params,$is_isp), - 'Content-Type:application/json', - 'Accept:application/json', - 'User-Agent:' . $is_isp?$this->isp_config['mch_id']:$this->config['mch_id'], - ]; - $result = json_decode(Http::post($url, $params,[],$headers),true); - if(isset($result['code'])){ - $this->error = 'code:' . $result['code'] . ',msg:' . $result['message']; - return false; - } - if(!isset($result['code_url'])){ - $this->error = 'Native下单接口请求失败'; - return false; - } - return $result['code_url']; - } - /** - * JSAPI下单API - * $out_trade_no=订单号, $total=支付金额,$openid=微信用户ID, ,$attach=订单描述 - * $profit_sharing=是否分账(有配送费要分账时传递) - */ - public function jsapi($out_trade_no,$total,$openid,$notify_url,$attach='订单支付',$profit_sharing = false) - { - $params = [ - 'description' => $attach,//商品描述 - 'attach' => $attach,//附加数据 - 'out_trade_no' => $out_trade_no,//商户订单号 - 'notify_url' => base_url() . $notify_url, //通知地址 - 'amount' => [ - 'total' => intval($total * 100),//订单总金额,单位为分 - ], - 'scene_info' => [ - 'payer_client_ip' => \request()->ip(),//用户终端IP - ], - ]; - if($this->config['is_sub'] == 1){ - //服务商 - $params['sp_appid'] = $this->isp_config['app_id'];//服务商应用ID - $params['sp_mchid'] = $this->isp_config['mch_id'];//服务商商户号 - $params['sub_appid'] = $this->config['app_id'];//子商户应用ID - $params['sub_mchid'] = $this->config['mch_id'];//子商户号 - $params['payer']['sub_openid'] = $openid; //子用户标识Openid - $url = $this->getUrl('pay/partner/transactions/jsapi');//服务商 - $is_isp = true; - }else{ - //直连商户 - $params['appid'] = $this->config['app_id'];//小程序ID - $params['mchid'] = $this->config['mch_id'];//商户号 - $params['payer']['openid'] = $openid; //用户标识Openid - $url = $this->getUrl('pay/transactions/jsapi');//直连商户 - $is_isp = false; - } - //判断是否开启分账 - $divide = Setting::getItem('divide',0); - if($profit_sharing or $divide['extract'] > 0){ - $params['settle_info']['profit_sharing'] = true; //开启分账 - } - $params = hema_json($params); - $headers = [ - 'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $this->sign($url,'POST',$params,$is_isp), - 'Content-Type:application/json', - 'Accept:application/json', - 'User-Agent:' . $is_isp?$this->isp_config['mch_id']:$this->config['mch_id'], - ]; - $result = json_decode(Http::post($url, $params,[],$headers),true); - if(isset($result['code'])){ - $this->error = 'code:' . $result['code'] . ',msg:' . $result['message']; - return false; - } - if(!isset($result['prepay_id'])){ - $this->error = 'JSAPI下单接口请求失败'; - return false; - } - $data = [ - 'timeStamp' => (string)time(), - 'nonceStr' => $this->nonce(), - 'package' => 'prepay_id=' . $result['prepay_id'], - 'signType' => 'RSA', - ]; - $data['paySign'] = $this->paySign($data); - return $data; - } - - /** - * 支付成功异步通知 - */ - public function notify($Model,$applet_id,$method='edit') - { - //接收微信服务器回调的数据流 - if (!$json = file_get_contents('php://input')) { - $this->returnHttpCode(false); - } - // 将服务器返回的json数据转化为数组 - $result = json_decode($json,true); - if(empty($applet_id)){ - $this->config = Setting::getItem('webpay',0)['wx'];//平台商户支付参数 - }else{ - $this->config = Setting::getItem('wxpay',$applet_id);//商家商户支付参数 - } - if($this->config['is_sub'] == 1){ - //服务商 - $api_key = $this->isp_config['api_key']; - //判断平台证书是否过期 - if($this->isp_config['expire_time'] < time()){ - //更新平台证书 - if(!$this->certificates()){ - $this->returnHttpCode(false,$this->error);//更新失败 - } - } - }else{ - //直连商户 - $api_key = $this->config['api_key']; - //判断平台证书是否过期 - if($this->config['expire_time'] < time()){ - //更新平台证书 - if(!$this->certificates(false,$applet_id)){ - $this->returnHttpCode(false,$this->error);//更新失败 - } - } - } - if(!$decrypt = new AesUtil($api_key)){ - $this->returnHttpCode(false,$decrypt->getError()); - } - if(!$res = $decrypt->decryptToString($result['resource']['associated_data'], $result['resource']['nonce'], $result['resource']['ciphertext'])){ - $this->returnHttpCode(false,$decrypt->getError()); - } - $data = json_decode($res,true); - // 订单信息 - if(!$order = $Model->payDetail($data['out_trade_no'])){ - $this->returnHttpCode(false,'订单不存在'); - } - - //判断支付状态 - if($data['trade_state'] == 'SUCCESS') { - if($method == 'add'){ - $Model->updatePayStatus($data['transaction_id'],$order); - Cache::delete($data['out_trade_no']); - }else{ - // 更新订单状态 - $order->updatePayStatus($data['transaction_id']); - } - // 返回状态 - $this->returnHttpCode(true); - } - // 返回状态 - $this->returnHttpCode(false, '支付失败'); - } - - /** - * 特约商户进件 - * 频率限制:15/s - */ - public function applyment($params) - { - //********************* 数据加密 ***************** - - //管理员姓名 - if(!$result = $this->getEncrypt($params['contact_info']['contact_name'])){ - return false; - } - $params['contact_info']['contact_name'] = $result; - //管理员电话 - if(!$result = $this->getEncrypt($params['contact_info']['mobile_phone'])){ - return false; - } - $params['contact_info']['mobile_phone'] = $result; - //管理员邮箱 - if(!$result = $this->getEncrypt($params['contact_info']['contact_email'])){ - return false; - } - $params['contact_info']['contact_email'] = $result; - //身份证姓名 - if(!$result = $this->getEncrypt($params['subject_info']['identity_info']['id_card_info']['id_card_name'])){ - return false; - } - $params['subject_info']['identity_info']['id_card_info']['id_card_name'] = $result; - //身份证号 - if(!$result = $this->getEncrypt($params['subject_info']['identity_info']['id_card_info']['id_card_number'])){ - return false; - } - $params['subject_info']['identity_info']['id_card_info']['id_card_number'] = $result; - - //身份证居住地址 - if(!$result = $this->getEncrypt($params['subject_info']['identity_info']['id_card_info']['id_card_address'])){ - return false; - } - $params['subject_info']['identity_info']['id_card_info']['id_card_address'] = $result; - - - //银行开户名称 - if(!$result = $this->getEncrypt($params['bank_account_info']['account_name'])){ - return false; - } - $params['bank_account_info']['account_name'] = $result; - //银行账号 - if(!$result = $this->getEncrypt($params['bank_account_info']['account_number'])){ - return false; - } - $params['bank_account_info']['account_number'] = $result; - - //********************* 上传图片 ***************** - //营业执照 - if(!$result = $this->upload($params['subject_info']['business_license_info']['license_copy'])){ - return false; - } - $params['subject_info']['business_license_info']['license_copy'] = $result; - //身份证正面 - if(!$result = $this->upload($params['subject_info']['identity_info']['id_card_info']['id_card_copy'])){ - return false; - } - $params['subject_info']['identity_info']['id_card_info']['id_card_copy'] = $result; - //身份证反面 - if(!$result = $this->upload($params['subject_info']['identity_info']['id_card_info']['id_card_national'])){ - return false; - } - $params['subject_info']['identity_info']['id_card_info']['id_card_national'] = $result; - //特殊资质 - if(!$result = $this->upload($params['settlement_info']['qualifications'][0])){ - return false; - } - $params['settlement_info']['qualifications'][0] = $result; - //门头照片 - if(!$result = $this->upload($params['business_info']['sales_info']['biz_store_info']['store_entrance_pic'][0])){ - return false; - } - $params['business_info']['sales_info']['biz_store_info']['store_entrance_pic'][0] = $result; - //店内照片 - if(!$result = $this->upload($params['business_info']['sales_info']['biz_store_info']['indoor_pic'][0])){ - return false; - } - $params['business_info']['sales_info']['biz_store_info']['indoor_pic'][0] = $result; - $params = hema_json($params); - $url = $this->getUrl('applyment4sub/applyment/'); - $headers = [ - 'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $this->sign($url,'POST',$params), - 'Content-Type:application/json', - 'Accept:application/json', - 'User-Agent:' . $this->isp_config['mch_id'], - 'Wechatpay-Serial:' . $this->isp_config['serial_no'], - ]; - $result = json_decode(Http::post($url, $params,[],$headers),true); - if(isset($result['code'])){ - $this->error = 'code:' . $result['code'] . ',msg:' . $result['message']; - return false; - } - return $result['applyment_id']; - } - /** - * 查询申请单状态 - */ - public function queryApplyment($no,$is_applyment_id = false) - { - if($is_applyment_id){ - $path = 'applyment_id/' . $no;//通过申请单号查询申请状态(官方返回的编号) - }else{ - $path = 'business_code/' . $no;//通过业务申请编号查询申请状态(第三方自定义的编号) - } - $url = $this->getUrl('applyment4sub/applyment/'.$path); - $headers = [ - 'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $this->sign($url,'GET'), - 'Accept:application/json', - ]; - return $this->result(json_decode(Http::get($url, [],[],$headers),true)); - } - /** - * 获取平台证书列表 - */ - private function certificates($is_isp=true,$applet_id='') - { - $url = $this->getUrl('certificates'); - $headers = [ - 'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $this->sign($url,'GET','',$is_isp), - 'Accept:application/json', - 'User-Agent:https://zh.wikipedia.org/wiki/User_agent', - ]; - $result = json_decode(Http::get($url,[],[],$headers),true); - if(isset($result['code'])){ - $this->error = 'code:' . $result['code'] . ',msg:' . $result['message']; - return false; - } - //验证是否获取到了数据 - if(!isset($result['data']) and sizeof($result['data']) == 0){ - $this->error = '未获取到可用的平台证书'; - return false; - } - $result = $result['data'][0];//获取证书列表中的第一个数据 - if($is_isp){ - $api_key = $this->isp_config['api_key']; - }else{ - $api_key = $this->config['api_key']; - } - if(!$decrypt = new AesUtil($api_key)){ - $this->error = $decrypt->getError(); - return false; - } - if(!$res = $decrypt->decryptToString($result['encrypt_certificate']['associated_data'], $result['encrypt_certificate']['nonce'], $result['encrypt_certificate']['ciphertext'])){ - $this->error = $decrypt->getError(); - return false; - } - //计算到期时间 - $expire_time = explode('T',$result['expire_time']); - $expire_time = strtotime($expire_time[0]); - $model = new Setting; - //更新平台证书 - if($is_isp){ - $this->isp_config['certificates'] = $res; - $this->isp_config['serial_no'] = $result['serial_no']; - $this->isp_config['expire_time'] = $expire_time; - $model->edit('wxpayisp',$this->isp_config,0); //保存到数据库 - return true; - } - //更新特约商户 平台证书 - $this->config['certificates'] = $res; - $this->config['serial_no'] = $result['serial_no']; - $this->config['expire_time'] = $expire_time; - if(empty($applet_id)){ - $config = Setting::getItem('webpay',0); - $config['wx']['certificates'] = $res; - $config['wx']['serial_no'] = $result['serial_no']; - $config['wx']['expire_time'] = $expire_time; - $model->edit('webpay',$config,0); //保存到数据库 - }else{ - $model->edit('wxpay',$this->config,$applet_id); //保存到数据库 - } - return true; - } - - /** - * 图片上传API - */ - private function upload($file_path) - { - $file = file_get_contents($file_path);//获取网络图片 - //获取文件名称 - $arr = explode('/',$file_path); - $filename = $arr[sizeof($arr)-1]; - $meta =[ - 'filename' => $filename, - 'sha256' => hash('sha256',$file), - ]; - $url = $this->getUrl('merchant/media/upload'); - $boundary = uniqid();//随机数 - $headers = [ - 'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $this->sign($url,'POST',hema_json($meta)), - 'Accept:application/json', - 'Content-Type:multipart/form-data;boundary=' . $boundary, - ]; - $params = '--' . $boundary . "\r\n"; - $params .= 'Content-Disposition:form-data; name="meta"' . "\r\n"; - $params .= 'Content-Type:application/json' . "\r\n\r\n"; - $params .= hema_json($meta) . "\r\n"; - $params .= '--' . $boundary . "\r\n"; - $params .= 'Content-Disposition:form-data;name="file";filename="' . $meta['filename'] . '"' . "\r\n"; - $params .= 'Content-Type:image/jpg' . "\r\n\r\n"; - $params .= $file . "\r\n"; - $params .= '--' . $boundary . '--' . "\r\n"; - $result = json_decode(Http::post($url, $params,[],$headers),true); - if(isset($result['code'])){ - $this->error = 'code:' . $result['code'] . ',msg:' . $result['message']; - return false; - } - if(isset($result['media_id'])){ - return $result['media_id']; - } - $this->error = '图片上传失败'; - return false; - } - - /** - * 调起支付签名 - */ - private function paySign($data) - { - $params = $this->config['app_id'] . "\n" . - $data['timeStamp'] . "\n" . - $data['nonceStr'] . "\n" . - $data['package'] . "\n"; - if($this->config['is_sub'] == 1){ - //服务商 - $private_key = $this->isp_config['key_pem']; //API私有证书 - }else{ - //直连商户 - $private_key = $this->config['key_pem']; //API私有证书 - } - $raw_sign = ''; - openssl_sign($params, $raw_sign, $private_key, 'sha256WithRSAEncryption'); - return base64_encode($raw_sign); - } - - /** - * 生成签名 - * $http_method = HTTP请求的方法(GET,POST,PUT - * serial_no 为你的商户证书序列号 - * $mch_private_key = 是商户API私钥,在商户平台下载的证书文件包含该文件,名称为apiclient_key.pem - * $is_isp 是否为服务商操作 - */ - private function sign($url,$http_method,$body='',$is_isp=true) - { - $timestamp = time(); //时间戳 - $nonce = $this->nonce(); //随机字符串 - $url_parts = parse_url($url); - $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : "")); - $params = $http_method . "\n" . - $canonical_url . "\n" . - $timestamp . "\n" . - $nonce . "\n" . - $body . "\n"; - if($is_isp){ - $mchid = $this->isp_config['mch_id']; //商户号 - $serial_no = $this->isp_config['api_serial_no']; //API证书序列号 - $mch_private_key = $this->isp_config['key_pem']; //API私有证书 - }else{ - $mchid = $this->config['mch_id']; //商户号 - $serial_no = $this->config['api_serial_no']; //API证书序列号 - $mch_private_key = $this->config['key_pem']; //API私有证书 - } - $raw_sign = ''; - openssl_sign($params, $raw_sign, $mch_private_key, 'sha256WithRSAEncryption'); - $sign = base64_encode($raw_sign); - //$schema = 'WECHATPAY2-SHA256-RSA2048'; - $token = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',$mchid, $nonce, $timestamp, $serial_no, $sign); - return $token; - } - /** - * 敏感信息加密 - */ - private function getEncrypt($str,$is_isp = true,$applet_id='') - { - //判断平台证书是否过期 - if($is_isp){ - //服务商 - if($this->isp_config['expire_time'] < time()){ - //更新平台证书 - if(!$this->certificates()){ - return false;//更新失败 - } - } - $public_key = $this->isp_config['certificates'];//平台证书 - }else{ - //直连商户 - if($this->config['expire_time'] < time()){ - //更新平台证书 - if(!$this->certificates(false,$applet_id)){ - return false;//更新失败 - } - } - $public_key = $this->config['certificates'];//平台证书 - } - $encrypted = ''; - if (!openssl_public_encrypt($str, $encrypted, $public_key, OPENSSL_PKCS1_OAEP_PADDING)) { - $this->error = '敏感信息加密失败'; - return false; - } - return base64_encode($encrypted);//base64编码 - } - /** - * 生成随机字符串 - */ - private function nonce() - { - return md5(uniqid()); - } - /* - * 拼接请求域名接口 - */ - private function getUrl($url) - { - return $this->api_url . '/' . $this->version . '/' . $url; - } - /** - * 获取Headers数据 - */ - private function getHeaders() - { - $headers = array(); - foreach ($_SERVER as $key => $value) { - if (substr($key, 0, 5) === 'HTTP_') { - $key = substr($key, 5); - $key = str_replace('_', ' ', $key); - $key = str_replace(' ', '-', $key); - $key = strtolower($key); - $headers[$key] = $value; - } - } - return $headers; - } - /** - * 返回状态给微信服务器 - */ - private function returnHttpCode($is_success = true, $msg = '失败') - { - $json = hema_json([ - 'code' => $is_success ? 'SUCCESS' : 'FAIL', - 'message' => $is_success ? '成功' : $msg, - ]); - if($is_success){ - header('HTTP/1.1 200 OK'); - }else{ - header('HTTP/1.1 404 Not Found'); - } - die($json); - } - /** - * 请求数据验证 - **/ - private function result($result) - { - if(isset($result['code'])){ - $this->error = 'code:' . $result['code'] . ',msg:' . $result['message']; - return false; - } - return $result; - } - public function getError() - { - return $this->error; - } - - /********** V2接口 **********/ - /** - * 付款码支付 - * $auth_code=付款码 $order_no=订单号 $openid=微信用户ID, $total_fee=支付金额, ,$attach=订单描述 $divide=是否分账 - */ - public function micropay($auth_code,$order_no, $total_fee,$profit_sharing = false,$attach = '订单支付') - { - // 当前时间 - $time = time(); - // 生成随机字符串 - $nonceStr = md5($time); - // API参数 - $params = [ - 'auth_code' => $auth_code,//付款码支付 - 'attach' => $attach, - 'nonce_str' => $nonceStr,//随机字符串 - 'body' => $attach,//商品描述 - 'out_trade_no' => $order_no,//商户订单号 - 'total_fee' => intval($total_fee * 100), // 价格:单位分 - 'spbill_create_ip' => \request()->ip(),//服务终端IP - ]; - if($this->config['is_sub'] == 1){ - //服务商统一下单 - $values = Setting::getItem('wxpayisp',0); - $this->config['api_key'] = $this->isp_config['api_key'];//服务商商户的密钥 - $params['appid'] = $this->isp_config['app_id'];//服务商商户的APPID - $params['mch_id'] = $this->isp_config['mch_id'];//服务商商户号 - $params['sub_appid'] = $this->config['app_id'];//当前调起支付的小程序APPID - $params['sub_mch_id'] = $this->config['mch_id'];//服务商分配的子商户号 - }else{ - $params['appid'] = $this->config['app_id'];//小程序ID - $params['mch_id'] = $this->config['mch_id'];//商户号 - } - //判断是否开启分账 - $divide = Setting::getItem('divide',0); - if($profit_sharing or $divide['extract'] > 0){ - $params['profit_sharing'] = 'Y';//开启分账 - } - - // 生成签名 - $params['sign'] = $this->makeSign($params); - $url = 'https://api.mch.weixin.qq.com/pay/micropay';// 请求API - $result = $this->postXmlCurl($this->toXml($params), $url); - $prepay = $this->fromXml($result); - // 请求失败 - if ($prepay['return_code'] === 'FAIL') { - die(hema_json(['code' => -10, 'msg' => $prepay['return_msg']])); - } - //判断付款码支付时,用户支付中,需要输入密码 - if ($prepay['result_code'] === 'USERPAYING') { - return false; - } - if ($prepay['result_code'] === 'FAIL') { - die(hema_json(['code' => -10, 'msg' => $prepay['err_code_des']])); - } - return $prepay['transaction_id'];//支付交易号 - } - - /** - * 查询付款码支付结果是否成功 - */ - public function orderquery($out_trade_no) - { - // 当前时间 - $time = time(); - // 生成随机字符串 - $nonceStr = md5($time); - // API参数 - $params = [ - 'out_trade_no' => $out_trade_no, - 'nonce_str' => $nonceStr,//随机字符串 - ]; - if($this->config['is_sub'] == 1){ - //服务商统一下单 - $this->config['api_key'] = $this->isp_config['api_key'];//服务商商户的密钥 - $params['appid'] = $this->isp_config['app_id'];//服务商商户的APPID - $params['mch_id'] = $this->isp_config['mch_id'];//服务商商户号 - $params['sub_appid'] = $this->config['app_id'];//当前调起支付的小程序APPID - $params['sub_mch_id'] = $this->config['mch_id'];//服务商分配的子商户号 - }else{ - $params['appid'] = $this->config['app_id'];//小程序ID - $params['mch_id'] = $this->config['mch_id'];//商户号 - } - // 生成签名 - $params['sign'] = $this->makeSign($params); - // 请求API - $url = 'https://api.mch.weixin.qq.com/pay/orderquery'; - $result = $this->postXmlCurl($this->toXml($params), $url); - $prepay = $this->fromXml($result); - // 请求失败 - if ($prepay['return_code'] === 'SUCCESS' AND $prepay['result_code'] === 'SUCCESS') { - return $prepay['trade_state']; - } - return 'ERROR'; - } - /** - * 输出xml字符 - */ - private function toXml($values) - { - if (!is_array($values) - || count($values) <= 0 - ) { - return false; - } - $xml = ""; - foreach ($values as $key => $val) { - if (is_numeric($val)) { - $xml .= "<" . $key . ">" . $val . ""; - } else { - $xml .= "<" . $key . ">"; - } - } - $xml .= ""; - return $xml; - } - /** - * 将xml转为array - */ - private function fromXml($xml) - { - // 禁止引用外部xml实体 - libxml_disable_entity_loader(true); - return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); - } - /** - * 以post方式提交xml到对应的接口url - */ - private function postXmlCurl($xml, $url, $cert = false, $second = 30) - { - $ch = curl_init(); - curl_setopt($ch, CURLOPT_TIMEOUT, $second);// 设置超时时间 - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);//https请求 不验证证书和host - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);//严格校验 - curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);// 要求结果为字符串且输出到屏幕上 - curl_setopt($ch, CURLOPT_POST, TRUE);// post提交方式 - curl_setopt($ch, CURLOPT_POSTFIELDS, $xml); - curl_setopt($ch, CURLOPT_HEADER, FALSE);// 是否返回请求头 - //判断是否使用证书 - if($cert){ - $path = root_path() . '/extend/hema/wechat/cert/'; - file_put_contents($path . 'apiclient_cert.pem',$this->config['cert_pem']); - file_put_contents($path . 'apiclient_key.pem',$this->config['key_pem']); - curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM'); - curl_setopt($ch,CURLOPT_SSLCERT,$path . 'apiclient_cert.pem'); - curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM'); - curl_setopt($ch,CURLOPT_SSLKEY,$path . 'apiclient_key.pem'); - } - $data = curl_exec($ch);// 运行curl - curl_close($ch); - return $data; - } - - /** - * 生成签名MD5 - */ - private function makeSign($values) - { - //签名步骤一:按字典序排序参数 - ksort($values); - $string = $this->toUrlParams($values); - //签名步骤二:在string后加入KEY - $string = $string . '&key=' . $this->config['api_key']; - //签名步骤三:MD5加密 - $string = md5($string); - //签名步骤四:所有字符转为大写 - $result = strtoupper($string); - return $result; - } - - /** - * 格式化参数格式化成url参数 - */ - private function toUrlParams($values) - { - $buff = ''; - foreach ($values as $k => $v) { - if ($k != 'sign' && $v != '' && !is_array($v)) { - $buff .= $k . '=' . $v . '&'; - } - } - return trim($buff, '&'); - } +isp_config = Setting::getItem('wxpayisp',0); + $this->config = Setting::getItem('wxpayisp',0); + $this->config['is_sub'] = 2; + } + + /********** V3接口 **********/ + + /** + * H5下单API + * $out_trade_no=订单号, $total=支付金额,,$attach=订单描述 + * $profit_sharing=是否分账(有配送费要分账时传递) + */ + public function h5($out_trade_no,$total,$notify_url,$attach='订单支付',$profit_sharing = false) + { + $params = [ + 'description' => $attach,//商品描述 + 'out_trade_no' => $out_trade_no,//商户订单号 + 'attach' => $attach,//附加数据 + 'notify_url' => base_url() . $notify_url, //通知地址 + 'amount' => [ + 'total' => intval($total * 100),//订单总金额,单位为分 + ], + 'scene_info' => [ + 'payer_client_ip' => \request()->ip(),//用户终端IP + ], + 'h5_info' => [ + 'type' => 'Wap' + ] + ]; + if($this->config['is_sub'] == 1){ + //服务商 + $params['sp_appid'] = $this->isp_config['app_id'];//服务商应用ID + $params['sp_mchid'] = $this->isp_config['mch_id'];//服务商商户号 + $params['sub_appid'] = $this->config['app_id'];//子商户应用ID + $params['sub_mchid'] = $this->config['mch_id'];//子商户号 + $url = $this->getUrl('pay/partner/transactions/h5');//服务商 + $is_isp = true; + }else{ + //直连商户 + $params['appid'] = $this->config['app_id'];//小程序ID + $params['mchid'] = $this->config['mch_id'];//商户号 + $url = $this->getUrl('pay/transactions/h5');//直连商户 + $is_isp = false; + } + //判断是否开启分账 + $divide = Setting::getItem('divide',0); + if($profit_sharing or $divide['extract'] > 0){ + $params['settle_info']['profit_sharing'] = true; //开启分账 + } + $params = hema_json($params); + $headers = [ + 'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $this->sign($url,'POST',$params,$is_isp), + 'Content-Type:application/json', + 'Accept:application/json', + 'User-Agent:' . $is_isp?$this->isp_config['mch_id']:$this->config['mch_id'], + ]; + $result = json_decode(Http::post($url, $params,[],$headers),true); + if(isset($result['code'])){ + $this->error = 'code:' . $result['code'] . ',msg:' . $result['message']; + return false; + } + return $result['h5_url']; + } + //扣取手续费 按照0.6%计算 + private function serviceFee($fee) + { + return intval(($fee - ($fee * 6 / 1000)) * 100); + } + /** + * 分账 + * $data:数组 =分账数据 + * [ + * out_order_no:第三方订单号 + * transaction_id:微信订单号 + * total:分账总金额 + * ] + * $applet_id=小程序编号 + * $delivery_fee=配送费分账金额 + */ + public function divide($data,$applet_id='',$delivery_fee=0) + { + $is_divide = false;//是否分账 + $total = $data['total'];//分账总金额 + $service_fee = 0;//平台分账金额(单位分) + $agent_fee = 0;//代理分账金额(单位分) + $agent_openid = '';//代理收款账号 + //判断外卖订单是否分账配送费 + if($delivery_fee > 0){ + $total = $total - $delivery_fee; + $delivery_fee = $this->serviceFee($delivery_fee);//去掉手续费 + $is_divide = true; //配送费大于0 开启分账 + } + $divide = Setting::getItem('divide',0); //分佣参数 + $applet = Applet::get($applet_id);//获取商家应用 + //如果开启分佣 + if($divide['extract'] > 0){ + $extract = $total * $divide['extract'] / 100;//抽取金额 + $service_fee = $this->serviceFee($extract);//去掉手续费 + if($divide['agent_extract'] > 0){ + //判断商家是否有代理商 + if($applet['agent_id'] > 0){ + if($account = DivideAccount::withoutGlobalScope()->where('applet_id',$applet_id)->find()){ + if(!empty($account['open_id'])){ + $agent_openid = $account['open_id']; + $agent_fee = $this->serviceFee($extract * $divide['agent_extract'] / 100);//去掉手续费 + $service_fee = $service_fee - $agent_fee; + } + } + } + } + $is_divide = true; //开启分账 + } + //判断是否要进行分账 + if(!$is_divide){ + $this->error = '不用分账'; + return false; + } + //***************** 添加分账接收方 *********************// + $receivers = [];//收款方账号列表 + //添加平台收佣账号 + if(($service_fee + $delivery_fee) > 0){ + if(!$this->addReceivers($applet_id)) { + $this->error = '添加平台分账接收方失败'; + return false; + } + $webpay = Setting::getItem('webpay',0)['wx']; //平台微信支付参数 + $receivers[] = [ + 'type' => 'MERCHANT_ID',//分账接收方类型 MERCHANT_ID=商户号 PERSONAL_OPENID=个人openid + 'account' => $webpay['mch_id'],//分账接收方账号 + 'amount' => $service_fee + $delivery_fee,//分账金额 + 'description' => '分佣给平台',//分账描述 + ]; + } + //添加代理收佣账号 + if($agent_fee > 0 and !empty($agent_openid)){ + if(!$this->addReceivers($applet_id,false,$agent_openid)) { + $this->error = '添加代理分账接收方失败'; + return false; + } + $receivers[] = [ + 'type' => $this->config['is_sub'] == 1 ? 'PERSONAL_SUB_OPENID':'PERSONAL_OPENID',//分账接收方类型 + 'account' => $agent_openid,//分账接收方账号 + 'amount' => $agent_fee,//分账金额 + 'description' => '分佣给代理',//分账描述 + ]; + } + //***************** 请求分账 *********************// + if(sizeof($receivers) == 0){ + $this->error = '收款方账号列表为空'; + return false; + } + if(!$this->profitSharing($data['transaction_id'],$data['out_order_no'],$receivers)) { + $this->error = '请求分账失败'; + return false; + } + //***************** 添加交易记录 *********************// + $record_log = [];//交易流水记录 + //是否增加平台分红记录(分佣) + if(($service_fee - $agent_fee) > 0){ + $money = sprintf("%.2f",$service_fee / 100);//计算金额 + //平台分红(分佣)记录 + array_push($record_log,[ + 'mode' => 40, //赠送 + 'type' => 30, //微信 + 'order_no' => $data['out_order_no'], + 'money' => $money, + 'remark' => '交易分佣' + ]); + //商户扣费记录 + array_push($record_log,[ + 'mode' => 50, //扣减 + 'type' => 30, //微信 + 'order_no' => $data['out_order_no'], + 'money' => $money, + 'user_id' => $applet['user_id'], + 'remark' => '交易服务费' + ]); + } + //是否增加配送费记录 + if($delivery_fee > 0){ + $money = sprintf("%.2f",$delivery_fee / 100);//计算金额 + //平台收取记录 + array_push($record_log,[ + 'mode' => 40, //赠送 + 'type' => 30, //微信 + 'order_no' => $data['out_order_no'], + 'money' => $money, + 'remark' => '第三方配送费' + ]); + //商户扣费记录 + array_push($record_log,[ + 'mode' => 50, //扣减 + 'type' => 30, //微信 + 'order_no' => $data['out_order_no'], + 'money' => $money, + 'user_id' => $applet['user_id'], + 'remark' => '第三方配送费' + ]); + } + //是否增加代理分佣记录 + if($agent_fee > 0){ + $money = sprintf("%.2f",$agent_fee / 100);//计算金额 + //平台收取记录 + array_push($record_log,[ + 'mode' => 40, //赠送 + 'type' => 30, //微信 + 'order_no' => $data['out_order_no'], + 'money' => $money, + 'user_id' => $applet['agent_id'], + 'remark' => '交易分佣' + ]); + } + //批量增加交易记录 + $model = new Record; + if(!$model->saveAll($record_log)){ + $this->error = '添加交易记录失败'; + return false; + } + return true; + } + /** + * 请求分账API + */ + private function profitSharing($transaction_id,$out_order_no,$receivers) + { + //服务商 + $params = [ + 'transaction_id' => $transaction_id,//微信订单号 + 'out_order_no' => $out_order_no,//商户分账单号 + 'receivers' => $receivers, + 'unfreeze_unsplit' => true,//是否解冻剩余未分资金 + ]; + if($this->config['is_sub'] == 1){ + //服务商 + $params['appid'] = $this->isp_config['app_id'];//服务商应用ID + $params['sub_appid'] = $this->config['app_id'];//子商户应用ID + $params['sub_mchid'] = $this->config['mch_id'];//子商户号 + $is_isp = true; + }else{ + //直连商户 + $params['appid'] = $this->config['app_id'];//小程序ID + $is_isp = false; + } + $params = hema_json($params); + $url = $this->getUrl('profitsharing/orders'); + $headers = [ + 'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $this->sign($url,'POST',$params,$is_isp), + 'Content-Type:application/json', + 'Accept:application/json', + 'User-Agent:' . $is_isp?$this->isp_config['mch_id']:$this->config['mch_id'], + 'Wechatpay-Serial:' . $this->isp_config['serial_no'], + ]; + return $this->result(json_decode(Http::post($url, $params,[],$headers),true)); + } + /** + * 添加分账接收方API + * $is_mchid = 接收方是否是商户 $account = 接收账号 + */ + private function addReceivers($applet_id,$is_mchid=true,$account='') + { + if($this->config['is_sub'] == 1){ + //服务商 + $params['appid'] = $this->isp_config['app_id'];//服务商应用ID + $params['sub_appid'] = $this->config['app_id'];//子商户应用ID + $params['sub_mchid'] = $this->config['mch_id'];//子商户号 + if($is_mchid){ + $webpay = Setting::getItem('webpay',0)['wx']; + $params['type'] = 'MERCHANT_ID';//分账接收方类型 + $params['account'] = $webpay['mch_id'];//分账接收方账号 + $params['name'] = $this->getEncrypt($webpay['name']); //(加密)分账个人接收方姓名 分账接收方类型是MERCHANT_ID时,是商户全称(必传) + }else{ + $params['type'] = 'PERSONAL_SUB_OPENID';//分账接收方类型 + $params['account'] = $account;//分账接收方账号 + } + $params['relation_type'] = 'SERVICE_PROVIDER'; //与分账方的关系类型 服务商 + $is_isp = true; + $serial_no = $this->isp_config['serial_no']; + }else{ + //直连商户 + $params['appid'] = $this->config['app_id'];//小程序ID + if($is_mchid){ + $webpay = Setting::getItem('webpay',0)['wx']; + $params['type'] = 'MERCHANT_ID';//分账接收方类型 + $params['account'] = $webpay['mch_id'];//分账接收方账号 + $params['name'] = $this->getEncrypt($webpay['name'],false,$applet_id); //(加密)分账个人接收方姓名 分账接收方类型是MERCHANT_ID时,是商户全称(必传) + }else{ + $params['type'] = 'PERSONAL_OPENID';//分账接收方类型 + $params['account'] = $account;//分账接收方账号 + } + $params['relation_type'] = 'PARTNER'; ////与分账方的关系类型 合作伙伴 + $is_isp = false; + $serial_no = $this->config['serial_no']; + } + $params = hema_json($params); + $url = $this->getUrl('profitsharing/receivers/add'); + $headers = [ + 'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $this->sign($url,'POST',$params,$is_isp), + 'Content-Type:application/json', + 'Accept:application/json', + 'User-Agent:' . $is_isp?$this->isp_config['mch_id']:$this->config['mch_id'], + 'Wechatpay-Serial:' . $serial_no, + ]; + return $this->result(json_decode(Http::post($url, $params,[],$headers),true)); + } + /** + * 申请退款API + */ + public function refunds($transaction_id,$out_refund_no,$refund_fee,$total_fee,$notify_url='',$reason='') + { + $params = [ + 'transaction_id' => $transaction_id,//微信支付订单号 + 'out_refund_no' => $out_refund_no,//退款订单号 + 'amount' => [ + 'refund' => intval($refund_fee * 100), // 退款金额,价格:单位分 + 'total' => intval($total_fee * 100), // 订单金额,价格:单位分 + 'currency' => 'CNY', //退款币种 只支持人民币:CNY + ], + ]; + if($this->config['is_sub'] == 1){ + //服务商 + $params['sub_mchid'] = $this->config['mch_id'];//子商户号 + $is_isp = true; + }else{ + $is_isp = false; + } + !empty($reason) && $params['reason'] = $reason;//退款原因 + !empty($notify_url) && $params['notify_url'] = base_url() . $notify_url; // 异步通知地址 + + $params = hema_json($params); + $url = $this->getUrl('refund/domestic/refunds'); + $headers = [ + 'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $this->sign($url,'POST',$params,$is_isp), + 'Content-Type:application/json', + 'Accept:application/json', + 'User-Agent:' . $is_isp?$this->isp_config['mch_id']:$this->config['mch_id'], + ]; + return $this->result(json_decode(Http::post($url, $params,[],$headers),true)); + + } + /** + * 退款成功异步通知 + */ + public function refundsNotify($Model,$applet_id='') + { + //接收微信服务器回调的数据流 + if (!$json = file_get_contents('php://input')) { + $this->returnHttpCode(false); + } + // 将服务器返回的json数据转化为数组 + $result = json_decode($json,true); + if(empty($applet_id)){ + $this->config = Setting::getItem('webpay',0)['wx'];//平台商户支付参数 + }else{ + $this->config = Setting::getItem('wxpay',$applet_id);//商家商户支付参数 + } + if($this->config['is_sub'] == 1){ + //服务商 + $api_key = $this->isp_config['api_key']; + //判断平台证书是否过期 + if($this->isp_config['expire_time'] < time()){ + //更新平台证书 + if(!$this->certificates()){ + $this->returnHttpCode(false,$this->error);//更新失败 + } + } + }else{ + //直连商户 + $api_key = $this->config['api_key']; + //判断平台证书是否过期 + if($this->config['expire_time'] < time()){ + //更新平台证书 + if(!$this->certificates(false,$applet_id)){ + $this->returnHttpCode(false,$this->error);//更新失败 + } + } + } + if(!$decrypt = new AesUtil($api_key)){ + $this->returnHttpCode(false,$decrypt->getError()); + } + if(!$res = $decrypt->decryptToString($result['resource']['associated_data'], $result['resource']['nonce'], $result['resource']['ciphertext'])){ + $this->returnHttpCode(false,$decrypt->getError()); + } + $data = json_decode($res,true); + // 订单信息 + if(!$order = $Model->refundDetail($data['out_refund_no'])){ + $this->returnHttpCode(false,'订单不存在'); + } + + if($data['refund_status'] == 'SUCCESS') { + // 更新订单状态 + $order->updateRefundStatus($data['refund_id']); + $this->returnHttpCode(true);// 返回状态 + } + $this->returnHttpCode(false, '退款失败'); + } + /** + * Native下单API + * $out_trade_no=订单号, $total=支付金额,$attach=订单描述 $profit_sharing=是否分账 + */ + public function native($out_trade_no,$total,$notify_url,$attach='订单支付',$profit_sharing = false) + { + $params = [ + 'description' => $attach,//商品描述 + 'out_trade_no' => $out_trade_no,//商户订单号 + 'attach' => $attach,//附加数据 + 'notify_url' => base_url() . $notify_url, //通知地址 + 'amount' => [ + 'total' => intval($total * 100),//订单总金额,单位为分 + ], + 'scene_info' => [ + 'payer_client_ip' => \request()->ip(),//用户终端IP + ], + ]; + if($this->config['is_sub'] == 1){ + //服务商 + $params['sp_appid'] = $this->isp_config['app_id'];//服务商应用ID + $params['sp_mchid'] = $this->isp_config['mch_id'];//服务商商户号 + //$params['sub_appid'] = $this->config['app_id'];//子商户应用ID + $params['sub_mchid'] = $this->config['mch_id'];//子商户号 + //$params['payer']['sub_openid'] = $openid; //子用户标识Openid + $url = $this->getUrl('pay/partner/transactions/native');//服务商 + $is_isp = true; + }else{ + //直连商户 + $params['appid'] = $this->config['app_id'];//小程序ID + $params['mchid'] = $this->config['mch_id'];//商户号 + $url = $this->getUrl('pay/transactions/native');//直连商户 + $is_isp = false; + } + //判断是否开启分账 + $divide = Setting::getItem('divide',0); + if($profit_sharing or $divide['extract'] > 0){ + $params['settle_info']['profit_sharing'] = true; //开启分账 + } + $params = hema_json($params); + $headers = [ + 'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $this->sign($url,'POST',$params,$is_isp), + 'Content-Type:application/json', + 'Accept:application/json', + 'User-Agent:' . $is_isp?$this->isp_config['mch_id']:$this->config['mch_id'], + ]; + $result = json_decode(Http::post($url, $params,[],$headers),true); + if(isset($result['code'])){ + $this->error = 'code:' . $result['code'] . ',msg:' . $result['message']; + return false; + } + if(!isset($result['code_url'])){ + $this->error = 'Native下单接口请求失败'; + return false; + } + return $result['code_url']; + } + /** + * JSAPI下单API + * $out_trade_no=订单号, $total=支付金额,$openid=微信用户ID, ,$attach=订单描述 + * $profit_sharing=是否分账(有配送费要分账时传递) + */ + public function jsapi($out_trade_no,$total,$openid,$notify_url,$attach='订单支付',$profit_sharing = false) + { + $params = [ + 'description' => $attach,//商品描述 + 'attach' => $attach,//附加数据 + 'out_trade_no' => $out_trade_no,//商户订单号 + 'notify_url' => base_url() . $notify_url, //通知地址 + 'amount' => [ + 'total' => intval($total * 100),//订单总金额,单位为分 + ], + 'scene_info' => [ + 'payer_client_ip' => \request()->ip(),//用户终端IP + ], + ]; + if($this->config['is_sub'] == 1){ + //服务商 + $params['sp_appid'] = $this->isp_config['app_id'];//服务商应用ID + $params['sp_mchid'] = $this->isp_config['mch_id'];//服务商商户号 + $params['sub_appid'] = $this->config['app_id'];//子商户应用ID + $params['sub_mchid'] = $this->config['mch_id'];//子商户号 + $params['payer']['sub_openid'] = $openid; //子用户标识Openid + $url = $this->getUrl('pay/partner/transactions/jsapi');//服务商 + $is_isp = true; + }else{ + //直连商户 + $params['appid'] = $this->config['app_id'];//小程序ID + $params['mchid'] = $this->config['mch_id'];//商户号 + $params['payer']['openid'] = $openid; //用户标识Openid + $url = $this->getUrl('pay/transactions/jsapi');//直连商户 + $is_isp = false; + } + //判断是否开启分账 + $divide = Setting::getItem('divide',0); + if($profit_sharing or $divide['extract'] > 0){ + $params['settle_info']['profit_sharing'] = true; //开启分账 + } + // $params = hema_json($params); + $params = json_encode($params); + $headers = [ + 'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $this->sign($url,'POST',$params,$is_isp), + 'Content-Type:application/json', + 'Accept:application/json', + 'User-Agent:' . $is_isp?$this->isp_config['mch_id']:$this->config['mch_id'], + ]; + + + + $result = json_decode(Http::post($url, $params,[],$headers),true); + + if(isset($result['code'])){ + $this->error = 'code:' . $result['code'] . ',msg:' . $result['message']; + return false; + } + if(!isset($result['prepay_id'])){ + $this->error = 'JSAPI下单接口请求失败'; + return false; + } + $data = [ + 'timeStamp' => (string)time(), + 'nonceStr' => $this->nonce(), + 'package' => 'prepay_id=' . $result['prepay_id'], + 'signType' => 'RSA', + ]; + $data['paySign'] = $this->paySign($data); + return $data; + } + + /** + * 支付成功异步通知 + */ + public function notify($Model,$applet_id,$method='edit') + { + + Log::write('机333','notice'); + + //接收微信服务器回调的数据流 + if (!$json = file_get_contents('php://input')) { + $this->returnHttpCode(false); + } + // 将服务器返回的json数据转化为数组 + $result = json_decode($json,true); + + Log::write($json,'notice'); + + if(empty($applet_id)){ + $this->config = Setting::getItem('webpay',0)['wx'];//平台商户支付参数 + }else{ + $this->config = Setting::getItem('wxpayisp',0); + } + + $this->config['is_sub']=2; + + if($this->config['is_sub'] == 1){ + //服务商 + $api_key = $this->isp_config['api_key']; + //判断平台证书是否过期 + if($this->isp_config['expire_time'] < time()){ + //更新平台证书 + if(!$this->certificates()){ + $this->returnHttpCode(false,$this->error);//更新失败 + } + } + }else{ + //直连商户 + $api_key = $this->config['api_key']; + //判断平台证书是否过期 + if($this->config['expire_time'] < time()){ + //更新平台证书 + if(!$this->certificates(false,$applet_id)){ + $this->returnHttpCode(false,$this->error);//更新失败 + } + } + } + if(!$decrypt = new AesUtil($api_key)){ + $this->returnHttpCode(false,$decrypt->getError()); + } + if(!$res = $decrypt->decryptToString($result['resource']['associated_data'], $result['resource']['nonce'], $result['resource']['ciphertext'])){ + $this->returnHttpCode(false,$decrypt->getError()); + } + $data = json_decode($res,true); + // 订单信息 + if(!$order = $Model->payDetail($data['out_trade_no'])){ + $this->returnHttpCode(false,'订单不存在'); + } + + //判断支付状态 + if($data['trade_state'] == 'SUCCESS') { + if($method == 'add'){ + $Model->updatePayStatus($data['transaction_id'],$order); + Cache::delete($data['out_trade_no']); + }else{ + // 更新订单状态 + $order->updatePayStatus($data['transaction_id']); + } + // 返回状态 + $this->returnHttpCode(true); + } + // 返回状态 + $this->returnHttpCode(false, '支付失败'); + } + + /** + * 特约商户进件 + * 频率限制:15/s + */ + public function applyment($params) + { + //********************* 数据加密 ***************** + + //管理员姓名 + if(!$result = $this->getEncrypt($params['contact_info']['contact_name'])){ + return false; + } + $params['contact_info']['contact_name'] = $result; + //管理员电话 + if(!$result = $this->getEncrypt($params['contact_info']['mobile_phone'])){ + return false; + } + $params['contact_info']['mobile_phone'] = $result; + //管理员邮箱 + if(!$result = $this->getEncrypt($params['contact_info']['contact_email'])){ + return false; + } + $params['contact_info']['contact_email'] = $result; + //身份证姓名 + if(!$result = $this->getEncrypt($params['subject_info']['identity_info']['id_card_info']['id_card_name'])){ + return false; + } + $params['subject_info']['identity_info']['id_card_info']['id_card_name'] = $result; + //身份证号 + if(!$result = $this->getEncrypt($params['subject_info']['identity_info']['id_card_info']['id_card_number'])){ + return false; + } + $params['subject_info']['identity_info']['id_card_info']['id_card_number'] = $result; + + //身份证居住地址 + if(!$result = $this->getEncrypt($params['subject_info']['identity_info']['id_card_info']['id_card_address'])){ + return false; + } + $params['subject_info']['identity_info']['id_card_info']['id_card_address'] = $result; + + + //银行开户名称 + if(!$result = $this->getEncrypt($params['bank_account_info']['account_name'])){ + return false; + } + $params['bank_account_info']['account_name'] = $result; + //银行账号 + if(!$result = $this->getEncrypt($params['bank_account_info']['account_number'])){ + return false; + } + $params['bank_account_info']['account_number'] = $result; + + //********************* 上传图片 ***************** + //营业执照 + if(!$result = $this->upload($params['subject_info']['business_license_info']['license_copy'])){ + return false; + } + $params['subject_info']['business_license_info']['license_copy'] = $result; + //身份证正面 + if(!$result = $this->upload($params['subject_info']['identity_info']['id_card_info']['id_card_copy'])){ + return false; + } + $params['subject_info']['identity_info']['id_card_info']['id_card_copy'] = $result; + //身份证反面 + if(!$result = $this->upload($params['subject_info']['identity_info']['id_card_info']['id_card_national'])){ + return false; + } + $params['subject_info']['identity_info']['id_card_info']['id_card_national'] = $result; + //特殊资质 + if(!$result = $this->upload($params['settlement_info']['qualifications'][0])){ + return false; + } + $params['settlement_info']['qualifications'][0] = $result; + //门头照片 + if(!$result = $this->upload($params['business_info']['sales_info']['biz_store_info']['store_entrance_pic'][0])){ + return false; + } + $params['business_info']['sales_info']['biz_store_info']['store_entrance_pic'][0] = $result; + //店内照片 + if(!$result = $this->upload($params['business_info']['sales_info']['biz_store_info']['indoor_pic'][0])){ + return false; + } + $params['business_info']['sales_info']['biz_store_info']['indoor_pic'][0] = $result; + $params = hema_json($params); + $url = $this->getUrl('applyment4sub/applyment/'); + $headers = [ + 'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $this->sign($url,'POST',$params), + 'Content-Type:application/json', + 'Accept:application/json', + 'User-Agent:' . $this->isp_config['mch_id'], + 'Wechatpay-Serial:' . $this->isp_config['serial_no'], + ]; + $result = json_decode(Http::post($url, $params,[],$headers),true); + if(isset($result['code'])){ + $this->error = 'code:' . $result['code'] . ',msg:' . $result['message']; + return false; + } + return $result['applyment_id']; + } + /** + * 查询申请单状态 + */ + public function queryApplyment($no,$is_applyment_id = false) + { + if($is_applyment_id){ + $path = 'applyment_id/' . $no;//通过申请单号查询申请状态(官方返回的编号) + }else{ + $path = 'business_code/' . $no;//通过业务申请编号查询申请状态(第三方自定义的编号) + } + $url = $this->getUrl('applyment4sub/applyment/'.$path); + $headers = [ + 'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $this->sign($url,'GET'), + 'Accept:application/json', + ]; + return $this->result(json_decode(Http::get($url, [],[],$headers),true)); + } + /** + * 获取平台证书列表 + */ + private function certificates($is_isp=true,$applet_id='') + { + $url = $this->getUrl('certificates'); + $headers = [ + 'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $this->sign($url,'GET','',$is_isp), + 'Accept:application/json', + 'User-Agent:https://zh.wikipedia.org/wiki/User_agent', + ]; + $result = json_decode(Http::get($url,[],[],$headers),true); + if(isset($result['code'])){ + $this->error = 'code:' . $result['code'] . ',msg:' . $result['message']; + return false; + } + //验证是否获取到了数据 + if(!isset($result['data']) and sizeof($result['data']) == 0){ + $this->error = '未获取到可用的平台证书'; + return false; + } + $result = $result['data'][0];//获取证书列表中的第一个数据 + if($is_isp){ + $api_key = $this->isp_config['api_key']; + }else{ + $api_key = $this->config['api_key']; + } + if(!$decrypt = new AesUtil($api_key)){ + $this->error = $decrypt->getError(); + return false; + } + if(!$res = $decrypt->decryptToString($result['encrypt_certificate']['associated_data'], $result['encrypt_certificate']['nonce'], $result['encrypt_certificate']['ciphertext'])){ + $this->error = $decrypt->getError(); + return false; + } + //计算到期时间 + $expire_time = explode('T',$result['expire_time']); + $expire_time = strtotime($expire_time[0]); + $model = new Setting; + //更新平台证书 + if($is_isp){ + $this->isp_config['certificates'] = $res; + $this->isp_config['serial_no'] = $result['serial_no']; + $this->isp_config['expire_time'] = $expire_time; + $model->edit('wxpayisp',$this->isp_config,0); //保存到数据库 + return true; + } + //更新特约商户 平台证书 + $this->config['certificates'] = $res; + $this->config['serial_no'] = $result['serial_no']; + $this->config['expire_time'] = $expire_time; + if(empty($applet_id)){ + $config = Setting::getItem('webpay',0); + $config['wx']['certificates'] = $res; + $config['wx']['serial_no'] = $result['serial_no']; + $config['wx']['expire_time'] = $expire_time; + $model->edit('webpay',$config,0); //保存到数据库 + }else{ + $model->edit('wxpay',$this->config,$applet_id); //保存到数据库 + } + return true; + } + + /** + * 图片上传API + */ + private function upload($file_path) + { + $file = file_get_contents($file_path);//获取网络图片 + //获取文件名称 + $arr = explode('/',$file_path); + $filename = $arr[sizeof($arr)-1]; + $meta =[ + 'filename' => $filename, + 'sha256' => hash('sha256',$file), + ]; + $url = $this->getUrl('merchant/media/upload'); + $boundary = uniqid();//随机数 + $headers = [ + 'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $this->sign($url,'POST',hema_json($meta)), + 'Accept:application/json', + 'Content-Type:multipart/form-data;boundary=' . $boundary, + ]; + $params = '--' . $boundary . "\r\n"; + $params .= 'Content-Disposition:form-data; name="meta"' . "\r\n"; + $params .= 'Content-Type:application/json' . "\r\n\r\n"; + $params .= hema_json($meta) . "\r\n"; + $params .= '--' . $boundary . "\r\n"; + $params .= 'Content-Disposition:form-data;name="file";filename="' . $meta['filename'] . '"' . "\r\n"; + $params .= 'Content-Type:image/jpg' . "\r\n\r\n"; + $params .= $file . "\r\n"; + $params .= '--' . $boundary . '--' . "\r\n"; + $result = json_decode(Http::post($url, $params,[],$headers),true); + if(isset($result['code'])){ + $this->error = 'code:' . $result['code'] . ',msg:' . $result['message']; + return false; + } + if(isset($result['media_id'])){ + return $result['media_id']; + } + $this->error = '图片上传失败'; + return false; + } + + /** + * 调起支付签名 + */ + private function paySign($data) + { + $params = $this->config['app_id'] . "\n" . + $data['timeStamp'] . "\n" . + $data['nonceStr'] . "\n" . + $data['package'] . "\n"; + /*if($this->config['is_sub'] == 1){ + //服务商 + }else{ + //直连商户 + $private_key = $this->config['key_pem']; //API私有证书 + }*/ + $private_key = $this->isp_config['key_pem']; //API私有证书 + + $raw_sign = ''; + openssl_sign($params, $raw_sign, $private_key, 'sha256WithRSAEncryption'); + return base64_encode($raw_sign); + } + + /** + * 生成签名 + * $http_method = HTTP请求的方法(GET,POST,PUT + * serial_no 为你的商户证书序列号 + * $mch_private_key = 是商户API私钥,在商户平台下载的证书文件包含该文件,名称为apiclient_key.pem + * $is_isp 是否为服务商操作 + */ + private function sign($url,$http_method,$body='',$is_isp=true) + { + $timestamp = time(); //时间戳 + $nonce = $this->nonce(); //随机字符串 + $url_parts = parse_url($url); + $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : "")); + $params = $http_method . "\n" . + $canonical_url . "\n" . + $timestamp . "\n" . + $nonce . "\n" . + $body . "\n"; + if($is_isp){ + $mchid = $this->isp_config['mch_id']; //商户号 + $serial_no = $this->isp_config['api_serial_no']; //API证书序列号 + $mch_private_key = $this->isp_config['key_pem']; //API私有证书 + }else{ + $mchid = $this->config['mch_id']; //商户号 + $serial_no = $this->config['api_serial_no']; //API证书序列号 + $mch_private_key = $this->config['key_pem']; //API私有证书 + } + $raw_sign = ''; + openssl_sign($params, $raw_sign, $mch_private_key, 'sha256WithRSAEncryption'); + $sign = base64_encode($raw_sign); + //$schema = 'WECHATPAY2-SHA256-RSA2048'; + $token = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',$mchid, $nonce, $timestamp, $serial_no, $sign); + return $token; + } + /** + * 敏感信息加密 + */ + private function getEncrypt($str,$is_isp = true,$applet_id='') + { + //判断平台证书是否过期 + if($is_isp){ + //服务商 + if($this->isp_config['expire_time'] < time()){ + //更新平台证书 + if(!$this->certificates()){ + return false;//更新失败 + } + } + $public_key = $this->isp_config['certificates'];//平台证书 + }else{ + //直连商户 + if($this->config['expire_time'] < time()){ + //更新平台证书 + if(!$this->certificates(false,$applet_id)){ + return false;//更新失败 + } + } + $public_key = $this->config['certificates'];//平台证书 + } + $encrypted = ''; + if (!openssl_public_encrypt($str, $encrypted, $public_key, OPENSSL_PKCS1_OAEP_PADDING)) { + $this->error = '敏感信息加密失败'; + return false; + } + return base64_encode($encrypted);//base64编码 + } + /** + * 生成随机字符串 + */ + private function nonce() + { + return md5(uniqid()); + } + /* + * 拼接请求域名接口 + */ + private function getUrl($url) + { + return $this->api_url . '/' . $this->version . '/' . $url; + } + /** + * 获取Headers数据 + */ + private function getHeaders() + { + $headers = array(); + foreach ($_SERVER as $key => $value) { + if (substr($key, 0, 5) === 'HTTP_') { + $key = substr($key, 5); + $key = str_replace('_', ' ', $key); + $key = str_replace(' ', '-', $key); + $key = strtolower($key); + $headers[$key] = $value; + } + } + return $headers; + } + /** + * 返回状态给微信服务器 + */ + private function returnHttpCode($is_success = true, $msg = '失败') + { + $json = hema_json([ + 'code' => $is_success ? 'SUCCESS' : 'FAIL', + 'message' => $is_success ? '成功' : $msg, + ]); + if($is_success){ + header('HTTP/1.1 200 OK'); + }else{ + header('HTTP/1.1 404 Not Found'); + } + die($json); + } + /** + * 请求数据验证 + **/ + private function result($result) + { + if(isset($result['code'])){ + $this->error = 'code:' . $result['code'] . ',msg:' . $result['message']; + return false; + } + return $result; + } + public function getError() + { + return $this->error; + } + + /********** V2接口 **********/ + /** + * 付款码支付 + * $auth_code=付款码 $order_no=订单号 $openid=微信用户ID, $total_fee=支付金额, ,$attach=订单描述 $divide=是否分账 + */ + public function micropay($auth_code,$order_no, $total_fee,$profit_sharing = false,$attach = '订单支付') + { + // 当前时间 + $time = time(); + // 生成随机字符串 + $nonceStr = md5($time); + // API参数 + $params = [ + 'auth_code' => $auth_code,//付款码支付 + 'attach' => $attach, + 'nonce_str' => $nonceStr,//随机字符串 + 'body' => $attach,//商品描述 + 'out_trade_no' => $order_no,//商户订单号 + 'total_fee' => intval($total_fee * 100), // 价格:单位分 + 'spbill_create_ip' => \request()->ip(),//服务终端IP + ]; + if($this->config['is_sub'] == 1){ + //服务商统一下单 + $values = Setting::getItem('wxpayisp',0); + $this->config['api_key'] = $this->isp_config['api_key'];//服务商商户的密钥 + $params['appid'] = $this->isp_config['app_id'];//服务商商户的APPID + $params['mch_id'] = $this->isp_config['mch_id'];//服务商商户号 + $params['sub_appid'] = $this->config['app_id'];//当前调起支付的小程序APPID + $params['sub_mch_id'] = $this->config['mch_id'];//服务商分配的子商户号 + }else{ + $params['appid'] = $this->config['app_id'];//小程序ID + $params['mch_id'] = $this->config['mch_id'];//商户号 + } + //判断是否开启分账 + $divide = Setting::getItem('divide',0); + if($profit_sharing or $divide['extract'] > 0){ + $params['profit_sharing'] = 'Y';//开启分账 + } + + // 生成签名 + $params['sign'] = $this->makeSign($params); + $url = 'https://api.mch.weixin.qq.com/pay/micropay';// 请求API + $result = $this->postXmlCurl($this->toXml($params), $url); + $prepay = $this->fromXml($result); + // 请求失败 + if ($prepay['return_code'] === 'FAIL') { + die(hema_json(['code' => -10, 'msg' => $prepay['return_msg']])); + } + //判断付款码支付时,用户支付中,需要输入密码 + if ($prepay['result_code'] === 'USERPAYING') { + return false; + } + if ($prepay['result_code'] === 'FAIL') { + die(hema_json(['code' => -10, 'msg' => $prepay['err_code_des']])); + } + return $prepay['transaction_id'];//支付交易号 + } + + /** + * 查询付款码支付结果是否成功 + */ + public function orderquery($out_trade_no) + { + // 当前时间 + $time = time(); + // 生成随机字符串 + $nonceStr = md5($time); + // API参数 + $params = [ + 'out_trade_no' => $out_trade_no, + 'nonce_str' => $nonceStr,//随机字符串 + ]; + if($this->config['is_sub'] == 1){ + //服务商统一下单 + $this->config['api_key'] = $this->isp_config['api_key'];//服务商商户的密钥 + $params['appid'] = $this->isp_config['app_id'];//服务商商户的APPID + $params['mch_id'] = $this->isp_config['mch_id'];//服务商商户号 + $params['sub_appid'] = $this->config['app_id'];//当前调起支付的小程序APPID + $params['sub_mch_id'] = $this->config['mch_id'];//服务商分配的子商户号 + }else{ + $params['appid'] = $this->config['app_id'];//小程序ID + $params['mch_id'] = $this->config['mch_id'];//商户号 + } + // 生成签名 + $params['sign'] = $this->makeSign($params); + // 请求API + $url = 'https://api.mch.weixin.qq.com/pay/orderquery'; + $result = $this->postXmlCurl($this->toXml($params), $url); + $prepay = $this->fromXml($result); + // 请求失败 + if ($prepay['return_code'] === 'SUCCESS' AND $prepay['result_code'] === 'SUCCESS') { + return $prepay['trade_state']; + } + return 'ERROR'; + } + /** + * 输出xml字符 + */ + private function toXml($values) + { + if (!is_array($values) + || count($values) <= 0 + ) { + return false; + } + $xml = ""; + foreach ($values as $key => $val) { + if (is_numeric($val)) { + $xml .= "<" . $key . ">" . $val . ""; + } else { + $xml .= "<" . $key . ">"; + } + } + $xml .= ""; + return $xml; + } + /** + * 将xml转为array + */ + private function fromXml($xml) + { + // 禁止引用外部xml实体 + libxml_disable_entity_loader(true); + return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); + } + /** + * 以post方式提交xml到对应的接口url + */ + private function postXmlCurl($xml, $url, $cert = false, $second = 30) + { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_TIMEOUT, $second);// 设置超时时间 + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);//https请求 不验证证书和host + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);//严格校验 + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);// 要求结果为字符串且输出到屏幕上 + curl_setopt($ch, CURLOPT_POST, TRUE);// post提交方式 + curl_setopt($ch, CURLOPT_POSTFIELDS, $xml); + curl_setopt($ch, CURLOPT_HEADER, FALSE);// 是否返回请求头 + //判断是否使用证书 + if($cert){ + $path = root_path() . '/extend/hema/wechat/cert/'; + file_put_contents($path . 'apiclient_cert.pem',$this->config['cert_pem']); + file_put_contents($path . 'apiclient_key.pem',$this->config['key_pem']); + curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM'); + curl_setopt($ch,CURLOPT_SSLCERT,$path . 'apiclient_cert.pem'); + curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM'); + curl_setopt($ch,CURLOPT_SSLKEY,$path . 'apiclient_key.pem'); + } + $data = curl_exec($ch);// 运行curl + curl_close($ch); + return $data; + } + + /** + * 生成签名MD5 + */ + private function makeSign($values) + { + //签名步骤一:按字典序排序参数 + ksort($values); + $string = $this->toUrlParams($values); + //签名步骤二:在string后加入KEY + $string = $string . '&key=' . $this->config['api_key']; + //签名步骤三:MD5加密 + $string = md5($string); + //签名步骤四:所有字符转为大写 + $result = strtoupper($string); + return $result; + } + + /** + * 格式化参数格式化成url参数 + */ + private function toUrlParams($values) + { + $buff = ''; + foreach ($values as $k => $v) { + if ($k != 'sign' && $v != '' && !is_array($v)) { + $buff .= $k . '=' . $v . '&'; + } + } + return trim($buff, '&'); + } } \ No newline at end of file diff --git a/public/.well-known/acme-challenge/MSXAiMoekTBByxVW78vewFjtSHH8qZ9O0Mwdzt1_dD8 b/public/.well-known/acme-challenge/MSXAiMoekTBByxVW78vewFjtSHH8qZ9O0Mwdzt1_dD8 new file mode 100644 index 0000000..a10ad66 --- /dev/null +++ b/public/.well-known/acme-challenge/MSXAiMoekTBByxVW78vewFjtSHH8qZ9O0Mwdzt1_dD8 @@ -0,0 +1 @@ +MSXAiMoekTBByxVW78vewFjtSHH8qZ9O0Mwdzt1_dD8.M2aqQcnvx01Y2S5zCFXJr1JyTjgYmG5xwwL0dfQzKco \ No newline at end of file diff --git a/public/uploads/20231201/1be072d5272f567b09e85a28953712d9.jpg b/public/uploads/20231201/1be072d5272f567b09e85a28953712d9.jpg new file mode 100644 index 0000000..9b7834a Binary files /dev/null and b/public/uploads/20231201/1be072d5272f567b09e85a28953712d9.jpg differ diff --git a/runtime/admin/temp/1135d99398657c0ae566d459308e8327.php b/runtime/admin/temp/1135d99398657c0ae566d459308e8327.php old mode 100644 new mode 100755 diff --git a/runtime/admin/temp/165f30f93e40130c15d885f561996cb2.php b/runtime/admin/temp/165f30f93e40130c15d885f561996cb2.php old mode 100644 new mode 100755 diff --git a/runtime/admin/temp/29a1b1f477dc444c90efb32e05e28fcd.php b/runtime/admin/temp/29a1b1f477dc444c90efb32e05e28fcd.php old mode 100644 new mode 100755 diff --git a/runtime/admin/temp/352d937338d3cbeaa5a6b2aef6a0495e.php b/runtime/admin/temp/352d937338d3cbeaa5a6b2aef6a0495e.php old mode 100644 new mode 100755 diff --git a/runtime/admin/temp/3a0f7010e1e6219083ad8c5646d41a40.php b/runtime/admin/temp/3a0f7010e1e6219083ad8c5646d41a40.php old mode 100644 new mode 100755 diff --git a/runtime/admin/temp/5c32e7932a0700ecea140e20f7bc660c.php b/runtime/admin/temp/5c32e7932a0700ecea140e20f7bc660c.php old mode 100644 new mode 100755 diff --git a/runtime/admin/temp/77873608a3a896bd3d43bafe9fe9a27f.php b/runtime/admin/temp/77873608a3a896bd3d43bafe9fe9a27f.php old mode 100644 new mode 100755 diff --git a/runtime/admin/temp/77d3402cf97c0a269213cffcfac5cd3c.php b/runtime/admin/temp/77d3402cf97c0a269213cffcfac5cd3c.php old mode 100644 new mode 100755 diff --git a/runtime/admin/temp/871d8f9ac37b49ddb1f8892d42b0b432.php b/runtime/admin/temp/871d8f9ac37b49ddb1f8892d42b0b432.php old mode 100644 new mode 100755 diff --git a/runtime/admin/temp/ce62fa7229051749de6651961ed8a08c.php b/runtime/admin/temp/ce62fa7229051749de6651961ed8a08c.php old mode 100644 new mode 100755 diff --git a/runtime/admin/temp/d0998e50cb4b95fe491115d630adb4d8.php b/runtime/admin/temp/d0998e50cb4b95fe491115d630adb4d8.php old mode 100644 new mode 100755 diff --git a/runtime/admin/temp/db3fc3ab033eae396bc223a1db61ffa3.php b/runtime/admin/temp/db3fc3ab033eae396bc223a1db61ffa3.php old mode 100644 new mode 100755 diff --git a/runtime/applet/log/202311/21_error.log b/runtime/applet/log/202311/21_error.log old mode 100644 new mode 100755 diff --git a/runtime/applet/temp/0401244b90b33ea4345ab01331660c33.php b/runtime/applet/temp/0401244b90b33ea4345ab01331660c33.php old mode 100644 new mode 100755 diff --git a/runtime/applet/temp/4d1c52033742f01e5be6650c8d5d5c31.php b/runtime/applet/temp/4d1c52033742f01e5be6650c8d5d5c31.php old mode 100644 new mode 100755 diff --git a/runtime/applet/temp/6d4c9daa5662bf5b4314aa7ff4421e3e.php b/runtime/applet/temp/6d4c9daa5662bf5b4314aa7ff4421e3e.php old mode 100644 new mode 100755 diff --git a/runtime/applet/temp/6e46255bb576ddd9bc889b5af5c6af2a.php b/runtime/applet/temp/6e46255bb576ddd9bc889b5af5c6af2a.php old mode 100644 new mode 100755 diff --git a/runtime/applet/temp/77dea72f140119eec7bc249b88fb2458.php b/runtime/applet/temp/77dea72f140119eec7bc249b88fb2458.php old mode 100644 new mode 100755 diff --git a/runtime/applet/temp/856c52ff20046a0878ce6c7c3f189901.php b/runtime/applet/temp/856c52ff20046a0878ce6c7c3f189901.php old mode 100644 new mode 100755 diff --git a/runtime/applet/temp/8f1b83cd3dd31541f148aeee4301fb03.php b/runtime/applet/temp/8f1b83cd3dd31541f148aeee4301fb03.php old mode 100644 new mode 100755 diff --git a/runtime/applet/temp/9fe3befe3ea695f4e50a001bee83c480.php b/runtime/applet/temp/9fe3befe3ea695f4e50a001bee83c480.php old mode 100644 new mode 100755 diff --git a/runtime/applet/temp/d406f6394afc907afff31febc70c8935.php b/runtime/applet/temp/d406f6394afc907afff31febc70c8935.php old mode 100644 new mode 100755 diff --git a/runtime/applet/temp/f23a297c97a3d0d4d3ea56de0ee9794f.php b/runtime/applet/temp/f23a297c97a3d0d4d3ea56de0ee9794f.php old mode 100644 new mode 100755 diff --git a/runtime/cache/13/0fd29bc1e1c9570496921b09ae2849.php b/runtime/cache/13/0fd29bc1e1c9570496921b09ae2849.php old mode 100644 new mode 100755 diff --git a/runtime/cache/21/413a1afbfae837472e4844bda5ddbc.php b/runtime/cache/21/413a1afbfae837472e4844bda5ddbc.php old mode 100644 new mode 100755 diff --git a/runtime/cache/30/4fce12426ae0229ae22216efc4ea5b.php b/runtime/cache/30/4fce12426ae0229ae22216efc4ea5b.php old mode 100644 new mode 100755 diff --git a/runtime/cache/4e/819c837d54a6ed09abc77a8560a66f.php b/runtime/cache/4e/819c837d54a6ed09abc77a8560a66f.php old mode 100644 new mode 100755 diff --git a/runtime/cache/90/11cab08498f44656fa8e2447787b43.php b/runtime/cache/90/11cab08498f44656fa8e2447787b43.php index 5811081..2b945a5 100644 --- a/runtime/cache/90/11cab08498f44656fa8e2447787b43.php +++ b/runtime/cache/90/11cab08498f44656fa8e2447787b43.php @@ -1,4 +1,55 @@ -a:0:{} \ No newline at end of file +a:3:{s:7:"ability";a:5:{s:3:"key";s:7:"ability";s:8:"describe";s:12:"功能设置";s:6:"values";a:6:{s:12:"applet_apply";s:1:"1";s:10:"applet_fee";s:1:"0";s:13:"applet_online";s:1:"1";s:9:"pay_apply";s:1:"1";s:7:"open_id";s:0:"";s:5:"wxmap";s:35:"OB4BZ-D4W3U-B7VVO-4PJWW-6TKDJ-WPB77";}s:9:"applet_id";i:0;s:11:"update_time";i:0;}s:3:"web";a:5:{s:3:"key";s:3:"web";s:8:"describe";s:12:"站点设置";s:6:"values";a:9:{s:4:"name";s:36:"蓝色畅想网络股份有限公司";s:7:"company";s:0:"";s:7:"address";s:0:"";s:3:"icp";s:0:"";s:11:"description";s:0:"";s:8:"keywords";s:0:"";s:11:"baidu_count";s:0:"";s:2:"qq";s:0:"";s:5:"phone";s:0:"";}s:9:"applet_id";i:0;s:11:"update_time";i:0;}s:8:"wxpayisp";a:5:{s:3:"key";s:8:"wxpayisp";s:8:"describe";s:27:"微信支付服务商设置";s:6:"values";a:9:{s:6:"app_id";s:18:"wx3668302906e3894f";s:6:"mch_id";s:10:"1658128914";s:7:"api_key";s:32:"GS4fwElUx6Ys9KbFMvFlmok1zkL3UMno";s:13:"api_serial_no";s:40:"51B38FC8749949FFEC70E7CDB6D8EC7057D7B250";s:8:"cert_pem";s:1504:"-----BEGIN CERTIFICATE----- +MIIEKzCCAxOgAwIBAgIUUbOPyHSZSf/scOfNttjscFfXslAwDQYJKoZIhvcNAQEL +BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT +FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg +Q0EwHhcNMjMxMTA4MTAzMjQwWhcNMjgxMTA2MTAzMjQwWjCBhDETMBEGA1UEAwwK +MTY1ODEyODkxNDEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMTAwLgYDVQQL +DCfpu4TovpvkuIDvvIjljqbpl6jvvInpo5/lk4HmnInpmZDlhazlj7gxCzAJBgNV +BAYMAkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAKUgYnkTu2HZT/eQoYNgWLYR/L5T1HRVO4jwBhrXaWqdqBOH6Jx+ +8VNhWAwg9C6ULjYfqBRlxoyAyH/0xJeFvmbL2mohpgflRsXjSqdaBgP449M3yr2T +D0lFlRfDRHDVCOkfzUEmpWFwytBZIjI+1t5/s5Wzz4tysHTOtmBBXhcfoLwy/gdQ +3nv1OAlH9nf9SAo9t/iZVC47Tz3gdu2WyNHepnaExUrC8cAypL9bXtCkOVHwO+Km +7ox5sR9lGKsQ6ArANHYmpwWXxy9iOm3TzNINnMvuJ26k4qOw69qsn+bAEBW0pe82 +14uQK1mdbFZeBl6dSqxtGg2AHUMkJlE56mECAwEAAaOBuTCBtjAJBgNVHRMEAjAA +MAsGA1UdDwQEAwID+DCBmwYDVR0fBIGTMIGQMIGNoIGKoIGHhoGEaHR0cDovL2V2 +Y2EuaXRydXMuY29tLmNuL3B1YmxpYy9pdHJ1c2NybD9DQT0xQkQ0MjIwRTUwREJD +MDRCMDZBRDM5NzU0OTg0NkMwMUMzRThFQkQyJnNnPUhBQ0M0NzFCNjU0MjJFMTJC +MjdBOUQzM0E4N0FEMUNERjU5MjZFMTQwMzcxMA0GCSqGSIb3DQEBCwUAA4IBAQCT +ovV7SSKsIAmiVmf0CqmRxucNIHQDPcUuBTrHFIaQYIIOwiJd2tfzzvF8CF3EAKpD +IkaZflQaGtYQQ81atJ8TNGzeTseS0mmjucea808bvHOFmxrMmY1D/l2NjklOEpVd +Rhs5HMtOAc4rq6cXbSK/a/sP/Lyc1vu39/bkCDITWtH8sVAxPgZpFHPR1PXxhKwJ +iMg70BWmzIBqIWSfB9NC0kbKOk9TjJNiZk8N+IoQaWiZY/n4X0rLNEKLernlvxBu +O+C3u/L9W1WAZM+GXsNNnPmGSF//GHPYEGWn0nKwTm9EvHERR/QGPDhMXg4h358I +j8bCl9IjOKZtzE1+ztVu +-----END CERTIFICATE-----";s:7:"key_pem";s:1703:"-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQClIGJ5E7th2U/3 +kKGDYFi2Efy+U9R0VTuI8AYa12lqnagTh+icfvFTYVgMIPQulC42H6gUZcaMgMh/ +9MSXhb5my9pqIaYH5UbF40qnWgYD+OPTN8q9kw9JRZUXw0Rw1QjpH81BJqVhcMrQ +WSIyPtbef7OVs8+LcrB0zrZgQV4XH6C8Mv4HUN579TgJR/Z3/UgKPbf4mVQuO089 +4HbtlsjR3qZ2hMVKwvHAMqS/W17QpDlR8Dvipu6MebEfZRirEOgKwDR2JqcFl8cv +Yjpt08zSDZzL7idupOKjsOvarJ/mwBAVtKXvNteLkCtZnWxWXgZenUqsbRoNgB1D +JCZROephAgMBAAECggEAOVfoupFOpmlYKunwHPaNeBUBB3uHMSsUNLbd995Mvnin +kLjG3+n5lnIcqIGdKrvM3IDb1tGNROfIOR9gUhphB8PNQsQSq3VEwZ3wI/PQWPrK +62PZpUH3sgNXBlyKXQCuSn7/wZtRHWiVFguOI5LM/ZGtZNR/w7Z9buMGVKD+stp7 +Gc4C15Vss7FVh00BLOoiyncUwkdiIGMMOfBqgCHiFrphSPIdGjzb1WqMjU/Np7N0 +dSwpg0m583u8/mBovfZ+NHe1FqtXtltzl4pYohHu9qgaPtuKdFo8z6Dh+8Y5QLip +31TzvZFpFn5ZJNBq3WQYdARkq+ZMCue6IUznA2NTjQKBgQDSTtFqs6fHvUvSLULZ +8w3HMAAD+3EEPQf4bjrZKpvbKyuRMdzTJzjyLFqURpYELiQ+PK3KmF3rl1X0wdby +383pHXhUjq6GfFGiYDaf8V2HMSKwrLKj8M/CGH0Z6rScE0FFM6RoSHLfZWmoLJI7 +JoEd99ekORKWLxiXGWMClq0Z4wKBgQDJAJvePrlzsCmJN4qW73b1aW7sUPpqJz8k +lm5Nrci5hQoTx52QKYYJw+/6hEM+z+K0j3cfMe4Q/jtRcBaCaIWBTmwK+x176NZy +4j+FsdQsIiBJDk5igGDLnuEPONJa96MSpbIgIUqgZvJs9W/j+DTwUakmiBtmzQdC +wHKREfTt6wKBgEBvxdpbkVyxszmChKkiv2X4XwjZUZdq27ZSj9VaKMbOQ1sJXA+W +ROxuipJDzlMZkCFBlj4s0RoOFFgZzDI+QGjcjrHZxb+O97Q4poP7AB0cAPUA9Psm +HYHq3unB7/SiMa1yVT1edVPdTrIodeWJtqXn+jpnAjrh0zb4oE16vS7hAoGAQCGP +mbNNnFnChuNPtqSkwdxn5cJYg3IONXBBtUsTVg3aj0ELRqnY+FipwrZcdjgBzzZO +/YcCvC1BY9RteiI7JmyNEFvapmQ9t930AoYgegxRXL3RyJ/JQm5oxGCOzTNhtltj +n9i/ZLoz8wvELWpOCbckTwTyKTSVcnjQlPSzvw0CgYAQB4hoFDmyUvS1XLN92q+N +tkJz8Dx5wpi094+tUiQj6Mpde0EuE5DdIdTEi3aixuazfqs5Fhe2ugoHk/l4bf44 +GJVyf61VD/ynOAmqhkp+wxILucu8oRLgHOKKjO9VFZ1Q+UIsMdYY/YD9oxRuFuOk +wZYLkEEnMm3Rvn658+iG8A== +-----END PRIVATE KEY-----";s:9:"serial_no";s:0:"";s:12:"certificates";s:0:"";s:11:"expire_time";s:1:"0";}s:9:"applet_id";i:0;s:11:"update_time";i:0;}} \ No newline at end of file diff --git a/runtime/cache/b4/1fbff599add95281dd146591f4da6f.php b/runtime/cache/b4/1fbff599add95281dd146591f4da6f.php index 5811081..5fb11b1 100644 --- a/runtime/cache/b4/1fbff599add95281dd146591f4da6f.php +++ b/runtime/cache/b4/1fbff599add95281dd146591f4da6f.php @@ -1,4 +1,78 @@ -a:0:{} \ No newline at end of file +a:1:{s:5:"wxpay";a:5:{s:3:"key";s:5:"wxpay";s:8:"describe";s:12:"微信支付";s:6:"values";a:10:{s:6:"app_id";s:18:"wx3668302906e3894f";s:6:"mch_id";s:10:"1658128914";s:7:"api_key";s:32:"GS4fwElUx6Ys9KbFMvFlmok1zkL3UMno";s:13:"api_serial_no";s:40:"51B38FC8749949FFEC70E7CDB6D8EC7057D7B250";s:8:"cert_pem";s:1504:"-----BEGIN CERTIFICATE----- +MIIEKzCCAxOgAwIBAgIUUbOPyHSZSf/scOfNttjscFfXslAwDQYJKoZIhvcNAQEL +BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT +FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg +Q0EwHhcNMjMxMTA4MTAzMjQwWhcNMjgxMTA2MTAzMjQwWjCBhDETMBEGA1UEAwwK +MTY1ODEyODkxNDEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMTAwLgYDVQQL +DCfpu4TovpvkuIDvvIjljqbpl6jvvInpo5/lk4HmnInpmZDlhazlj7gxCzAJBgNV +BAYMAkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAKUgYnkTu2HZT/eQoYNgWLYR/L5T1HRVO4jwBhrXaWqdqBOH6Jx+ +8VNhWAwg9C6ULjYfqBRlxoyAyH/0xJeFvmbL2mohpgflRsXjSqdaBgP449M3yr2T +D0lFlRfDRHDVCOkfzUEmpWFwytBZIjI+1t5/s5Wzz4tysHTOtmBBXhcfoLwy/gdQ +3nv1OAlH9nf9SAo9t/iZVC47Tz3gdu2WyNHepnaExUrC8cAypL9bXtCkOVHwO+Km +7ox5sR9lGKsQ6ArANHYmpwWXxy9iOm3TzNINnMvuJ26k4qOw69qsn+bAEBW0pe82 +14uQK1mdbFZeBl6dSqxtGg2AHUMkJlE56mECAwEAAaOBuTCBtjAJBgNVHRMEAjAA +MAsGA1UdDwQEAwID+DCBmwYDVR0fBIGTMIGQMIGNoIGKoIGHhoGEaHR0cDovL2V2 +Y2EuaXRydXMuY29tLmNuL3B1YmxpYy9pdHJ1c2NybD9DQT0xQkQ0MjIwRTUwREJD +MDRCMDZBRDM5NzU0OTg0NkMwMUMzRThFQkQyJnNnPUhBQ0M0NzFCNjU0MjJFMTJC +MjdBOUQzM0E4N0FEMUNERjU5MjZFMTQwMzcxMA0GCSqGSIb3DQEBCwUAA4IBAQCT +ovV7SSKsIAmiVmf0CqmRxucNIHQDPcUuBTrHFIaQYIIOwiJd2tfzzvF8CF3EAKpD +IkaZflQaGtYQQ81atJ8TNGzeTseS0mmjucea808bvHOFmxrMmY1D/l2NjklOEpVd +Rhs5HMtOAc4rq6cXbSK/a/sP/Lyc1vu39/bkCDITWtH8sVAxPgZpFHPR1PXxhKwJ +iMg70BWmzIBqIWSfB9NC0kbKOk9TjJNiZk8N+IoQaWiZY/n4X0rLNEKLernlvxBu +O+C3u/L9W1WAZM+GXsNNnPmGSF//GHPYEGWn0nKwTm9EvHERR/QGPDhMXg4h358I +j8bCl9IjOKZtzE1+ztVu +-----END CERTIFICATE-----";s:7:"key_pem";s:1703:"-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQClIGJ5E7th2U/3 +kKGDYFi2Efy+U9R0VTuI8AYa12lqnagTh+icfvFTYVgMIPQulC42H6gUZcaMgMh/ +9MSXhb5my9pqIaYH5UbF40qnWgYD+OPTN8q9kw9JRZUXw0Rw1QjpH81BJqVhcMrQ +WSIyPtbef7OVs8+LcrB0zrZgQV4XH6C8Mv4HUN579TgJR/Z3/UgKPbf4mVQuO089 +4HbtlsjR3qZ2hMVKwvHAMqS/W17QpDlR8Dvipu6MebEfZRirEOgKwDR2JqcFl8cv +Yjpt08zSDZzL7idupOKjsOvarJ/mwBAVtKXvNteLkCtZnWxWXgZenUqsbRoNgB1D +JCZROephAgMBAAECggEAOVfoupFOpmlYKunwHPaNeBUBB3uHMSsUNLbd995Mvnin +kLjG3+n5lnIcqIGdKrvM3IDb1tGNROfIOR9gUhphB8PNQsQSq3VEwZ3wI/PQWPrK +62PZpUH3sgNXBlyKXQCuSn7/wZtRHWiVFguOI5LM/ZGtZNR/w7Z9buMGVKD+stp7 +Gc4C15Vss7FVh00BLOoiyncUwkdiIGMMOfBqgCHiFrphSPIdGjzb1WqMjU/Np7N0 +dSwpg0m583u8/mBovfZ+NHe1FqtXtltzl4pYohHu9qgaPtuKdFo8z6Dh+8Y5QLip +31TzvZFpFn5ZJNBq3WQYdARkq+ZMCue6IUznA2NTjQKBgQDSTtFqs6fHvUvSLULZ +8w3HMAAD+3EEPQf4bjrZKpvbKyuRMdzTJzjyLFqURpYELiQ+PK3KmF3rl1X0wdby +383pHXhUjq6GfFGiYDaf8V2HMSKwrLKj8M/CGH0Z6rScE0FFM6RoSHLfZWmoLJI7 +JoEd99ekORKWLxiXGWMClq0Z4wKBgQDJAJvePrlzsCmJN4qW73b1aW7sUPpqJz8k +lm5Nrci5hQoTx52QKYYJw+/6hEM+z+K0j3cfMe4Q/jtRcBaCaIWBTmwK+x176NZy +4j+FsdQsIiBJDk5igGDLnuEPONJa96MSpbIgIUqgZvJs9W/j+DTwUakmiBtmzQdC +wHKREfTt6wKBgEBvxdpbkVyxszmChKkiv2X4XwjZUZdq27ZSj9VaKMbOQ1sJXA+W +ROxuipJDzlMZkCFBlj4s0RoOFFgZzDI+QGjcjrHZxb+O97Q4poP7AB0cAPUA9Psm +HYHq3unB7/SiMa1yVT1edVPdTrIodeWJtqXn+jpnAjrh0zb4oE16vS7hAoGAQCGP +mbNNnFnChuNPtqSkwdxn5cJYg3IONXBBtUsTVg3aj0ELRqnY+FipwrZcdjgBzzZO +/YcCvC1BY9RteiI7JmyNEFvapmQ9t930AoYgegxRXL3RyJ/JQm5oxGCOzTNhtltj +n9i/ZLoz8wvELWpOCbckTwTyKTSVcnjQlPSzvw0CgYAQB4hoFDmyUvS1XLN92q+N +tkJz8Dx5wpi094+tUiQj6Mpde0EuE5DdIdTEi3aixuazfqs5Fhe2ugoHk/l4bf44 +GJVyf61VD/ynOAmqhkp+wxILucu8oRLgHOKKjO9VFZ1Q+UIsMdYY/YD9oxRuFuOk +wZYLkEEnMm3Rvn658+iG8A== +-----END PRIVATE KEY-----";s:9:"serial_no";s:40:"2A61BFFACF420E57F1D73A069F2EA1C30961207A";s:12:"certificates";s:1475:"-----BEGIN CERTIFICATE----- +MIIEFDCCAvygAwIBAgIUKmG/+s9CDlfx1zoGny6hwwlhIHowDQYJKoZIhvcNAQEL +BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT +FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg +Q0EwHhcNMjMxMTA4MTAzMjM5WhcNMjgxMTA2MTAzMjM5WjBuMRgwFgYDVQQDDA9U +ZW5wYXkuY29tIHNpZ24xEzARBgNVBAoMClRlbnBheS5jb20xHTAbBgNVBAsMFFRl +bnBheS5jb20gQ0EgQ2VudGVyMQswCQYDVQQGDAJDTjERMA8GA1UEBwwIU2hlblpo +ZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDoIoi8kZC6F+pMZRYg +n1NN1YsFtb6eEaf+kZtqjlj4Pe9DLAxegnsGMv/AAZyOK2i2Q1NCr6omH8YjKjFw +rqRD/0mR3+cl0RfSQxTwF02phycmYF8s52RhYimYtD1/eISjBFN9GiEgci1P8uzy +f62oVmSjJif5X4Elc/exoOWiCerYFF+5oAANoS59kkrLwHfNrFnKm8ZvkOjsEn1N +0/GqjMXMvBMrOhCDD6jXtJRwixwIU7DXRhSKRJJnQS/1xQTA6VGDZTQzsQCm5tPW +MSItnsOGocNBJU/ie8B3RKlrqxEhra882k59Z9k4b3fXsU5ap8JHRBhi39XnwME1 +sJW3AgMBAAGjgbkwgbYwCQYDVR0TBAIwADALBgNVHQ8EBAMCA/gwgZsGA1UdHwSB +kzCBkDCBjaCBiqCBh4aBhGh0dHA6Ly9ldmNhLml0cnVzLmNvbS5jbi9wdWJsaWMv +aXRydXNjcmw/Q0E9MUJENDIyMEU1MERCQzA0QjA2QUQzOTc1NDk4NDZDMDFDM0U4 +RUJEMiZzZz1IQUNDNDcxQjY1NDIyRTEyQjI3QTlEMzNBODdBRDFDREY1OTI2RTE0 +MDM3MTANBgkqhkiG9w0BAQsFAAOCAQEAK3O+Tjsmljv25DAsenDxq1DZLUkf0Ehy ++Y4pF9aUuf1hCZcoXgqlNdFqQvE5v6yYVcK8hpv04bkX/2ZSKvWvrmIWEn9Lb5Yu +rAStXkMjBbNxpeK5PUrHo3n5LXEGuB0bamSD+i8PZPmRxA0M+crdJxdsM6DY3vSg +TstrkoKrxgJKonUi3lRt3wUHWzPIfZe6icwGAUBWZ6csP2gFaVZzqIPN56+8Np2X +2JJbdB2KwhEQXjNGx6wbB3qD505U0d7QStkdvy9EdpNlVwl4WKWERRpAsuUw3eiN +cn+D5Xis/c7HL1qD35bCwC3xdJCL17uIiiQ8mOsXchORdCybEOW/dw== +-----END CERTIFICATE-----";s:11:"expire_time";i:1857052800;s:6:"is_sub";i:2;}s:9:"applet_id";i:10001;s:11:"update_time";i:0;}} \ No newline at end of file diff --git a/runtime/cache/eb/300fe116b3568a7e80a6c2812b1a38.php b/runtime/cache/eb/300fe116b3568a7e80a6c2812b1a38.php index 60db4cb..36fe805 100644 --- a/runtime/cache/eb/300fe116b3568a7e80a6c2812b1a38.php +++ b/runtime/cache/eb/300fe116b3568a7e80a6c2812b1a38.php @@ -1,4 +1,4 @@ -1700723253 \ No newline at end of file +1701756591 \ No newline at end of file diff --git a/runtime/index/temp/60a64cd47b22d798d9e777f4f707b2cd.php b/runtime/index/temp/60a64cd47b22d798d9e777f4f707b2cd.php old mode 100644 new mode 100755 diff --git a/runtime/index/temp/b430673016f1b8d1351a534a69510985.php b/runtime/index/temp/b430673016f1b8d1351a534a69510985.php old mode 100644 new mode 100755 diff --git a/runtime/index/temp/b84ab2a86a49fb8098a55f114226b794.php b/runtime/index/temp/b84ab2a86a49fb8098a55f114226b794.php old mode 100644 new mode 100755 diff --git a/runtime/index/temp/c17836b361a86127d4c136cc0bb98e5b.php b/runtime/index/temp/c17836b361a86127d4c136cc0bb98e5b.php old mode 100644 new mode 100755 diff --git a/runtime/session/sess_31e79552bdc9d8bfd196f0495656145c b/runtime/session/sess_31e79552bdc9d8bfd196f0495656145c old mode 100644 new mode 100755 diff --git a/runtime/store/log/202311/21_error.log b/runtime/store/log/202311/21_error.log old mode 100644 new mode 100755 diff --git a/runtime/store/temp/0c8787a77f02614aefcaa341d7335ca2.php b/runtime/store/temp/0c8787a77f02614aefcaa341d7335ca2.php old mode 100644 new mode 100755 diff --git a/runtime/store/temp/10eaa1c936787f73e9ca337f946da334.php b/runtime/store/temp/10eaa1c936787f73e9ca337f946da334.php old mode 100644 new mode 100755 diff --git a/runtime/store/temp/233e0da4a493f66c5eda33831df6debb.php b/runtime/store/temp/233e0da4a493f66c5eda33831df6debb.php old mode 100644 new mode 100755 diff --git a/runtime/store/temp/32927b1e6f229976b3bfb1d748722e68.php b/runtime/store/temp/32927b1e6f229976b3bfb1d748722e68.php old mode 100644 new mode 100755 diff --git a/runtime/store/temp/39bcbcc718db9ee53e923309aaeb92b9.php b/runtime/store/temp/39bcbcc718db9ee53e923309aaeb92b9.php old mode 100644 new mode 100755 diff --git a/runtime/store/temp/409e4e4a205ca0731d204c8584cbd9de.php b/runtime/store/temp/409e4e4a205ca0731d204c8584cbd9de.php old mode 100644 new mode 100755 diff --git a/runtime/store/temp/5ba392d1c9e1e74ec22aae78b0af9092.php b/runtime/store/temp/5ba392d1c9e1e74ec22aae78b0af9092.php old mode 100644 new mode 100755 diff --git a/runtime/store/temp/5eecfbdd931a94d55dafc8f38d15c9ab.php b/runtime/store/temp/5eecfbdd931a94d55dafc8f38d15c9ab.php old mode 100644 new mode 100755 diff --git a/runtime/store/temp/6da5e1cd8c29396c8903d1413abd1e55.php b/runtime/store/temp/6da5e1cd8c29396c8903d1413abd1e55.php old mode 100644 new mode 100755 diff --git a/runtime/store/temp/8e50fcdf9dfa90740feb9f2ee72e8a28.php b/runtime/store/temp/8e50fcdf9dfa90740feb9f2ee72e8a28.php old mode 100644 new mode 100755 diff --git a/runtime/store/temp/988feca942d491d8bbd9f5550fca01cf.php b/runtime/store/temp/988feca942d491d8bbd9f5550fca01cf.php old mode 100644 new mode 100755 diff --git a/runtime/store/temp/acbc153a7dd97ab50d0d10d18165b7bc.php b/runtime/store/temp/acbc153a7dd97ab50d0d10d18165b7bc.php old mode 100644 new mode 100755 diff --git a/runtime/store/temp/ae9927b8c2651c650d93812e8343c6e9.php b/runtime/store/temp/ae9927b8c2651c650d93812e8343c6e9.php old mode 100644 new mode 100755 diff --git a/runtime/store/temp/b309110cddd7c2715b4a38353ff0bb36.php b/runtime/store/temp/b309110cddd7c2715b4a38353ff0bb36.php old mode 100644 new mode 100755 diff --git a/runtime/store/temp/b7355a86bf291b1b080d4bff48d89329.php b/runtime/store/temp/b7355a86bf291b1b080d4bff48d89329.php old mode 100644 new mode 100755 diff --git a/runtime/store/temp/c496503fb310b9f0807d3690b9becaa7.php b/runtime/store/temp/c496503fb310b9f0807d3690b9becaa7.php old mode 100644 new mode 100755 diff --git a/runtime/store/temp/c778416e005d01626bafe09f7eec06d2.php b/runtime/store/temp/c778416e005d01626bafe09f7eec06d2.php old mode 100644 new mode 100755 diff --git a/runtime/store/temp/ca970d4ab4bd1237b6f93eb72cba4306.php b/runtime/store/temp/ca970d4ab4bd1237b6f93eb72cba4306.php old mode 100644 new mode 100755 diff --git a/runtime/store/temp/d6e8468d5e2899d8e0a2a06666a55b1e.php b/runtime/store/temp/d6e8468d5e2899d8e0a2a06666a55b1e.php old mode 100644 new mode 100755 diff --git a/runtime/store/temp/d7390d1714e1d942ac842975d838ebd7.php b/runtime/store/temp/d7390d1714e1d942ac842975d838ebd7.php old mode 100644 new mode 100755 diff --git a/runtime/store/temp/f2a615aee8ef64e5e71245bee61efdcc.php b/runtime/store/temp/f2a615aee8ef64e5e71245bee61efdcc.php old mode 100644 new mode 100755 diff --git a/runtime/store/temp/f2d764740df911d8d11f8c0d29ea314f.php b/runtime/store/temp/f2d764740df911d8d11f8c0d29ea314f.php old mode 100644 new mode 100755 diff --git a/runtime/store/temp/f5a702ff70f080324a5f05ce3e1cc418.php b/runtime/store/temp/f5a702ff70f080324a5f05ce3e1cc418.php old mode 100644 new mode 100755 diff --git a/runtime/user/log/202311/21_error.log b/runtime/user/log/202311/21_error.log old mode 100644 new mode 100755 diff --git a/runtime/user/temp/2d3218e5f4e26e3b8b658949082baf1f.php b/runtime/user/temp/2d3218e5f4e26e3b8b658949082baf1f.php old mode 100644 new mode 100755 diff --git a/runtime/user/temp/7ed378d2e688fc3af98e70c4fc2797ba.php b/runtime/user/temp/7ed378d2e688fc3af98e70c4fc2797ba.php old mode 100644 new mode 100755 diff --git a/runtime/user/temp/7eddf9dad1c49a6d7f1c63d22923ff77.php b/runtime/user/temp/7eddf9dad1c49a6d7f1c63d22923ff77.php old mode 100644 new mode 100755 diff --git a/runtime/user/temp/874e2d7a5be2959b9dc4ef7ce6faa47b.php b/runtime/user/temp/874e2d7a5be2959b9dc4ef7ce6faa47b.php old mode 100644 new mode 100755 diff --git a/runtime/user/temp/93ed04fe573c38439d4a42fb7d368b2f.php b/runtime/user/temp/93ed04fe573c38439d4a42fb7d368b2f.php old mode 100644 new mode 100755 diff --git a/runtime/user/temp/afec97ae6c4cbf0aeb5fe21866576881.php b/runtime/user/temp/afec97ae6c4cbf0aeb5fe21866576881.php old mode 100644 new mode 100755