第4回 1999年の Perl チャットを2026年に動かす
:このホームページには、1999年から由綺チャットという人工無能チャットがあります。
人工無能というのは、チャットに書き込むと、辞書ファイルをもとにキャラクター(由綺ちゃん)が返事をしてくれる仕組みです。
Perl の CGI で、データはすべてテキストファイル。テレホーダイの時代に作ったものです(^^;
サーバーの引っ越し(第3回)にあわせて、これを2026年のサーバーで動かしてみました。
作業は Claude(生成AI)と一緒に進めました。
まずはそのまま動かしてみる
新しいサーバーの Perl は 5.34。27年前のスクリプトをそのまま置いてみると、当然エラーです。直したところは次のとおり。
- 古い関数呼び出しの文法。
文字コード変換のライブラリの中に、
do 関数名(引数)という昔の書き方がありました。 これは Perl 5.20 で廃止されたので、&関数名(引数)に書き換えました。do convf(*_); # 昔の書き方(今はエラー) &convf(*_); # こう直す - パーミッション。CGI ファイルは 755 にしないと動きません。(これは昔と同じ)
- 古いサーバーのアドレス。 フォームの送信先や「戻る」リンクが、昔のサーバーのアドレスで書かれていたので、相対パスに直しました。
- 他サイトのチャットとつながる機能。 昔は、よそのチャットの様子を隣のフレームに表示する機能がありましたが、相手のチャットがもう無いので止めました。
これだけで、なんと普通に動きました。Perl の互換性、すごい。。
修正したら、まず手元の PC(Git for Windows に入っている Perl)で動かしてから、サーバーに上げるようにしました。
作り直し:Shift_JIS から UTF-8 へ
動くには動きましたが、ファイルが Shift_JIS、画面はフレーム、デザインも1999年のまま。 せっかくなので、中身を作り直しました。
- ファイルを全部 UTF-8 に変換(元の Shift_JIS 版はバックアップしてから)
- フレームをやめて1ページに。発言の一覧は、ページ全体を読み直さずに JavaScript で更新
- デザインをホームページと同じに
- 名前や発言など、利用者が入力したものはすべて HTML のエスケープをしてから表示
UTF-8 化で、Perl ならではのハマりどころが2つありました。
-
正規表現の
[ ]の中に全角文字を入れない。 Perl に「この文字列は UTF-8 の文字だよ」と教えずに扱うと、全角1文字は3バイトのばらばらの値として扱われます。[、。]のように書くと、「、」「。」ではなく、それぞれのバイトのどれか1つにマッチしてしまい、文字化けの原因になります。(?:、|。)のように書くと安全です。 -
\p{Han}は漢字だけではない。 文章から話題になりそうな漢字の並びを取り出す処理で\p{Han}(漢字)を使ったら、なぜか読点「、」までマッチ。 調べてみると、「、」は漢字と一緒に使われる記号なので、漢字の仲間(Script_Extensions)にも入っているんですね。\p{sc=Han}と書くと、本当に漢字だけになります。
由綺ちゃんの返事を自然に
昔のままだと、同じ返事を繰り返したり、分からない言葉に毎回同じように返したりしていたので、少し手を入れました。
- 辞書の言葉が長く一致したものほど選ばれやすくする(短い言葉に引っかかりにくくする)
- 直前に言ったことは、しばらく言わない
- 分からないときの返事を、質問・びっくり・笑い・短い発言など、相手の書き込みの種類に合わせて変える
- 書き込みの中の言葉を拾って「〇〇?」と聞き返す
- 由綺ちゃんが分からないとき、ほかのキャラクターがたまに口をはさむ
ちなみに、昔はサブキャラクターが ToHeart の2人だったのですが、せっかくなので由綺ちゃんと同じ WHITE ALBUM のマナちゃんと美咲さんに替えました。
セキュリティの見直し
1999年の CGI なので、今の目で見るとけっこう無防備でした。 チャットを再開した翌日に、ひととおり見直してもらったところ、いくつか見つかりました。
- ログや辞書のファイルが、URL を直接打つと読めた。
昔のログには参加者の接続元が記録されていました。
.htaccessでデータファイルへのアクセスを禁止し、ログには接続元を残さないようにしました。 - 誰でも辞書に言葉を教えられた。 悪用されると、変な返事ばかりにされてしまいます。教えてもらった言葉は、いったん「承認待ち」にして、自分が確認してから辞書に入るようにしました。
- 連続投稿の制限がなかった。短い間隔の連続投稿は受け付けないようにしました。
ついでにバグも1つ見つかりました。ファイルを「読み書き用に開く。無ければ新しく作る」という処理を、
open(FH, "+<$file") || open(FH, "+>$file");
と書いていたのですが、これだとファイルが無いときに、最初に書き込んだ内容が消えることがありました。
「無ければ作る、あれば中身はそのまま」を一度にやってくれる sysopen に書き換えて解決です。
use Fcntl;
sysopen(FH, $file, O_RDWR | O_CREAT, 0600);
おまけ:Twitter bot は Bluesky へ
昔は由綺ちゃんの Twitter bot も動かしていたのですが、X の API が無料では使えなくなっていたので、 Bluesky に引っ越しました。(くわしくは日記に書きました)
振り返り
- Perl は意外と動く。27年前のスクリプトが、数か所の修正で動いたのには驚きました。
- 文字コードの変換は、バックアップを取ってから。Shift_JIS のファイルに UTF-8 の文字を混ぜると、元に戻すのが大変です。
- 昔のプログラムは、公開する前にセキュリティを見直す。当時は大丈夫だったことが、今はそうではないことがあります。(自分は再開してから見直したので、順番が逆でした。。)
今は訪問者も少ない静かなチャットですが、由綺ちゃんはいつでも待っています。よかったら話しかけてみてください。
以上、です。