読者です 読者をやめる 読者になる 読者になる

YukiWikiMiniのコードを読んでみよう

Wikiってあんまりちゃんと触ったことないなぁ・・・


というわけではてなの人や多くのWiki制作者に多大な影響を与えたYukiWikiのコードを読んでみよう。
http://www.hyuki.com/yukiwiki/
まずはminiから・・・


解凍してみる。ファイルは4つしかない。

[mikeda@cent ykwk]$ unzip ykwkmini_102.zip 
Archive:  ykwkmini_102.zip
  inflating: ykwkmini.cgi            
  inflating: .htaccess               
  inflating: ykwkmini.txt            
  inflating: jcode.pl

CGI本体はykwkmimi.cgi。先頭のperlのパスは必要に応じて修正。


改行コードがCrLfなので修正しておく。
そのままだと「Premature end of script headers」というエラーがでる。先頭のperlの後に「 -」を足すだけでも可。

[mikeda@cent ykwkmini]$ cat -A ykwkmini.cgi 
#!/usr/bin/perl^M$
#^M$
# YukiWikiMini Version 1.0.2^M$
....
[mikeda@cent ykwkmini]$ perl -i -pe 'tr/\r//d' ykwkmini.cgi
[mikeda@cent ykwkmini]$ cat -A ykwkmini.cgi | head
#!/usr/bin/perl$
#$
# YukiWikiMini Version 1.0.2$
#$
...

それじゃCGIの中身を見てみよう。定数宣言の後に以下のコード。
フォームデータと保存データの定義。jcode.plの読込み。main関数の実行。終了。

my %form;
my %database;

require 'jcode.pl';
&main;
exit(0);

メイン関数はこんな感じ。

sub main {
    &init_form;
    &sanitize_form;
    foreach (keys %form) {
        if (/^($WikiName)$/) {
            $form{mycmd} = 'read';
            $form{mypage} = $1;
            last;
        }
    }
    unless (dbmopen(%database, $dbname, 0666)) {
        &print_error("(dbmopen)");
    }
    $_ = $form{mycmd};
    if (/^read$/) {
        &do_read;
    } elsif (/^write$/) {
        &do_write;
    } elsif (/^edit$/) {
        &do_edit;
    } elsif (/^index$/) {
        &do_index;
    } else {
        $form{mypage} = $frontpage;
        &do_read;
    }
    dbmclose(%database);
}


まずは最初に呼ばれてるinit_form関数。

sub init_form {
    my ($query);
    if ($ENV{REQUEST_METHOD} =~ /^post$/i) {
        read(STDIN, $query, $ENV{CONTENT_LENGTH});
    } else {
        $query = $ENV{'QUERY_STRING'};
    }
    my @assocarray = split(/&/, $query);
    foreach (@assocarray) {
        my ($property, $value) = split /=/;
        $value =~ tr/+/ /;
        $value =~ s/%([A-Fa-f0-9][A-Fa-f0-9])/pack("C", hex($1))/eg;
        &jcode'convert(\$value, $kanjicode);
        $form{$property} = $value;
    }
}
  1. クエリストリングの読込み。POSTの場合は標準入力から、GETの場合は環境変数から。
  2. フォームデータの取り出し。(クエリストリングを&でsplit)
  3. コントロール名と値に分割。(=でsplit)
  4. URLエンコードを復元
    1. 「+」を半角スペースに
    2. 「%16進文字コード」を文字に戻す
  5. 文字コードを変換
  6. ハッシュ(%form)にセット


今日はここまで。