Thinkphp6在线预约按摩系统H5对接杉德宝支付开发 第三方支付平台

在线预约按摩系统后端使用的是thinkphp6开发的 前端是使用uniapp开发的,在微信浏览器里面一打开就会自动授权登录
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
1、在\app\common.php底部增加一个打印测试使用的

if (!function_exists('ljLog')) {function ljLog($data, $logName='DEBUG', $fname="testlog"){// file_put_contents("testlog", "[".date('Y-m-d H:i:s')."] ".$logName.":" . json_encode($data,JSON_UNESCAPED_UNICODE) . "\r\n", FILE_APPEND);file_put_contents($fname, "[".date('Y-m-d H:i:s')."] ".$logName.":" . var_export($data,true) . "\r\n\r\n", FILE_APPEND);}
}

2、\app\shop\route\route.php 底部增加

//支付
Route::any('IndexSandPay/returnPay', 'IndexSandPay/returnPay');

3、增加 \app\shop\controller\IndexSandPay.php

<?php
namespace app\shop\controller;use app\ApiRest;use think\App;
use think\facade\Db;class IndexSandPay extends ApiRest
{// 支付接口地址// private $apiUrl = 'https://sandcash-uat01.sand.com.cn'; //测试private $apiUrl = 'https://sandcash.mixienet.com.cn';// 退款接口地址// private $refundApiUrl = 'https://smp-uat01.sand.com.cn/gw/api/order/refund'; //测试private $refundApiUrl = 'https://cashier.sandpay.com.cn/gw/api/order/refund';// 代付接口地址// private $dfApiUrl = 'https://dsfp-uat01.sand.com.cn/agent-main/openapi'; //测试private $dfApiUrl = 'https://caspay.sandpay.com.cn/agent-main/openapi';// 商户号// private $mer_no = "68888TS121355"; //测试private $mer_no = "6888803121355";// 公钥文件// private $publicKeyPath = "sandcert/sand-test-test.cer"; //测试private $publicKeyPath = "sandcert/sand.cer";// 私钥文件// private $privateKeyPath = "sandcert/sand_test.pfx"; //测试private $privateKeyPath = "sandcert/sand456.pfx";// 私钥证书密码private $privateKeyPwd = "123456";public function __construct ( App $app = null){}/*** @param $paymentApp* @param $openid* @param $uniacid* @param $body* @param $attach* @param $totalprice* @throws \WxPayException* 支付*/public function createWeixinPay($paymentApp, $openid, $uniacid, $body, $attach, $totalprice, $return_url=''){// 支付扩展域$pay_extra["mer_app_id"]    = $paymentApp['app_id']; //公众号mer_app_id$pay_extra["openid"]        = $openid; //使用微信公众号的mer_app_id获取每个用户的openid// 终端/网站参数$meta_option[]  = ["s"=>"Android","n"=>"","id"=>"","sc"=>""];$meta_option[]  = ["s"=>"IOS","n"=>"","id"=>"","sc"=>""];// ljLog(compact('paymentApp','openid','uniacid','body','attach','totalprice'), 'createWeixinPay');$data = ["version"       => "10","mer_no"        => $this->mer_no,"mer_order_no"  => $attach['out_trade_no'],"create_time"   => date('YmdHis',time()),"order_amt"     => $totalprice, //例:"order_amt"="0.11"    单位: 元"notify_url"    => "https://".$_SERVER['HTTP_HOST']."/index.php/shop/IndexSandPay/returnPay","return_url"    => $return_url,"create_ip"     => str_ireplace(".", "_", $_SERVER['REMOTE_ADDR']),"pay_extra"     => json_encode($pay_extra), //支付扩展域"accsplit_flag" => "NO","sign_type"     => "RSA","store_id"      => "000000","expire_time"   => date('YmdHis',strtotime('+1 hour')),"goods_name"    => $body, //商品名称"product_code"  => "02010002", //产品编码"clear_cycle"   => "3", //3-D1;0-T1;1-T0;2-D0"jump_scheme"   => "vcannft://scpay","meta_option"   => json_encode($meta_option), //终端/网站参数"extend"        => json_encode($attach), //扩展域];// step2: 使用私钥签名报文$priKey = $this->loadPk12Cert($this->privateKeyPath, $this->privateKeyPwd);// $data['sign'] = $this->sign($this->getSignStr($data), $priKey);$data['sign'] = $this->sign($this->getSignStr($data), $priKey);ljLog($data, 'createWeixinPay data');$query = http_build_query($data);$payurl = $this->apiUrl."/pay/h5/wechatpay?".$query;ljLog($payurl, 'URL链接');ljLog($attach['out_trade_no'], '商户订单号');ljLog($data['create_time'], '请求时间');return $payurl;global $_GPC, $_W;$setting['mini_appid']         = $paymentApp['app_id'];$setting['mini_appsecrept']    = $paymentApp['secret'];$setting['mini_mid']           = $paymentApp['payment']['merchant_id'];$setting['mini_apicode']       = $paymentApp['payment']['key'];$setting['apiclient_cert']     = $paymentApp['payment']['cert_path'];$setting['apiclient_cert_key'] = $paymentApp['payment']['key_path'];define('WX_APPID', $setting['mini_appid']);define('WX_MCHID', $setting['mini_mid']);define('WX_KEY', $setting['mini_apicode']);define('WX_APPSECRET', $setting['mini_appsecrept']);define('WX_SSLCERT_PATH', $setting['apiclient_cert']);define('WX_SSLKEY_PATH', $setting['apiclient_cert_key']);define('WX_CURL_PROXY_HOST', '0.0.0.0');define('WX_CURL_PROXY_PORT', 0);define('WX_REPORT_LEVENL', 0);require_once PAY_PATH . "/weixinpay/lib/WxPay.Api.php";require_once PAY_PATH . "/weixinpay/example/WxPay.JsApiPay.php";$tools = new \JsApiPay();$input = new \WxPayUnifiedOrder();$input->SetBody($body);$input->SetAttach(json_encode($attach));$input->SetOut_trade_no($attach['out_trade_no']);$input->SetTotal_fee($totalprice *100);$input->SetTime_start(date("YmdHis"));$param_arr=['i' => $uniacid,'t' => $_GPC['t'],'v' => $_GPC['v'],'is_app' => $paymentApp['is_app'],'n' => APP_MODEL_NAME,];$reply_path=json_encode($param_arr);//需要判断 是否是微擎的版本if(defined('IS_WEIQIN')){$path  = "https://" . $_SERVER['HTTP_HOST'] ."/addons/".APP_MODEL_NAME."/core2/app/Common/wexinPay.php?params=".$reply_path;$paths = "https://" . $_SERVER['HTTP_HOST'] ."/addons/".APP_MODEL_NAME."/core2/app/Common/wexinPay.php?ck=789";$a     = @file_get_contents($paths);if($a != 1){$this->errorMsg('发起支付失败');}}else{$path  = "https://" . $_SERVER['HTTP_HOST'] ."/wexinPay.php?params=".$reply_path;$paths = "https://" . $_SERVER['HTTP_HOST'] ."/wexinPay.php?ck=789";$a     = @file_get_contents($paths);if($a != 1){$this->errorMsg('发起支付失败');}}$this ->lb_logOutput('BaseApiPath:-----'.$path);$input->SetNotify_url($path);if($paymentApp['is_app']!=1){$input->SetTrade_type("JSAPI");$input->SetOpenid($openid);}else{$input->SetTrade_type("APP");}$order = \WxPayApi::unifiedOrder($input);if(!empty($order['return_code'])&&$order['return_code'] == 'FAIL'){$this->errorMsg($order['return_msg']);}$order['mini_mid'] = $setting['mini_mid'];if($paymentApp['is_app']!=1){$jsApiParameters = $tools->GetJsApiParameters($order);$jsApiParameters = json_decode($jsApiParameters, true) ;} else{$jsApiParameters = $this->getOrder($order);}if (!empty($jsApiParameters['return_code']))$this->errorMsg( '发起支付失败');return $jsApiParameters;}/*** 支付回调*/public function returnPay(){ljLog('**',"in--sandNotify");$this->lb_logOutput("in--sandNotify");//支付数据$sign = $_POST['sign'] ?? ''; //签名// $data = stripslashes($_POST['data'] ?? ''); //支付数据$data = $_POST['data'] ?? ''; //支付数据// ljLog($data, 'xmlData in sand:-----');$this->lb_logOutput('xmlData in sand:-----'.$data);// ljLog($sign, 'xmlData in sand sign:-----');$this->lb_logOutput('xmlData in sand sign:-----'.$sign);// $data = '{"head":{"version":"1.0","respTime":"20230810190914","respCode":"000000","respMsg":"成功"},"body":{"mid":"6888803121355","orderCode":"20230810190903024400000244","tradeNo":"20230810190903024400000244","clearDate":"20230810","totalAmount":"000000000001","orderStatus":"1","payTime":"20230810190914","settleAmount":"000000000001","buyerPayAmount":"000000000001","discAmount":"000000000000","txnCompleteTime":"20230810190911","payOrderCode":"20230810001268010000000000057674","accLogonNo":"ogI_86v3QDXmfeUp3jwr0OS3fEts","accNo":"","midFee":"000000000000","extraFee":"000000000000","specialFee":"000000000000","plMidFee":"000000000000","bankserial":"4200001943202308102035947438","externalProductCode":"00002020","cardNo":"","creditFlag":"","bid":"","benefitAmount":"000000000000","remittanceCode":"","extend":"{\\"type\\":\\"Massage\\",\\"out_trade_no\\":\\"20230810190903024400000244\\"}"}}';// $sign = 'h9SfF1aQYRsBiLctZcMa8oX9Ogq/5umE0+Uf0ssT8F3ofQsfbVJP7oXANBbp5ld+uUboOpF714BzmlI7Hywhwv+Xn3Sot8GtAg2QRKXzH8y1NSmrgFBIrcHdpE2LPJ66Xul2/gZGRDNRSDIoz67t5yEPifihj8gRRNW9bK/lEoxnmj7ToIem3G5/Cc1kqZohtdY0zMhvLcE6Y7DOP5scHaHgvSp9wLcP05rchPEE7w8tGOgTk0FlewpQts6Wo1oW5z7ruVRqcKsNIRkSObjFngHVDxI9vUWHnlWeWPSdQymPjlj0Jj830jGWqe/MXAIp/JOJTOsyiy66SFzQL8tWCw==';//验签$pubKey = $this->loadX509Cert($this->publicKeyPath);$verifyResult = $this->verify2($data, $sign, $pubKey);//halt($verifyResult);if($verifyResult){$result = json_decode($data, true);// dump($result);exit;$head   = $result['head'];$body   = $result['body'];dump($head);dump($body);if ($head['respCode'] === '000000' && $head['respMsg'] === '成功') {$extend = isset($body['extend']) && $body['extend'] ? json_decode($body['extend'], true) : [];if(isset($extend['type']) && $extend['type']){$type       = $extend['type'];$orderCode  = $body['orderCode'];dump($type);dump($orderCode);if($type == 'Balance'){$order_model = new \app\massage\model\BalanceOrder();$res         = $order_model->orderResult($orderCode, $body['payOrderCode'] ?? $orderCode);if($res){return "respCode=000000";}else{return "FAIL";}}elseif($type == 'Massage'){$order_model = new \app\massage\model\Order();$res         = $order_model->orderResult($orderCode, $body['payOrderCode'] ?? $orderCode);if($res){return "respCode=000000";}else{return "FAIL";}}elseif($type == 'Mall'){$order_model = new \app\massage\model\CoachOrder();$res         = $order_model->orderResult($orderCode, $body['payOrderCode'] ?? $orderCode);if($res){return "respCode=000000";}else{return "FAIL";}}}}}return "FAIL";}// 退款public function orderRefundApi($paymentApp, $total_fee, $refund_fee, $order_code, $ori_order_code){$head['version'] = "1.0"; //* 版本号$head['method'] = "sandpay.trade.refund"; //* 接口名称$head['productId'] = "00002020"; //* 产品编码  云账户合作电子支付户余额支付:00002046  云账户合作电子宝易付支付:00002047  云账户组合支付:00002048$head['accessType'] = 1; //* 接入类型 1-普通商户接入 2-平台商户接入$head['mid'] = $this->mer_no; //* 商户ID 收款方商户号// $head['plMid'] = ; //平台ID  接入类型为2时必填,在担保支付模式下填写核心商户号  在杉德宝平台终端模式下填写平台商户号$head['channelType'] = "08"; //* 渠道类型  商户的真实应用场景,可选项包括:07-互联网 08-移动端$head['reqTime'] = date('YmdHis',time()); //* 请求时间  格式:yyyyMMddHHmmss$body = ['orderCode' => $order_code, //* 商户订单号 指发起交易的流水号,建议订单号有日期'oriOrderCode' => $ori_order_code, //* 原商户订单号 待退款的商户订单号'refundAmount' => str_pad(intval($refund_fee * 100),12,0,STR_PAD_LEFT), //* 退款金额 例 000000000101 代表 1.01 元// 'refundByfAmt' => , //退宝易付金额 如产品编码为00002047,则必填// 'refundBonus' => , //退奖励金金额// 'refundAccountAmt' => , //退账户金额 如产品编码为00002046,则必填'notifyUrl' => "https://".$_SERVER['HTTP_HOST']."/index.php/shop/IndexSandPay/returnRefund", //* 异步通知地址 杉德支付主动通知商户退款申请结果的http/https路径// 'refundReason' => , //退款原因 描述退款申请原因// 'extend' => , //扩展域 如上送,在异步通知和查询接口中将返回相同的值];$data = [ 'head' => $head, 'body' => $body ];// step2: 生成AESKey并使用公钥加密$AESKey = $this->aes_generate(16); $pubKey = $this->loadX509Cert($this->publicKeyPath);$priKey = $this->loadPk12Cert($this->privateKeyPath, $this->privateKeyPwd);$encryptKey = $this->RSAEncryptByPub($AESKey, $pubKey);// step3: 使用AESKey加密报文$encryptData = $this->AESEncrypt($data, $AESKey);// step4: 使用私钥签名报文$sign = $this->sign($data, $priKey);// step5: 拼接post数据$post['charset'] = "utf-8"; //* 编码方式  默认utf-8$post['data'] = json_encode($data); //* 交易报文  包含head(公共报文)和body(接口请求报文)$post['signType'] = "01"; //* 签名类型 默认01,表示采用SHA1+RSA算法$post['sign'] = $sign; //* 签名 对data进行签名,签名结果采用base64编码// $post['extend'] = ; //扩展域$url = $this->refundApiUrl;// $ret = $this->http_post_json($url, $post);// ljLog($ret, 'orderRefundApi $ret');$ret = 'charset%3DUTF-8%26signType%3D01%26sign%3DV8iTQRbbnhNNGLQGXSZwrktm%2BKqedJWrN%2FFJtnl3vLnIoztPv6UZ0onjoFwTQDvTtrdJm0rhvzirbX%2FZRe%2FAFHp6d%2FG%2F6HG%2BtKZhoyuKKRpjV84crUmunADlEL1M0MCidOntuEDWk0idqSsFT4oisgn61GYVRPLGe9UgvqIbtg9K7FUf2N9GQ9GUc1tEq%2FrYfEcqfcq%2Fzt0FsObHjSftZyUH2c2AjokjHqrYOVgPGghBsgPKg8AUcRLNcNcfn7gSyBlzV5Jcuuibz7rofOZDBOr%2FZnON1Hu%2FVSj7BbQdGk4p1UJGrIpSgrdd1DK2icthN3MXjrKnKR%2Fn2u3pHOtYiA%3D%3D%26data%3D%7B%22head%22%3A%7B%22respTime%22%3A%2220230811152809%22%2C%22respMsg%22%3A%22%E4%BD%99%E9%A2%9D%E4%B8%8D%E8%B6%B3%2F%E8%B6%85%E9%99%90%22%2C%22version%22%3A%221.0%22%2C%22respCode%22%3A%22040004%22%7D%2C%22body%22%3A%7B%7D%7D';$ret = rawurldecode($ret);$ret = str_replace('+', '%2B', $ret);parse_str($ret, $arr);try {// step7: 使用公钥验签报文$this->verify2(($arr['data']), $arr['sign'], $pubKey);return  ['code'      => 200,'verify'    => $arr['data'] ?? '','jjson'     => $data,'vjson'     => json_encode($post),'json'      => json_encode($arr),'url'       => 'https://open.sandpay.com.cn/product/detail/43324/43895/',];} catch (\Exception $e) {ljLog(['code'          => 400,'err_code_des'  =>  $e->getMessage(),'url'           => 'https://open.sandpay.com.cn/product/detail/43324/43895/',], 'orderRefundApi err');return ['code'          => 400,'err_code_des'  =>  $e->getMessage(),'url'           => 'https://open.sandpay.com.cn/product/detail/43324/43895/',];echo $e->getMessage();exit;}}/*** 退款回调*/public function returnRefund(){ljLog('**',"in--sandRefundNotify");$this->lb_logOutput("in--sandRefundNotify");//支付数据$sign = $_POST['sign'] ?? ''; //签名// $data = stripslashes($_POST['data'] ?? ''); //支付数据$data = $_POST['data'] ?? ''; //支付数据ljLog($data, 'xmlData in sandRefund:-----');// $this->lb_logOutput('xmlData in sand:-----'.$data);ljLog($sign, 'xmlData in sandRefund sign:-----');// $this->lb_logOutput('xmlData in sand sign:-----'.$sign);exit;// $data = '{"head":{"version":"1.0","respTime":"20230810190914","respCode":"000000","respMsg":"成功"},"body":{"mid":"6888803121355","orderCode":"20230810190903024400000244","tradeNo":"20230810190903024400000244","clearDate":"20230810","totalAmount":"000000000001","orderStatus":"1","payTime":"20230810190914","settleAmount":"000000000001","buyerPayAmount":"000000000001","discAmount":"000000000000","txnCompleteTime":"20230810190911","payOrderCode":"20230810001268010000000000057674","accLogonNo":"ogI_86v3QDXmfeUp3jwr0OS3fEts","accNo":"","midFee":"000000000000","extraFee":"000000000000","specialFee":"000000000000","plMidFee":"000000000000","bankserial":"4200001943202308102035947438","externalProductCode":"00002020","cardNo":"","creditFlag":"","bid":"","benefitAmount":"000000000000","remittanceCode":"","extend":"{\\"type\\":\\"Massage\\",\\"out_trade_no\\":\\"20230810190903024400000244\\"}"}}';// $sign = 'h9SfF1aQYRsBiLctZcMa8oX9Ogq/5umE0+Uf0ssT8F3ofQsfbVJP7oXANBbp5ld+uUboOpF714BzmlI7Hywhwv+Xn3Sot8GtAg2QRKXzH8y1NSmrgFBIrcHdpE2LPJ66Xul2/gZGRDNRSDIoz67t5yEPifihj8gRRNW9bK/lEoxnmj7ToIem3G5/Cc1kqZohtdY0zMhvLcE6Y7DOP5scHaHgvSp9wLcP05rchPEE7w8tGOgTk0FlewpQts6Wo1oW5z7ruVRqcKsNIRkSObjFngHVDxI9vUWHnlWeWPSdQymPjlj0Jj830jGWqe/MXAIp/JOJTOsyiy66SFzQL8tWCw==';//验签$pubKey = $this->loadX509Cert($this->publicKeyPath);$verifyResult = $this->verify2($data, $sign, $pubKey);//halt($verifyResult);if($verifyResult){$result = json_decode($data, true);// dump($result);exit;$head   = $result['head'];$body   = $result['body'];dump($head);dump($body);if ($head['respCode'] === '000000' && $head['respMsg'] === '成功') {$extend = isset($body['extend']) && $body['extend'] ? json_decode($body['extend'], true) : [];if(isset($extend['type']) && $extend['type']){$type       = $extend['type'];$orderCode  = $body['orderCode'];dump($type);dump($orderCode);if($type == 'Balance'){$order_model = new \app\massage\model\BalanceOrder();$res         = $order_model->orderResult($orderCode, $body['payOrderCode'] ?? $orderCode);if($res){return "respCode=000000";}else{return "FAIL";}}elseif($type == 'Massage'){$order_model = new \app\massage\model\Order();$res         = $order_model->orderResult($orderCode, $body['payOrderCode'] ?? $orderCode);if($res){return "respCode=000000";}else{return "FAIL";}}elseif($type == 'Mall'){$order_model = new \app\massage\model\CoachOrder();$res         = $order_model->orderResult($orderCode, $body['payOrderCode'] ?? $orderCode);if($res){return "respCode=000000";}else{return "FAIL";}}}}}return "FAIL";}/*** 实时付款*/public function agentpay($orderCode, $tranAmt, $accNo, $accName){$data = ["version"       => "01","productId"     => "00000004", //付款对私:00000004 付款对公:00000003"tranTime"      => date('YmdHis'), //格式:yyyyMMddHHmmss"orderCode"     => $orderCode, //订单号  AN12..30"tranAmt"       => str_pad(intval($tranAmt * 100),12,0,STR_PAD_LEFT), //金额,精确到分,不足12位前面补0"currencyCode"  => 156,"accAttr"       => 0, //0-对私 1-对公  注:accAttr选择对私时,accType选银行卡"accType"       => 4, //3-公司账户 4-银行卡  注:accAttr选择对公时,accType选公司账户"accNo"         => $accNo, //收款人账户号"accName"       => $accName, //收款人账户名// "provNo"        => , //收款人开户省份编码// "cityNo"        => , //收款人开户城市编码// "bankName"      => , //收款账户开户行名称// "bankType"      => , //收款人账户联行号"remark"        => '提现', //摘要"payMode"       => 1, //付款模式"channelType"   => "07", //渠道类型// "extendParams"  => , //业务扩展参数// "reqReserved"   => , //请求方保留域  如需发送交易结果至收款方,则必填,值为收款方的短信通知内容// "extend"        => , //extend// "phone"         => , //手机号  如需发送交易结果至收款方,则必填];// step2: 生成AESKey并使用公钥加密$AESKey = $this->aes_generate(16); $pubKey = $this->loadX509Cert($this->publicKeyPath);$priKey = $this->loadPk12Cert($this->privateKeyPath, $this->privateKeyPwd);$encryptKey = $this->RSAEncryptByPub($AESKey, $pubKey);// step3: 使用AESKey加密报文$encryptData = $this->AESEncrypt($data, $AESKey);// step4: 使用私钥签名报文$sign = $this->sign($data, $priKey);// step5: 拼接post数据// $post['transCode'] = 'RTPM'; //交易码  RTPM-实时代付  RPRN-实时代付结果通知$post['accessType'] = 0; //接入类型 0-商户接入,默认   1-平台接入$post['merId'] = $this->mer_no; //合作商户ID  杉德系统分配,唯一标识$post['plId'] = ''; //平台商户ID  平台接入必填,商户接入为空$post['encryptKey'] = $encryptKey;$post['encryptData'] = $encryptData;$post['sign'] = $sign;$url = $this->dfApiUrl.'/agentpay';$ret = $this->http_post_json($url, $post);parse_str($ret, $arr);try {// step7: 使用私钥解密AESKey$decryptAESKey = $this->RSADecryptByPri($arr['encryptKey'], $priKey);// step8: 使用解密后的AESKey解密报文$decryptPlainText = $this->AESDecrypt($arr['encryptData'], $decryptAESKey);// step9: 使用公钥验签报文$this->verify2($decryptPlainText, $arr['sign'], $pubKey);return  ['code'      => 200,'verify'    => $decryptPlainText,'jjson'     => json_encode($data),'vjson'     => json_encode($post),'json'      => json_encode($arr),'url'       => 'https://open.sandpay.com.cn/product/detail/43324/43895/',];} catch (\Exception $e) {return ['code'          => 400,'err_code_des'  =>  $e->getMessage(),'url'           => 'https://open.sandpay.com.cn/product/detail/43324/43895/',];echo $e->getMessage();exit;}}/*** @param $data* @param int $flag* @return void|null* 打印数据*/public function lb_logOutput($data,$flag=0) {if($flag==0){return ;}//数据类型检测if (is_array($data)) {$data = json_encode($data);}$filename = "./".date("Y-m-d").".log";$str = date("Y-m-d H:i:s")."   $data"."\r\n";file_put_contents($filename, $str, FILE_APPEND|LOCK_EX);return null;}//验证private function verify($plainText, $sign){$resource = openssl_pkey_get_public($this->publicKey());$result   = openssl_verify($plainText, base64_decode($sign), $resource);openssl_free_key($resource);//var_dump('校验结果===========');//var_dump($result);//0是失败,  1是成功的return $result;}//公共keyprivate function publicKey(){try {$file = file_get_contents('sandcert/sand.cer');if (!$file) {throw new \Exception('getPublicKey::file_get_contents ERROR');}$cert   = chunk_split(base64_encode($file), 64, "\n");$cert   = "-----BEGIN CERTIFICATE-----\n" . $cert . "-----END CERTIFICATE-----\n";$res    = openssl_pkey_get_public($cert);$detail = openssl_pkey_get_details($res);openssl_free_key($res);if (!$detail) {throw new \Exception('getPublicKey::openssl_pkey_get_details ERROR');}return $detail['key'];} catch (\Exception $e) {throw $e;}}//获取签名字符串private function getSignStr($data){//按照键名进行升序排序ksort($data,SORT_NATURAL);$signStr = "";foreach ($data as $key => $value) {if(in_array($key, ['version','mer_no','mer_order_no','create_time','order_amt','notify_url','return_url','create_ip','pay_extra','accsplit_flag','sign_type','store_id','extend'])){if($value != ""){if($signStr) $signStr .= "&";$signStr .= "{$key}={$value}";}}}return $signStr;}// ***** 代付 *******/*** 发送请求* @param $url* @param $param* @return bool|mixed* @throws Exception*/private function http_post_json($url, $param){if (empty($url) || empty($param)) {return false;}$param = http_build_query($param);ljLog($param, $url);try {$ch = curl_init();//初始化curlcurl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch, CURLOPT_POST, 1);curl_setopt($ch, CURLOPT_POSTFIELDS, $param);curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);//正式环境时解开注释curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);$data = curl_exec($ch);//运行curl$error = curl_error($ch);$header = curl_getinfo($ch, CURLINFO_HEADER_OUT); curl_close($ch);ljLog($url,'请求URL');ljLog($param,'请求参数');ljLog($data,'请求响应');ljLog($header,'请求响应 header');if (!$data) {throw new \Exception('请求出错');}return $data;} catch (\Exception $e) {throw $e;}}/*** 生成AESKey* @param $size* @return string*/private function aes_generate($size){$str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';$arr = array();for ($i = 0; $i < $size; $i++) {$arr[] = $str[mt_rand(0, 61)];}return implode('', $arr);}/*** 获取公钥* @param $path* @return mixed* @throws Exception*/private function loadX509Cert($path){try {$file = file_get_contents($path);if (!$file) {throw new \Exception('loadx509Cert::file_get_contents ERROR');}$cert = chunk_split(base64_encode($file), 64, "\n");$cert = "-----BEGIN CERTIFICATE-----\n" . $cert . "-----END CERTIFICATE-----\n";$res = openssl_pkey_get_public($cert);$detail = openssl_pkey_get_details($res);openssl_free_key($res);if (!$detail) {throw new \Exception('loadX509Cert::openssl_pkey_get_details ERROR');}return $detail['key'];} catch (\Exception $e) {throw $e;}}/*** 获取私钥* @param $path* @param $pwd* @return mixed* @throws Exception*/private function loadPk12Cert($path, $pwd){try {$file = file_get_contents($path);if (!$file) {throw new \Exception('loadPk12Cert::file_get_contents');}if (!openssl_pkcs12_read($file, $cert, $pwd)) {throw new \Exception('loadPk12Cert::openssl_pkcs12_read ERROR');}return $cert['pkey'];} catch (\Exception $e) {throw $e;}}/*** 私钥签名* @param $plainText* @param $path* @return string* @throws Exception*/private function sign($plainText, $path){if(is_array($plainText)) $plainText = json_encode($plainText);ljLog($plainText, '签名字符串');try {$resource = openssl_pkey_get_private($path);$result = openssl_sign($plainText, $sign, $resource);openssl_free_key($resource);if (!$result) {throw new \Exception('签名出错' . $plainText);}return base64_encode($sign);} catch (\Exception $e) {throw $e;}}/*** 公钥加密AESKey* @param $plainText* @param $puk* @return string* @throws Exception*/private function RSAEncryptByPub($plainText, $puk){if (!openssl_public_encrypt($plainText, $cipherText, $puk, OPENSSL_PKCS1_PADDING)) {throw new \Exception('AESKey 加密错误');}return base64_encode($cipherText);}/*** 私钥解密AESKey* @param $cipherText* @param $prk* @return string* @throws Exception*/private function RSADecryptByPri($cipherText, $prk){if (!openssl_private_decrypt(base64_decode($cipherText), $plainText, $prk, OPENSSL_PKCS1_PADDING)) {throw new \Exception('AESKey 解密错误');}return (string)$plainText;}/*** AES加密* @param $plainText* @param $key* @return string* @throws \Exception*/private function AESEncrypt($plainText, $key){$plainText = json_encode($plainText);$result = openssl_encrypt($plainText, 'AES-128-ECB', $key, 1);if (!$result) {throw new \Exception('报文加密错误');}return base64_encode($result);}/*** AES解密* @param $cipherText* @param $key* @return string* @throws \Exception*/private function AESDecrypt($cipherText, $key){$result = openssl_decrypt(base64_decode($cipherText), 'AES-128-ECB', $key, 1);if (!$result) {throw new \Exception('报文解密错误', 2003);}return $result;}/*** 公钥验签* @param $plainText* @param $sign* @param $path* @return int* @throws Exception*/private function verify2($plainText, $sign, $path){ljLog($plainText, 'orderRefundApi verify2');$resource = openssl_pkey_get_public($path);$result = openssl_verify($plainText, base64_decode($sign), $resource);openssl_free_key($resource);if (!$result) {throw new \Exception('签名验证未通过,plainText:' . $plainText . '。sign:' . $sign, '02002');}return $result;}
}

4、\app\massage\controller\IndexOrder.php 下单

  * @author chenniang* @DataTime: 2021-03-22 09:53* @功能说明:下单*/public function payOrder(){$input = $this->_input;$address_order_model = new OrderAddress();$address_model       = new Address();$coupon_record_model = new CouponRecord();$coach_model         = new Coach();$cap_dis[] = ['user_id','=',$this->getUserId()];//查看是否是团长$my_cap_id = $coach_model->where($cap_dis)->value('id');$cap_info  = $coach_model->dataInfo(['id'=>$input['coach_id']]);$order_id = !empty($input['order_id'])?$input['order_id']:0;if($input['coach_id']==$my_cap_id){//$this->errorMsg('技师不能给自己下单');}if($cap_info['is_work']==0){$this->errorMsg('该技师未上班');}if($cap_info['status']!=2){$this->errorMsg('该技师已下架');}$coupon_id  = !empty($input['coupon_id'])?$input['coupon_id']:0;//加钟订单if(!empty($order_id)){$p_order = $this->model->dataInfo(['id'=>$order_id]);$can_add = $this->model->orderCanAdd($p_order);if($can_add==0){$this->errorMsg('该订单不能加钟');}$address = $p_order['address_info'];$address['id'] = $address['address_id'];//加钟订单不计算车费$input['car_type'] = 0;//加钟$input['start_time'] = $this->model->addOrderTime($order_id)+1;}else{$address = $address_model->dataInfo(['id'=>$input['address_id']]);}if(empty($address)){$this->errorMsg('请添加地址');}$order_info = $this->model->payOrderInfo($this->getUserId(),$input['coach_id'],$address['lat'],$address['lng'],$input['car_type'],$coupon_id,$order_id);$config_model = new Config();$config = $config_model->dataInfo(['uniacid'=>$this->_uniacid]);Db::startTrans();$key = $order_info['coach_id'].$input['start_time'].'order_key';incCache($key,1,$this->_uniacid);$key_value = getCache($key,$this->_uniacid);if($key_value!=1){decCache($key,1,$this->_uniacid);$this->errorMsg('下单人数过多,请重试');}//检查技师时间(返回结束时间)$check = $this->model->checkTime($order_info,$input['start_time'],$order_id);if(!empty($check['code'])){decCache($key,1,$this->_uniacid);$this->errorMsg($check['msg']);}//默认微信$pay_model = isset($input['pay_model'])?$input['pay_model']:1;$order_insert = ['uniacid'    => $this->_uniacid,'over_time'  => time()+$config['over_time']*60,'order_code' => orderCode(),'user_id'    => $this->getUserId(),'pay_price'  => $order_info['pay_price'],'balance'    => $pay_model==2?$order_info['pay_price']:0,'init_service_price'=> $order_info['init_goods_price'],'service_price'=> $order_info['goods_price'],'true_service_price' => $order_info['goods_price'],'discount'    => $order_info['discount'],'car_price'   => $order_info['car_price'],'true_car_price' => $order_info['car_price'],'pay_type'    => 1,'coach_id'    => $order_info['coach_id'],'start_time'  => $input['start_time'],'end_time'    => $check['end_time'],'distance'    => $order_info['distance'],'time_long'   => $check['time_long'],'true_time_long' => $check['time_long'],//备注'text'        => !empty($input['text'])?$input['text']:'','can_tx_time' => $config['can_tx_time'],'car_type'    => $input['car_type'],'channel_id'  => !empty($input['channel_id'])?$input['channel_id']:0,'app_pay'     => $this->is_app,//技师出发地址'trip_start_address' => $cap_info['address'],//订单到达地址'trip_end_address' => $address['address'].' '.$address['address_info'],//加钟fu'add_pid' => $order_id,'is_add'  => !empty($order_id)?1:0,'pay_model' => $pay_model];//下单$res = $this->model->dataAdd($order_insert);if($res!=1){decCache($key,1,$this->_uniacid);Db::rollback();$this->errorMsg('下单失败');}decCache($key,1,$this->_uniacid);$order_id = $this->model->getLastInsID();//使用优惠券if(!empty($coupon_id)){$coupon_id = $coupon_record_model->couponUse($coupon_id,$order_id);$this->model->dataUpdate(['id'=>$order_id],['coupon_id'=>$coupon_id]);}//添加下单地址$res = $address_order_model->orderAddressAdd($address['id'],$order_id);if(!empty($res['code'])){Db::rollback();$this->errorMsg($res['msg']);}if(empty($order_info['order_goods'])){Db::rollback();$this->errorMsg('请选择服务项目,请刷新重试');}//添加到子订单$res = $this->order_goods_model->orderGoodsAdd($order_info['order_goods'],$order_id,$input['coach_id'],$this->getUserId());if(!empty($res['code'])){Db::rollback();$this->errorMsg($res['msg']);}$order_insert_data = $this->model->dataInfo(['id'=>$order_id]);//处理各类佣金情况$order_update = $this->model->getCashData($order_insert_data);if(!empty($order_update['code'])&&$order_update['code']==300){$this->errorMsg('请添加技师等级');}$res = $this->model->dataUpdate(['id'=>$order_id],$order_update['order_data']);Db::commit();//如果是0元if($order_insert['pay_price']<=0){$this->model->orderResult($order_insert['order_code'],$order_insert['order_code']);return $this->success(true);}//余额支付if($pay_model==2){$user_model = new User();$user_balance= $user_model->where(['id'=>$this->getUserId()])->value('balance');if($user_balance<$order_insert['pay_price']){$this->errorMsg('余额不足');}$this->model->orderResult($order_insert['order_code'],$order_insert['order_code']);return $this->success(true);}elseif ($pay_model==3){$pay_model = new PayModel($this->payConfig());$jsApiParameters = $pay_model->aliPay($order_insert['order_code'],$order_insert['pay_price'],'按摩订单');$arr['pay_list']= $jsApiParameters;$arr['order_code']= $order_insert['order_code'];
//增加的杉德宝微信支付}elseif ($pay_model==10){//微信支付(衫德)$pay_controller = new \app\shop\controller\IndexSandPay($this->app);//支付$jsApiParameters= $pay_controller->createWeixinPay($this->payConfig(),$this->getUserInfo()['openid'],$this->_uniacid,"anmo",['type' => 'Massage' , 'out_trade_no' => $order_insert['order_code']],$order_insert['pay_price'], $return_url = $input['return_url'] ?? '');$arr['pay_list']= $jsApiParameters;//增加的杉德宝微信支付}else{//微信支付$pay_controller = new \app\shop\controller\IndexWxPay($this->app);//支付$jsApiParameters= $pay_controller->createWeixinPay($this->payConfig(),$this->getUserInfo()['openid'],$this->_uniacid,"anmo",['type' => 'Massage' , 'out_trade_no' => $order_insert['order_code']],$order_insert['pay_price']);$arr['pay_list']= $jsApiParameters;}return $this->success($arr);}

5、重新支付

/*** @author chenniang* @DataTime: 2021-03-25 15:59* @功能说明:重新支付*/public function rePayOrder(){$input = $this->_input;$order_insert = $this->model->dataInfo(['id'=>$input['id']]);if($order_insert['pay_type']!=1){$this->errorMsg('订单状态错误');}if($order_insert['app_pay']==1&&$this->is_app!=1){$this->errorMsg('请到APP完成支付');}if($order_insert['app_pay']==0&&$this->is_app!=0){$this->errorMsg('请到小程序完成支付');}if($order_insert['app_pay']==2&&$this->is_app!=2) {$this->errorMsg('请到公众号完成支付');}if($order_insert['pay_model']==2){$user_model = new User();$user_balance= $user_model->where(['id'=>$this->getUserId()])->value('balance');if($user_balance<$order_insert['pay_price']){$this->errorMsg('余额不足');}$this->model->orderResult($order_insert['order_code'],$order_insert['order_code']);return $this->success(true);}elseif ($order_insert['pay_model']==3){$pay_model = new PayModel($this->payConfig());$jsApiParameters = $pay_model->aliPay($order_insert['order_code'],$order_insert['pay_price'],'按摩订单');$arr['pay_list']= $jsApiParameters;$arr['order_code']= $order_insert['order_code'];//增加的杉德宝微信支付}elseif ($order_insert['pay_model']==10){$new_order_code = orderCode();$this->model->dataUpdate(['id'=>$order_insert['id']],['order_code'=>$new_order_code]);//杉德宝微信支付$pay_controller = new \app\shop\controller\IndexSandPay($this->app);//支付$jsApiParameters= $pay_controller->createWeixinPay($this->payConfig(),$this->getUserInfo()['openid'],$this->_uniacid,"anmo",['type' => 'Massage' , 'out_trade_no' => $new_order_code],$order_insert['pay_price'], $return_url = $input['return_url'] ?? '');$arr['pay_list']= $jsApiParameters;
//增加的杉德宝微信支付}else{//微信支付$pay_controller = new \app\shop\controller\IndexWxPay($this->app);//支付$jsApiParameters= $pay_controller->createWeixinPay($this->payConfig(),$this->getUserInfo()['openid'],$this->_uniacid,"anmo",['type' => 'Massage' , 'out_trade_no' => $order_insert['order_code']],$order_insert['pay_price']);$arr['pay_list'] = $jsApiParameters;}return $this->success($arr);}

6、\app\massage\model\Order.php

   /*** @author chenniang* @DataTime: 2021-03-15 14:37* @功能说明:后台列表*/public function adminDataList($dis,$page=10){$data = $this->alias('a')->join('massage_service_coach_list b','a.coach_id = b.id')->join('massage_service_order_goods_list c','a.id = c.order_id')->join('massage_service_order_address d','a.id = d.order_id')->join('massage_channel_list e','a.channel_id = e.id','left')->join('massage_channel_cate f','f.id = e.cate_id','left')->where($dis)->field('a.*,b.coach_name,d.mobile,d.user_name,e.user_name as channel_name,f.title as channel')->group('a.id')->order('a.id desc')->paginate($page)->toArray();if(!empty($data['data'])){$user_model = new User();$refund_model = new RefundOrder();foreach ($data['data'] as &$v){$v['nickName'] = $user_model->where(['id'=>$v['user_id']])->value('nickName');$v['distance'] = distance_text($v['distance']);$v['refund_price'] = $refund_model->where(['order_id'=>$v['id'],'status'=>2])->sum('refund_price');//加钟订单if($v['is_add']==0){$v['add_order_id'] = $this->where(['add_pid'=>$v['id']])->where('pay_type','>',1)->field('id,order_code')->select()->toArray();}else{$v['add_pid'] = $this->where(['id'=>$v['add_pid']])->field('id,order_code')->find();}//新增的if($v['pay_model'] == 10) $v['pay_model'] = 1;//新增的}}return $data;}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/87977.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Qt做警告处理界面

解决的问题&#xff1a; 做上位机时&#xff0c;多有检测仪器状态&#xff0c;事实显示警告&#xff0c;错误等状态&#xff0c;笔者就是需要显示各种仪器状态&#xff0c;做显示&#xff0c;后做出处理逻辑 Axure设计图&#xff1a; 需求&#xff1a;更新状态&#xff0c;根…

考研算法第40天:众数 【模拟,简单题】

题目 本题收获 又是一道比较简单的模拟题&#xff0c;就不说解题思路了&#xff0c;说一下中间遇到的问题吧&#xff0c;就是说cin输入它是碰到空格就停止输入的&#xff0c;详细的看下面这篇博客对于cin提取输入流遇到空格的问题_while(cin) 空格_就是那个党伟的博客-CSDN博…

KafkaStream:Springboot中集成

1、在kafka-demo中创建配置类 配置kafka参数 package com.heima.kafkademo.config;import lombok.Data; import org.apache.kafka.common.serialization.Serdes; import org.apache.kafka.streams.StreamsConfig; import org.springframework.boot.context.properties.Configu…

C#引用Web Service 类型方法,添加搜索本地服务器Web Service 接口调用方法

首先保证现在网络能调用web service接口&#xff0c;右键项目添加服务引用 ![![在这里插入图片描述](https://img-blog.csdnimg.cn/555ba4fa5e2a418f8f85539a9406bcd6.png) 点击高级 添加web服务 输入搜索的服务器接口&#xff0c;选中你要添加调用的方法即可 添加完成调用方…

【快应用】list组件如何区分滑动的方向?

【关键词】 list组件、滑动方向、scroll 【问题背景】 有cp反馈list这个组件在使用的时候&#xff0c;不知道如何区分它是上滑还是下滑。 【问题分析】 list组件除了通用事件之外&#xff0c;还提供了scroll、scrollbottom、scrolltop、scrollend、scrolltouchup事件&#x…

Zookeeper集群

目录 一、Zookeeper 概述 1&#xff09;Zookeeper 定义 2&#xff09;Zookeeper 工作机制 3&#xff09;Zookeeper 特点 4&#xff09;Zookeeper 数据结构 5&#xff09;Zookeeper 应用场景 6&#xff09;Zookeeper 选举机制 ●第一次启动选举机制 ●非第一次启动选举机…

智能质检技术的核心环节:语音识别和自然语言处理

随着呼叫中心行业的快速发展和客户服务需求的不断提高&#xff0c;越来越多的企业开始采用智能质检技术&#xff0c;以提高呼叫中心的质量和效率。而在智能质检技术中&#xff0c;语音识别和自然语言处理是其核心环节&#xff0c;对于提高质检的准确性和效率具有重要作用。 语音…

python爬虫5:requests库-案例3

python爬虫5&#xff1a;requests库-案例3 前言 ​ python实现网络爬虫非常简单&#xff0c;只需要掌握一定的基础知识和一定的库使用技巧即可。本系列目标旨在梳理相关知识点&#xff0c;方便以后复习。 申明 ​ 本系列所涉及的代码仅用于个人研究与讨论&#xff0c;并不会对网…

centos7 nginx1.18.0离线升级至1.25.1

centos7 nginx1.18.0离线升级至1.25.1 项目背景 系统&#xff1a;centos 7 nginx版本&#xff1a; 1.18.0 最近护网行动查出来 有关Nginx的几个安全漏洞&#xff0c;解决方案只需要更新Nginx版本到最新即可。 Nginx升级过程 1. 下载新版本nginx 下载地址&#xff1a;https:…

SpringBoot复习:(41)配置文件中配置的server开头的属性是怎么配置到Servlet容器中起作用的?

ServletWebServerFactoryAutoConfiguration类&#xff1a; 可以看到其中使用了EnableConfigurationProperties导入了ServerProperties 而ServerProperties通过使用ConfigurationProperties注解导入了配置文件中已server开头的那些配置项。 可以看到ServletWebServerFactory定…

Centos7.6 安装mysql过程全记录

在centos 7.6上 离线安装mysql 的步骤&#xff0c;可参考下文&#xff1a; 一、查看当前MySQL的安装情况并卸载 1. 查看当前MySQL的安装情况 查找之前是否安装了MySQL rpm -qa|grep -i mysql 2.卸载mysql 如果已经安装mysql&#xff0c;则需要先停止MySQL&#xff0c;再删除…

前后端分离------后端创建笔记(03)前后端对接(上)

本文章转载于【SpringBootVue】全网最简单但实用的前后端分离项目实战笔记 - 前端_大菜007的博客-CSDN博客 仅用于学习和讨论&#xff0c;如有侵权请联系 源码&#xff1a;https://gitee.com/green_vegetables/x-admin-project.git 素材&#xff1a;https://pan.baidu.com/s/…

Mybatis动态SQL

此文章为笔记&#xff0c;为阅读其他文章的感受、补充、记录、练习、汇总&#xff0c;非原创&#xff0c;感谢每个知识分享者。 文章目录 一、MyBatis动态 sql 是什么二、MyBatis标签三、MyBatis关联查询 一、MyBatis动态 sql 是什么 动态 SQL 是 MyBatis 的强大特性之一。在 …

JavaWeb 中对 HTTP 协议的学习

HTTP1 Web概述1.1 Web和JavaWeb的概念1.2 JavaWeb技术栈1.2.1 B/S架构1.2.2 静态资源1.2.3 动态资源1.2.4 数据库1.2.5 HTTP协议1.2.6 Web服务器 1.3 Web核心 2 HTTP2.1 简介2.2 请求数据格式2.2.1 格式介绍2.2.2 实例演示 2.3 响应数据格式2.3.1 格式介绍2.3.2 响应状态码2.3.…

Nonebot实战之编写插件1

前言 应粉丝群内粉丝要求&#xff0c;我也决定写一个Nonebot插件编写教程&#xff0c;从0开始教学。有些不对的地方也欢迎大家指正&#xff0c;修改。 开始 准备 合适的代码编辑器一定的python基础懂得提问的方式 代码编辑器 代码编辑器有很多种选择&#xff0c;比如 vsc…

TFRecords详解

内容目录 TFRecords 是什么序列化(Serialization)tf.data 图像序列化&#xff08;Serializing Images)tf.Example函数封装 小结 TFRecords 是什么 TPU拥有八个核心&#xff0c;充当八个独立的工作单元。我们可以通过将数据集分成多个文件或分片&#xff08;shards&#xff09;…

Redis 搭建分片集群

文章目录 0.10.2 散列插槽0.3 集群伸缩0.3.1 需求分析0.3.1 创建新的 Redis 实例0.3.3 添加新节点到 Redis0.3.4 转移插槽 0.4 故障转移0.4.1 自动故障转移0.4.2 生动故障转移 0.5 RedisTemplate访问分片集群 1. 集群架构2. 准备实例和配置3. 启动4. 创建集群5. 测试 0.1 主从…

企业服务器被devos勒索病毒攻击后怎么处理,devos勒索病毒如何攻击的

众所周知&#xff0c;科学技术是第一生产力&#xff0c;科学技术的发展给企业与人们的生活带来了极大变化&#xff0c;但随之而来的网络安全威胁也不断增加。最近&#xff0c;我们收到很多企业的求助&#xff0c;企业的计算机服务器遭到了devos勒索病毒的攻击&#xff0c;导致企…

第17章-Spring AOP经典应用场景

文章目录 一、日志处理二、事务控制三、参数校验四、自定义注解五、AOP 方法失效问题1. ApplicationContext2. AopContext3. 注入自身 六、附录1. 示例代码 AOP 提供了一种面向切面操作的扩展机制&#xff0c;通常这些操作是与业务无关的&#xff0c;在实际应用中&#xff0c;可…

Golang-语言源码级调试器 Delve

前言 Go 目前的调试器有如下几种&#xff1a; GDB 最早期的调试工具&#xff0c;现在用的很少。LLDB macOS 系统推荐的标准调试工具&#xff0c;单 Go 的一些专有特性支持的比较少。Delve 专门为 Go 语言打造的调试工具&#xff0c;使用最为广泛。 本篇简单说明如何使用 Del…