#! /usr/bin/perl # # fmail.cgi # CAPTCHA付きフォームメール # # 1.003 : 12/2/06 : メールチェックを修正 # 1.002 : 11/28/06 : デフォルトをCAPTCHAオフに修正 # 1.001 : 11/23/06 : 受取人メールには送信アドレスを表示するように修正 # 1.0 : 11/21/06 : Initial revision # # http://www.hidekik.com # # Copyright(c) 2005-2006, Hideki Kanayama All rights reserved use strict; use CGI qw(:cgi-lib); use CGI::Carp qw(fatalsToBrowser); use File::Basename; use Jcode; use GD::SecurityImage::AC; my $lastupdatedyear = 2006; my $version = "1.003"; my $script = basename($0); my $setupfile = "fmail_setup.pl"; my $admindat = "adminpwd.dat"; my $charset = "Shift_JIS"; my $lang = 0; ########################################### # Enable mail our $enable_mail = 1; # Title our $title = ('フォームメール','Form mail')[$lang]; # Background our $bgimage_en = 0; our $bgimage_file = ''; our $bgcolor = "#ffffff"; # Back link our $backlink_en = 1; our $backlink = '..'; our $backlink_name = '戻る'; # Body width our $body_width = '100'; # Display admin link our $setup_en = 1; our $setup_name = '管理用'; # return page after sending a mail # 0: form mail, 1: done page, 2: top page our $return_page = 0; # mail command our $mail_cmd = '/usr/sbin/sendmail -t'; # Recipient our $to_mail = 'yourname@yourdomain.com'; # Name on To:, From:, Bcc: # 1: display, 0:no display our $mail_name = 1; # body_head our $body_head = "

フォームメール

"; # body_tail our $body_tail = ' '; #セキュリティイメージ our $captcha_en = 0; our $capimage_width = 230; our $capimage_height = 80; our $scramble_en = 1; our $cap_text_num = 4; #文字数 our $cap_expire = 60; #有効期限(分) # セキュリティイメージデータディレクトリ our $capdatadir = 'capdata'; # ttffontファイルを絶対パスで。 "Document and Setting"のようなパス内のspace禁止 our $ttffont = "c:/windows/fonts/cour.ttf"; # ttfrontのポイントサイズ our $ttffont_ptsize = 30; # Style Sheet our $style_sheet_en = 0; our $style_sheet = ' '; # Head insert our $head_insert_en = 0; our $head_insert = ' '; ####################################### require "$setupfile" if (-e "$setupfile"); my $mail_pattern = '(^[\w\.\-]+\@[\w\.\-]+\.[a-zA-Z]{2,4}$|^$)'; my $q = CGI->new; my $cgierror = $q->cgi_error; &error($cgierror) if ($cgierror); my %in = $q->Vars; if (! -e "$admindat"){ if ($in{mode} eq 'wradminpwd'){ &wradminpwd($in{pwd},$admindat); } else { &setadminpwd($admindat); } } my $captcha; if ($captcha_en){ $captcha = GD::SecurityImage::AC->new; $captcha->gdsi( new => { width => $capimage_width, height => $capimage_height, lines => 10, scramble => $scramble_en, font => "$ttffont", ptsize => $ttffont_ptsize, }, create => ['ttf', 'rect', '#000000', '#555555'], particle => [500], ); if (! -d "$capdatadir") {mkdir $capdatadir;} $captcha->data_folder($capdatadir); $captcha->output_folder($capdatadir); $captcha->expire($cap_expire * 60); } if ($in{mode} eq 'setup'){ &setup; } elsif ($in{mode} eq 'setupwrite'){ &setupwrite; } elsif ($in{mode} eq 'send'){ &send; } else { &mainpage; } sub mainpage { &htmlhead($title); print $body_head; print "$backlink_name
" if ($backlink_en); print qq(

\n); print qq(\n); print qq(送信者の名前
\n); print qq(

\n); print qq(送信者のメールアドレス
\n); print qq(
\n); print qq(メールアドレスの確認(もう一度入力してください)
\n); print qq(

\n); print qq(タイトル
\n); print qq(
\n); print qq(
本文
\n); print qq(

\n); &wrticket; print qq(

\n); print "$body_tail"; print "

管理用
\n" if ($setup_en); &htmltail; } sub wrticket { if ($captcha_en){ my $md5sum = $captcha->generate_code($cap_text_num); print "
\n"; print "\n"; print "投稿するためには上の文字を下のテキストボックスに入力してください。
"; print "

