だれかがamezo.cgiの説明をしてくれたので、HTMLにして見やすくしてみました。
やっぱり、全体を把握した方が、改造しやすいです。
一通り感謝の気持ちをこめて、熟読せよ!!
http://sv.amezor.net/~bbs/support/000702172024.html

はじまりです。まちがってたら。掲示板に。書きこんでくれたらありがとう



#!/usr/bin/perl

perlがおいてあるディレクトリの指定。 どの鯖をつかうかにによって変わる。
amezor.netの場合は、そのままでいい(のかな?)


require 'jcode.pl';

日本語文字コードを変換するパールスクリプト(jcode.pl)の呼びだし。
パスの指定をすれば、別ディレクトリでもいいけど、
めんどいから同じディレクトリに置いとけば、書きかえる必要はない。


$copyright = <<EOL;
<!-- Script for amezo-like BBS
Copyright (C) 1999-2000 amezo_
http://www17.big.or.jp/~amezo_/
-->
EOL

スカラー変数($copyright)に、 html表示ではコメント文として表示されないようにして スクリプトの著作権表示を代入している。 162行目で使っている。 一回しか使わない変数だけど、スクリプトの著作権表示の意味もあるから この位置に置かれているのだろう。 礼儀として、ここは、絶対に書き換えないものなのだろう。 スクリプトをいじったら、ここは書きかえるんじゃなくて、書き加えるってことなのだろう。

プラスコメント:今はアドレスをhttp://ame.x0.com/に変えるべきですね。移転したから。
ソースに表示するのもカッコイイが、HTMLの右下に著作権表示+リンクの方がメジャーかなと思って
私が改造したときはそっちにも著作権表示を書きこみました。

$amezo = '@あめぞう(仮)';

''のなかをてきとーに変える 。

$urlbase = 'http://www17.big.or.jp/~amezo_/';

''のなかを、自分がアメスクをおいたURLに変える。

$admin = 'サポート';

''内を、管理者名に変える。

$ENV{'SCRIPT_FILENAME'} =~ /\/([^\/]+)$/;
$cgi = $1;
if($ENV{'REQUEST_METHOD'} eq 'GET'){
print "Content-type: text/plain\n\n";
open(R, "./$cgi");
print while <R>;
close(R);
exit;
}

上の二行は、自分のファイル名を取得するのに必要。 あとの部分は、自分自身を表示するため。


つまり、amezo.cgiが自分自身のソースを表示するわけです。これは配布を前提にしているので、自分で使うときは
このいろ の部分は消してもいいと思います。消した方がいろいろと安全ですね。


19投稿者:IKeJI 投稿日:07月07日(金)22時14分34秒

その処理は、いうならば「ハッカーだましい」です。
このすばらしいスクリプトを公開しましょうっていう処理です。

このように、サポートさんはハカーです。

read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
length($buffer) > 5000 && &error('投稿内容が大きすぎます');

カキコを読みこんで、長すぎたらサブルーチンに 「投稿内容が大きすぎます」って引数渡して、 errorサブルーチンよびだして、「投稿内容が大きすぎます」を表示させる。 「投稿内容が大きすぎます」は書き換えてもいい。 「もっと短く書いてね」とか、 ただし、''を間違って削除しちゃだめ

$referer = $ENV{'HTTP_REFERER'};
$referer =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$referer =~ /^$urlbase([\w\.\-]+)/ || &error('エラー');
$folder = $1;

2行目(通しで29行目)は、おまじないだから、気にしない 3行目(通しで30行目)で、動いているディレクトリを$1にとりこんで後の作業に使うためのフォルダ(ディレクトリ)を次の行で$folderに代 入してる 3行目(通しで30行目)の「エラー」は、書き換えてもいい。

@pairs = split(/&/,$buffer);
foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair);
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
&jcode'convert(*value,'sjis');
$value =~ s/&/&/g;
$value =~ s/\"/"/g;
$value =~ s/ $value =~ s/>/>/g;
$value =~ s/\r\n/\r/g;
$value =~ s/\n/\r/g;
$value =~ s/\r/ /g;

