SSI(Server Side Includes),是嵌套在 HTML 网页中的指示语句,由后台服务器进行代码的解释计算。使用 SSI 能够动态的建立一部分网页内容而不须要编写复杂的 JSP/ASP/PHP 等程序。SSI 是如此的小巧以致于不该算做一门语言,由于他远没有JSP/ASP/PHP 等程序那么复杂,只有一些极其有限的语法规则。javascript
不少 HTTP Server 程序都支持 SSI,可能语法稍有不一样,好比: IIS/Novell HTTP Server 等等,大同小异,本文要说明的是 Apache 2.0 的 SSI。闲话少说,我想告诉你们的是,这是一篇实践经验总结性的文章,后文中的示例解决方案都是来自实际的网站应用中。php
<Directory "D:/myProject/web"> AddType text/html .ssi #这里能够是 .shtml 或其余 不必定要 .ssi, 设置.ssi后缀的也是text/html类型的文件 Options Includes AddOutputFilterByType INCLUDES; DEFLATE text/html #输出处理器 </Directory>
测试SSI是否成功启用 编辑文件html
// test.ssi : # echo指令输出变量 DATE_LOCAL <!--#echo var="DATE_LOCAL" --> ## 特别注意 <!--# 之间不能有任何空格,否则指令是无效的,被看成html注释
由于不少IDE都有注释代码行的快捷键, 如 sublime text( ctrl + /) 可是会变成 <!-- #echo var="..." -->
,因为多了个空格,因此ssi指令被当成注释了。 java
浏览器访问 http://localhost/test.ssi 能看到打印当前时间 说明SSI已启用web
这些文档也能够在 Apache的安装文件夹找到:
Apache Tutorial: Introduction to Server Side Includes
Apache mod_include正则表达式
<!--#fn attribute=value attribute=value ... -->
fn能够理解成函数或者指令。 例子:express
#环境变量习惯大写 http://<!--#echo var="SERVER_NAME" var="DOCUMENT_URI"--> #virtual的值能够是相对路径或绝对路径 如 virtual="/ssi/footer.ssi" <!--#include virtual="ssi/footer.ssi" --> #file的值只能是相对路径 <!--#include file="footer.ssi" --> #设置自定义变量 <!--#set var="protocol" value="http" -->
SSI 语句是直接嵌套在 HTML 页面中的,能够放置在任意的位置。因此 SSI 语句先后采用 HTML 注释的写法,这样一旦服务器关闭了对 SSI 的支持,此时访问页面的话,也不会直接在网页上显示出没必要要的代码。apache
SSI不区分大小写,环境变量用大写是很好的习惯;
SSI中只有一种数据类型:字符串;
SSI中的转义符是 ,字符串能够用双引号或单引号包裹 ,同JS浏览器
自定义变量使用 set 命令来建立:<!--#set var="protocol" value="http" -->
环境变量是系统已经存在的一些默认的变量和变量值,能够直接使用。 <!--#echo var=”DATE_LOCAL” -->
DATE_LOCAL 就是一个环境变量,用来显示当前本地时间。相似的环境变量还有不少,好比经常使用HTTP_HOST、SERVER_NAME、DOCUMENT_URI、DOCUMENT_NAME 等等。安全
# 查看全部环境变量 # 因为无换行因此按ctrl+u,以网页源代码的方式查看更清晰点 <!--#printenv--> # ------- 应用示例: -------------- <body> <!--#include virtual="/bnn/ssi/header.ssi"--> <div id="Main"> <div id="Content"> <p>This is "<a href="http://<!--#echo var='SERVER_NAME' -->">Learning Apache SSI</a>" testing page!</p> <p>Hello SSI</p> <p>Today is: <!--#echo var="DATE_LOCAL" --></p> </div> </div> <!--#include virtual="ssi/footer.ssi"--> </body>
<!--#set var=”MyFirstVar” value=”120” --> <!--#set var=”MySecondVar” value=”20” --> # $MyFirstVar < $MySecondVar //由于2个变量都是字符串值 因此执行的是字符串比较(比较每一个字符的ASCII码大小)
SSI 的元素并很少,下面列出经常使用的元素和属性,其它请查看官方参考。
#能够一次输出多个变量值 <!--#echo var="DATE_LOCAL"--> http://<!--#echo var=”SERVER_NAME” var=”DOCUMENT_URI” -->
include 是 SSI 中最经常使用的命令,也是 SSI 主要功能的体现。
# virtual的值能够是相对路径或绝对路径, 但注意路径中不能包含主机名; #路径能够是相对当前文件(SSI 语句所在的页面)或者从“/”开始,相对网站根目录的路径; <!--#include virtual="ssi/header.ssi"--> # 路径后容许加参数 <!--#include virtual="/cgi-bin/ap/optin_cn.pl?btn=send&fax=yes" -->
SSI 是容许嵌套的;例如,假设有三个文件,file1 include file2,file2中 include file3。
<!--#set var=”Protocol” value=”http” --> # 若变量值带引号,能够这样: <!--#set var="MyVar1" value='"IBM"' --> //value的值能够是字符串常量或者变量 如:value="$MyVar2" <!--#set var="MyVar2" value="\"IBM\"" -->
SSI中的变量都带$前缀 如:$Myvar,为了更清晰的表达一个变量 一般用大括号把变量名包起来 ${MyVar} , 同php
<!--#set var="MyVar1" value="IBM" --> <!--#set var="MyVar2" value="Services" --> <!--#set var="MyVar3" value="${MyVar1}${MyVar2}" --> //设置 MyVar3 = MyVar1+MyVar2 <!--#echo var="MyVar3" --> <!--#set var="MyVar3" value="abc${MyVar1}_${MyVar1}def" --> // 修改MyVar3的值 <!--#echo var="MyVar3" --> <!--#set var=”MyVar1” value=”IBM” --> <!--#set var=”MyVar2” value=”\$MyVar1” --> // 变量值为 "$IBM" # 另外一个把变量写在 SSI 语句中的例子: <!--#include virtual="/servers/eserver/${cc}/ssi/nav_left.ssi" --> // 这个比较有用。
显示指定文件的大小(fsize)和指定文件的最后修改时间(flastmod)
virtual
– 与元素 include 中的属性相同,<!--#fsize virtual=”/cgi-bin/cmail.pl” -->
结果返回的是这个 Perl 脚本文件的大小,而不是运行这段 Perl 脚本的结果。
config指令
配置一些 SSI 运行结果;错误信息、文件大小格式、时间格式。
errmsg属性 当 SSI 语句运行出错时显示的信息。 例如:<!--#config errmsg="出错啦# " -->
sizefmt 显示以何种方式显示文件大小。这个属性有两个值:bytes 和 abbrev。
<!--#config sizefmt="bytes" --> //按bytes大小显示 <!--#config sizefmt="abbrev" --> //按bytes、Kb或Mb动态显示 视文件大小
timefmt 显示时间的格式。属性值的参数同 C 标准库中的strftime(3) 相同;
<!--#config timefmt="%Y-%m-%d"--> <!--#config timefmt="%Y-%m-%d"--> <meta name="DC.DATE" scheme="iso8610" content="<!--#echo var=’LAST_MODIFIED’-->">
SSI 中只有条件语句一种结构,并且结构很简单。基本的控制元素:
<!--#if expr="test_condition"--> html or SSI statements <!--#elif expr="test_condition"--> html or SSI statements <!--#else--> html or SSI statements <!--#endif--> ## if 语句能够嵌套,你能够在 if 块中再加入一个 if 块语句。
非空字符串为真,空串为假
<!--#if expr="IBM" --> // 表示条件成立; <!--#if expr="" --> //空字符,返回 假,条件不成立。
判断一个变量是否为空字符串的一种写法:<!--#if expr="$MyVar = ‘’" -->
<!--#if expr="$DOCUMENT_URI = ‘/bnn/index.html’" --> codes <!--#endif -->
运算符优先级 比较运算符优先级高于逻辑运算符 ; && 和 || 具备相同的优先级,可使用括号 () 进行分组。
<!--#if expr="$a = test1 && $b = test2" --> <!--#if expr="($a = test1) && ($b = test2)" -->
任何不被识别为变量或者操做符都被看成是一个字符串。字符串也可使用引号(单引号或者双引号)括起来。不被引号括起来的字符串中不容许有空格或者 Tab,由于空格是被用来起到分隔的做用。若是一个字符串中包含空格,请使用引号括起来。
<!--#if expr="$a = test1 && $b = ‘test 2’" -->
Regular expression (正则表达式,缩写 RE),是一种对字符串进行匹配查找的高效模式。几乎每一种语言都支持 RE;Apache SSI 中的 RE 语法同 Perl(版本 5)语言中的相同,但并不完整的支持
<!--#if expr="$QUERY_STRING = /^sid=([a-zA-Z0-9]+)/" --> <!--#set var="session" value="$1" --> <!--#endif -->
说明:此例表示从参数中提取子字符串。$QUERY_STRING 是环境变量,表示经过网页 URL 传递过来的参数,例如:
http://www.IBM.com/index.html?sid=safsaf43513sadfz&cntry=cn
其中,问号后面的部分就是 $QUERY_STRING 的值。
若是等号右边的比较部分是 / / 这种形式,则表示,这部分是正则表达式
/^sid=([a-zA-Z0-9]+)/ 括号表示分组,用圆括号分组的同时,程序自动会将圆括号内匹配的部分提取出来保存在 $1 这个变量中;这个 $1 是系统变量,用来保存正则表达式分组提取出来的各个部分值,一共有 9个,$1-$9。
SSI 与 JS 如何一块儿使用呢?是这样的,因为服务器并不能识别 JS 代码,因此能够把 SSI 语句放到 JS 代码行中,这样取代一部分 JS 代码的工做,将这部分工做放到服务器端运行。
<!--#if expr="$DOCUMENT_URI = /\/bnn\//" --> //正则匹配 形如:/bnn/ 的路径,而后设置变量 SSI变量在JS中输出 <!--#set var="LASLink" value="http://localhost/bnn/" --> <!--#set var="LASText" value="Learning Apache SSI" --> <!--#endif --> <script type="text/javascript"> //<![CDATA[ document.write(‘<a class="fbox" href="<!--#echo var="LASLink" -->"><!--#echo var="LASText" --></a>’); //]]> </script>
前几天遇到这样一个需求:一个 Promotion - 3月3日以前显示默认的内容,3月3日以后显示另一个内容。下面给出这段代码,分享一下相似这种的要求该如何入手。
<!--#config timefmt="%Y-%m-%d"--> # 配置日期格式 <!--#if expr="$DATE_LOCAL = /(.+)-(.+)-(.+)/" --> # 流程控制语句实现逻辑 正则匹配当前本地日期 捕获年月日 <!--#if expr="($2 = '03') && ($3 != /0[1-3]/)" --> # 嵌套的if 正则跟字符串比较? 3月3日以后 <!--#else --> 默认 <!--#endif --> <!--#endif -->
页面布局中一些相对固定的模块,能够经过include的方式包含到页面中。
一般状况下,上面有 4个区域是不常常变更的:Header、Left Nav、Nav Trail 和 Footer。
<body> <!--#include virtual="ssi/header.ssi"--> # 把头部模块包含进来 <div id="Main"> <div id="LeftNav"><!--#include virtual="ssi/nav_left.ssi"--></div> # 左侧导航模块包含进来 <div id="RightNav"><!--#include virtual="ssi/nav_right.ssi"--></div> # ~右侧导航模块include进来 <div id="Content"> <div id="NavTrail"><!--#include virtual="ssi/nav_trail.ssi"--></div> # 面包屑模块include进来 <p>Hello SSI</p> </div> </div> <!--#include virtual="ssi/footer.ssi"--> # 页脚模块include进来 </body> <!--#set var="protocol" value="" --> # 设置变量protocol初始值 <!--#if expr="$HTTPS != /ON/" --> # 若环境变量$HTTPS 开启,则设置变量protocol的值 <!--#set var="protocol" value="http://${SERVER_NAME}" --> <!--#endif --> <!--#set var="protocols" value="https://${SERVER_NAME}" --> # 设置变量 变量名比较长的话用大括号包起来比较清晰,易于解析。 # 根据请求的路径 高亮显示相应的栏目连接 <ul> <li class="TopLink"> <a class="left-nav-overview" href="<!--#echo var='protocol' -->/ ">IBM</a> </li> <li class="PrimaryLink<!--#if expr='$DOCUMENT_URI = /\/systems\/cn\//' -->-Highlight<!--#endif -->"> <a class="left-nav" href="<!--#echo var='protocol' -->/systems/cn/">Systems</a> </li> <li class="PrimaryLink<!--#if expr='$DOCUMENT_URI = /\/contact\/index.html/' -->-Highlight<!--#endif -->"> <a class="left-nav" href="<!--#echo var='protocols' -->/contact/index.html">联系咱们</a> </li> </ul>
Nav Trail 又叫作 Breadcrumb,中文里咱们叫作“当前位置”。在页面上,根据当前页面所在不一样,在这个地方会有提示访问者当前所在的位置。若是在每一个页面都存在这个提示的话,编辑起来会很麻烦。但如今可使用 SSI 解决这个问题,只要在每一个页面的这个位置 include 一个 SSI 文件就能够了,当前所在位置的工做交给 SSI 来完成。
<!--#set var="protocol" value="" --> # 设置变量protocol初始值 <!--#if expr="$HTTPS != /ON/" --> # 若url是 https:// 安全访问模式 <!--#set var="protocol" value="http://${SERVER_NAME}" --> # 设置变量 protocol的值 <!--#endif --> <!--#set var="protocols" value="https://${SERVER_NAME}" --> # 设置一系列变量值 当前位置的连接和文本 <!--#set var="NavTrailLink1" value="" --> <!--#set var="NavTrailLinkName1" value="" --> <!--#set var="NavTrailLink2" value="" --> <!--#set var="NavTrailLinkName2" value="" --> <!--#set var="NavTrailLink3" value="" --> <!--#set var="NavTrailLinkName3" value="" --> # 设置值时是多重if嵌套 <!--#if expr="$DOCUMENT_URI = /\/bnn\// && $DOCUMENT_URI != /\/bnn\/index.html/" --> # 如果访问/bnn/下非index.html页面 <!--#set var="NavTrailLink1" value="${protocol}/bnn/" --> # 设置一级文本和连接变量值 <!--#set var="NavTrailLinkName1" value="BNN" --> <!--#if expr="$DOCUMENT_URI = /\/bnn\/books\// && $DOCUMENT_URI != /\/bnn\/books\/index.html/" --> # 如果访问/bnn/books/下非index.html页面 <!--#set var="NavTrailLink2" value="${protocol}/bnn/books/" --> # 设置二级文本和连接变量值 如此类推 <!--#set var="NavTrailLinkName2" value="图书馆" --> <!--#elif expr="$DOCUMENT_URI = /\/bnn\/food\// && $DOCUMENT_URI != /\/bnn\/food\/index.html/" --> <!--#set var="NavTrailLink2" value="${protocol}/bnn/food/" --> <!--#set var="NavTrailLinkName2" value="好吃的" --> <!--#if expr="$DOCUMENT_URI = /\/bnn\/food\/strawberry\// && $DOCUMENT_URI != /\/bnn\/food\/strawberry\/index.html/" --> <!--#set var="NavTrailLink3" value="${protocol}/bnn/food/strawberry/" --> <!--#set var="NavTrailLinkName3" value="草莓" --> <!--#endif --> <!--#endif --> <!--#endif --> # 输出当前位置时也是多重if嵌套 <img alt="" class="display-img" height="6" src="//www.ibm.com/i/c.gif" width="1" /> <!--#if expr="$NavTrailLink1" --> <a class="bctl" href="<!--#echo var='NavTrailLink1' -->"><!--#echo var="NavTrailLinkName1" --></a><span class="bct"> > </span> <!--#if expr="$NavTrailLink2" --> <a class="bctl" href="<!--#echo var='NavTrailLink2' -->"><!--#echo var="NavTrailLinkName2" --></a><span class="bct"> > </span> <!--#if expr="$NavTrailLink3" --> <a class="bctl" href="<!--#echo var='NavTrailLink3' -->"><!--#echo var="NavTrailLinkName3" --></a><span class="bct"> > </span> <!--#endif --> <!--#endif --> <!--#endif -->
语法: <!--#directive [parm=value] -->
,指令包括:
config
:设置日期格式等,如:(<!--#config timefmt="%B %Y" -->
)echo
:打印变量值 (<!--#echo var="VARIABLE_NAEM" -->
)exec
:用来执行服务器端的命令include
:文件包含 (<!--#include virtual="file-name" -->
)flastmod
:输出指定文件最后修改时间(<!--#flastmod file="filename.shtml" -->
)fsize
:输出指定文件的大小(<!--#fzie file="filename.shtml" -->
)printenv
:打印全部环境变量(<!--#printenv -->
)set
:设置或修改变量 (<!--#set var="foo" value="Bar" -->
)if elif endif else
:建立条件分支