\n"; } } sub security_check { if ($captcha_en){ my $result = $captcha->check_code($in{ticket},$in{capmd5}); if ($result == 0){ &retry_captcha("コードのチェックに失敗しました。"); } elsif ($result == -1){ &retry_captcha("コードの有効期限が過ぎています。"); } elsif ($result == -2){ &retry_captcha("無効なコードです。"); } elsif ($result == -3){ &retry_captcha("コードがマッチしません。"); } } } sub retry_captcha { my $msg = shift; &htmlhead($msg); print "

$msg

\n"; print "もう一度コードを入力してください。

\n"; foreach (qw(sender mailaddress1 mailaddress2 subject main)){ $in{$_} =~ s/
/\n/gi; $in{$_} =~ s/<//g; $in{$_} =~ s/&\#44;/,/g; } print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print ""; &wrticket; print ""; print "\n"; print "

\n"; print "
\n"; &htmltail; } sub send { my $subject = $in{subject}; my $sender = $in{sender}; my $contents = $in{main}; my $mailaddress = $in{mailaddress1}; &error("送信者の名前を記入してください。") if ($sender eq ''); &error("送信者のメールアドレスは必ず記入してください。") if ($mailaddress eq ''); &error("メールアドレスが一致しません。") if ($mailaddress ne $in{mailaddress2}); &error('タイトルと本文は必ず書いてください。') if ($subject eq '' or $contents eq ''); if ($mailaddress !~ /$mail_pattern/){ my $message = ('無効なメールアドレスです','Invalid mail address')[$lang]; &error("$mailaddress:$message"); } unless ($enable_mail){ &error('メール機能は現在無効になっています。'); } &security_check; $contents = jcode($contents)->jis; my $from_mail; $from_mail = $mail_name ? "$sender <$mailaddress>" : "$mailaddress"; my $header; foreach my $repeat (0 .. 1) { $header = "From: " . jcode("$from_mail")->mime_encode . "\n"; $header .= "To: " . jcode("$to_mail")->mime_encode . "\n" if ($repeat == 0); $header .= "Bcc: " . jcode("$from_mail")->mime_encode . "\n" if ($repeat == 1); $header .= "Subject: " . jcode($subject)->mime_encode . "\n"; $header .= "MIME-Version: 1.0\n"; $header .= "Content-type: text/plain; charset=ISO-2022-JP\n"; $header .= "Content-Transfer-Encoding: 7bit\n\n"; if (open(SMAIL, "| $mail_cmd")){ print SMAIL $header; print SMAIL $contents; close(SMAIL); } else { &error("メールコマンドが実行できません。
$mail_cmdが正しいか確認してください。"); } } if ($return_page == 0) { print "Location: $script\n\n"; } elsif ($return_page == 1) { &error("送信しました。

$title

$backlink_name"); } else { print "Location: $backlink\n\n"; } } sub htmlhead { my $title = shift; my $bgimage; if ($bgimage_en == 1){ $bgimage = "background=\"$bgimage_file\""; } else { $bgimage = "bgcolor=\"$bgcolor\""; } print $q->header(-charset=>$charset); print "\n"; print "\n"; print "\n"; print "$title\n"; if ($head_insert_en == 1){ print "$head_insert\n"; } if ($style_sheet_en == 1){ print "\n"; } print "\n"; print "\n"; print "
\n"; } sub copyright { my $mysite = ('http://www.hidekik.com/','http://www.hidekik.com/en/')[$lang]; print "
fmail.cgi Ver. $version
\n"; print "Copyright(C) $lastupdatedyear, hidekik.com
\n"; } sub htmltail { ©right; print "
\n"; exit; } sub error { my ($msg) = shift; &htmlhead($msg); print "

$msg
\n"; print "
"; print "
"; &htmltail; exit; } sub makecrypt { my $plain = shift; my $salt = join "", ('.', '/', 0..9, 'A'..'Z', 'a'..'z')[rand 64, rand 64]; my $result = crypt($plain,$salt) or crypt($plain,'$1$'.$salt.'$'); return $result; } sub setadminpwd { my $file = shift; &htmlhead('パスワードを入力してください'); print "
\n"; if (! defined $file){ print "
管理者用パスワードを入力してください。
\n"; print "\n"; print "\n"; print "\n"; } else { print "
管理者用パスワードを設定してください。
\n"; print "\n"; print "\n"; print "\n"; } print "

