插件静态资源(运行时发布,不入库) * - config/database.php 数据库私密配置 * - config/ywxapp.php 框架配置(含版本号等,安装/升级时不应覆盖) */ const FRAMEWORK_EXCLUDES = [ 'public/uploads', 'public/addons', 'config/database.php', 'config/ywxapp.php', ]; /** * 递归收集框架文件相对路径。 * @return string[] 形如 ['app/backend/controller/Admin.php', 'config/app.php', ...] */ function frameworkFiles(): array { $root = dirname(__DIR__); // scripts/ 的上一级 = 项目根 $files = []; // 自动发现插件静态资源(addon/ 下每个子目录对应 public/static/<插件名>/),从清单中剔除 $addonStatic = []; $addonRoot = $root . DIRECTORY_SEPARATOR . 'addon'; if (is_dir($addonRoot)) { foreach (array_diff(scandir($addonRoot), ['.', '..']) as $entry) { if (is_dir($addonRoot . DIRECTORY_SEPARATOR . $entry)) { $addonStatic[] = 'public/static/' . $entry . '/'; } } } $isExcluded = static function (string $rel) use ($root, $addonStatic): bool { // 顶层排除项 if (in_array($rel, FRAMEWORK_EXCLUDES, true)) { return true; } // addon/ 下的任何内容都不属于框架包 if (strpos($rel, 'addon/') === 0) { return true; } // 上传目录整体排除 if (strpos($rel, 'public/uploads/') === 0) { return true; } // 插件静态资源(public/static/<插件名>/)整体排除 foreach ($addonStatic as $staticPrefix) { if (strpos($rel, $staticPrefix) === 0) { return true; } } // 跳过 .git / 运行时目录(防御性) if (preg_match('#(^|/)(\.git|runtime|vendor)(/|$)#', $rel)) { return true; } return false; }; $scan = static function (string $dir, string $prefix) use (&$scan, $root, &$files, $isExcluded): void { if (!is_dir($dir)) { return; } foreach (scandir($dir) as $name) { if ($name === '.' || $name === '..') { continue; } $rel = $prefix === '' ? $name : $prefix . '/' . $name; if ($isExcluded($rel)) { continue; } $abs = $root . DIRECTORY_SEPARATOR . $rel; if (is_dir($abs)) { $scan($abs, $rel); } elseif (is_file($abs)) { $files[] = $rel; } } }; foreach (FRAMEWORK_DIRS as $d) { $scan($root . DIRECTORY_SEPARATOR . $d, $d); } sort($files); return $files; } // 作为数组返回:直接 require 本文件即可得到框架所有文件的相对路径数组 return frameworkFiles();