$form{$name} = $value;
}

26行目でスカラーとして読みこんどいたカキコを「&」つー文字で区切って@pairsつー配列を作る その配列を、「=」つー文字で区切って、後でカキコを処理するためのハッシュをつくってる ん?なんか説明が違うかも。

つーか、ここら辺はいろいろとHTMLの表現のあれでコレだから、本物を見たほうがいいです。
とくに、赤い部分は表示されている所と、本物のソースで違います。面倒臭い。

19投稿者:IKeJI 投稿日:07月07日(金)22時14分34秒

この部分は「お決まりの処理」ですましてもイイかもしれません。 ようするに、投稿されたモノの中の日本語を正確に表示し、 タグを無効化する処理です。

$name = $form{'name'};
$mail = $form{'mail'};
$comm = $form{'comm'};
$subj = $form{'subj'};
$folder = $form{'folder'} if $form{'folder'};
$res = $form{'res'};
$form{'sub'} && &res;

ここも「お決まりの処理」つーことですね。 5行目(通しで53行目)は、ハッシュformのキーfolderに値が入っていれば、スカラーfolderを作るってことかな? 最後の行(通しで55行目)は、ハッシュformのキーsubに値が入っていなければ、レスのサプルーチンresを呼び出すってことかな? そのsubは、後に220行あたりで、出てくる。まだ、よく読んでないので、何に使われているかわからない。たぶん、ページ数と関係して いる。

$next = $form{'next'};
$next = 1 if !$next;
$next += 20;

ここは、あめざーには見なれた、〈「次のページへ」[21]〜〉ってところの数字を作ってる。 2行目(通しで57行目)は、前の行で取得したスカラーnextが0のときだけ、スカラーnextに1を代入するってことなんだろうなぁ? んで、この2行やってから、スカラーnextを20増やしているのが三行目。

$reload = 1 if $name eq $subj && $name eq $comm;
$reload = 1 unless $name || $subj || $comm;

これは、説明がないぞコラ。とりあえず、投稿者と題名とコメントが同じだったら、または、それらすべてが空白だったら$reloadに1が代入されて、amezo.cgiがただのリロードと同じになるということです。なぜリロードと同じになるかはこのまま読めばわかるはず。もしくは飛んでみて

@a = ($comm =~ /<br> /g);
(@a + 0 > 20 || $comm =~ / ̄ ̄/) && &error("コメントが長すぎます");
$name =~ s/ | //g;


上の2行は、カキコが長すぎるときのカキコを防いでいる。 2行目(通しで62行目)の20を別の数字に変えると、カキコの上限を変更できるのだろう。 感心するのは、カキコの全体の長さではなく、行数で、長すぎるかを判断しようっていう発想。 3行目(通しで63行目)は、投稿者欄の空白を削除してるんだろうけど、なぜここで?