"; print "
"; &htmltail; exit; } sub wradminpwd { my $plain = shift; my $file = shift; $file = "$admindat" unless (defined $file); my $passwd = &makecrypt($plain); if (open(FILE,"> $file")){ print FILE "$passwd"; close(FILE); } else { &error('パスワードファイル作成に失敗しました'); } print "Location: $script\n\n"; } sub checkadmin { my $pwd = shift; my $file = shift; $file = "$admindat" unless (defined $file); if (open(FILE,"< $file")){ my $filepwd = ; close(FILE); my $inpwd = crypt($pwd,$filepwd); return ("$inpwd" eq "$filepwd"); } else { &error('パスワードファイルが存在しません'); } } sub setup { my $subname = 'setup'; &setadminpwd if ($in{pwd} eq ''); &error(('管理用パスワードが違います。','Wrong admin password')[$lang]) unless &checkadmin($in{pwd}); &htmlhead($title); my %check; $check{backlink}[$backlink_en] = "checked"; $check{bgimage}[$bgimage_en] = "checked"; $check{setup}[$setup_en] = "checked"; $check{style_sheet}[$style_sheet_en] = "checked"; $check{head_insert}[$head_insert_en] = "checked"; $check{return_page}[$return_page] = "checked"; $check{mail_name}[$mail_name] = "checked"; $check{enable_mail}[$enable_mail] = "checked"; my @captcha_check; my @scramble_check; $captcha_check[$captcha_en] = "checked"; $scramble_check[$scramble_en] = "checked"; print "\n"; print "\n"; print "\n"; my $notice = ("
  • セットアップリンクを非表\示にしている場合は、$script?mode=setupからパスワードを入力してこのページに入ってください。
  • 数字やカラー指定は必ず半角で指定してください。全角やブランクだとCGIが起動しなくなります。万一間違って全角で書いてしまった場合は、$setupfileをエディタで開きその場所を半角に正しく修正してください。それで直ります。
  • ", "
  • If you disable to display admin setup link, you can open the page with $script?mode=setup and change the setting.
  • ")[$lang]; print <
      $notice
    メール送信機能\ 有効 無効
    END print (('バックグランド','background')[$lang]); print < END print (('画像を使う','image')[$lang]); print " "; print (('カラー設定にする','color')[$lang]); print < END print (('画像を使う場合の画像ファイル','image file')[$lang]); print < END print (('カラー設定の場合のカラー番号(白:#ffffff 又は white)','color code(white:white or #ffff)')[$lang]); print < END print (('タイトル名','title')[$lang]); print <
    ブラウザのタイトルバーに表\示されるタイトルです。ページのタイトルは「ページ上部」で自由にタイトル表\示させることができます。 END print (('トップへのリンク','link to top')[$lang]); my $disp = ('表示','display')[$lang]; my $nondisp = ('非表示','not display')[$lang]; my $linkname = ('リンク名','link name')[$lang]; print < $disp $nondisp
    $linkname
    URL
    END print (('表示幅','table width')[$lang]); print " "; print (('ブラウザ全体の','')[$lang]); print <% END print (('セットアップのリンク','link to setup')[$lang]); print < $disp $nondisp
    $linkname
    END print "送信後の戻りページ"; print < $title
    送信完了ページ
    「$backlink_name」ページ END print (('メールコマンド','Mail command')[$lang]); print qq(To:などのヘッダ情報が本文に埋め込まれて送信されるのでsendmailの場合は「sendmail -t」のように-tを必ず付けてください。
    \n\n); print "\n"; print < END print (('宛先','To address')[$lang]); print qq(\n\n); print "\n"; print < END print (('From:に名前を表示','Display name on From:')[$lang]); print "\n\n"; print <$disp $nondisp
    END print "\n"; print "\n"; print (('<head>内挿入文','sentense in <head>')[$lang]); my $valid = (('有効','valid')[$lang]); my $invalid = (('無効','invalid')[$lang]); print < $valid $invalid
    END print ((' HTML書式
    ポップアップ広告やJavascript、<META>を挿入したい場合にここに記述する。
    以下の記述が<head>〜</head>内に挿入される。
    ','HTML format. Javascript, popup ads, <META> and so on can be inserted in here. ')[$lang]); print <$head_insert
    セキュリティイメージ設定 有効 無効
    画像サイズ:幅、 高さ
    スクランブル 有効 無効
    スクランブルを有効にすると文字が散らばるので画像サイズを大きめに設定しないといけません。
    文字数
    コードの有効期限
    データディレクトリ
    TTFフォントファイル(絶対パス)
    "Document and Setting"のようなパス内のspace無効
    TTFフォントポイントサイズ
    END my $stylesheetname = ('スタイルシート','style sheet')[$lang]; print < $stylesheetname $valid $invalid

    ページ上部 ページ上部に表\示させるものをHTML表\記

    ページ下部 ページ下部に表\示させるものをHTML表\記

    END my $setting = (('設定','setting')[$lang]); print "\n"; print "\n"; &htmltail; } sub setupwrite { &error(('管理人パスワードが違います','Wrong admin password')[$lang]) unless ( &checkadmin($in{pwd})); foreach (keys(%in)){ $in{$_} =~ s/\s*$//; } open(SETUP,"> $setupfile"); print SETUP <