在线预约按摩系统后端使用的是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
<?phpnamespace app\shop\controller;use app\ApiRest;use think\App;use think\facade\Db;class IndexSandPay extends ApiRest{// 支付接口地址// private $apiUrl = 'https://sandcash-'; //测试private $apiUrl = '';// 退款接口地址// private $refundApiUrl = 'https://smp-/gw/api/order/refund'; //测试private $refundApiUrl = '/gw/api/order/refund';// 代付接口地址// private $dfApiUrl = 'https://dsfp-/agent-main/openapi'; //测试private $dfApiUrl = '/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" => "0002", //产品编码"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":"0810190914","respCode":"000000","respMsg":"成功"},"body":{"mid":"6888803121355","orderCode":"0810190903024400000244","tradeNo":"0810190903024400000244","clearDate":"0810","totalAmount":"000000000001","orderStatus":"1","payTime":"0810190914","settleAmount":"000000000001","buyerPayAmount":"000000000001","discAmount":"000000000000","txnCompleteTime":"0810190911","payOrderCode":"0810001268010000000000057674","accLogonNo":"ogI_86v3QDXmfeUp3jwr0OS3fEts","accNo":"","midFee":"000000000000","extraFee":"000000000000","specialFee":"000000000000","plMidFee":"000000000000","bankserial":"420000194308102035947438","externalProductCode":"0000","cardNo":"","creditFlag":"","bid":"","benefitAmount":"000000000000","remittanceCode":"","extend":"{\\"type\\":\\"Massage\\",\\"out_trade_no\\":\\"0810190903024400000244\\"}"}}';// $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'] = "0000"; //* 产品编码 云账户合作电子支付户余额支付: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%220811152809%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' => '/product/detail/43324/43895/',];} catch (\Exception $e) {ljLog(['code'=> 400,'err_code_des' => $e->getMessage(),'url' => '/product/detail/43324/43895/',], 'orderRefundApi err');return ['code'=> 400,'err_code_des' => $e->getMessage(),'url' => '/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":"0810190914","respCode":"000000","respMsg":"成功"},"body":{"mid":"6888803121355","orderCode":"0810190903024400000244","tradeNo":"0810190903024400000244","clearDate":"0810","totalAmount":"000000000001","orderStatus":"1","payTime":"0810190914","settleAmount":"000000000001","buyerPayAmount":"000000000001","discAmount":"000000000000","txnCompleteTime":"0810190911","payOrderCode":"0810001268010000000000057674","accLogonNo":"ogI_86v3QDXmfeUp3jwr0OS3fEts","accNo":"","midFee":"000000000000","extraFee":"000000000000","specialFee":"000000000000","plMidFee":"000000000000","bankserial":"420000194308102035947438","externalProductCode":"0000","cardNo":"","creditFlag":"","bid":"","benefitAmount":"000000000000","remittanceCode":"","extend":"{\\"type\\":\\"Massage\\",\\"out_trade_no\\":\\"0810190903024400000244\\"}"}}';// $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' => '/product/detail/43324/43895/',];} catch (\Exception $e) {return ['code'=> 400,'err_code_des' => $e->getMessage(),'url' => '/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('报文解密错误', );}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: -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: -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: -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;}