$x = $subj.$name.$comm;
$x =~ /山/ && $x =~ /本/ && ($subj =~ s/山//g, $name =~ s/山//g, $comm =~ s/山//g);
$x =~ /隆/ && $x =~ /雄/ && ($subj =~ s/隆//g, $name =~ s/隆//g, $comm =~ s/隆//g);


これは、カリレン・オリジナル、つーか、わひょみさんオリジナルなのか? サポートさんの時代からあったのか?それとも、まさか本家の時代から!! まんなことはいいや 解釈しなくてもわかるでしょ。

何も知らない人のために:これは正義なんです。 山本、隆雄の2つをNGワードにするのは正義なんです。
もちろん、普通に使うときは削除してかまわない2行です。

if($next == 21 && !$reload){

このifは133行目まで。 途中69、73、79、94、106に空白行がある。 このifは、1ページ目をつくる処理。

はい、ここで$reloadに1が入っていると、以下の処理が行なわれないことになります。さっきの話ね。

$_ = $admin;
s/(\W)/\\$1/g;
$name =~ s/$_/#$admin/g;

この3行で、偽管理人対策をしてるんだと思う。 2行目(通しで、71行目)は、/とかのいたずら対策かな。 3行目の#(全角のシャープ)を変えると、いろんな偽表示になるんだろう。 この板でどうしてるかは、やったことないので、知らない。

crypt($name, 'am') eq 'amsqKfBaSfYYU' && &del;

管理者削除の処理。 cryptは暗号化処理。「投稿者」欄をamで暗号化して、それを「amsqKfBaSfYYU」と比較して、おなじだったらdelというサブルーチンを呼び出している。 たぶん、amとamsqKfBaSfYYUの両方を変える必要がある。 そのやり方は、メンドイから、考えたくない。 たぶん、パスワード・ファイルを別に作るやり方がいいんだろうけど、 考えたくないので、誰か教えてください。 むしろ、この板のどっかで誰かがが言っていたように次のように変えるのが簡単。

#crypt($name, 'am') eq 'amsqKfBaSfYYU' && &del;
$name eq '好きなパスワード' && &del;


別に上の行は、削除してもいいけどね。もとスクに敬意をはらってコメントアウト。 あと、この書き換えだと、たぶん、簡単にパスワードを知られちゃうよ。

さっきの、自分のソースを表示する公開用の行を消さないと、削除パスがバレバレうんこたれです。

39投稿者:32 投稿日:07月09日(日)14時42分16秒

crypt($name, 'am') eq 'amsqKfBaSfYYU' && &del;

$name をsalt 'am' で暗号化してamsqKfBaSfYYU と一致したら削除。 'am'sqKfBaSfYYU 最初の2文字はam で暗号化されたって事。 暗号化する前のパスワードを投稿者欄に入れてレスすると消せるの。 その時に何もコメントを書かないとスレッド削除 数字を書くとその番号の書き込みが削除される。

 

$res && undef $subj;

レスなのかどうかを判断して、レスだったら、スカラーsubjを消す レスじゃなかったら、何にもしない

$name || &error('投稿者を記入してください.');
$comm || &error("コメントが入力されていません");
$res || $subj || &error("題名が入力されていません");

レスや新しいスレッドをたてるときの記入漏れチェック スカラーnameが空だったら、引数「投稿者を記入してください」を渡してサプルーチンerrorを実行 同じくスカラーcommについてやる どっちも空じゃなかったらなにもしない んでスカラーresが空だったらスカラーsubjが空か見て、空だったら、errorを実行。

$comm =~ s/(http\:[\w\.\~\-\/\?\+\=\:\@\%\;\#]+)/<a href=$1 target=_blank>$1<\/a>/g;
$mail && ($name = "<a href=\"mailto:$mail\">$name</a> ");


1行目(通しで80行目)は、カキコのなかのリンクを新しい画面できちんと開けるようにする処理 2行目(通しで81行目)は、メアドを書いた人のメアドを投稿者名のところでリンクする処理

($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
$month = ($mon + 1); $year %= 100;
$year < 10 && ($year = "0$year");
$month < 10 && ($month = "0$month");
$mday < 10 && ($mday = "0$mday");
$sec < 10 && ($sec = "0$sec");
$min < 10 && ($min = "0$min");
$hour < 10 && ($hour = "0$hour");
$wday = ("日", "月", "火", "水", "木", "金", "土")[$wday];
$date = "$month月$mday日($wday)$hour時$min分$sec秒";
$res = "$year$month$mday$hour$min$sec" unless $res;


1行目時刻取得 3行目以降、時刻フォーマット設定。

1行目(通しで82行目)は、時間をリストとして取得。 2行目(通しで83行目)は、リストとして取得したスカラーmonは、代入される戻り値が0から始まってるので1を足している。 3行目(通しで84行目)は、$yearを100でわって、桁を少なくしている。 あとは、一桁か二桁かを判断して、二桁ならなにもしないで、人桁なら、01とかにして代入しなおしている。 10行目(通しで91行目)は、日本語の曜日のリストを作っておいて、そこから$wdayが0から6までの数字であることを利用して、$wdayに 日本語の曜日を代入している。 で最後の行で、これを一まとめにして、あめざー同じみの日付け表示を作ってる。

$res = "$year$month$mday$hour$min$sec" unless $res;

93行目は、時刻の設定ではなく、 「レス全部を見る」でいくファイル名とか、レスする時の「レス先」とかを指定するためのスカラーresを 作ってる

$file = "./$folder/$res.html";

31行目か53行目で作っておいた$folderと93行目で作っておいた$resを使って スレッドごとのファイルの位置を$fileに代入

open(W, "+< $file") || $subj && open(W, "> $file") || &error('スレッドがありません.'

$fileっていうファイルがあれば、 それを読み書きどっちもできるかたちで(「+<」がその指定)、 ファイルハンドル「W」として開く、 (ここでWを開いたら、次は実行しない) なければ、$subj(つまり、スレッドタイトル)があるかを調べて、 あれば $fileを書きこみよう(出力用)としてファイルハンドルWで開く (ここでWを開いたら、次は実行しない) これまでの確認で、Wを開けなければ、「スレッドがありません」つー引数を渡して サプルーチンerrorを実行

flock(W, 2);

96行目で、Wが開けてたら、 それを、書きこみできないようにしちゃう。 この書きこみの禁止(排他的ロックとか言うらしい)は、 130行目で解除されている。 flockもcryptとおんなじunix的操作で、わたしにはよくわかんない。 おんなじスレッドに同時にカキコされないようにしているってことだろう。

while(<W>){
last unless /<dt> (\d+)/;
$cnt = $1;
$pos = tell(W);
$prev = $_;
}

開いたWから、古いカキコを取り出したりする作業 whileだから、各スレッドのhtmlファイルの最後の行まで繰り返し処理をするけど、 2行目(通しで99行目)で、最後のカキコの行で、このwhileからぬけだしている。 (これで、レスカキコ用のform部品は読みこまれない)。 で、2行目でついでに、最後のカキコの番号を取得しといて、 それを3行目(通しで100行目)で、$cntに代入している。 そして、4行目(通しで101行目)で、2行目でぬけだした位置を$posに代入し、次のseekで利用する。 んで、その抜け出すまでの行(つまり、古いカキコ全部)を5行目(通しで102行目)で、$prevに代入している。 この処理は、素人ながらにも、うまいなぁ、と思う。 それとも、ふつーなのか?

 

seek(W, $pos, 0);

新しいカキコやレス用formをどこに書き足すかを指定している。 スレッドのhtmlファイルの先頭から、 上の101行目で取得した$posのバイト分のところに 書き足すということだろう。 ま、つまり、スレッドのhtmlファイルの古いバージョンから、 カキコ用formを除いた最後の位置に、 新しいカキコと、カキコ用formを 付け足すように、設定している。

$cnt++;

新しいカキコの番号を指定。 上の100行目でとりこんだ、最後のカキコ番号の数字を1増やしている。 インクリメント。

56投稿者:IKeJI 投稿日:07月09日(日)21時54分33秒

flock はこの場合、別な人が書き終るまで待ちます。 私はWin を使っているので、 eval 'flock(W,2);'; のように書き変えています。

 

$prev =~ /<b>(.+) <\/b>.+<dd>(.+) <\/dl>/;
$name eq $1 && $comm eq $2 && print W && &error('二重カキコです.');

2重カキコを防ぐ処理
$prev(102行目で取得したもの)のなかから、投稿者名と投稿内容をさがす それぞれは$1と$2となるので、それを次の行で$name、$commと順番に比較し、 両方と同じであれば、「二重カキコです.」っていう引数をわたしてサブルーチンerrorを実行

 

なんとなく次のページヘイコウ