トップページ | 利用規定
  FAQ・2

カレッヂ
カレッヂ


次のページ


ログやカウンタが消えるのですが

UNIXはマルチタスクと言って、複数の人が同時に同じプログラムを実行したり見たりできます。 見る(読み出し)だけならいいのですが、そのファイルが書き込みされるものの場合、 書き込み最中のわずかな時間の間にそのファイルを読み出そうとすると、 ファイルはカラッポ状態になっています。 書き込みには2種類あります。追加書き込みと上書き書き込みです。 チャットのログやカウンタは、先にデータを読み出して処理してから上書きします。 したがって、もし上記のカラッポ状態の時に読み出したらどうなるでしょう。 例えばカウンタの場合、現在のカウント数を読み出してから+1処理をして上書き書き込みします。 この場合、上記のわずかな時間のカラッポ状態にアクセスされてしまった場合、 何もないファイルを読み出して+1をいくらしようとしても何もなりません。 そのまま処理後の何もないものを上書きしてしまい、ここで消えてしまうのです。 チャットやアクセス数の多いページのカウンタは、この同時アクセスの確率が非常に高くなります。

例えば簡易BBSなら、最大記録件数を多くしない方がファイルが大きくない分、処理時間が多少でも少なくなり、 その危険が少なくなります。そうであっても、データは何事においてもバックアップが重要です!

[MEMO] これを防止するには、書き出し中に読み出されないような仕組みを組み込む必要があります。 いろいろありますが、書き出し中かをチェックしているわずかな時間に読み出されたらどうでしょう。 きりがありませんが、これを防止するためには、処理中は次の処理をしないようにさせるようにします。 これをファイルロック処理と呼ぶことにします。

この処理は無限ループを応用しているもので、扱い方を間違えればサーバダウンに直結します。 このロック機構のついていないスクリプトに組み込む十分設計に自信がある方のみ参考にしてください。 この件について当サイトでは一切質問は受けません。

