You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CodeIgniter4多租户应用如何访问public目录外的公共资源文件

CodeIgniter4 多租户架构下共享公共静态资源实现方案

核心原则:公共资源只存一份,不重复复制到每个租户目录,优先选择无PHP开销的直出方案。

方案1:Web服务器直出(性能最优,生产环境推荐)

静态资源直接由Nginx/Apache返回,不经过CI4框架解析,性能是PHP转发方案的5~10倍,适合无特殊权限要求的JS/CSS/图片等公共资源。

  • 第一步:创建公共资源存储目录
    在所有租户目录的同级位置(即域名映射的网站根目录,和test、test1租户文件夹平级)新建shared_assets目录,按资源类型分子目录存放文件,最终目录结构如下:
    网站根目录/
    ├── test/          # test租户的原public目录内容
    ├── test1/         # test1租户的原public目录内容
    └── shared_assets/ # 公共资源根目录
        ├── css/       # 公共样式文件
        ├── js/        # 公共脚本文件
        └── img/       # 公共图片文件
    
  • 第二步:配置Web服务器规则
    配置规则的作用是:无论当前访问的是哪个租户路径,所有指向公共资源的请求都会被统一映射到上述公共目录,不会走到租户的入口文件。
    Apache环境:在网站根目录新建.htaccess文件,写入以下规则:
    RewriteEngine On
    # 统一拦截所有路径下的公共资源请求,映射到根目录的公共资源文件夹
    RewriteRule ^(.*)shared_assets/(.*)$ /shared_assets/$2 [L]
    # 禁止访问敏感配置文件
    <FilesMatch "\.(htaccess|htpasswd|ini|env)">
      Order Allow,Deny
      Deny from all
    </FilesMatch>
    
    Nginx环境:在域名对应的server配置块中加入以下规则,重载Nginx配置即可生效:
    location ~* /shared_assets/ {
        root /网站根目录的绝对路径/;
        expires 30d; # 开启30天浏览器缓存,可选
        access_log off;
        add_header Cache-Control "public, max-age=2592000";
    }
    
  • 第三步:视图中引用资源
    直接使用绝对根路径引用即可,不受当前租户路径影响:
    <!-- 公共CSS -->
    <link rel="stylesheet" href="/shared_assets/css/common.css">
    <!-- 公共JS -->
    <script src="/shared_assets/js/common.js"></script>
    <!-- 公共图片 -->
    <img src="/shared_assets/img/site-logo.png" alt="站点logo">
    
    为了方便后续路径调整,可以在app/Config/Constants.php中定义全局常量:
    define('SHARED_ASSETS_URL', '/shared_assets/');
    
    视图中用常量拼接路径即可,后续调整公共资源路径只需要修改这一处配置。

方案2:CI4路由转发(适合有权限控制的场景)

如果部分公共资源需要登录校验、租户权限判断后才能访问,可以用这个方案,所有资源请求经过CI4框架处理,灵活度高但性能稍差。

  • 第一步:创建公共资源存储目录
    在CI4项目根目录(和app、system目录平级,不在任何租户的public目录内)新建shared_assets目录,按类型存放公共资源。
  • 第二步:新建资源控制器
    在app/Controllers目录下创建SharedAssets.php控制器,注意加白名单和路径过滤,防止目录遍历漏洞:
    <?php
    namespace App\Controllers;
    use CodeIgniter\Controller;
    
    class SharedAssets extends Controller
    {
        public function serve(string $type = '', string $filename = '')
        {
            // 资源类型白名单,不在白名单内的请求直接返回404
            $allowedTypes = ['css', 'js', 'img'];
            if (!in_array($type, $allowedTypes)) {
                throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
            }
            // 拼接资源实际路径,用basename过滤非法路径字符,防止目录遍历
            $filePath = ROOTPATH . 'shared_assets/' . $type . '/' . basename($filename);
            if (!is_file($filePath)) {
                throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
            }
            // 此处可加权限校验逻辑,比如判断租户状态、用户登录状态等
            // 按资源类型返回对应响应头
            $mimeMap = [
                'css' => 'text/css',
                'js' => 'application/javascript',
                'img' => mime_content_type($filePath)
            ];
            return $this->response
                ->setHeader('Content-Type', $mimeMap[$type])
                ->setHeader('Cache-Control', 'public, max-age=2592000')
                ->setBody(file_get_contents($filePath));
        }
    }
    
  • 第三步:添加路由规则
    在app/Config/Routes.php中加入路由,适配所有租户路径下的资源请求:
    $routes->get('(:any)/shared-assets/(:any)/(:any)', 'SharedAssets::serve/$2/$3');
    $routes->get('shared-assets/(:any)/(:any)', 'SharedAssets::serve/$1/$2');
    
  • 第四步:视图中引用资源
    用CI4自带的base_url辅助函数生成路径即可:
    <link rel="stylesheet" href="<?= base_url('shared-assets/css/common.css') ?>">
    

注意事项

  • 无特殊权限需求时优先选方案1,不要用PHP处理静态资源,避免不必要的性能开销。
  • 两种方案都只需要存储一份公共资源,更新时所有租户实时生效,不需要逐个租户目录复制文件。
  • 所有对外提供文件访问的逻辑必须加白名单和路径过滤,避免被恶意利用读取敏感文件。

内容的提问来源于stack exchange,提问作者PRADEEP AGGARWAL

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 15:57:50