とほほのSSI入門

目次

SSIとは?

SSI は Server Side Includes の略です。HTML文書中に以下のようなコメントを挿入することにより、サーバー側がコメントの場所に外部ファイルやコマンドの実行結果を置き換えてくれたりする機能です。

<!--#exec cmd="/usr/bin/ls -l" -->

SSI により、例えば次のようなことが可能になります。

SSIの使用準備

SSI を使用するには、WWW サーバーが SSI をサポートしており、SSI を許可する設定が行われている必要があります。サーバーが Apache の場合は httpd.conf に下記を追記してサーバーを再起動してください。

<Directory "/var/www/html">
    (略)
    #
    # SSI
    #
    Options +Includes
    AddType text/html .shtml
    AddOutputFilter INCLUDES .shtml
</Directory>

SSIの使用例

SSI を埋め込むファイルの拡張子は .shtml にする必要があります。

example.shtml

下記の例はファイルの最終更新時刻を表示します。

このファイルは
<!--#config timefmt="%Y/%m/%d %X" -->
<!--#echo var="LAST_MODIFIED" -->
に更新されました。

下記はダウンロードファイルの最終更新日とサイズを表示します。

<a href="xxx.zip">xxx.zip</a>
(<!--#config timefmt="%Y/%m/%d" -->
<!--#flastmod file="xxx.zip" --> 更新,
<!--#config sizefmt="abbrev" -->
Size:<!--#fsize file="xxx.zip" -->)
をダウンロードしてください。

ヘッダ/フッタを指定します。

<doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Sample Page</title>
</head>
<body>
<!--#include file="header.html" -->
本文
<!--#include file="footer.html" -->
</body>
</html>

ディレクティブ

ファイル読みこみ(#include)

<!--#include file="~" -->

<!--#include virtual="~" -->

指定したファイルの中身を読込んで表示します。file="~" の ~ にはファイル名を指定します。../ や絶対パス名は使用できない場合があります。virtual="~" の ~ には指定するファイルの仮想パス名(「http://サーバー名/パス名」の「/パス名」の部分)を指定します。

<!--#include file="header.html" -->
          :
<!--#include file="footer.html" -->

onerror 属性でファイルが見つからなかった場合に表示するエラーファイルを指定することができます。

<!--#include file="header.html" onerror="error.html" -->

ファイルサイズ(#fsize)

<!--#fsize file="~" -->

<!--#fsize virtual="~" -->

指定したファイルのサイズを表示します。表示のフォーマットは <!--#config sizefmt="..." --> で指定したものに従います。file="~"virtual="~" の説明は #include と同様です。

<!--#config sizefmt="abbrev" -->
<a href="xxx.zip">ダウンロード</a>
(サイズ:<!--#fsize file="xxx.zip" -->)

最終更新時刻(#flastmod)

<!--#flastmod file="~" -->

<!--#flastmod virtual="~" -->

指定したファイルの最終更新時刻を表示します。表示のフォーマットは <!--#config timefmt="..." --> で指定したものに従います。file="~"virtual="~" の説明は #include と同様です。

最終更新日:<!--#flastmod file="this.html" -->

変数表示(#echo)

<!--#echo var="~" -->

指定した環境変数の値を表示します。~ には LAST_MODIFIED などの環境変数名を指定します。

最終更新日:<!--#echo var="LAST_MODIFIED" -->

環境変数名には次のようようなものがあります。

環境変数意味
DOCUMENT_NAMEこの文書のファイル名(ssi.html)
DOCUMENT_URI文書の仮想パス名(/ex/ssi.html)
QUERY_STRING_UNESCAPEDWWWクライアントから検索用に送信された文字列。いくつかの記号文字(UNIXのシェルのメタ文字)はパックスラッシュ( \ )でエスケープされているので注意。
DATE_LOCAL現在の時刻(ローカル時刻)
DATE_GMT現在の時刻(グリニッジ標準時)
LAST_MODIFIEDこの文書の最終更新時刻

サーバーによっては、「CGIスクリプトが参照可能な環境変数」も表示できます。時間の表示は <!--#config timefmt="..." --> で指定したフォーマットに従います。

encoding 属性を指定することもできます。規定値は entity です。

decoding 属性を指定することもできます。規定値は none です。

decodingencoding 属性は var 属性よりも先に記述してください。

<!--#echo decoding="base64" encoding="url" var="QUERY_STRING" -->

環境変数表示(#printenv)

<!--#printenv -->

使用可能な環境変数の一覧を表示します。Apache 1.2 以上のバージョンで使用できます。printenv--> の間にスペースを忘れないでください。

<pre>
<!--#printenv -->
</pre>

変数設定(#set)

<!--#set var="~" value="~" -->

変数 ~ に、値 ~ を代入します。Apache 1.2 以上のバージョンで使用可能です。

<!--#set var="msg" value="Hello!!" -->
<!--#echo var="msg" -->

#echo と同様に encoding, decoding 属性を指定することができます。

コンフィグ(#config)

<!--#config errmsg="~" -->

文書処理中にエラーが発生した場合のエラーメッセージを指定します。これはWWWサーバーのエラーログにも記録されます。

<!--#config errmsg="ERROR!!!!!!" -->
<!--#include file="no-file.html" -->     # ファイルが存在しないエラー

<!--#config sizefmt="~" -->

#fsize コマンドなどで表示されるファイルサイズのフォーマットを指定します。~ に bytes を指定するとバイト単位で、abbrev を指定すると Bytes, KBytes, MBytes などの適切な単位で表示されるようになります。

<!--#config timefmt="~" -->

#echo コマンドなどで時刻を表示する際のフォーマットを指定します。~ には %Y/%m/%d %H:%M:%s などの文字列を指定します。 %Y%m は次のような意味を持ちます。

置換文字表示例意味
%c10/30/97 11:22:33月/日/年 時:分:秒
%x10/30/97月/日/年
%X11:22:33時:分:秒
%y97年(2桁)
%Y1997年(4桁)
%bOct月(3文字)
%BOctober月(フルスペル)
%m08月(2桁)
%aSat曜日(3文字)
%ASaturday曜日(フルスペル)
%d30日(2桁)
%j2231月1日からの日数
%w6日曜日からの日数
%pPMAMもしくはPM
%H23時(24時間制)
%I11時(12時間制)
%M44
%S56
%ZJSTタイムゾーン

<!--#config echomsg="~" -->

#echo で未定義の変数を出力しようとした際のエラーメッセージを設定します。

<!--#config echomsg="ERROR: Unknown parameter." -->
<!--#echo var="UNDEFINED_PARAMETER" -->             # 変数が存在しないエラー

コマンド実行(#exec)

<!--#exec cmd="~" -->

<!--#exec cgi="~" -->

~ で指定したコマンドやCGIを実行し、その結果を表示します。cgi="..." で呼び出す際は、CGI側で Content-type: text/html などのヘッダを出力してやる必要があります。

<!--#exec cmd="/bin/ls -l" -->
<!--#exec cgi="/cgi-bin/count.cgi" -->

cmd="~" に引数(arg1, arg2, ...)を引数を渡す場合は次の様に指定します。

<!--#exec cmd="command.pl arg1 arg2" -->

cgi="~" にも引数を渡してみたかったのですが、下記の様に指定したり、@ARGV を参照したり $ENV{"QUERY_STRING"} を参照したりなどいろいろ試してみたのですがうまく渡せませんでした。

× <!--#exec cgi="/cgi-bin/test.cgi arg1 arg2" -->
× <!--#exec cgi="/cgi-bin/test.cgi?arg1+arg2" -->

制御構文(#if, #elif, #else, #endif)

<!--#if expr="~" -->

<!--#elif expr="~" -->

<!--#else -->

<!--#endif -->

条件によって表示する内容を制御します。if, elseif, else は、もし、さもなくばもし、さもなくばを、 endif は条件式の終わりを意味します。以前は下記のような書式で記述していました。(参考↗)

<!--#if expr="$HTTP_USER_AGENT = /(iPhone|iPod|Android|Windows Phone)/" -->
  スマホですね
<!--#else -->
  パソコンですね
<!--#endif -->

最近は下記のような記述に代わっているようです。(参考↗)

<!--#if expr="%{HTTP_USER_AGENT} =~ /(iPhone|iPod|Android|Windows Phone)/" -->
  スマホですね
<!--#else -->
  パソコンですね
<!--#endif -->

SSIの注意点

使えると便利な SSI ですが、いくつか注意点があります。

パフォーマンスの注意点

下記の様に .html を追記すると .html に対しても SSI を埋め込むことができるようになりますが、SSI 対象となるファイルは Web サーバーがファイルの終端までを読み込み、SSI 処理の有無を確認する必要があるため、パフォーマンスに影響を与えてしまいます。

<Directory "/var/www/html">
        :
    Options +Includes
    AddType text/html .shtml .html
    AddOutputFilter INCLUDES .shtml .html
</Directory>

必要なファイルのみ拡張子を .shtml として SSI 対象とするようにしてください。XBitHack ディレクティブ(↗) を指定すると +w ビットを立てた .html ファイルのみを SSI 対象とするとありますが、AlmaLinux 9 + Apache 2.4.62 環境ではうまく動作させることができませんでした。(誰かうまく設定できたら教えてください)

セキュリティの注意点

SSI を使用可能にしたファイルが クロスサイトスクリプティング(XSS) 攻撃を受けてしまうと、サーバー側に任意の悪意のあるコマンドが実行されてしまい、非常に危険な状態になります。

<article>
  <h3>このサーバーは乗っ取ったぞ</h3>
  <p>このサーバーは XSS 問題を含んでいるので、
  <!--#exec cmd="/usr/bin/cat /etc/passwd" -->
  こんなコマンドも実行できちゃうね。</p>
</article>

SSI を使用する際はセキュリティに十分な注意を払ってください。

参考文献