DS216jでWEBサーバーを構築する備忘録の続き。
サーバーにImage::Magickのインストールができない状況で現状のBBSを温存するためには、何か別の方法でCAPTCHA画像の生成をしなければならない。画像の生成だけならPHPで書かれた「Securityimage」で比較的簡単に出来たが、cgiから呼び出して使うにはキーの認証に難がある。で、perlでImage::Magickを使わずにCAPTCHA画像を生成する方法が無いか調べてみたところ、GD::SecurityImageというperlモジュールが使えそう。
試しにCPANを利用して下記コマンド実行したところエラー無くインストールは完了。
keyinit.plの改造
GD::SecurityImageはCAPTCHA画像の生成のみを行うもので、キーの認証機能は含まれない。そこで、キーコードの生成・認証については今までどおりこちらで配布されているスクリプトを使うことにした。keyinit.plはキーのランダム生成と、出力する画像フォーマットの設定、キーの暗号化と復号の役割を持ち、cgiのプラグインとして動作する。これを以下のように改修した。
まずはImage::Magick用の設定項目である下記部分はザックリ削除。
#-# 文字画像の幅と高さ
$W = '60'; # 幅
$H = '22'; # 高さ
# バックグラウンド画像ファイル
# 単一色のキャンバスを自動生成するか、予め用意された画像を指定
# 画像(gif/jpg形式のみ)を利用する場合は、文字画像の高さ+20ピクセル程度
# の画像を用意すること。
$bgfile = '#ffffff'; # キャンバス色
#$bgfile = 'bg.gif'; # 画像ファイル名
# 画像生成に使用するフォントのパス
# truetypeフォントを絶対パスで指定すること。
# 波型加工する場合は、文字を選ばないと判読不能になる。
# (CentOSはtruetypeフォントはほとんど入っていないので、
# 別途、RHELのSRPMをリビルドしてインストールすると良い。)
# SuSE9.3
#$font = '/usr/X11R6/lib/X11/fonts/truetype/luxirb.ttf';
# SuSE10.2
#$font = '/usr/share/fonts/truetype/luxirb.ttf';
# CentOS4.4
#$font = '/usr/X11R6/lib/X11/fonts/TTF/luxirb.ttf';
# WindowsXP
$font = 'C:\WINDOWS\Fonts\TIMESBD.TTF';
# フォント色
$font_color = '#ee0000';
# フォントサイズ
$font_size = '20';
# 文字が詰まって文字画像が見難い場合の文字間調整
$space = '0'; # 0:なし 1:あり(スペース挿入)
# 文字の高さ方向の微調整(デフォルト:0, 負数可 ex. '-2')
$vert = '0';
# 文字画像の波状加工の振幅とピッチ
# 波状加工しない場合は両方とも0にすること
$amp = '1'; # 振幅
$pitch = '10'; # ピッチ
#$amp = '0'; # 波状加工しない場合は両方とも0にすること
#$pitch = '0';
#-----設定終了----------------------------------------------#
代わりにGD::SecurityImage用の設定項目を追記する。なお、フォントのluxirb.ttfはNASにインストールされていなかったので、古いサーバーからコピーした。画像フォーマットについてはこちらのサイトを参考にパラメータを設定。
# スタイル
#$style = 'default';
#$style = 'rect';
#$style = 'box';
#$style = 'circle';
$style = 'ellipse';
#$style = 'ec';
#$style = 'blank';
#$style = 'line';
# 文字画像の幅と高さ
$captcha_w = '60'; # 幅
$captcha_h = '22'; # 高さ
# フォント色
$font_color = '#ffffff';
# フォントサイズ
$font_size = '12';
#背景色
$bg_color = '#000000';
# 撹乱ラインの設定
$line_color = '#bbbbbb';
$line_n = '3'; #ラインの数
$line_w = '1'; #ラインの幅
#撹乱ドットの設定
$density = '1'; #隣接ドット密度
$maxdots = '15'; #ドットの数
# 画像生成に使用するフォントのパス
# truetypeフォントを絶対パスで指定すること。
$ttf_font = '/volume1/web/bbs/luxirb.ttf';
#-----設定終了----------------------------------------------#
image_gen.cgiの改造
image_gen.cgiは暗号化された確認キーを引数として受け取り、keyinit.plを通じて復号し、CAPTCHA画像を出力する役割を持つ。これを下記のように書き換えた。
#!/usr/bin/perl --
#
# 確認キー用画像表示モジュール
# GD::SecurityImage 版に改造(2017.9.27)by niga
require './keyinit.pl';
use GD::SecurityImage;
# パラメータ受け取り
$val = $ENV{'QUERY_STRING'};
$val =~ s/<//g;
$val =~ s/>//g;
$val =~ s/"//g;
$val =~ s/&//g;
$val =~ s/\s//g;
$val =~ s/\r\n//g;
$val =~ s/\r//g;
$val =~ s/\n//g;
# 確認キーデコード
($text,$old_time) = &de_key($val);
if($space){ $text =~ s/(\w)/$1 /g; chomp($text); }
#---------------------------------------------------
# GD::SecurityImage での画像作成
$image = GD::SecurityImage->new(
width => $captcha_w,
height => $captcha_h,
lines => $line_n,
thickness => $line_w,
bgcolor => $bg_color,
font => $ttf_font,
ptsize => $font_size,
# rnd_data => [ 'A' .. 'Z' ],
rndmax => '4',
scramble => '0',
angle => '0',
);
$image->random($text); #文字列の定義
$image->create('ttf', $style, $font_color, $line_color);
$image->particle($density, $maxdots);
# 画像書き出し
my($image_data, $mime_type, $text) = $image->out( force => 'gif');
#----------ファイル出力テスト用
#print "$mime_type, $text\n";
#open my $fh, '>', "$text.gif";
#binmode($fh);
#print $fh $image_data;
#close($fh);
#----------画像出力用
print "Content-type: image/gif\n\n";
binmode(STDOUT);
print $image_data;
undef $image;
exit;
これらの改修にて、BBSのcgi上でCAPTCHA画像の生成と認証が正常にできるようになった。Image::Magickを使った時と比べてやや単調なイメージになってしまうが、一応キーは暗号化されているし、ロボットSPAMに対しては一定の抑止力にはなるだろう。