mod_include 是 Apache 的服务器端包含(SSI)模块,仅支持静态内容拼接,不具备变量、循环或条件逻辑等编程能力。

mod_include 是什么,为什么它不是“服务器端编程”
mod_include(通常叫 SSI)只是 Apache 的文本替换模块,不支持变量、循环或条件分支的完整逻辑,只做静态内容拼接。它适合在 HTML 里插入日期、文件内容、环境变量值这类简单操作,别指望用它写 if-else 或读数据库。
常见错误现象:Parse error: unable to parse 或页面直接显示 <!--#if expr="..." --> 原样文本——说明 SSI 没启用,或文件后缀/响应头被忽略。
- 必须启用模块:
a2enmod include(Debian/Ubuntu),或确认LoadModule include_module modules/mod_include.so在配置中已加载 - 文件扩展名默认只对
.shtml生效;若想用于.html,需加配置:AddType text/html .html+AddOutputFilter INCLUDES .html - Apache 默认禁用
exec和复杂表达式,要开IncludesNOEXEC或Includes(后者有安全风险)
怎么写一个可用的 #include 指令
#include 是最常用也最安全的指令,用于嵌入其他文件内容。它不执行脚本,只做字面量插入,适合页眉、页脚复用。
使用场景:统一更新网站底部版权信息,或把导航栏抽成独立文件维护。
-
virtual参数走 URL 路径(如<!--#include virtual="/inc/header.html" -->),路径相对于 DocumentRoot -
file参数走文件系统路径(如<!--#include file="footer.html" -->),路径相对于当前文件所在目录,且不能跨目录(../会被拒绝) - 被包含文件不会被再次解析为 SSI——除非显式设置
SSIEnable on并用virtual引用,否则嵌套#include不生效
示例:<!--#include virtual="/shared/footer.shtml" --> —— 这行会把 /var/www/html/shared/footer.shtml 的内容原样塞进来。
用 #echo 和 #config 控制输出格式与行为
#echo 读取环境变量或 CGI 变量并输出,#config 则用来调整 SSI 解析行为,比如错误提示开关或时间格式。
容易踩的坑:直接写 <!--#echo var="HTTP_USER_AGENT" --> 可能输出空值——因为默认不传递所有 HTTP 头,Apache 为安全只暴露有限变量(DOCUMENT_URI、DATE_LOCAL 等)。
- 想输出时间?用
<!--#config timefmt="%Y-%m-%d" --><!--#echo var="DATE_LOCAL" --> - 调试时打开错误提示:
<!--#config errmsg="[SSI error]" -->,否则失败时静默丢弃 -
sizefmt影响#fsize输出单位(bytes或abbrev),但#fsize本身不支持动态路径,只能写死文件名
为什么 #if 表达式常失效,以及怎么让它真正工作
#if 看似支持条件判断,但实际能力极弱:只支持简单字符串比较、正则匹配(expr)、和少数预定义变量(REQUEST_URI、QUERY_STRING),不支持算术、函数调用或自定义变量。
典型错误:<!--#if expr="$myvar = 'test'" --> —— $myvar 根本不存在,SSI 没有变量赋值语法。
- 合法表达式只有:
<!--#if expr="($QUERY_STRING = /debug=true/)" -->(注意正则斜杠包裹) - 必须启用
Includes选项(而非默认的IncludesNOEXEC),否则#if直接被忽略 - 嵌套
#if不支持;#elif存在但不可靠,建议用多个独立#if+ 不同条件覆盖 - 性能影响小,但每次请求都要触发 Apache 的 SSI 解析器,比纯静态响应慢 10%–20%,高并发下明显
复杂点在于:你得同时控制好模块加载、目录权限(Options +Includes)、文件类型识别、表达式语法和变量白名单——漏掉任意一环,#if 就变成注释文本。

















