在线预约按摩系统后端使用的是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
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;
}
//公共key
private 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();//初始化curl
curl_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;
}