- 18 张公共表更名(addon/attachment/configure/links/spider_log/spider_stat/sms/notice/ad/task/prop/medal/help/card -> common_*,member_wallets->member_wallet,score_rule/score_log -> member_*,addon_config->common_addonconf),模型全部对齐新表名,Db 直引用清零 - Attachment 模型补 表名绑定,修复富文本上传查 wxapp_attachment 1146 隐患 - install.sql + 迁移 SQL:backend_admin/backend_role delete_at 默认 0,修复软删除(NULL != 0)误过滤导致后台菜单为空 - AppService::boot() 支持插件 info.php 声明 commands 自动注册插件命令(psr-4 自动加载,坏类名自动跳过) - 各插件(haonav/mqttbroker/wxchat/articles/blog/forum 等)字段与配置同步调整 - 框架版本 1.1.0 -> 1.1.1
170 lines
6.1 KiB
PHP
170 lines
6.1 KiB
PHP
<?php
|
||
// +----------------------------------------------------------------------
|
||
// | YwxApp [ WE CAN DO IT JUST THINK ]
|
||
// +----------------------------------------------------------------------
|
||
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
|
||
// +----------------------------------------------------------------------
|
||
// | Author: ywxapp<admin@ywxapp.cn>
|
||
// +----------------------------------------------------------------------
|
||
|
||
if (!function_exists('addon_url')) {
|
||
/**
|
||
* 生成插件访问地址(MultiApp 多应用模型:/<addon>/<controller>/<action>)
|
||
* @param string $name 插件标识
|
||
* @param string $url 相对路径,如 'admin/index' 或 '/admin/index'
|
||
* @param array $vars 附加 GET 参数
|
||
* @return string
|
||
*/
|
||
function addon_url(string $name, string $url = '', array $vars = []): string
|
||
{
|
||
$path = '/' . trim($name, '/');
|
||
if ($url !== '' && $url !== '/') {
|
||
$path .= '/' . ltrim($url, '/');
|
||
}
|
||
return $vars ? $path . '?' . http_build_query($vars) : $path;
|
||
}
|
||
}
|
||
|
||
if (!function_exists('get_addon_instance')) {
|
||
/**
|
||
* 获取插件主类实例(addon\<name>\Addon)
|
||
* @param string $name 插件标识
|
||
* @return object|null
|
||
*/
|
||
function get_addon_instance(string $name)
|
||
{
|
||
$class = '\\addon\\' . $name . '\\Addon';
|
||
if (!class_exists($class)) {
|
||
return null;
|
||
}
|
||
return app($class);
|
||
}
|
||
}
|
||
|
||
if (!function_exists('get_addon_info')) {
|
||
/**
|
||
* 读取插件信息(优先缓存,force=true 强制重读)
|
||
* @param string $name 插件标识
|
||
* @param bool $force
|
||
* @return array
|
||
*/
|
||
function get_addon_info(string $name = '', bool $force = false): array
|
||
{
|
||
$instance = get_addon_instance($name);
|
||
return $instance ? $instance->getInfo($name, $force) : [];
|
||
}
|
||
}
|
||
|
||
if (!function_exists('get_addon_config')) {
|
||
/**
|
||
* 读取插件配置(优先缓存,force=true 强制重读)
|
||
* @param string $name 插件标识
|
||
* @param bool $force
|
||
* @return array
|
||
*/
|
||
function get_addon_config(string $name = '', bool $force = false): array
|
||
{
|
||
$instance = get_addon_instance($name);
|
||
return $instance ? $instance->getConfig($name, $force) : [];
|
||
}
|
||
}
|
||
|
||
if (!function_exists('is_market_client')) {
|
||
/**
|
||
* 市场是否处于「客户机」模式(「谁是中心站」由 config/ywxapp.php 决定):
|
||
* - market_mode=center → 强制中心站
|
||
* - market_mode=client → 强制客户机
|
||
* - market_mode=auto(默认):
|
||
* · api_url 为空 → 本机即中心站(直接读写本地市场 wxapp_appmarket_addon_list)
|
||
* · api_url 指向本机(同主机)→ 仍视为中心站(配置纠偏)
|
||
* · api_url 指向其他主机 → 本机作为客户机,经 RemoteService 连接该中心站
|
||
*
|
||
* auto 模式下依赖「当前请求主机」判定自身:改用框架 Request 抽象(可测试、CLI 可控),
|
||
* 不再直接读 $_SERVER['HTTP_HOST']。CLI(路由缓存/refresh-menu)无法取得主机时保守判为客户机——
|
||
* 因此中心站请保持 api_url 为空,或显式设置 market_mode=center 以彻底解除该约束。
|
||
* @return bool
|
||
*/
|
||
function is_market_client(): bool
|
||
{
|
||
$mode = \think\facade\Config::get('ywxapp.market_mode', 'auto');
|
||
if ($mode === 'center') {
|
||
return false;
|
||
}
|
||
if ($mode === 'client') {
|
||
return true;
|
||
}
|
||
|
||
// auto:基于 api_url + 自身主机推导
|
||
$apiUrl = \think\facade\Config::get('ywxapp.api_url', '');
|
||
if (empty($apiUrl)) {
|
||
return false;
|
||
}
|
||
$host = parse_url($apiUrl, PHP_URL_HOST);
|
||
if (empty($host)) {
|
||
return false;
|
||
}
|
||
|
||
// 用框架 Request 抽象主机(可 mock / CLI 可控),替代直接读 $_SERVER['HTTP_HOST']
|
||
$req = function_exists('request') ? request() : null;
|
||
$self = $req ? (string) $req->host() : '';
|
||
if ($self === '') {
|
||
// CLI(如路由缓存/refresh-menu)无法判定主机:回退到 market_mode 显式配置。
|
||
// 只有显式声明 market_mode=client 才当作客户机;否则(auto/center)按中心站处理,
|
||
// 避免中心站 CLI 刷新菜单时误删 centerOnly 项(应用市场审核/开发者/收益等运营菜单)。
|
||
return \think\facade\Config::get('ywxapp.market_mode', 'auto') === 'client';
|
||
}
|
||
$selfHost = preg_replace('/:\d+$/', '', $self);
|
||
$cmpHost = preg_replace('/:\d+$/', '', $host);
|
||
if (strcasecmp($selfHost, $cmpHost) === 0) {
|
||
return false; // api_url 指向自身 = 视为中心站(配置纠偏)
|
||
}
|
||
return true;
|
||
}
|
||
}
|
||
|
||
|
||
if (!function_exists('cross_url')) {
|
||
function cross_url(string $appName, string $url = '', array $vars = [], string $suffix = ''): string
|
||
{
|
||
$map = config('app.domain_bind', []);
|
||
$mainDomain = config('app.url_main_domain');
|
||
|
||
$domainKey = '';
|
||
foreach ($map as $key => $mappedApp) {
|
||
if ($mappedApp === $appName) {
|
||
$domainKey = $key;
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 解析 host 和 port
|
||
$host = '';
|
||
$port = '';
|
||
|
||
if ($domainKey === '') {
|
||
$host = true; // 用当前域名
|
||
} elseif (str_contains($domainKey, ':')) {
|
||
// 带端口:api.example.com:8080
|
||
[$host, $port] = explode(':', $domainKey, 2);
|
||
$port = ':' . $port;
|
||
} elseif (str_contains($domainKey, '.')) {
|
||
// 完整域名
|
||
$host = $domainKey;
|
||
} else {
|
||
// 子域名
|
||
$host = "{$domainKey}.{$mainDomain}";
|
||
}
|
||
|
||
return (string) \think\facade\Url::build($url)
|
||
->vars($vars)
|
||
->suffix($suffix)
|
||
->domain($host);
|
||
}
|
||
}
|
||
if (!function_exists('L')) {
|
||
function L($value)
|
||
{
|
||
return \think\facade\Lang::get($value);
|
||
}
|
||
}
|