文件
xionggeshop/addons/shopro_huifu/library/HuifuConfig.php

205 行
6.4 KiB
PHP

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

<?php
namespace addons\shopro_huifu\library;
use think\Db;
class HuifuConfig
{
protected static $instance;
protected $items = [];
public static function getInstance()
{
if (!self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
public static function reload()
{
self::$instance = new self();
return self::$instance;
}
protected function __construct()
{
try {
$this->items = Db::name('shopro_huifu_config')->column('value', 'name');
} catch (\Exception $e) {
$this->items = [];
}
}
public function all()
{
return $this->items;
}
public function get($name, $default = '')
{
return $this->items[$name] ?? $default;
}
public function getGatewayUrl()
{
$env = $this->get('env', 'test');
$url = $this->get('gateway_url');
if ($url) {
return rtrim($url, '/');
}
return $env === 'prod' ? 'https://api.huifu.com' : 'https://spin-test.cloudpnr.com';
}
public function isProdEnv()
{
return $this->get('env', 'prod') !== 'test';
}
/**
* 供汇付 SDK 使用:仅返回 base64 密钥体(不含 PEM 头尾)。
* SDK 内部会自行包裹 -----BEGIN PRIVATE KEY----- 后再签名。
*/
public function getPrivateKey()
{
return $this->extractKeyBody($this->get('merchant_private_key'));
}
public function getPublicKey()
{
return $this->extractKeyBody($this->get('huifu_public_key'));
}
public function validateKeys()
{
$privateBody = $this->getPrivateKey();
$publicBody = $this->getPublicKey();
if ($privateBody === '') {
throw new \RuntimeException('商户RSA私钥未配置');
}
if ($publicBody === '') {
throw new \RuntimeException('汇付RSA公钥未配置');
}
$privatePem = $this->wrapPem($privateBody, 'PRIVATE KEY');
$privateRes = openssl_pkey_get_private($privatePem);
if ($privateRes === false) {
$privatePem = $this->wrapPem($privateBody, 'RSA PRIVATE KEY');
$privateRes = openssl_pkey_get_private($privatePem);
}
if ($privateRes === false) {
throw new \RuntimeException('商户RSA私钥格式无效,请从汇付控台复制完整私钥后重新保存');
}
$publicPem = $this->wrapPem($publicBody, 'PUBLIC KEY');
$publicRes = openssl_pkey_get_public($publicPem);
if ($publicRes === false) {
throw new \RuntimeException('汇付RSA公钥格式无效,请从汇付控台复制完整公钥后重新保存');
}
$signature = '';
if (!openssl_sign('huifu_key_probe', $signature, $privateRes, OPENSSL_ALGO_SHA256) || $signature === '') {
throw new \RuntimeException('商户RSA私钥无法用于签名,请重新粘贴汇付控台商户私钥');
}
}
public function shouldDelayAcct()
{
$split = Db::name('shopro_split_config')->column('value', 'name');
if (($split['split_enable'] ?? '0') !== '1') {
return false;
}
if (($split['delay_acct_enable'] ?? '0') !== '1') {
return false;
}
if (in_array($split['split_mode'] ?? '', ['huifu', 'both'])) {
return true;
}
return ($split['split_provider'] ?? 'auto') === 'huifu';
}
/**
* 站点公网 HTTPS 根地址(notify 必须稳定可达,不能依赖单次 request()->root())
*/
public function getSiteBaseUrl()
{
$custom = trim((string) $this->get('site_base_url'));
if ($custom !== '') {
return rtrim($custom, '/');
}
try {
$row = Db::name('shopro_config')->where('name', 'shopro')->find();
if ($row && !empty($row['value'])) {
$value = json_decode($row['value'], true);
if (!empty($value['domain'])) {
$domain = rtrim((string) $value['domain'], '/');
if (strpos($domain, 'http') !== 0) {
$domain = 'https://' . ltrim($domain, '/');
}
return $domain;
}
}
} catch (\Exception $e) {
// ignore
}
$root = request()->root(true);
if (strpos($root, 'https://') !== 0) {
if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
$scheme = trim(explode(',', (string) $_SERVER['HTTP_X_FORWARDED_PROTO'])[0]);
if ($scheme === 'https') {
$root = preg_replace('#^https?://#', 'https://', $root);
}
}
if (strpos($root, 'https://') !== 0 && !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') {
$root = preg_replace('#^http://#', 'https://', $root);
}
}
return rtrim($root, '/');
}
public function getNotifyUrl($type = 'pay', $platform = 'wxMiniProgram')
{
if ($type === 'refund') {
$custom = trim((string) $this->get('refund_notify_url'));
if ($custom !== '') {
return rtrim($custom, '/');
}
return $this->getSiteBaseUrl() . '/addons/shopro/pay/notifyhuifurefund/platform/' . $platform;
}
$custom = trim((string) $this->get('pay_notify_url'));
if ($custom !== '') {
return rtrim($custom, '/');
}
// 走 shopro 主插件路由(与 prepay 同入口,避免 shopro_huifu 子插件路由不可达)
return $this->getSiteBaseUrl() . '/addons/shopro/pay/notifyhuifu';
}
protected function extractKeyBody($key)
{
$key = trim((string) $key);
if ($key === '') {
return '';
}
$key = preg_replace('/-----BEGIN[^-]+-----/', '', $key);
$key = preg_replace('/-----END[^-]+-----/', '', $key);
return preg_replace('/\s+/', '', $key);
}
protected function wrapPem($body, $label)
{
return "-----BEGIN {$label}-----\n" . wordwrap($body, 64, "\n", true) . "\n-----END {$label}-----";
}
public function formatGoodsDesc($orderSn)
{
$tpl = $this->get('goods_desc_tpl', '商城订单{order_sn}');
return str_replace('{order_sn}', $orderSn, $tpl);
}
}