flock()関数を用意しているサーバでは、あたかもこれでファイルロックをするようにできそうですが、 実際に活用しても経験上殆ど役に立ちませんでした。この関数がどのようなものなのかは よく知りませんので悪しからず。では、実際にどのような処理をすればいいでしょうか。 処理に入る前に、処理中であることを示すフラッグ(旗)を揚げるて、そのフラッグがあるうちは 待機するようなルーチンの中に実際の処理を置くことにします。待機しているだけでは、万が一 フラッグが降りなかったら無限に待ち続けることになり危険なので、設定された時間間隔で 指定回数確認してもフラッグが降りない場合は処理を中止して終了するようにしておくことは大変重要です。 実際にファイルロック処理するには、できるだけ早くフラッグを揚げるようにします。 メイン処理開始時点で揚げはじめるわけですので、ゆっくり揚げていては、 次のアクセスがフラッグを確認できずに処理を同時に開始してしまう恐れがあります。 フラッグを何にするかは、早くできる方法は何かによります。広野**さんのページ (http://www.st.rim.or.jp/~hirono/cgitips/)で紹介されている方法に、シンボリックリンクを 使う方法があります。この方法は通常のファイルをフラッグに使うのに比べて、早く認識されるようです。 ただし、これが作成できないサーバもありますので、通常のファイルを使う方法も合わせて紹介します。 この処理をする前にシェルテストして、必ず終了するプログラムかどうかを確認する必要がありますが、 そのテスト中に終わらなくなってしまった場合のために、手動で強制終了する方法を覚えておきます。 UNIX上の各処理はプロセス番号という実行番号が付けられて処理されます。コントロールZで 強制終了できますが、この状態では一時終了の状態であって完全に終了していません。 そこでその処理のプロセス番号を調べて、その処理を削除しなければなりません。これらの仕組みに ついてはUNIXの本で勉強しておくといいでしょう。みんなで使う共用サーバですので、 ゴミプロセスを残したままだと無駄なメモリを食ってしまうことになるので注意しましょう。 プロバイダによっては24時間プロセス管理をしてくれて、ユーザがこれらを気にしないで使える 親切なところもありますが、これらは最低限ぜひ覚えておいてください。

	% ps プロセス一覧
	% kill <プロセス番号>

なお、これらのコマンドの説明は、% man <コマンド名> で読むこともできますので参考してください。 どちらも、ロック中は2秒待機3回リトライとなっています。3回目でもロック中の場合は終了します。 終了前にエラールーチンに通してもいいでしょう。この処理は無限ループを応用したものですので、 ちょっとした設計ミスが終わらないプログラムになり、サーバダウンを引き起こし兼ねませんので、 必ずシェル上でロック処理動作テストを行います。$lockfileを置く(と言ってもファイルを用意する 必要はなく自動で生成/削除される)ディレクトリのパーミッションは777または707にしないと 正常に動作しません。(常にBUSYになってしまう) 最初はsymlink()を使った方法を使います。まず通常に実行して正常に終了することを確認します。 この時点でBUSYとなる場合は、symlink()関数が利用できないものと思われますので、open()を使った 方法にします。open()よりはsymlink()の方が処理が早いのが使われる理由だと思いますが、 どちらにしても完璧に隙間が空かないわけではありませんので、ファイルは壊れるものだと 思ってバックアップをこまめにとることを忘れないようにしましょう。 次に、手動でロック中の状態を作成します。/lock/ディレクトリの中にfile.lock という名前のファイルを置いてください。空っぽのファイルで結構です。この状態で実行すると、 規定秒数後にBUSYを返して終了することを確認します。file.lockを削除すれば正常にメイン処理をして 終了すればOKです。ロックを解除する処理を忘れると次の処理ができませんので注意してください。 特に、ロック開始後に何らかのエラーで終了してしまった場合はロックファイルは残ったままに なることを覚えておいてください。

#!/usr/local/bin/perl
$lockfile = "./lock/file.lock"; #ロックファイルが置かれるパスも指定する
&lock; #ロック開始
<<メイン処理>>
unlink($lockfile); #ロック解除
exit;

sub lock {

	#symlink()を使った方法

	local($retry) = 3;
	while (!symlink(".", $lockfile)) {

		if (--$retry <= 0) { unlink($lockfile); print "BUSY"; exit; }
		sleep(2);
	}
}

sub lock {

	#open()を使った方法

	$c = 0;
	while(-f "$lockfile") {

		$c++;
		if ($c >= 3) { unlink($lockfile); print "BUSY"; exit; }
		sleep(2);
	}
	open(LOCK,">$lockfile");
	close(LOCK);
}

海外時間を日本時間に修正する

海外サーバの場合、時刻は現地時間になっています。サマータイム時間がある場合もありますので注意しましょう。 これを日本時間に直す場合は、時刻を取得する部分の前に次のうちいずれかを置く事で日本時間に修正できます。 数字は例ですので、時差に応じて変更してください。

環境変数で基準時刻を設定 $ENV{'TZ'} = "GMT-9";
環境変数で基準時刻を設定 $ENV{'TZ'} = "Japan";
秒単位で直接調整     localtime(time) --> localtime(time +18*60*60)
秒単位で直接調整     localtime(time) --> gmtime(time +9*60*60)              gmtime()は世界標準時なので、+9時間で日本時間となる.

半角カナは使えないの?

使えません。パソコン通信にしてもインターネットにしても、半角カナを読めない機器がたくさんあります。 ネットは日本だけのものではないので、データ通信上問題のあるコードは使わないことが鉄則です。 知らない方も多いようですので、ちょっと添え書きするといいでしょう。 なお、日本語コード変換ライブラリ jcode.pl の v2.0 以降には、半角カナを全角カナに変換する機能もありますが、 単にライブラリをv2.0にするだけでは駄目で、スクリプト中で処理しなければなりません。 当サイトのスクリプトで、v2.0を使うように指示しているものはこの処理をしています。

jcode.plが使えない環境?

jcode.plはjperlには対応していないという情報があります。詳しいことはよくわかりませんが、 実際にjperlとperl上で比較試験をして、日本語処理のところでエラーになったことがあります。 さらに、jcode.pl v1.9 以前のものなら大丈夫とかいう情報もあり、錯綜しています。参考程度に読んでください。

あなたのサーバのperlがどうなのかは、perlのバージョン表示で知ることができます。 シェルに入って、

% /usr/local/bin/perl -v
This is perl, version 5.003 with EMBED
built under solaris
+ suidperl security patch

この時、「This is perl」か「This is jperl」と表示されます。 シェルテストしたときに、

/\216([\241-\337])(\216([\336\337]))?/: unmatched () in regexp at jcode.pl line ***.

のようなエラーが出ている場合はこの件を検討するといいでしょう。

暗号ってみな同じなの?

当サイトのスクリプトで管理者モードなどがついているものには、管理者を識別するために、 パスワードを使っています。設定されるパスワードは crypt()関数を使って暗号化しています。 同じロジックを使っている処理であれば、サーバ間で互換性があります。 私が知る範囲では2種類の暗号処理方式を確認しています。 暗号化された文字列が13文字になっているか、頭文字が $1$ で始まっているかで区別します。 同じ形式なら、もしサーバを移動して移転設置しても、パスワードもそのまま移動できるでしょう。

[MEMO] これはFreeBSDの実装暗号でアメリカの武器輸出規制でDESを標準で組み込めないため、 MD5は頭に$1$を追加する仕様になっています。$1$が無ければDES暗号という扱いになり、 国際化DES(アメリカ国外で作成されたもの)を使用します。 SunのワークステーションとFreeBSDでNISを使用するときには、 FreeBSD側にDESを入れないと動かないのも暗号化実装方法が異なるためだそうです。 Linuxはアメリカ外で開発されたのでこの問題はないそうです。 というレポートをいただきましたが、私もよくわかりません。^^;

暗号解読されないかな?

暗号で解読できないものはありません。 CGIプログラムで一般に利用している手法は、 そのパスワードによって簡単に解読される可能性がありますので、 悪いパスワードを使わないようにする、させることが重要です。 その前に、推測されたり盗まれたりしてしまってはこの限りではありません。 メモしておいたり、推測されやすいパスワードを設定することは問題外です。 CGIとセキュリティについて十分理解するといいでしょう。

記録されたデータの修正をしたい

例えば簡易BBSでは、データにはWINDOWSでは扱わない文字コードが記録されています。 行の終わりを意味する改行はアスキーモード転送をすることで自動変換されることは知っていると思いますが、 記事内容の中の改行を、行の終わりを意味する改行とは別のコードで記録しておかなければなりません。 幸いブラウザは、\nでも\rでも改行として認識してくれますので、 UNIXの1行の終わりを示す改行である\nではなく、\rを記事内容の改行として記録しています。 これは、WINDOWSでもUNIXでもお互いに都合のいい方法です。 ですから、アスキーモードでデータを取り出してメモ帳等で表示すると、記事の途中の改行の位置に、 黒く塗りつぶされた四角い記号が見えると思います。この場合これが\rです。 これに注意すれば編集後転送すれば修正OKということになります。 もちろん、失敗したときのためにバックアップを忘れずにしましょう。

この方法で記録されている場合、MAC上で編集することは非常に困難です。 というのは、MACの改行コードは\rですので、MAC上ではどちらを意味するコードも同じになってしまうために、 MAC上に展開した時点でこのファイルは改行がメチャクチャになってしまいます。 私はMACを持っていないので詳しいことはこれ以上わかりません。 データの修正はサポートしていませんので、削除して再投稿することが原則です。

簡易BBSなどで画像やリンクを入れたいのですが

これをするにはプログラミングの知識が必要になります。 プログラム内をみてみると、HTMLがところどころにあるのがわかると思います。 これらをみて見よう見まねでできるのであれば、以下の点に注意すればいいでしょう。

ホームページへのリンク http://foo.bar/~user/ を入れたい場合、
print '<a href="http://foo.bar/~user/">ホームページへ</a><p>' . "\n";
のようにします。画像タグや文章も同様で、
print 'ここに書いた内容がそのまま表示される<p>' . "\n";
のようにします。

なお、print "ここに書いた内容がそのまま表\示される<p>\n"; のように、""で囲む場合は、
文字化けの可能性があるので、化ける「表」等は、「表\」にエスケープする。

電子私書箱は誰にも見られていないの?

パスワードが盗用されていないことは言うまでもありません。 ただ、電子メールやFTPやWWWなど、インターネット網には様々なプロトコルを使ってデータが流れています。 これらはそのルートにいる人間には自由に閲覧できることになります。 インターネットが高速道路だとすれば、各データはオープンカーです。 車のボンネットには来た場所と行く場所がみんなに見える形で書かれており、 中に乗っている人(データ)も、高速道路に入れる人には見えるわけです。 そんな中、もしクレジットカード番号が流れれば危険なことですから、 暗号化して誰かに見られても解読できないように加工して流しているのです。 ですから、電子メールは気分的に自分だけしか見られないような親書のように感じているかもしれませんが、 実は誰かに見られていても不思議ではないのです。電子メールでもWWWでも、 形態が違うだけでこれらは同じことで、 たとえ電子私書箱のデータをパスワードを知っている人しか見られないとしても、 そのデータが端末を通ってあなたのパソコン画面に流れてくる途中で見られてしまってはどうしようもありません。 もっと詳しく言うと、どこのプロバイダを利用して接続していて、 いつどこのページを見にいったということもわかるわけで、もしあなたがアダルトサイトにアクセスしたとして、 誰かから「あのページを見にいったHなやつだ」とメールがいつ来るかもしれません。 これはインターネットの仕組みなので、 こういうことを知った上でインターネット上のすべてのサービスを利用することが必要です。 ですから、重要なデータはインターネット上では流さないことです。 と言っても、運輸業なのに交通事故が恐くて車に乗らなくては何もできないのと同様に、 こういうことを知った上で利用するということが重要なのではないでしょうか。 何でもそうですが、便利なシステムは反面何らかのリスクも抱えているということです。

/cgi-bin/にファイルを置いても Not Found になってしまうのですが

これはサーバの環境によって違いますが、/cgi-bin/ がサーバの共通ディレクトリに通じている可能性があります。 プロバイダに確認してください。

簡易BBSなどでホスト名を表示させたくない

プログラムによって変数名が異なることがありますが、スクリプト内に $host という変数を探してみてください。 それがprint文の中に書かれていれば削除してみてください。それで表示されなくなればそれでOKです。

簡易BBS v8.8 の例

if ($email) { print "<b>投稿者</b> <a href=\"mailto:$email\">$name</a> [$host]  "; }
 else { print "投稿者 $name [$host]  "; }
if ($email) { print "<b>投稿者</b> <a href=\"mailto:$email\">$name</a> "; }
 else { print "投稿者 $name "; }

ホスト名で投稿者がわかりますか?

わかる場合もありますし、わからない場合もあります。 わかる場合でも、相手の名前等がわかるわけではありません。 その人が利用しているプロバイダを介してその時刻に接続した人を特定するだけで、 もしわかったとしてもプロバイダでその人の情報を教えてくれることはありません。 もし悪戯等で困ったときにはプロバイダを通してクレームを出せばいいでしょう。 どちらにしてもプロバイダのサポート対応の善し悪しによるでしょう。 あくまでもホスト名記録はいたずら防止の抑止力になることは確かですが、 プロキシ経由やアノミナイザ経由ではわからないこともあります。

簡易BBSで、minibbs.dat.txt になってしまうのですが

データファイル名が minibbs.dat なのでそれをWINDOWSのエクスプローラ等で作成すると、 ファイル名の最後に .txt がついてしまうことがあります。 ファイル名を minibbs.dat になるように変更すればいいことです。

*.tar.gzがダウンロードできないのですが

ダウンロードしようとしてもブラウザに変な文字が表示されてしまうなど、ファイルに保存できない場合、 ブラウザのヘルパーアプリケーションに、拡張子 .gz が何かに関連付けられている可能性があります。 この拡張子のファイルにアクセスしたらファイルに保存するように設定してください。

画面に表示されたダウンロードしたスクリプトを保存する方法は?

画面上のリストをコピーするのではなく、[ファイル]メニューから[名前を付けて保存]を選択して保存してください。 画面コピーでは文字化けやゴミが入ることがあります。

フォントのサイズがブラウザによって違うのですが

たとえば、IEでは<pre></pre>タグ内だと通常フォントより小さく表示されます。 フォントだけではなく、<textarea></textarea>のサイズ指定もそうですね。 HTMLタグは柔軟なもので、どのタグを使ったときに大体こういう処理をする、 というようなもので、フォントのサイズ等の細かいことになると、 ブラウザによって違ってきます。

同じタグなのにブラウザによって表示が違うのはどうしようもないことで、 タグも多種多様になってきて、文字フォントや絶対サイズまでも指定できるかも しれませんが(私はあまり最近のタグを知りません)、もともとHTML言語は、 どのブラウザで見ても大体なんとなく意味がわかる程度に表示できるような 共通言語のような感じで開発されたものです。

余談ですが、今後将来はどうなるかはわかりませんが、 ブラウザが何であっても同じように表示するような護送船団式な仕様になった方がいいのか、 基本は同じでも、ブラウザ毎に独自の発展をしていくような方がいき、 ユーザが利用の選択をして勝ったものが生き残るような方がいいのか、 あなたはどちらを望みますか?

requireや@INCに関するエラー

サーバによっては、requireやファイルパスなどを絶対パスで記述しないと動作しないサーバもあります。 また、requireを探すパスを何らかの形で指定する必要があることもあります。 これらはプロバイダの指示を聞かなければわかりません。 これが原因でエラーになったのかを見極めるのにはかなりのCGI施工経験が必要ですが、 参考までに記載しておきます。

タグ禁止のスクリプトをタグが使えるようにしたいのですが

タグを使えるようにするということは、それなりのリスクを伴うことを念頭に置いてください。 タグを使うかどうかを選択できるようになっているものは、 ある程度の危険タグ対策をしていますが、それでも完全ではありません。 タグを禁止する処理というのは、

   $value =~ s/</&lt;/g;
   $value =~ s/>/&gt;/g;

というような処理で、タグの括弧を変換してしまうものです。 これを削除すれば、記入されたタグはそのまま記録されます。 もしこれを削除したら、少なくとも次のものを入れておいてください。

   $value =~ s/<!--#(.|\n)*-->//g;

これはSSIの記録を防止するものですが、 直接HTML形式で記録するようなタイプのもので、読み出し時にSSIが起動しないようにするためですが、 当サイトのスクリプトにはそういう処理を行うものはなく、 CGIでHTMLを形成するようになっています。CGI上でSSIは起動しませんので、 万が一記録されてもこの点では安全です。

私のサーバではsymlink()が使えるのでしょうか?

一部のアクセスカウンタやファイルロック機構を備えているシステムの場合、 これが使えないサーバだと常にBUSYを返します。しかし、設置ミスでも同様なので、 最初にこれが使えるかどうかをチェックするCGIを読者の方からご提供いただきました。

slchk.cgi (symlink support checker)


Powered by CGI RESCUE(R)