149 lines
5.3 KiB
PHP
149 lines
5.3 KiB
PHP
<?php
|
|
// +----------------------------------------------------------------------
|
|
// | 企油通配置读取
|
|
// +----------------------------------------------------------------------
|
|
// | 三层来源,从低到高:
|
|
// | 1. config/qyt.php —— 读 .env,含【密钥】与接口域名(接入方级)
|
|
// | 2. 后台「企油通对接设置」—— yoshop_store_setting.key='qyt'(接入方级默认值)
|
|
// | 3. 企业信息 —— yoshop_qyt_enterprise(企业级:执照号 / 通道 / 机构号 …)
|
|
// |
|
|
// | 分级依据见《企油通接口对接文档.md》:appId 与 RSA 密钥属于「接入方(慧明)」,
|
|
// | 一个 appId 下可挂多个企业;business_license、passageway、institution_id 是企业级。
|
|
// |
|
|
// | 敏感项(private_key、platform_public_key)只从 .env 读,任何一层都不能覆盖,
|
|
// | 数据库备份 / SQL 注入 / 后台账号失窃都拿不到签名私钥。
|
|
// +----------------------------------------------------------------------
|
|
declare (strict_types=1);
|
|
|
|
namespace app\common\service;
|
|
|
|
use app\common\enum\Setting as SettingEnum;
|
|
use app\common\model\qyt\Enterprise as EnterpriseModel;
|
|
use think\facade\Db;
|
|
|
|
class QytConfig
|
|
{
|
|
/** 常驻进程内缓存有效期(秒):后台改完最迟这么久生效 */
|
|
const TTL = 10;
|
|
|
|
/** 后台设置可覆盖的接入方级标量项 */
|
|
const OVERRIDABLE = [
|
|
'base_url', 'app_id', 'no_prefix', 'voucher_name',
|
|
'h5_base_url', 'h5_app_id', 'consume_notify_url', 'waybill_notify_url',
|
|
];
|
|
|
|
/** @var array|null */
|
|
protected static $cache = null;
|
|
|
|
/** @var int */
|
|
protected static $cacheAt = 0;
|
|
|
|
/**
|
|
* 接入方级配置(不含任何企业信息)
|
|
*/
|
|
public static function get(): array
|
|
{
|
|
if (self::$cache !== null && (time() - self::$cacheAt) < self::TTL) {
|
|
return self::$cache;
|
|
}
|
|
|
|
$conf = (array) config('qyt');
|
|
$db = static::dbValues();
|
|
|
|
foreach (self::OVERRIDABLE as $k) {
|
|
if (isset($db[$k]) && trim((string) $db[$k]) !== '') {
|
|
$conf[$k] = trim((string) $db[$k]);
|
|
}
|
|
}
|
|
// 布尔项 0 是合法值,不能用非空判断
|
|
if (isset($db['log'])) {
|
|
$conf['log'] = (bool) $db['log'];
|
|
}
|
|
if (isset($db['waybill_notify'])) {
|
|
$conf['waybill_notify'] = (bool) $db['waybill_notify'];
|
|
}
|
|
|
|
self::$cache = $conf;
|
|
self::$cacheAt = time();
|
|
return $conf;
|
|
}
|
|
|
|
/**
|
|
* 叠加企业级参数,得到某个企业实际使用的完整配置
|
|
*
|
|
* @param EnterpriseModel|array $enterprise
|
|
* @return array 额外带 enterprise_id / enterprise_name / passageway_code / passageway_name
|
|
*/
|
|
public static function forEnterprise($enterprise): array
|
|
{
|
|
$conf = self::get();
|
|
$e = $enterprise instanceof EnterpriseModel ? $enterprise->toArray() : (array) $enterprise;
|
|
|
|
$passageway = (string) ($e['passageway'] ?? 'alipay');
|
|
!isset(EnterpriseModel::PASSAGEWAY_CODE[$passageway]) && $passageway = 'alipay';
|
|
|
|
$conf['enterprise_id'] = (int) ($e['enterprise_id'] ?? 0);
|
|
$conf['enterprise_name'] = (string) ($e['company_name'] ?? '');
|
|
$conf['business_license'] = (string) ($e['business_license'] ?? '');
|
|
$conf['passageway'] = $passageway;
|
|
$conf['passageway_code'] = EnterpriseModel::PASSAGEWAY_CODE[$passageway];
|
|
$conf['passageway_name'] = EnterpriseModel::PASSAGEWAY_NAME[$passageway];
|
|
$conf['institution_id'] = (string) ($e['institution_id'] ?? '');
|
|
|
|
// 以下留空则回落接入方级默认值
|
|
foreach (['app_id', 'no_prefix', 'voucher_name'] as $k) {
|
|
$v = trim((string) ($e[$k] ?? ''));
|
|
$v !== '' && $conf[$k] = $v;
|
|
}
|
|
|
|
return $conf;
|
|
}
|
|
|
|
/**
|
|
* 取单项,支持点号:QytConfig::item('h5_base_url')
|
|
* @param mixed $default
|
|
* @return mixed
|
|
*/
|
|
public static function item(string $path, $default = null)
|
|
{
|
|
$node = self::get();
|
|
foreach (explode('.', $path) as $seg) {
|
|
if (!is_array($node) || !array_key_exists($seg, $node)) {
|
|
return $default;
|
|
}
|
|
$node = $node[$seg];
|
|
}
|
|
return $node;
|
|
}
|
|
|
|
/** 清掉进程内缓存(单元测试 / 后台保存后使用) */
|
|
public static function flush(): void
|
|
{
|
|
self::$cache = null;
|
|
self::$cacheAt = 0;
|
|
}
|
|
|
|
/**
|
|
* 读后台设置。直接查表而不用 Setting 模型,是因为常驻命令行进程里
|
|
* BaseModel::$storeId 不会被初始化(只有 store/api 模块才赋值),
|
|
* 走模型会查不到数据。本项目为单商城部署,取 store_id 最小的一条即可。
|
|
*/
|
|
protected static function dbValues(): array
|
|
{
|
|
try {
|
|
$json = Db::name('store_setting')
|
|
->where('key', SettingEnum::QYT)
|
|
->order('store_id', 'asc')
|
|
->value('values');
|
|
if (empty($json)) {
|
|
return [];
|
|
}
|
|
$arr = json_decode((string) $json, true);
|
|
return is_array($arr) ? $arr : [];
|
|
} catch (\Throwable $e) {
|
|
// 表不存在 / 库连不上时静默回落到 .env,不能因为读设置失败就中断发放
|
|
return [];
|
|
}
|
|
}
|
|
}
|