Contents
- はじめに
- 表示と編集機能を作る.
- 全体の流れ
- 表示(show)
- 編集(edit)
- 保存(save)
- 設置と動作確認
- ページの追加,削除,一覧とWiki記法の改良.
- 必要な仕組みの検討
- URLエンコードとページ名/ファイル名の相互変換
- initializeとoutput
- ページやURLへのリンク(show)
- 各ページの編集(edit,save)
- ページ一覧(list)
- 設置と動作確認
- Wikiの機能と仕組み
Wikiの仕組み
Wikiの仕組みをご紹介!
はじめに
こんにちは,塚本牧生です.第一回のコラムに続いての登場になります.
今回はwikiがどんな仕組みになっているか,簡単なWikiアプリケーションを元にご紹介します.今では非常に多くのWikiアプリケーションが登場していますが,根っこの部分では大体同じような仕組みを持っており,様々なWikiを見る,あるいは自分で改造や作成する時に,Wikiの勘所をつかんでいることが役に立つと思います.
表示と編集機能を作る.
Wikiの鍵となる機能は,まずページの表示,それから編集です.
図1を見てください.通常,Wikiサイトにアクセスするとまずトップページが表示されます.ページ内には「編集」「edit」などのボタンがあって,これでそのページの全文を編集することができます.この辺りで「Wikiらしい」ところも指摘しておくと,編集は管理者だけではなく,訪問者でもできます.
ソース1がこの機能を実装したPerlスクリプトのソースです.早速,どんな仕組みになっているか見ていきましょう!
全体の流れ
CGIにアクセスすると,まずmainサブルーチンが呼ばれます.mainはCGIオブジェクトを生成した後,以下の3つの作業をします.
- モードの確認.initializeサブルーチンで現在のモードを取得する.
- HTMLの生成.モードと同名のサブルーチンでHTMLデータを取得する.
- 表示データの送出.outputサブルーチンにHTMLデータを渡し,ヘッダ等を付加してクライアント(ブラウザなど)へ送らせる.
initializeでは,まずフォームデータからmodeの値を取得しています.次にこの値をチェックして,未設定,あるいは存在しないモードであればshowとみなすようにしています.
outputではHTTPヘッダ,HTMLヘッダ,ページヘッダ,</html>タグなどのHTMLフッタを生成し,引数で受け取ったHTMLデータと合わせて標準出力に出力しています.ページヘッダ以外はほぼCGIモジュールにお任せですが,ページヘッダはページのタイトルと他のモードを呼び出すためのリンク部を作りこんでいます.このデータは,HTTPサーバによってクライアントに送出されます.
表示(show)
ページを表示するためのshowサブルーチンは,以下の作業をします.
- ページデータの読み込み.
- HTMLへの変換.
データ読み込み用のpage_readサブルーチンを用意し,これで読み込んだページデータを,(2)以下の数行でHTMLに変換しています.この変換ルールは「Wiki記法」と呼ばれるのですが,Wikiアプリケーションごとに少しずつ違いがあるのが実情です.ここでは,ひとまず「ほぼそのまま表示できる」を目標に,HTMLエスケープ,改行部に<br>タグを追加,空白をそのままの幅で表示されるように<span>タグでくくる,といった変換をしています.
編集(edit)
ページを編集するためのeditサブルーチンは,以下の作業をします.
- ページデータの読み込み.
- HTMLフォームの生成.
先ほどのpage_readサブルーチンでページデータを読み込み,続いて(3)以下でHTMLフォームを生成しています.HTTPヘッダなどと同様,ここでもHTMLタグを直接書かずにCGIモジュールにお任せの形をとっています.単純なタグと違い,例えば<form>タグのmethod,action,enctypeといった属性や各フィールドのデフォルト値とそのエスケープなど,ケアするところが多い部分はモジュールに任せると楽に適切なタグを生成できます.
editモードはこのHTMLデータがmainサブルーチンに返され,outputサブルーチンでクライアントに送り出されれば終了です.
保存(save)
クライアントから送信されてきた編集データを保存するためのsaveサブルーチンは,以下の作業をします.
- ページデータの保存.
- 保存結果のHTMLデータ生成.
データ書き込み用にも専用のサブルーチンを用意しており,保存時にはこの中で文字コードや改行コードの統一もしています.また,Wikiでは「空のページデータが送られてきたらページ削除」というルールが広く使われていますので,ページデータが空の時はファイルを削除します.(4)でこのサブルーチンを呼び出し,返り値で保存結果を受け取っています.
saveモードは,この保存結果をHTMLエスケープしたデータがmainサブルーチンに返され,outputサブルーチンでクライアントに送り出されれば終了です.
設置と動作確認
これでひとまず「表示と編集機能を持つCGI」ができました.ちゃんと動作するか,実際に設置してみてください.設置方法は一般的なCGIと同じで,簡単にまとめると次のようになります.
- 先頭行のPerlのパスを修正する.
- サーバーにアスキーモードで転送する.
- 実行権限を付加(パーミッションの変更)する.
- 現在のディレクトリに書き込み権限があることを確認しておく.
このスクリプトではCGI,CGI::Carp,そしてJcodeモジュールの3つを使用しますが,Jcodeモジュールは入っていないISPなども見かけます.この時は,CPANからJcodeモジュール(http://search.cpan.org/dist/Jcode-0.88/)のtarボールを入手し,図2のように配置してみてください.
これで,ページの表示,編集,保存ができれば動作確認は完了です.
ページの追加,削除,一覧とWiki記法の改良.
もう一つ,Wikiの鍵となるのはページを追加できることです.
図3を見てください.まずページが複数になるので,ページの一覧が必要です.最初はトップページだけですが,addというリンクからページを追加できます.追加後に一覧を表示すれば,このページも表示されます.もちろん,これらも訪問者でも自由にできます.それから,ページ間でリンクを張れるようにもしましょう.
こうした機能を追加したのがソース2です.さあ,どんな仕組みになっているか見ていきましょう!
必要な仕組みの検討
ソース1をベースに,次のような修正をします.
- ページごとにデータファイルを分ける.
- リンクURLにページ名を加える.
- 編集フォームに,ページ名のフィールドを追加する.
- モードにtop(トップページに移動),add(ページ追加),list(ページ一覧)を追加する.
- ページ名やURLをリンクに変換して表示する.
データファイルを分けるにはページ名とファイル名の対応付けが必要です.また,URLにページ名を含めるには,ページ名をURLエンコードする必要があります.まずこうしたサブルーチン群を用意するところから始めます.
URLエンコードとページ名/ファイル名の相互変換
まず,URLエンコード用にはencodeURLサブルーチンを用意します.ロジックは一般的なものです.
次にページ名/ファイル名の相互変換を考えることにします.ここではYukiWikiなどに倣って,次の手順でファイル名を決めることにします.
- ページ名の文字コードをeucに変換する.
- アルファベットとアンダーバー以外はURLエンコードの要領で変換する.
これを行うためのサブルーチンがget_file_nameで,引数でページ名を受け取り,ファイル名を返します.ただし,ページ名が渡されなかった時などはundef(未定義)を返します.同様に,逆の変換を行うget_page_nameも用意す.
ここで,ページの読書きをする部分も直しておきましょう.page_read,page_writeの二つのサブルーチン内で,ファイル名を決定している(7)と(7')の部分を,get_file_nameで取得するように書き換えるだけです.
initializeとoutput
initializeでは,モードが増えたことへの対応と,ページ名についてもチェックを行うようになりました.特にtopはトップページに対するshowと同じ,addは新規ページに対するeditと同じとみなして,モードとページを置き換えていることに注意してください.こうすることで,この二つのモードには専用のサブルーチンを作成せずに済ませています.
initializeでもう一点注意して欲しいのは,(2)と(2')の処理です.PerlのTipsになりますが,paramメソッドではCGIオブジェクトから値の取得するだけではなく,セットもできます.ここで再設定済みのモードとページ名をセットしてやると,他のサブルーチンではCGIオブジェクトからこの値を取得できるるので,いちいち引数で受け渡すような煩雑なことを避けられます.
outputでは,タイトル部にページ名も表示する,ページヘッダにtop,list,addなどのモードへのリンクも表示するといった修正をしています.(3)と(3')では,URLにページ名を含めるようになっています.
ページやURLへのリンク(show)
いよいよモードの修正や追加を行います.まず,各ページや,外部URLにリンクを張れるようにします.
まず変換ルールを決めましょう.Wikiでは伝統的に「大文字で始まる2語以上の単語を連結したもの」をWikiNameと呼び,これを同名のページへのリンクします.しかし,これだとページ名が日本語のページにリンクできないので,日本語圏のWikiではさらに""と"
"で挟まれた語をブラケットネームと呼び,同様に扱うのが一般的です.この二つをページへのリンクとし,さらにURLが書かれていればこれもリンクに変換することにしましょう.
「変換ルールを追加する」ことなので,showサブルーチンを修正します.まずURLはそのままリンクに,WikiNameやブラケットネームはそのページを表示するためのリンクに変換する,conv_to_linkというサブルーチンを用意しました.(4)から(4')の部分でWikiName,ブラケットネーム,URLにマッチする正規表現を用意し,マッチした部分をこのconv_to_linkで変換しています.
各ページの編集(edit,save)
次に,編集時に保存ページ名を指定できるようにします.デフォルト値を現在のページ名とすれば,ページ編集にもページ追加にも対応できるでしょう.
この修正は,editサブルーチンの(5)の'page'という名前のフィールドを追加する作業一つで済みます.デフォルト値については,CGIオブジェクトがフォームデータから取得してくれます.その後の保存については,page_writeサブルーチンが修正済みですので,特に修正の必要はありません.
ページ一覧(list)
ページを一覧を表示するためのlistサブルーチンは以下の作業をします.
- 既存ページ名の取得.
- 一覧HTMLデータの生成.
既存ページ名の取得にはget_page_listというサブルーチンを用意しました.これはデータディレクトリ内の全ファイル名を取得し,これをページ名に変更し,ソートしたものを返します.(6)でこれを呼び,各ページ名に対してテーブル行を生成して,テーブルとして返すところまでがlistサブルーチンの作業です.
返されたHTMLデータはoutputサブルーチンでブラウザ等に送られ,listモードの処理が完了します.
設置と動作確認
これで簡単なものですがWikiアプリケーションができました.設置方法はソース1とほぼ一緒ですが,図4のようにCGI本体と同じディレクトリ内に「data」というディレクトリを作成し,書き込み権限を与えてください.
これで,一通りの機能が使えるか,確認してみてください.
Wikiの機能と仕組み
ここまででWikiの基本となる機能と,その仕組みをご紹介してきました.
Wikiのキーとなる機能は,まずページの編集,追加,削除ができること.ページの一覧などが見られること.そしてページ編集時にリンクなどをWiki記法と呼ばれる簡単な書き方でできること,とこんなところでしょう.これを実現している仕組みは,まず表示,編集,保存,一覧などの動作モード.ページ名に紐付けたページデータの保存方法.Wiki記法の実体である,テキストからHTMLへの変換ロジックといったものがあります.
もちろん,実際には機能はこれだけというWikはまず見当たりません.ですが,ポピュラーな機能を見ていくと,例えば表示時にCSSやサイドバーといったものが利用できたり,一覧が更新日付順に出たりRSS形式になったり,コメント機能が付加されたりと,ほとんどはここまで出作り上げた仕組みに,ちょっとづつ手を加えて作り上げられることに気づくはずです.実際に,今回のサンプルコードが160行ほど,私の配布しているWalWikiがメインスクリプトだけで2,000行超ですが,処理の大枠は同じような流れです.
第三回からは,様々なWikiアプリケーションとその活用事例が出てきます.その時に今回のサンプルと見比べていただくと,そこで登場する機能や仕組み,活用の工夫が「どんなにオリジナリティあるものなのか」が分かり,より深く味わっていただけると思います.


