252 lines
12 KiB
PHP
252 lines
12 KiB
PHP
<?php
|
||
/**
|
||
* SaaSMall商城系统 - 团队十年电商经验汇集巨献!
|
||
* =========================================================
|
||
* Copy right 2019-2029 成都SAAS云科技有限公司, 保留所有权利。
|
||
* ----------------------------------------------
|
||
* 官方网址: https://www.gobuysaas.com
|
||
* =========================================================
|
||
*/
|
||
|
||
namespace addon\cypay\model;
|
||
use addon\weapp\model\Config as weAppConfig;
|
||
use app\model\BaseModel;
|
||
use think\exception\ValidateException;
|
||
|
||
class RequestApi extends BaseModel
|
||
{
|
||
|
||
|
||
// 接口请求地址:正式环境=https://pay.chanpay.com/merchant/gateway;测试环境=https://cpay.chanpay.com/merchant/gateway
|
||
private string $apiLink = 'https://pay.chanpay.com/merchant/gateway';// 正式环境
|
||
private string $institutionNumber = '49072480';// 合作机构号
|
||
private string $productCode = '1000';// 营销产品编码,由畅捷支付分配
|
||
// 基础产品编码,由畅捷支付分配
|
||
private array $functionCode = [
|
||
'chanpay.merchanttrade.weixin.appletpay' => '1000140001',// 微信小程序
|
||
// '' => '1000100003',// 付款码-银联-借记
|
||
// '' => '1000100003',// 付款码-银联-贷记
|
||
// '' => '1000100002',// 付款码-支付宝
|
||
// '' => '1000110003',// 扫码-银联-借记
|
||
// '' => '1000110003',// 扫码-银联-贷记
|
||
// '' => '1000340005',// 分账
|
||
// '' => '1000110001',// 扫码-微信
|
||
'chanpay.merchanttrade.appletpay.cashier' => '1000160001',// 微信小程序收银台
|
||
// '' => '1000160002',// 支付宝小程序收银台
|
||
];
|
||
// 畅捷公钥 RSA
|
||
private string $publicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCQedhgpTUxuWDof5uiHWszPP/462Q/ORos8uV11g8nYmchcyE3x8jOXE5ZKRAua5HUDNkLQG/8wu4+tPVicKe3r9DOefZf+zxZgHB/uddA+Sl54h9BzjPB8RscBtDM2DWRZhdnVu4LMRb9Lp9eRYTLbviPazCEm13FqttHT35oAQIDAQAB';
|
||
// 畅捷公钥 RSA2
|
||
private string $publicKeyTwo = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsNU7PbTNvy16IF5sjzMxS3wQo0kvkq3iNmIIbcLnhatlbdeqdTG+P4wnSM+28Eums/izjL2TKdshoPcuvZ18/rGOUprCeeL7VfTtKu/mlS5H+FCXkdG0a0kstvjloqwRcksV2IiAiFttdB85zI4stu4NBMh4oFd5+nO8Jt7JMPI1J/4zd6VGn4bJ6DEcKVfXn+xpZ9fp0LRRREB5AbqJKpSLS7G+cQE1YT9kRHnAvCZcE+WPwwv24lIOiEXcNacz1vuDC4kZf3ahweuHAGlWve00/O9iIzSkB0FazUGLjOf6WcQiugEz1DtL8wKW2OlAwuk8VU3sSuLbDmzLdYG84QIDAQAB';
|
||
// 配置信息
|
||
private $config;
|
||
|
||
|
||
public function __construct($siteId)
|
||
{
|
||
// 配置获取
|
||
$this->config = (new Config())->getConfig($siteId);
|
||
}
|
||
|
||
/**
|
||
* Common: 请求发送
|
||
* Author: wu-hui
|
||
* Time: 2024/07/23 13:32
|
||
* @param string $method
|
||
* @param array $bizContent
|
||
* @param string $apiLink
|
||
* @return array
|
||
*/
|
||
private function requestApi(string $method, array $bizContent, string $apiLink = '')
|
||
{
|
||
try {
|
||
// 判断:如果不存在指定请求地址 使用默认地址
|
||
if (!$apiLink) $apiLink = $this->apiLink;
|
||
// 处理请求内容
|
||
$bizContent = $this->handleBizContent($bizContent);
|
||
// 请求数组
|
||
$data = [
|
||
'method' => $method,// 请求接口
|
||
'acq_sp_id' => $this->institutionNumber,// 合作机构号,由畅捷支付分配
|
||
'product_code' => $this->productCode,// 营销产品编码,由畅捷支付分配
|
||
'function_code' => $this->functionCode[$method],// 基础产品编码,由畅捷支付分配 商户管理-商户维护-商户详情
|
||
'format' => 'JSON',
|
||
'charset' => 'UTF-8',
|
||
'sign_type' => 'RSA2',
|
||
'timestamp' => date("YmdHis"),
|
||
'version' => '1.0',
|
||
'biz_content' => $bizContent
|
||
];
|
||
var_dump($apiLink, $data);
|
||
return 1111;
|
||
$data['sign'] = $this->getSign($data);
|
||
// 发起请求
|
||
$result = curlPost($apiLink, $data);
|
||
// 结果处理
|
||
if ($result['sub_code'] == 'FAIL') {
|
||
throw new ValidateException($result['sub_msg']);
|
||
} else {
|
||
// 返回成功 信息解密
|
||
$content = $result['content'] ?? [];
|
||
if ($content) $content = $this->handleResultContent($content);
|
||
|
||
return $this->success($content);
|
||
}
|
||
} catch (\Exception $e) {
|
||
trace(['msg' => $e->getMessage()], '好收银 - 接口请求错误');
|
||
|
||
return $this->error([], $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Common: 请求数据主要参数加密
|
||
* Author: wu-hui
|
||
* Time: 2024/07/22 14:44
|
||
* @param $bizContent
|
||
* @return string
|
||
*/
|
||
private function handleBizContent($bizContent)
|
||
{
|
||
// 基本参数
|
||
$bizContentJson = json_encode($bizContent);
|
||
$publicKey = "-----BEGIN PUBLIC KEY-----\n" . trim($this->publicKeyTwo) . "\n-----END PUBLIC KEY-----";
|
||
// 获取秘钥详细信息
|
||
if (strlen($bizContentJson) > 255) {
|
||
// 加密每段最大245,解密每段最大256
|
||
$bizContentArray = mb_str_split($bizContentJson, 245, 'UTF-8');
|
||
$useBizContent = '';
|
||
foreach ($bizContentArray as $bizContentString) {
|
||
openssl_public_encrypt($bizContentString, $encryptedChunk, $publicKey);
|
||
$useBizContent .= $encryptedChunk;
|
||
}
|
||
} else {
|
||
openssl_public_encrypt($bizContentJson, $useBizContent, $publicKey);
|
||
}
|
||
|
||
return base64_encode($useBizContent);
|
||
}
|
||
|
||
/**
|
||
* Common: 生成签名
|
||
* Author: wu-hui
|
||
* Time: 2024/07/22 16:04
|
||
* @param $data
|
||
* @return string
|
||
*/
|
||
private function getSign($data)
|
||
{
|
||
// 请求参数转字符串
|
||
$signStr = 'method' . '=' . $data['method'] . '&';
|
||
$signStr .= 'acq_sp_id' . '=' . $this->institutionNumber . '&';
|
||
$signStr .= 'function_code' . '=' . $data['function_code'] . '&';
|
||
$signStr .= 'product_code' . '=' . $data['product_code'] . '&';
|
||
$signStr .= 'biz_content' . '=' . $data['biz_content'];
|
||
$signStr = trim($signStr, '&');
|
||
// 生成签名
|
||
$privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" . $this->config['private_key'] . "\n-----END RSA PRIVATE KEY-----";
|
||
$key = openssl_get_privatekey($privateKey);
|
||
openssl_sign($signStr, $signature, $key, "SHA256");
|
||
return base64_encode($signature);
|
||
}
|
||
|
||
/**
|
||
* Common: 返回数据解密
|
||
* Author: wu-hui
|
||
* Time: 2024/07/23 11:51
|
||
* @param $content
|
||
* @return array|mixed
|
||
*/
|
||
public function handleResultContent($content)
|
||
{
|
||
// 私钥信息
|
||
$privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" . $this->config['private_key'] . "\n-----END RSA PRIVATE KEY-----";
|
||
$privateKey = openssl_get_privatekey($privateKey);
|
||
// 信息解密
|
||
$bizContentArray = str_split(base64_decode($content), 256);
|
||
$content = '';
|
||
foreach ($bizContentArray as $bizContentString) {
|
||
openssl_private_decrypt($bizContentString, $decrypted, $privateKey, OPENSSL_PKCS1_PADDING);
|
||
$content .= $decrypted;
|
||
}
|
||
return is_json($content) ? json_decode($content, true) : [];
|
||
}
|
||
|
||
// 异步通知 签名验证
|
||
public function signValidate($params)
|
||
{
|
||
// 是否开启收银台
|
||
$isUseCashier = $this->config['is_isppay'] ?? 0;
|
||
$data = [
|
||
'function_code' => $params['function_code'],
|
||
'product_code' => $params['product_code'],
|
||
'biz_content' => $params['biz_content'],
|
||
];
|
||
|
||
if ($isUseCashier == 1) $data['method'] = 'chanpay.merchanttrade.appletpay.cashier';
|
||
else $data['method'] = 'chanpay.merchanttrade.weixin.appletpay';
|
||
|
||
|
||
$sign = $this->getSign($data);
|
||
|
||
|
||
// debug([
|
||
// 'sign' => $sign,
|
||
// 'noti' => $params['sign']
|
||
// ]);
|
||
|
||
|
||
return true;//$sign == $params['sign'];
|
||
}
|
||
|
||
|
||
/**
|
||
* Common: 微信小程序支付 - 创建支付
|
||
* Author: wu-hui
|
||
* Time: 2024/07/23 13:31
|
||
* @param $params
|
||
* @return array
|
||
*/
|
||
public function getWeAppPayInfo($params)
|
||
{
|
||
$isUseCashier = $this->config['is_cashier'] ?? 0;
|
||
// 小程序支付 公共请求参数生成
|
||
$outTradeNo = $params['out_trade_no'] ?? '';
|
||
$outTradeNo = $outTradeNo . '_' . rand(1000, 9999);
|
||
$bizContent = [
|
||
'merchant_id' => $this->config['mch_id'],// 商户编号,由畅捷支付分配
|
||
'out_trade_no' => $outTradeNo,// 商户订单号,商户系统的内部订单号。5~32个字符、可包含字母、数字、下划线商户系统需保证不重复
|
||
// 'total_amount' => (int)sprintf("%.0f", $params['pay_money'] * 100),// 订单总金额,单位为分,取值范围[1,10000000000],不允许包含任何文字、符号
|
||
'total_amount' => 10,// 订单总金额,单位为分,取值范围[1,10000000000],不允许包含任何文字、符号
|
||
'body' => $params['pay_body'],// 商品描述,订单的标题信息,鉴于风控等因素,建议该字段严格按照规范传递,可参见【参数规定】
|
||
// 'goods_tag' => '',// 订单优惠标记,代金券或立减优惠功能的参数
|
||
// 'attach' => '',// 订单附加数据,该字段主要用于商户携带订单的自定义数据,在查询API和支付通知中原样返回
|
||
// 'limit_credit_pay' => '',// 是否限制信用卡,限定用户使用时能否使用信用卡,值为1=禁用信用卡;值为0或者不传此参数则不禁用
|
||
'mch_create_ip' => $params['mch_create_ip']??"127.0.0.1",// 终端IP,支持IPV4和IPV6两种格式的IP地址。调用API的机器IP
|
||
// 'device_info' => '',// 终端序列号,收银设备的唯一产品序列号(SN) ,多用于鉴别交易场景、风控合规等因素
|
||
// 'op_shop_id' => '',// 门店编号,由商户自定义,若有门店则必传
|
||
// 'op_user_id' => '',// 收银员,操作员帐号,或者默认为商户号
|
||
// 'need_receipt' => '',// 电子发票【微信】,需要和微信公众平台的发票功能联合,传入Y时,微信支付成功消息和支付详情页将出现开票入口
|
||
// 'time_start' => '',// 订单生成时间,格式为yyyymmddhhmmss,该时间取自商户服务器。备注:订单生成时间与超时时间需要同时传入才会生效。
|
||
// 'time_expire' => '',// 订单超时/时间,格式为yyyymmddhhmmss,该时间取自商户服务器。备注:订单生成时间与超时时间需要同时传入才会生效
|
||
'notify_url' => $params['notify_url'],// 异步通知地址
|
||
];
|
||
// 根据是否开启收银台 进行对应的操作
|
||
if ($isUseCashier == 1) {
|
||
// 启用收银台
|
||
$result = $this->requestApi('chanpay.merchanttrade.appletpay.cashier', $bizContent);
|
||
return $result;
|
||
$result['data']['is_cashier'] = 1;
|
||
} else {
|
||
// 未启用收银台
|
||
$weAppConfig = (new weAppConfig())->getWeappConfig($params['site_id'])['data']['value'];
|
||
// 参数补齐
|
||
$bizContent['sub_openid'] = $params['sub_openid'];// 子用户标识,此参数为微信用户在商户对应sub_appid下的唯一标识
|
||
$bizContent['sub_appid'] = $weAppConfig['appid'] ?? '';// 子用户标识,此参数为微信用户在商户对应sub_appid下的唯一标识
|
||
$result = $this->requestApi('chanpay.merchanttrade.weixin.appletpay', $bizContent);
|
||
$result['data']['is_cashier'] = 0;
|
||
}
|
||
return $result ?? [];
|
||
}
|
||
}
|