Apache SSI 摘要
SSI是Server-Side Inclues的縮寫。 其意為,提供一個可含括(Includes)在html文件的控制指令,並能在伺服端(Server-Side)加以解析的功能。在閱讀本文前,我假設各位跟我一樣,了解SSI的用途,曾閱讀過Apache所提供的SSI文件(Module mod_include),並在使用時,和我碰到一樣的困擾。
目錄
指令(Elements)列表
案例問答
前言
SSI是Apache中,一項基本的網頁內容程式化機制,但不知是文件寫的太簡單,還是我不習慣,SSI的語法對我來說,可還真是獨特,我花了許多功夫才搞清楚要如何撰寫。
但是在實際使用過後,才發現SSI其實是一項非常方便的功能,利用幾個簡單的控制動作,就可以做到許多人用CGI或一些Server-Side Script所要做的事。 我主要在利用其控制網頁內容的版面。
在閱讀本文前,我假設各位跟我一樣,了解SSI的用途,曾閱讀過Apache所提供的SSI文件(Module mod_include),並在使用時,和我碰到一樣的困擾。
什麼是SSI
SSI是Server-Side Inclues的縮寫。 其意為,提供一個可含括(Includes)在html文件的控制指令,並能在伺服端(Server-Side)加以解析的功能。
啟動SSI
啟動SSI的控制權在網頁主機管理者的手上,一般使用者請去函詢問。
網頁主機管理者,可利用下列指令查詢你的httpd server是否支援SSI功能:
# httpd -l
若是組態設定檔(通常是 httpd.conf)中,是否載入了 mod_include 的 module:
LoadModule includes_module path_of_your_module/mod_include.so
若其中包含了 mod_include ,則 httpd server 可支援 SSI 。
而以下的指令,將影嚮各網頁提供者,對 SSI 功能使用上的限制。
AddType/AddHandler
Apache 建議在組態設定檔中,加上下列兩項設定指令,以提供 SSI :
AddType text/html .shtml AddHandler server-parsed .shtml
第一行在指示將 .shtml 的文件之 MIME 型態,視為 text/html ,即一般的 HTML文件。 這表示了 SSI 只能用在 HTML文件中,你無法在非 HTML文件中,如純文字文件中使用,因為只要碰到這種檔案, http server 一律是回傳 text/html型態給瀏覽器。 而第二行在指示,將 .shtml文件,交給 server-parsed 這個 handler 去處理,這個 handler 將讀取 .shtml文件的內容,將一般的文字直接送給瀏覽器,而碰到 SSI 指令時,則先解析,再將執行後的結果送給瀏覽器。
為了相容前版的使用,其 MIME TYPE 被設定為 text/x-server-parsed-html
或 text/x-server-parsed-html3
者,亦會被解析。
除了利用副檔名來判別外,尚可利用檔案屬性的 execute 位元來決定。 這要利用 XBitHack 指令來設定。 當 XBitHack On 時,具有 user execute 位元的一般html文件,亦將被解析。 當 XBitHack Full 時,也會將具有 group execute 位元的一般html文件,交由 SSI 解析。
Options
光是加上 handler 的指示尚不足,還必須要以 Options 指令,指示可使用 SSI 的範圍。 一般是用在 <Directory> 區段中,但若有設定 AllowOverride Options 時,也允許在 .htaccess 檔案中使用 Options 指令。
若想提供此範圍完整的 SSI 功能,加上指令 Options Includes (只提供 SSI 功能),或 Options +Includes (在原有功能上,再加上 SSI 的功能), Apache 的老手該了解,有無 '+' 號的意義並不相同。
若提供 SSI 功能,但不希望使用 SSI 的 #exec 及 #include 指令時,可在 Options 後面再加上 +IncludesNOEXEC 的設定。
基本指令
在原文件中,將 SSI 的控制字彙,稱為 Elements ,不過一般來說,我們都把它當指令看待。
SSI 根據 SGML 文件的說明,使用下列語法:
<!--#element attribute="value" attribute="value" ... -->
要注意的是,屬性值必須要用雙引號括號,不可省略。 而終端符號 (-->) 前,必須要有一個空格。
指令(Elements)列表
config
控制指令的輸出結果。屬性(attribute)有下列可用:
- errmsg
當 SSI指令執行有誤時,傳回給瀏覽器的訊息。 - sizefmt
檔案大小的輸出格式。若屬性值為 "bytes" ,則以 bytes 為大小輸出單位。若屬性值為 "abbrev" ,則以 KB 或 MB 為大小輸出單位。 - timefmt
設定時間的輸出格式。其屬性值為一格式表示字串,此字串的格式表示內容,與 strftime(3) 一致,請參考 strftime(3) 的 manpage 。
例:
<!--#config errmsg="SSI Error" sizefmt="abbrev" timefmt="%b %d, %Y" -->
以 KB 或 MB 為大小輸出單位。使用美式時間格式(月 日, 年)。
echo
印出一個變數的值,若變數未設定,則印出 (none) 。 屬性有:
- var
屬性值是變數的名稱。 變數名稱前,不加 '$' 符號。
例:
<!--#echo var="QUERY_STRING" var="REMOTE_HOST"-->
exec
執行一個 shell 命令或 CGI script。 命令或 script 的輸出將被印出。 屬性有:
- cgi
執行一個 CGI script , script 的位置,必須用 URL 表示法。 而 PATH_INFO 及 QUERY_STRING 的內容,是來自瀏覽器送給該.shtml文件的值,不能把它寫在 script 的 URL 中。 若 CGI script 傳回了一個 Location: 的 header 時 (這表示要轉導向別的文件) ,將被轉換成一個 <A> 標籤表示。 - cmd
呼叫 /bin/sh 執行這個字串中的命令。
SSI所定義的變數,將透過環境變數,傳遞給命令或 script 。例:
Document loaded on <!--#exec cmd="/bin/date" -->
fsize
印出指定檔案的大小。 屬性有:
- file
一個檔案,其路徑不可超出目前文件的路徑。 - virtual
一個以 URL 路徑表示的文件,其路徑不可以 '/' 開頭。
例:
<!--#fsize file="download/xyz.tar.gz" -->
flastmod
印出指定文件的最後修改時間。 屬性值跟 fsize 一樣。
include
將其他文件的內容插入目前文件中。 若其他文件是可執行的檔案,則像 exec 一樣地執行該檔案後,將其輸出結果插入文件中。
若只想提供插入其他文件內容的動作,而不想提供執行的動作,則可利用 Option +IncludesNOEXEC 設定限定之。
屬性有:
- file
插入一個一般檔案的內容。 - virtual
插入一個 URL 指示的文件的內容。
屬性值的注意事項與 exec 相同。例:
<!--#include file="my_head.inc" -->
printenv
印出目前所有變數的值,沒有屬性。 這算是一個純測試用功能,實用性不大。例:
<!--#printenv -->
set
設定一個變數。
屬性有:
- var
指定變數的名稱。 - value
指定該變數的值。
例:
<!--#set var="myvar1" value="123" --> <!--#set var="myvar2" value="${myvar1}.html" --> <!--#echo var="myvar2" -->
變數
若要在 value 中引用其他變數的值時,須在變數名稱前加上 '$' 符號,若變數名稱後沒有空格來分隔一般字元的話,請用 '{ }' 括起欲引用的變數名稱。
環境變數將自動成為 SSI 中可用的變數,亦可使用 #set 自定變數。 SSI 中的變數,也能給被呼叫的程式參用。
下面是 SSI 額外提供的變數:
- DATE_GMT
現在的格林威治標準時間。 - DATE_LOCAL
現在的本地時區時間。 - DOCUMENT_NAME
不包含目錄的檔案名稱。 - DOCUMENT_URI
被索求的文件的 URL 。 - LAST_MODIFIED
目前文件的最後修改時間。
流程控制指令
流程控制指令可讓我們選擇性的印出網頁的內容,而不是將所有內容都送往瀏覽器。
<!--#if expr="test_condition" --> <!--#elif expr="test_condition" --> <!--#else --> <!--#endif -->
#if 和 #endif 必須成對表示,不可省略後面的 #endif 。
流程控制指令中,最麻煩的是 test_condition 的寫法,整個 test_condition 必須被雙引號括起,而要在 test_condition 中表示一個字串時,該字串也必須用單引號或雙引號括起,這時在字串的雙引號前,就要加上 '\' 符號才行,因此,一個字串比較的 test_condition 往往以 "\"$DOCUMENT_URI\" = \"abc/foot.html\"" 的難看型式表示。
有下列的 test_condition
- string
若 string 不是空的,即為 true 。 - string1 = string2
- string1 != string2
- string1 < string2
- string1 <= string2
- string1 > string2
- string1 >= string2
比較 string1 和 string2 ,若 string2 是以 '/ /' 括起的,則表示使用常規表示法(regex)來比較。
可以使用 (), !, &&, 和 || 來組來多個 test_condition 。例:
<!--#if expr="$QUERY_STRING" --> I get a query string. <!--#if expr="'$QUERY_STRING' = '/^[0-9]/'" --> NUMBER. <!--#elif expr="'$QUERY_STRING' = '/^[a-zA-Z]/'" --> ALPHA. <!--#else --> SPECIAL. <!--#endif --> <!--#endif -->
案例問答
- Q1: 是由我的router偵測,資料秀在螢幕上??還是我router的專屬網站執行程式透過router讀取到訊號強度才秀在螢幕上的呢??
- Q2: 如果是由專屬網站執行程式才做到這個顯示訊號強度的功能,是否我不連到那個網站就不會有這個顯示訊號強度的功能
- Q3: 「啟動SSI的控制權在網頁主機管理者的手上」是指我的router還是router的專屬網站???
Q1 跟 Q2 實際上是一個問題。流程如下:
- Browser 閱讀 web server 上的 html 文件 (包含 SSI 語法), web server 依 html 文件中的 SSI 指令啟動訊號強度偵測程式,訊號強度偵測程式向 router 查詢訊號強度後,將輸出結果透過 web server 傳送給 Browser 。
-
router 和 web server 之間必須能進行連線,訊號強度偵測程式的存放位置可以有下列情形:
- router 有專屬的通訊協定可以查詢訊號強度,則強度偵測程式應該放在 web server 上,偵測程式透過 router 專屬通訊協定向 router 查詢訊號強度。
-
router 本身亦提供 http 服務,則偵測程式即可以放在 router 上也可放在 webserver 上。但 SSI 語法必須要用
<!--#include virtual="http://your.server.which.you.put.cgi/cgi-bin/wireless_single_detect.cgi" -->
example: browser open http://your.webserver.com/welcome.html ---[welcome.html]--- <html> <body> <img src="<!--#include virtual='http://your.server.which.you.put.cgi/cgi-bin/wireless_single_detect.cgi' -->" /> </body> </html> --------------------
wireless_single_detect.cgi 查詢訊號強度後,將訊號強度以圖形格式 (image/jpeg or image/gif) 輸出。附帶一提,在這種作法下,使用者也可以用 browser 直接啟動這支 cgi 而得到一張訊號強度圖,請特別注意 cgi 的安全性問題。
關於 Q3 :
- 觀念一: html 文件要放在 web server (網頁主機) 上,才能透過網頁被瀏覽閱讀。
- 觀念二: 如果想要在 html 文件中使用 SSI 語法的話,必須要 web server 的管理者在設定檔中 (httpd.conf) 開啟 SSI 的選項。
你的 router 和 web server 是同一台主機嗎?再者,你有權限修改 web server 的設定嗎?「網頁主機」指的是 web server 。在某些使用者權限劃份明確的組織裡,就算 router 和 web server 是安裝在同一台電腦主機中, router 的管理者也可能沒有權限修改 web server 的設定,而要與 web server 的管理者協調後,再由 web server 管理者修改。