CGIが動作しない?
【注記】
2012年11月より、ヤフーではホームページの運用規制を厳しくしたようです。
数年間、問題なく動作していたソフトが、突如動作しなくなりました。
あくまで想像ですが、例えば管理が不可能なログインページによる運用だとか、メール機能を使った迷惑メールを送信したりする人が多かったためではないかと考えております。
このページでは、ヤフーのホームページに於ける動作の解説を行ってまいりましたが、メールソフトの解説(動作デモも含む)や、特殊フォルダ関係が全て動作不能になってしまいました。
やはり、プロバイダによるホームページの作成には、制約が多くて限界があるようです。
今後は、自宅サーバーの運用のみに切り替えたいと思います。
ヤフーのホームページにCGIのプログラムをアップロードして動作させた時に驚かされるのは下の画面でしょう。(クリックで拡大)
内容は、「申し訳ありませんが、このページは現在利用できなくなっています。しばらくたってからもう一度お試しください。」
これを見た人は、ヤフーのサーバーが混雑(アクセス数が多くて)していて、処理できないのだろうと考えると思います。少なくとも私はそう考えました。
だから大手のプロバイダは嫌なんだと思いながら、しばらくしてからアクセスして見ます。
いくら待っても動作しません。
え〜、私のプログラムが間違っているのかなと見直しを始めます。
いくら単純で動作確認の取れているプログラムでも動作しない事に気が付いて、初めてヤフーでCGIのプログラムを動作させるのは特別なフォルダとかあるのかと考えるようになります。
実際はヤフーにCGIを動作させるような特別なフォルダ(cgi-bin)とかは存在しません。
その代わり、URLの頭の部分にcgiを付加する必要があるのです。
ヤフーをプロバイダにしている人は身に染みているでしょうが、そうでない人のために具体的なプログラムを作成してみましょう。
http://cgi.geocities.jp/yukke_no_kobeya/homepage/phpinfo.php
サーバーを構築したことのある人ならPHPの動作確認に必ずと言ってよいほど使用するPHPのインフォメーションです。
1行のプログラムなのですが、PHPだけではなく、ヤフーのサーバーのシステムの情報も表示してくれますのでなかなか便利です。
次にURLのcgiの部分を通常のwwwにしてアクセスして見ます。
http://www.geocities.jp/yukke_no_kobeya/homepage/phpinfo.php
こちらの方が自然な書き方のように思えますが、前述した表示になってしまいました。
なぜヤフーではこのような仕様にしているのかは不明ですが、恐らくは管理上の理由からでしょう。
レンタルサーバーでもサーバーの負荷が大きい場合は料金が変わる場合もあるようですから個別に監視しているのだろうと思います。
cgiの記入が必要な事はホームページの説明には書いてあるのですが、ホームページ作成の経験の多い人ほど嵌ってしまうでしょう。
私?嵌ってしまいましたとも。
cgiを使用しない場合に、cgiを記入してあっても動作はしますが、動きがトロくなる感じですから切換は必要のようです。
はっきりいって迷惑な仕様ですよ!!孫さん。
geo_cgi_privateは無用の長物?
ヤフーのジオプラスでホームページを作ろうとした場合に、自分のサーバーの領域にgeo_cgi_privateと言う名前のフォルダが作成されている事に気づくと思います。
最初の状態では中身は空になっているでしょう。
ヤフーの説明によると、このフォルダは外部からアクセスする事の出来ないフォルダと言う事です。
私は便利に使用しているのですが、ホームページ作成の初心者には、このフォルダの存在意義を理解するのが難しいと思います。
超初心者の方のために、まず外部からアクセスできないとはどういう事なのかを説明したいと思います。
http://www.geocities.jp/yukke_no_kobeya/homepage/index.html
こちらは、このホームページ作成のトップページのリンクで、homepageフォルダの中のindex.htmlファイルを開いています。
通常はどのフォルダのファイルでも開く事ができますが、geo_cgi_privateフォルダで試してみましょう。
http://www.geocities.jp/yukke_no_kobeya/geo_cgi_private/index.html
実際にgeo_cgi_privateフォルダにindex.htmlを入れてあるのですが、ファイルが存在しないと言うエラーが出ています。
確かにアクセスする事ができません。
勿論htmlファイルだけではなくて、画像ファイルなども表示してくれません。
そうなんです。ここは公開したくないファイルを入れておくための一時的な倉庫として使用するために存在しているのです。
なんて書いたら、相当数の反論があるでしょう。
このフォルダを倉庫代わりに使うのは自由ですが、それでは本来の使い方の半分以下の使用方法でしょう。
まず、geo_cgi_privateをどう使ったら良いのかのヤフー掲示板に記載してあった質問とベスト回答をピックアップします。
(私にはgeo_cgi_privateフォルダ無用論に近い回答が多くて、唖然としてしまいました。)
- 質問その1
CGIをgeo_cgi_private内にUPし、テスト送信したら「アクセスしたページは、以下のいずれかの理由で閲覧できません」となってしまいました。なにが間違っているのでしょうか?
CGIのディレクトリ はホームページ内に自由に設置できるようだし、アクセスは、http://cgi.geocities.jp/[Yahoo! JAPAN ID/geo_cgi_private/○○○.cgi としたのですがうまくいきません。解決策教えてください。
この質問の記載ページ
【解決済のベストアンサー】
CGIをgeo_cgi_private内にUPし、テスト送信したら「アクセスしたページは、以下のいずれかの理由で閲覧できません」
geo_cgi_privateは名前の通りプライベートフォルダです、そこにCGIを置いてはいけません。
「geo_cgi_private」に置いたファイルは外部から保護されています、YAHOO独特のシステムです、そこに置くファイルは、例えば貴方が掲示板(BBS)等を設置したとしたら、書き込みデータなどは他人に見せたくないですね(書き込みした人の電子メールアドレス、場合によればIPアドレスも記録できます)、こう言う物は他人がファイル名を予測してアクセスすることが可能です、ダウンロードすることも出来ます、こう言う場合に「書き込みデータ」(bbs.log等の名前が多いようです)を「geo_cgi_private」フォルダに置いておけば外部からアクセスできません、YAHOOのCGIサーバーが拒否してくれます。
例えば(bbs.log)を「geo_cgi_private」に置いたとしたら、次のようにしてアクセスしたら見えるはずですが、アクセスする権限がありません等とのメッセージが出て保護されます。
http://cgi.geocities.jp/[Yahoo! JAPAN ID/geo_cgi_private/bbs.log
【管理人記】
このフォルダにbbs.logを置いてhttp://cgi.geocities.jp/yukke_no_kobeya/geo_cgi_private/bbs.logをアクセスしても、アクセスする権限がありません等とのメッセージは出ません。(少なくとも私の環境では昔からそうです)
ヤフーの会員ではない人(多分)が回答すると、どうしても推定で書いてしまうのでしょう。
それ以外にはYAHOOのCGIサーバーがログファイルを作成するときがあります。
YAHOOは「sendmail」を使ったメールCGIが使えます、これを使った時に送信エラーが出るときがあります、その場合「geo_cgi_private」フォルダ内に、エラーログが保存され、CGI設置者(貴方です)がエラー修正に役立てることが出来るようになっています。
「geo_cgi_private」フォルダを使用しないのであれば削除してもかまいません、必要なときはYAHOOのCGIサーバーが自動的に生成します。
CGIのディレクトリ はホームページ内に自由に設置できるようだし、−−−
CGIはサイト内であればYAHOOの場合は何処においてもかまいませんが「geo_cgi_private」だけは上の理由でだめです。
他のサーバーなどでは指定しているところがあります、「cgi-bin」と言うのが多いようです、これには理由があるのですがややこしいので省きます。
以上ご参考までに。
【私の独善的な感想】
どうでも良い事ですが、回答者の方の写真を拝見すると、私のようなおじんくさい年齢の方のようです。
この方の解説では、geo_cgi_privateフォルダはデータ(データベースやログファイル)を置く場所と認識されているようですが、私は適切な回答ではないと思います。
「geo_cgi_privateは名前の通りプライベートフォルダです、そこにCGIを置いてはいけません。」の記載には少々カチンときました。
この人から見れば、私はやってはいけない事をやっている人になります。
なぜなら、geo_cgi_privateフォルダには、htmlも置いてますし、CGIも置いてますし、しかもそれらをそこで動かしています。
外部から直接アクセスできないですし、URLにも表示されないので、このフォルダは利用価値があります。
オールCGIで作成すれば、geo_cgi_privateフォルダだけで動作させる事も可能でしょう。(そこからの起動だけは無理ですが)
この回答がベストアンサーでは、初心者の方はgeo_cgi_privateフォルダは限定的な用途向の不要に近いフォルダだと思うでしょう。
「他のサーバーなどでは指定しているところがあります、「cgi-bin」と言うのが多いようです、これには理由があるのですがややこしいので省きます。」
この記載もここでは無意味ですから、単に自分の知識の多さをアピールしたいために書いたような気がして、私は不快に感じました。
ここまで書いたのだから「cgi-bin」について説明してよと言いたいです。(内心ではまともな説明は出来ないのではと思っていますが)
「YAHOOのCGIサーバーが拒否してくれます。」は、CGIサーバーとか呼ばれるサーバーがあるとは私は知りませんでした。
通常はWEBサーバーがCGIの処理もしますので、初めて耳にしましたがCGIを専門に処理するサーバーをそのように呼ぶのでしょうか。
このような掲示板の回答には、一般的な呼び方(世間的に通用しない名称)でないものは記載すべきではないと思います。
私も念のためにCGIサーバーの名前で検索して見ましたが、検索用語の中にはありましたがCGIサーバーの名称で呼ばれているサーバーを見つける事は出来ませんでした。
それと気になったのは、この人はgeo_cgi_privateに関する質問を一手に引き受けて回答(常連の回答者)しているようですが、どうかと思う回答も散見しています。
例えば、ジオシティーズでCGI設置がうまくいきません。の回答では、「CGIはテキストですから画像などのバイナリーで転送してはいけません、手紙を写真だと言って送ってはいけないと言うことです?。」との記載がありましたが、これも正しくありません。
FTPの転送モードについて誤解されているようで、cgiと画像を手紙と写真に例えているのは不適切だと思います。
バイナリデータをテキストモードで送るというのならあきらかにミスですが、テキストデータをバイナリで送る事に問題はありません。
私は改行コードなどを指定できるエディタを使用して、全てのファイルをバイナリモードでアップロードしております。
その方が変な整形をされないので安心だからです。当然ですが、それで不都合が生じた事はありません。
ちなみにLinuxサーバー(普及率99%?)なら改行コードはLFにしておけば、問題が生じる事は無いでしょう。
CGIは改行コードが不適切だと、動作しない場合があります。
どうかと思った質問と回答をたくさん載せようと思ったのですが、特定の人を批評するような内容ばかりになりそうなので止めました。
善意の気持ちで回答しているのでしょうから、他人の揚げ足を取るような真似は避けた方が良いだろうと思ったからです。
勿論、善意の気持ちからの行動なら多少の間違いは許されるだろう(許されるべき)とは全く思っておりませんが。
パーミッションは変えられないの?
ヤフーのサーバーではアップロードしたファイルのパーミッションを自由に変えられません。
変えられるようにすると、ファイルのパーミッションを全て777にしたりする人が出て、ハッカー攻撃を受ける人が出る事を恐れているのだと思います。
まかり間違えば、そこからシステムが影響を受ける程のダメージを受ける事もありますから、大手のプロバイダのサーバーとしては仕方のない事だと思います。
通常はパーミッションを変えられなくてもファイルの拡張子で適切なパーミッションに設定されるようですから不都合を生じる事はまずありません。
問題が起きるのは、ソフトをインストールした時に、所定のパーミッションで設定されているかを確認するソフトがありますので、その時に引っかかってセットアップが進まない事があることです。
最近ではそんなソフトも少なくなってきているようですから、パーミッションが変えられない事による影響は少ないと思います。
拡張子によってアップロードできないファイルがある?
ヤフーでは拡張子によってアップロードできないファイルがあります。
一般的なファイルは全てアップロードできますから、これが問題になる事は少ないのですが、以前にMT(ムーバブルタイプ)を構築する場合に多くのファイルが拡張子が特殊なためにアップロードできなかった事がありました。
MT(ムーバブルタイプ)はバージョン別で2度入れた事がありますが、2回目はアップロードできないファイルは激減しておりました。(2回目で激減したのは、ヤフー側で対応できる拡張子を増やしたためと思われます。)
そのような場合には、私は裏ワザとして、一旦別な名前でアップロードしてから、拡張子を変更するプログラムを作成して対処しました。
私の場合は、MT(ムーバブルタイプ)を普段に使用しておりませんので、簡単な動作確認だけなのですが、ヤフーでMT(ムーバブルタイプ)をインストールしたいと思う方はチャレンジしてください。
新しいバージョンのMT(ムーバブルタイプ)はSQliteに対応していないので無理のようですが、古いバージョンなら大丈夫の筈です。
かなり以前に書いたものですが、ブログ(MT4.1)に構築方法を記載しております。
geo_cgi_privateフォルダのhtmlファイルを起動するには
geo_cgi_privateフォルダは一部の人が解説しているような、データだけを入れるためだけに存在しているのではありません。
どんなファイルを入れようとも、それは使用者の勝手なのですが、htmlfやcgiをこのフォルダに入れてはいけません等と解説するのは明らかに間違った(説明不足の)解説でしょう。
特に掲示板(BBS)ソフトやメールソフトは直接アクセスする事が出来ないこのフォルダを利用すれば、多少なりともスパムの被害を減少させる事が出来そうです。
geo_cgi_privateフォルダのhtmlファイルを外部から直接起動する事は出来ませんが、内部からcgiを使用すれば起動する事が出来ます。
そんなcgiでhtmlファイルを起動させるソフトが10年以上前から存在しています。
まさに、こんな用途にはぴったりではないでしょうか。
以下がソースになります。(ダウンロード html.lzh )
#!/usr/bin/perl
# Copyright (c) CGIROOM. http://cgiroom.nu
#======================================================================#
# [Ver 1.00] HTML CGI
#
# このプログラムによって起きた事にCGIROOMは責任を負いません。
# 利用契約に同意できない方のご利用は、遠慮下さい。
#======================================================================#
# ファイル関連
#◇ 読み込むHTMLファイル
$html{'default'}='geo_cgi_private/index.html';
#======================================================================#
$ENV{'REMOTE_HOST'} = $ENV{'REMOTE_HOST'} || $ENV{"REMOTE_ADDR"};
if($ENV{'REQUEST_METHOD'} eq "POST"){
read(STDIN, $QUERY, $ENV{'CONTENT_LENGTH'});
}else{
$QUERY = $ENV{'QUERY_STRING'};
}
foreach(split(/&/,$QUERY)){
($n,$v) = split(/=/);
$v =~ tr/+/ /;
$v =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$v=~ s/</g;
$v=~ s/>/>/g;
$v=~ s/"/"/g;
$FORM{$n} = $v if $v ne "";
}
$FORM{'T'} =~ s/\W//g;$html=$html{$FORM{'T'}}||$html{'default'};
open(HTML,$html) || &error('HTMLファイルがありません。');
$HTML .= $_ while ;
close(HTML);
foreach (split(/;/,$ENV{'HTTP_COOKIE'})){
($n,$v) = split(/=/);
$n =~ s/ //g;
$v=~ s/</g;
$v=~ s/>/>/g;
$v=~ s/"/"/g;
$v=~ s/=/=/g;
$COOKIE{$n}=$v;
}
($sec,$min,$hou,$day,$mon,$year,$wday) = gmtime(time+9*60*60);
$mon++;
$FORM{'YEAR'} = $year + 1900;
$FORM{'SEC'} = $sec < 10 ? "0$sec": $sec;
$FORM{'HOUR'} = $hou < 10 ? "0$hou": $hou;
$FORM{'DAY'} = $day < 10 ? "0$day": $day;
$FORM{'MON'} = $mon < 10 ? "0$mon": $mon;
$FORM{'SEC'} = $sec < 10 ? "0$sec": $sec;
$FORM{'SEC'} = $sec < 10 ? "0$sec": $sec;
$FORM{'Year'} = sprintf("%0.2d",$DATA{'YEAR'} % 100);
$FORM{'Month'} = ('','January','February','March','April','May','June','July','August','September','October','November','December')[$DATA{'MON'}];
$FORM{'Mon'} = ('','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec')[$DATA{'MON'}];
$FORM{'YOUBI'} = ('日','月','火','水','木','金','土')[$wday];
$FORM{'Weekday'}= ('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday')[$wday];
$FORM{'Wday'} = $DATA{'Weekday'} =~ /^(...)/;
&set_;
print "Expires: 0\n";
print "Cache-Control: no-cache\n";
print "Pragma: no-cache\n";
print "Content-type: text/html\n\n";
&pro(\$HTML,\%FORM);
print $HTML;
exit;
sub error{
&lock(8) if $lock;
print "Content-type: text/html\n\n";
print "<h1>ERROR</h1>$_[0]<hr><a href=onlyone.cgi>戻る</a> | system:<a href=\"http://cgiroom.nu\" target=cgiroom>CGIROOM</body></html>";
exit;
}
#======================================================================#
sub a{
*_ = shift;
s/("|>|<)/ $1 /go;
s/<br>/\n/go;
s/(http:\/\/[\!-;\=\?-\~]+)|([\x81-\x9F|\xE0-\xEF][\x40-\x7E|\x80-\xFC])*([\x21-\x7E]+\@[\x21-\x7E]+\.[\x21-\x7E]+)/$3 ? "$2<a href=\"mailto:$1$3\" target=_blank>$1$3<\/a>" : "$2<a href=\"$1$3\" target=_blank>$1$3<\/a>"/eog;
s/ ("|>|<) /$1/go;
s/\n/<br>/go;
}
sub encode_url{
*_ = shift;
s/(\W)/sprintf("%%%02X", ord($1))/eg;
}
sub cut{
local(*cut,$cut_size)=@_;
return $cut if $cut_size >= length($cut);
$cut = substr($cut,0,$cut_size);
chop $cut if $cut !~ /^(?:(?:[\x81-\x9F|\xE0-\xEF][\x40-\x7E|\x80-\xFC])|(?:[\x20-\x7E\xA0-\xDF]))*$/;
}
sub tagout{
*_ = shift;
s/</g;
s/>/>/g;
s/"/"/g;
}
sub formats{
$v=$2;
if(index($v,":last") >= 0){
$a = $TMP{$1}
}elsif(index($v,":form") >= 0){
$a = $FORM{$1};
}elsif(index($v,":env") >= 0){
$a = $ENV{$1};
}elsif(index($v,":cookie") >= 0){
$a = $COOKIE{$1};
}elsif($list{$1} ne ""){
$a = $list{$1}
}else{
$a = $HEAD{$1}
}
foreach(split(/\:/,$v)){
if($If{$_}){
$If{$_}->(\$a);
}elsif(/^auto\-br\((\d+)\)/o){
my($br)=$1;
$a =~ s/(\w{$br})/$1<br>/g;
}elsif(/^([\*\%\/\+\-])\((\-?\d+(?:\.\d+)?)\)/o){
$a = $If{$1}->($a,$2);
}elsif(/^cut\((\d+)\)/o){
&cut(\$a,$1)
}elsif(/^color\((.+?)\)/o){
&color(\$a,$1)
}
}
$a;
}
sub pro{
(*html,*list) = @_;
$html =~ s/__(.+?)((?::cut\(\d+\)|:last|:auto\-br\(\d+\)|:a|:encode|:form|:tagout|:cookie|:res|:env|:,|:\+\+|:\-\-|:[\*\%\/\+\-]\(\-?\d+(?:\.\d+)?\))*)__/&formats/eg;
1 while $html =~ s/<\!\-\-IF(\d*)=(\S+?)(?: (\S+) (.+?))?\-\->(.*?)(?:<\!\-\-ELSE\1=\2\-\->(.*?))?<\!\-\-END\1=\2\-\->/&ifs($2,$3,$4,$5,$6)/eis;
$html =~ s/<\!\-\-(.*?)\-\->//g if $comment_tag;
}
sub ifs{
@a = @_;
$a[0] =~ s/([^:]+)((?::cut\(\d+\)|:last|:auto\-br\(\d+\)|:a|:encode|:form|:tagout|:cookie|:res|:env|:,|:\+\+|:\-\-|:[\*\%\/\+\-]\(\-?\d+(?:\.\d+)?\))*)/&formats/eg;
if($a[1] && $IF{$a[1]}){
return $IF{$a[1]}->($a[0],$a[2]) ? $a[3] : $a[4]
}
return $a[0] ne "" ? $a[3] : $a[4]
}
sub set_{
$IF{"<"} = sub { return 1 if $_[0] < $_[1] };
$IF{">"} = sub { return 1 if $_[0] > $_[1] };
$IF{"lt"} = sub { return 1 if $_[0] lt $_[1] };
$IF{"gt"} = sub { return 1 if $_[0] gt $_[1] };
$IF{"<="} = sub { return 1 if $_[0] <= $_[1] };
$IF{">="} = sub { return 1 if $_[0] >= $_[1] };
$IF{"le"} = sub { return 1 if $_[0] le $_[1] };
$IF{"ge"} = sub { return 1 if $_[0] ge $_[1] };
$IF{"=="} = sub { return 1 if $_[0] == $_[1] };
$IF{"!="} = sub { return 1 if $_[0] != $_[1] };
$IF{"eq"} = sub { return 1 if $_[0] eq $_[1] };
$IF{"ne"} = sub { return 1 if $_[0] ne $_[1] };
$IF{"index"} = sub { return 1 if index($_[0],$_[1],0) >= 0 };
$If{"+"} = sub { $_[0] + $_[1] };
$If{"-"} = sub { $_[0] - $_[1] };
$If{"*"} = sub { $_[0] * $_[1] };
$If{"/"} = sub { $_[1] >= 1 ? $_[0] / $_[1] : 0 };
$If{"%"} = sub { $_[1] >= 1 ? $_[0] % $_[1] : 0 };
$If{"a"} = \&a;
$If{"encode"} = \&encode_url;
$If{"tagout"} = \&tagout;
$If{"++"} = sub { *if = shift; $if++ };
$If{"--"} = sub { *if = shift; $if-- };
$If{"br"} = sub { *if = shift; $if =~ s/<br>/\n/ig};
$If{"int"}= sub { *if = shift; $if = int($if) };
$If{"res"}= sub { *if = shift; $if =~ s/^|(<br>|\n)/$1> /ig};
$If{","} = sub { *if = shift; 1 while $if =~ s/(.*\d)(\d\d\d)/$1,$2/;};
}
__END__
2001
02/20 Ver 1.00
このソフトは、CGIROOMさんと言う方が開発されたものです。(コピーはソース上部のダウンロードで行ってください)
大変有益なcgi(Perl)プログラムの掲載が多かったサイトでしたが、残念ながら現在は閉鎖されてしまったようです。
このまま埋もれさせてしまうのはもったいないと思いましたので、一部ではありますが私が掲載させていただきました。
このプログラムの 説明書 です。
言うまでも無く、このプログラムの著作権はCGIROOMさんにあります。
この設定(変更可能)では、geo_cgi_privateフォルダ内にあるindex.htmlファイルを起動します。
このファイル自体は、それ以外の場所(この例ではトップページ)に置かなくてはなりません。
このcgiのファイル名はhtml.cgiですから、私の環境ではhttp://cgi.geocities.jp/yukke_no_kobeya/html.cgiとなります。
ヤフーでホームページを作成している方は、geo_cgi_privateフォルダのindex.html(変更可能)が開ける事を御確認ください。
その他では、KentWebさんのWeb Protectと言うcgiソフトを使用すれば同様の事が出来ます。
このフォルダのCGIプログラムを起動したいのであれば、こちらのコードを参考にされると良いでしょう。
私もこのプログラムを、認証ページに使用させていただいております。
画像データなどもこのフォルダに置いておけば直接アクセスされる心配はないのですが、ブラウザが勝手に画像を公開してしまいます。
画像を直接ダウンロードさせたくないのであれば、ブラウザ対策もしなければなりませんので、これは初心者には難しいでしょう。
それとここに画像を置くと、画像の表示もimgタグでは表示してくれませんのでcgiを使って表示させなければなりません。
これも結構面倒ですから、余程ダウンロードさせたくない画像でもなければ、このフォルダに画像を置くメリットは少ないでしょう。
後述する予定ですが、それなら画像を暗号化してFLASHで表示させる方が楽です。(そんなソフトが公開されています)
どの方法も完璧ではありませんが、そのような対策をすれば8〜9割の人はサイト内の画像をダウンロードする事をあきらめると思います。
私もエロ画像(?)はそのようにしています。
後日、CGIでhtmlファイルを起動させる方法を調べていたら、超簡単に出来る事が判明しました。
以下がそのファイルです。
#!/usr/bin/perl
$file = 'geo_cgi_private/index.html';
open IN,"$file";
while(){
$html .= $_;
}
close IN;
if($html){
print "Content-type:text/html\n\n";
print $html;
exit;
}
これのファイル名を index.cgi として起動させて見る事にしました。
http://cgi.geocities.jp/yukke_no_kobeya/index.cgi
私の環境では動きました。
ヤフーでメールを送っても届かない?
ヤフーでホームページを作成して、その中にメールフォームを作成した場合にメールが配信されない場合があります。
どうやらヤフーでは、ヤフーのメールアドレスを持っている人や登録してあるメールアドレスでないと配信してくれないようです。
ようですと書いたのは、私の場合はヤフーのメールアドレスを持っておりますので、メールが届かなかった事は一度もありませんので現象を確認できないためです。
ただ、色々な情報を総合して考えると上記のようになっているのではないかと推定できるのです。
ヤフーがこのようにしているのは、第三者からの迷惑メールの発信場所として使用されるのを避けようとしているのではないかと考えます。
ヤフーの会員ならそのような行為は自由に出来る訳ですが、会員の場合は管理を行い易いと言う事ではないでしょうか。
そのような仕様になっているとすると、ヤフーの会員ではない人がメールの発信者となる事ができませんから、メールフォームで送るのは無理なのかと言うと対策方法はあります。
1つは発信者をヤフーの会員にすれば良い訳です。
つまりは、メールのFrom欄を私(管理人)の名前にすれば、私は間違いなくヤフーの会員ですからメールは発信されます。
受け取る側(宛先)も私(管理人)になる訳ですから、私自身が自分の所へメールを送信した形にしてメールを書いて貰えばメールは配信されると言う訳です。
この考えに沿って作成したのが、 管理人へメール です。
フリーのCGIメールフォームソフトを一部改造して使用しております。
表面上は一般的なメールフォームと全く変わりがありませんが、差出人のメールアドレスは私(管理人)の物と差し替えてメールを発信するようになっています。
ヤフーのホームページに作成する場合はヤフーのメールアドレス、その他のプロバイダの場合はそのプロバイダから支給されたメールアドレスを使用すれば間違いなく発信されるでしょう。
本来の差出人のメールアドレスも本文中に記載されておりますから、私が返信するのに困るような事はありません。
メールフォームによるメールの最大の利点は、メールアドレスを一切公開する必要がない事です。
個人が使用しているメーラーを使う方法は配信は確実ですが、どこへ(メールアドレス)送信したのかは知られてしまいます。
しかし、この方法なら送信者が送信先を知る事は出来ません。(知るにはネット回線の情報を解析しなければなりません)
私は現在の究極の方法ではないかと思っております。
自分所へメールを送って貰う場合の主流になるのではないかとさえ思っています。
この方式の欠点と言われている部分については、その内容と対策方法を後述する予定です。
なぜ迷惑メールが来るのか(対策)
なぜ迷惑メールが来るかと言えば、メールアドレス収集ロボットと言う「メールアドレス収集プログラム」に収集されてしまうからです。
収集した人(組織)は、そのメールアドレスを販売したり、自分の販売商品の宣伝や勧誘をしたり、ウィルスを送りつけたりします。
一般の人でも一日で数十通、多い人なら数百通の迷惑メールが来ますので、メールにフィルターなどを入れて対処していると思います。
通常はメールアドレスは、<a href="mailto:example@example.com">example@example.com</a>のように記載します。
画面上では、example@example.com のように表示されます。
これでは、mailtoや@(アットマーク)を手がかりに、メール収集ロボットにメールアドレスを簡単に収集されてしまいます。
メール収集ロボットに収集されないように、色々な対策が考えられてきました。
私は実用的なのは、下記の3点の方法に絞られると思っております。
All About の スパムを防ぐ!メールアドレスの公開方法 にも色々方法が書いてありましたので参考にしてください。
1.メールアドレス全体を画像化する方法
具体例1 他サイトの例
この方法は、私も以前から一部で使用しております。
確かにメールアドレス収集ロボットは、画像の文字の内容までは見れないですから、収集されません。
画像認識装置や手入力でならメールアドレスを収集できますが、効率が悪くて採算が合わないでしょう。
しかし、この方式のデメリットは、メールアドレスの入力の面倒さに尽きると思います。
はっきり言って実用性に欠けます。
しいて使うとすれば、苦情メールの受付メールアドレスの表示にでも使えば、苦情メールを送りたい人でも、アドレス入力の面倒くささに諦めるかも知れません。(笑)
2.数値文字参照を使って記述する
この方法を簡単に言えば、<a href="mailto:exampleexample.com"> exampleexample.com </a>のように数値文字でHTMLに記入する方法です。
上記の場合では、@マークだけを数値文字にしていますが、通常は全ての文字を数値文字にします。
私の場合もこの方式を現在主流として使っておりますが、収集されやすい HTML の中に記入するのではなくて、これを JAVAScript にして外部ファイルにしております。
外部ファイルのJAVAScriptの文字も全て数値文字にすると言う念の入れようです。
この私のやり方が、この方式の最強のやり方ではないでしょうか。
実際の動作例は下記のようになります。
動作例:お問い合わせは、 お願い致します。
さすがに、これはメールアドレス収集ロボットには解析が無理なようで、今までにメールアドレスが収集された形跡はありません。
表示している送信先のメールアドレスもヤフーの使い捨てメールアドレスと言われるものなので、スパムが多くなったらいつでも削除できます。
第三者に公開するメールアドレスは、このようにすべきではないでしょうか。
3.メール送信フォームを使用する
メール送信用CGIを使用して、メール送信フォームからメールを送信して貰う方法です。
この方法の最大の利点は、送信先のメールアドレスを記載しませんので、アドレスを手入力でも収集できません。
やろうと思えば、送信者に一切のメールの宛先のアドレス情報を表示させない事も出来ます。
ネットワークのパケットを解析すれば配信先は解りますが、一般の人がそこまでしてメールの送信先を知ろうとは思わないでしょう。
メールアドレス収集ロボットは当然ながら無理ですし、手入力でも無理ですから現在の最強の方法ではないかと考えております。
ネットワークのメールの通信を暗号化すれば(出来るかも含めてやった事はありませんが)、ほぼ完ぺきな方法ではないかと思います。
このメールフォームによるメールのデメリットとして、AllAbout に記載されていたものを以下に抜粋します。
(1)掲示板への投下を目的にしたスパムが送られてくる可能性があります。
(2)送信者の手元にコピーが残りません。メーラを使いたい人には不便です。
(3)差出人アドレスの入力が誤っていると、返信したくてもできません。
(1)は掲示板のように、いたずら書きや広告宣伝の類の記載やスパムが送られてくる可能性が高いと言うことでしょうか。
これは、現在でも同様ですから、メール送信フォームにしたから増えると言うものではないと思います。
それどころか、現在は送られてきたメールをフィルターに掛ける事しか出来ませんが、メール送信フォームの場合は記入の時点でフィルターに掛けて除外できますので、メールフォーム方式の方が遥かに優れていると思います。
(2)は、送信時に控えメールを送信者に送る事で対応できます。
(3)は当たり前の事で、サーバー側にデータベースでも構築すれば、常連者にはある程度は防げるでしょうが、単なるメールフォームがそこまで対応してあげる必要があるのかどうかは疑問です。(メンバー登録制のメールの場合は当然の対策ですが)
通常のメーラーの場合は、確かにアドレス張に自分のメールアドレスを記入しますから記載ミスは生じませんが、これは送信者の自己責任と言っても良いでしょう。
私は(4)として、メールフォームによるメールの投稿は、日本人には馴染んでいない事が挙げられると思います。
長年ホームページを運営してきてつくづく感じるのは、日本人は警戒心の強い民族だなと思う事です。(悪く言えば閉鎖的で臆病な民族)
新しい物、見慣れない物に触ったり、使用するのを極度に恐れるようです。
大昔から小さい島国で生活してきたのですから、仕方のない事だとは思いますが、結果的には何事にも対応が遅れてしまいます。
メールはマイクロソフトが提供している、アウトルックエクスプレス(Outlook Express)以外は使用した事がないと言う日本人が圧倒的大多数でしょう。
そんな人は、誰が作ったのかも判らないメールフォームでの送信などは、恐ろしくて絶対出来ないと思います。
メールフォームの作成例1
フォームメールを作成するにはCGIを使用します。
フリーのフォームメール作成ソフトを検索すると数多くのソフトがピックアップされます。
Perlで作成したものやPHPで作成したもの、FLASHで作成したものなどよりどりみどりです。
使う分には出来るだけ高機能なソフトの方が良いのでしょうが、動作しない場合に原因を調べるのが大変です。
FLASHのソフトの場合は、ソースが添付していないものが多いですし、改造も改造ツール(FLASH作成ソフト)を持って居ない人が多いでしょうから、止めておきます。
やはり、一番ソフトの数が多いPerlを使用するのが、手っ取り早いでしょう。
ここでは、フォームメール を利用させていただきました。
このフォームメールの特長は、解説によると以下の通りです。
(1)CAPTCHAによるスパム送信防止機能
(2)CAPTCHA機能有効、無効選択可
(3)メールアドレス書式チェック機能
(4)メールアドレスタイプミス防止機能
(5)送信者へコピー送信
(6)送信者へのコピーにはあて先アドレス非表示
(7)設置したままメール送信だけを無効にするモード完備
(8)送信後の戻りページを指定可
(9)簡単セットアップ
CAPTCHAと言うのは、画像で表示した数字を入力させて照合させるもので、比較的よく見かけるものです。
この機能も入れたかったのですが、サーバーへのGDのインストールがうまくいかなくて、あきらめました。
All CGI(Perl)のソフトで、プログラムも見易くて好感を持てます。
以下が変更した、fmailyahoo.cgi のプログラム内容です。(多くの部分を改変しております)
#!/usr/bin/perl
#################################################
# fmailyahoo.cgi #
# http://www.hidekik.com #
# 上記サイトのfmailをYahooで使用するために改変 #
# http://openlab.ring.gr.jp/Jcode/index-j.html #
# 上記サイトの jcord.pm が同じフォルダ内に必要 #
#################################################
use strict;
use CGI qw(:cgi-lib);
use CGI::Carp qw(fatalsToBrowser);
use File::Basename;
use Jcode;
my $script = basename($0);
my $setupfile = "fmail_setup.pl";
my $admindat = "adminpwd.dat";
my $charset = "Shift_JIS";
my $lang = 0;
##### ヤフーに登録のメールアドレス(受取先)#####
our $to_mail = 'mymail@yahoo.co.jp';
#################################################
our $title = ('管理人へメール','Form mail')[$lang];
our $bgimage_en = 0;
our $bgimage_file = ''; #background image file
our $bgcolor = "#ffffff";
our $backlink_en = 1;
our $backlink = '..';
our $backlink_name = '戻る';
our $body_width = '90'; #ブラウザの使用領域 100=100%の使用
our $return_page = 0; # 0: form mail, 1: done page, 2: top page
our $mail_cmd = '/usr/sbin/sendmail -t';
our $mail_name = 1; # 1: display, 0:no display
our $body_head = "<left><h1>管理人へメール</h1></left><p>";
our $body_tail = '';
our $style_sheet_en = 0;
our $style_sheet = '';
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);
}
}
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 "<a href=\"$backlink\">$backlink_name</a><br>" if ($backlink_en);
print qq(<form method=post name="mailform" action="$script">\n);
print qq(<input type=hidden name=mode value=send>\n);
print qq(送信者のお名前(必須)<br>\n);
print qq(<INPUT type="text" size="60" name="sender"><br>\n);
print qq(送信者のメールアドレス(控えメール送信先)<br>\n);
print qq(<INPUT type="text" size="60" name="mailaddress1"><br>\n);
print qq(件名(必須)<BR>\n);
print qq(<INPUT type="text" size="60" name="subject">\n);
print qq(<br>メール本文(必須)<BR>\n);
print qq(<TEXTAREA rows="10" cols="70" name="main" wrap="soft"></TEXTAREA><br>\n);
print qq(<P><INPUT type="submit" value="送信"><p>\n);
print qq((注)ヤフーの迷惑メール防止対策のため、管理人のメールアドレスを内部的に使用しております。<br>\n);
print qq(もし、送信者のメールアドレスに控えのメールが届かない場合は、メールの送信に失敗しています。\n);
print "$body_tail";
&htmltail;
}
sub send {
my $subject = $in{subject};
my $sender = $in{sender};
my $contents = $in{main};
my $contents1 = $in{mailaddress1} . " さんより\n" . $in{main};
my $mailaddress = $in{mailaddress1};
&error("送信者の名前を記入してください。") if ($sender eq '');
&error("送信者のメールアドレスは必ず記入してください。") if ($mailaddress eq '');
&error('タイトルと本文は必ず書いてください。') if ($subject eq '' or $contents eq '');
if ($mailaddress !~ /$mail_pattern/){
my $message = ('無効なメールアドレスです','Invalid mail address')[$lang];
&error("$mailaddress:$message");
}
$contents = jcode($contents)->jis;
$contents1 = jcode($contents1)->jis;
my $from_mail;
$from_mail = $mail_name ? "$sender <$to_mail>" : "$to_mail";
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 .= "To: " . jcode("$mailaddress")->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;
if ($repeat == 0){
print SMAIL $contents1;
}else{
print SMAIL $contents;
}
close(SMAIL);
} else {
&error("メールコマンドが実行できません。<br>$mail_cmdが正しいか確認してください。");
}
}
if ($return_page == 0) {
print "Location: $script\n\n";
} elsif ($return_page == 1) {
&error("送信しました。<p><a href=\"$script\">$title</a><p><a href=\"$backlink\">$backlink_name</a>");
} 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 "<html>\n";
print "<HEAD>\n";
print "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=$charset\">\n";
print "<TITLE>$title</TITLE>\n";
if ($head_insert_en == 1){
print "$head_insert\n";
}
if ($style_sheet_en == 1){
print "<STYLE type=\"text/css\">\n";
print "$style_sheet";
print "\n</style>\n";
}
print "</HEAD>\n";
print "<BODY TEXT=\"#000000\" $bgimage LINK=\"#0000EE\" VLINK=\"#551A8B\" ALINK=\"#FF0000\">\n";
print "<table cols=1 border=0 width=\"${body_width}%\" style=\"border:0px\" align=center><tr><td style=\"border:0px;background-color:transparent\" >\n";
}
sub htmltail {
print "</td></tr></table></body></html>\n";
exit;
}
sub error {
my ($msg) = shift;
&htmlhead($msg);
print "<br><center>$msg</center>\n";
print "<br><div align=\"right\">";
print "</div>";
&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 "<form name=\"setpwd\" action=\"$script\" method=\"post\">\n";
if (! defined $file){
print "<center>管理者用パスワードを入力してください。<br>\n";
print "<input type=password name=\"pwd\" size=20>\n";
print "<input type=submit name=\"sub\" value=\"入力\">\n";
print "<input type=hidden name=\"mode\" value=\"$in{mode}\">\n";
} else {
print "<center>管理者用パスワードを設定してください。<br>\n";
print "<input type=hidden name=\"mode\" value=\"wradminpwd\">\n";
print "<input type=input name=\"pwd\" size=20>\n";
print "<input type=submit name=\"sub\" value=\"設定\">\n";
}
print "<p><div align=\"right\">";
print "</div>";
&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 = <FILE>;
close(FILE);
my $inpwd = crypt($pwd,$filepwd);
return ("$inpwd" eq "$filepwd");
} else {
&error('パスワードファイルが存在しません');
}
}
長くなるので、セットアップファイルの作成用のコードを削除しました。(パスワードファイルの作成は残してあります)
jcord.pm をインストールして、ヤフーに登録のメールアドレス(受取先)を自分用にするだけで、基本的には動くと思います。
初心者のために設置のポイントを上げるとすれば、新規に作成したフォルダにインストール(例えば mail フォルダを作成してパーミッション777)する事と、このプログラムのパーミッションも 775 or 755 にするぐらいでしょう。
改造点としては、送信者の部分を私(管理人)にして、ヤフーからのメール送信が出来るようにしただけです。
動作例としてヤフーに設置しておりますが、フォームメールになります。
実際にメールが送信されますので、テストの類はご遠慮ください。(いたずらや迷惑メールが多い場合には、閉鎖します)
メールフォームの作成例2
ここでは、フォームメール(WebFORM) (@CGI RESCUE)を利用させていただきました。
理由は単純で、このページを書いている時にフォームメールCGI提供サイトとして、All Aboutで紹介されていたからです。
実際にソフトをダウンロードして見ると、機能も単純ですから改造するには適していると思いました。
改造は、送信者のメールアドレスを固定(私自身)にするだけです。
以下が変更した、webform.cgi のプログラム内容です。(見易いように一部整形してます)
#!/usr/bin/perl
;##########################################################################
;#
;# WebFORM v4.4 <フリーソフト>
;#
;# (c)CGI-RESCUE
;# http://www.rescue.ne.jp/
;#
;# Hostory
;# 06/Jun/1998 v3.0 セキュリティ強化
;# 08/Aug/1998 v3.1 カーボンコピー処理改善
;# 29/Oct/1998 v4.0 カーボンコピー処理はセキュリティの問題で廃止
;# 16/Feb/2006 v4.1 スパムに対する脆弱性を修正
;# 08/Jul/2006 v4.2 スパムに対する脆弱性を修正(v4.1の修正ミスを修正)
;# 13/Nov/2006 v4.3 スパムメール防止機能を追加(スパムキー機能)
;# 18/Jan/2007 v4.4 スパムに対する脆弱性を修正、およびSENDMAILの誤作動データの置換処理
;#
;##########################################################################
#------ 初期設定 ----------------------------------------------------------
#■日本語コード変換ライブラリ
require './jcode.pl';
#■SENDMAILの設定
$sendmail = '/usr/sbin/sendmail';
#■受信先メールアドレス
$mailto = 'example@gmail.com';
#■名称
$title = 'メールの送信';
#■画面のボディ設定
$body = '<body bgcolor="#ffffff">';
#■記入者メールアドレス( name="email"の時 )未入力でも送信する 1:する 0:しない
$mailcheck = 1;
#■タイトル欄に入力がない場合のデフォルト値
$subject = '- NO SUBJECT -';
#■Eメール発信元のデフォルト値
$email1 = 'example@yahoo.co.jp';
#■スパムキー機能を使う場合のキーワード設定
# 画面に表示した単語、文章、文字列を入力させたり、それを画像にしたものを入力させる
# または質問の答えを書かせるなどして、このCGIの送信機能を悪用して自動で送信してくるスパムを
# 自動(ロボット)では処理できない段取りを挿入することにより防止する機能です。
# スパムキー <input type="text" name="spam_key">
# のように、「name=」を「spam_key」にして入力した内容は、CGI内に設定したキーワードと
# 「一致」(半角・全角・大文字・小文字などは区別される)しなければ送信しないという機能です。
# これを設定しても、CGI内にキーワードを設定しない場合は設定エラーになります。
# キーワードを設定しても、フォームに設定しない場合は無視されます。
# キーワードは '' の間に設定してください。例:'日本' 例:'123'
$spam_base_key = '';
#--------------------------------------------------------------------------
### 時刻取得
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
@mon_array = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
@wday_array = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
$date_now = sprintf("%s, %02d %s %04d %02d:%02d:%02d +0900 (JST)",$wday_array[$wday],$mday,$mon_array[$mon],$year +1900,$hour,$min,$sec);
### データ入力
if ($ENV{'REQUEST_METHOD'} ne "POST"){
&error('エラー','標準入力METHOD=POSTでご利用ください.');
}
read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
if ($buffer eq '') {
&error('エラー','プログラムの直接起動はできません','使い方を御確認ください');
}
$ref = &encTag($ENV{'HTTP_REFERER'});
$buffer2 = $ENV{'QUERY_STRING'};
if ($buffer2 ne '') {
&error('エラー','標準入力 METHOD=POST でご利用ください.','又は、クエリーにデータが検出されました.');
}
### デコード
@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;
$name =~ tr/+/ /;
$name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
&jcode'convert(*name,'sjis'); &jcode'convert(*value,'sjis');
#$value =~ s/http/"><s>te&st<\/s>/;#debug用
if ($value =~ /\r\n/) {
$value =~ s/\r//g;
}elsif ($value =~ /\r/) {
$value =~ s/\r/\n/g; }
if ($name eq "location") {
$lct = &encTag($value);
}elsif ($name eq "c_copy" && $value eq "on") {
$cc = "on";
}elsif ($name eq "no_check" && $value eq "on") {
$nocheck = "on";
}elsif ($name eq "space_check" && $value eq "on") {
$spcheck = "on";
}elsif ($name eq "no_check") {
;
}elsif ($name eq "ref_url") {
$ref_url = &encTag($value);
}elsif ($name eq "ref_name") {
$ref_name = &encTag($value);
}elsif ($name eq "spam_key") {
$spam_key = $value; $spam = 1;
}elsif ($name eq "subject" && $value ne "") {
$subject = &encTag($value);
}elsif ($name eq "subject") {
;
}elsif ($name eq "ref_page") {
$ref = &encTag($value);
}elsif ($name eq "password"){
$password = $value;
push(@DATA_N,$name);
push(@DATA_V,$value);
}else{
if ($name =~ /^email/i || $name =~ /^e\-mail/i) {
$value =~ s/ / /g;
if ($value =~ / / || $value =~ /;/) {
$value = "";
}
if (!($value =~ /(.*)\@(.*)\.(.*)/)) {
$value = "";
}
$email = $value;
}
push(@DATA_N,$name);
push(@DATA_V,$value);
$name = &encTag($name);
$value = &encTag($value);
push(@DATA_NS,$name);
push(@DATA_VS,$value);
}
}
### 入力チェック
$ref =~ s/\n|\r//g;
$lct =~ s/\n|\r//g;
if (!$mailcheck && $email eq '') {
&error('エラー','Eメールを入力してください.');
}
if ($mailcheck && $email eq '') {
$email = 'anonymous@on.the.net';
}
if ($spcheck eq "on"){
foreach (@DATA_V) {
if ($_ eq "") {
&error('送信できません','受信者の意向により、全ての項目を埋めないと送信できません.');
}
}
}
if ($mailto eq '' || !($mailto =~ /(.*)\@(.*)\.(.*)/)) {
&error('設定ミス','受信先メールアドレスが設定されていません.');
}
if ($spam_base_key eq '' && $spam) {
&error('設定ミス','スパムキー用のキーワードが設定されていません.');
}
if ($spam_base_key ne '' && $spam_base_key ne $spam_key) {
&error('送信できません','画面に書かれていることに従ってキーワードを入力してください.');
}
### 確認画面を出さずに送信
if ($nocheck eq "on") {
&sendmail;
}
### 内容確認画面出力
print "Content-type: text/html\n\n";
print <<"EOF";
<html>
<head>
<title>$title</title>
<META HTTP-EQUIV=Content-Type CONTENT="text/html; charset=Shift_JIS">
</head>
$body
<h1>内容確認</h1>
<form method="POST" action="webform.cgi">
<blockquote>
<table border=0 cellpadding=3 cellspacing=3>
<tr><td bgcolor="#ffcccc"><b><font size=+1>項目</font></b></td><td bgcolor="#ffcccc"><b><font size=+1>内容</font></b></td></tr>
EOF
$count = @DATA_NS;
foreach (0..$count-1) {
print "<input type=hidden name=\"$DATA_NS[($_)]\" value=\"$DATA_VS[($_)]\">\n";
print "<tr><td bgcolor=\"#ffeedd\">$DATA_NS[($_)] <br></td>";
if ($DATA_VS[($_)] =~ /\n/) { print "<td bgcolor=\"#ffffff\"><pre>$DATA_VS[($_)]</pre></td></tr>\n"; }
else { print "<td bgcolor=\"#ffffff\">$DATA_VS[($_)]</td></tr>\n"; }
print "</td></tr>\n";
}
print "</table></blockquote><p>\n";
print "<input type=hidden name=\"no_check\" value=\"on\">\n";
print "<input type=hidden name=\"ref_page\" value=\"$ref\">\n";
if ($lct ne "") { print "<input type=hidden name=\"location\" value=\"$lct\">\n"; }
if ($cc eq "on") { print "<input type=hidden name=\"c_copy\" value=\"on\">\n"; }
if ($ref_url ne "") { print "<input type=hidden name=\"ref_url\" value=\"$ref_url\">\n"; }
if ($ref_name ne "") { print "<input type=hidden name=\"ref_name\" value=\"$ref_name\">\n"; }
if ($subject ne "") { print "<input type=hidden name=\"subject\" value=\"$subject\">\n"; }
if ($password ne "") { print "<input type=hidden name=\"password\" value=\"$password\">\n"; }
if ($spam_key ne "") { print "<input type=hidden name=\"spam_key\" value=\"$spam_key\">\n"; }
if ($email eq '' || $email =~ /\,/) { print "<font size=+2><b>メールアドレスを正しく1つ入力しないと送信できません</b></font><p>\n"; }
else { print "<input type=submit value=\" 送 信 \"><p>\n"; }
print "</form><p><hr>\n";
print "<i>送信先:<a href=\"mailto:$mailto\">$mailto</a><i>\n";
print "<p></body></html>\n";
exit;
sub sendmail {
$email =~ s/\n//g;
if (length($email) > 255) { &error('エラー','メールアドレスの長さ制限は255バイトまでです.');}
if ($email =~ /\,/) { &error('エラー','メールアドレスを入力しないと送信できません.');}
$subject =~ s/\n//g;
if (length($subject) > 255) { &error('エラー','メール題名の長さ制限は255バイトまでです.'); }
$host = $ENV{'REMOTE_HOST'};
$addr = $ENV{'REMOTE_ADDR'};
if ($host eq "" || $host eq $addr) { $host = gethostbyaddr(pack('C4',split(/\./,$host)),2) || $addr; }
if (!(open(OUT,"| $sendmail -t"))) { &error('システム異常','何らかの原因で処理できません.'); }
print OUT "X-Mailer: WebFORM v4.4 by CGI-RESCUE\n";
print OUT "X-HTTP-User-Agent: " . &encTag($ENV{'HTTP_USER_AGENT'}) . "\n";
print OUT "X-Remote-host: $host \[$addr\]\n";
$Ref = &decTag($ref); print OUT "X-HTTP-REFERER: $Ref\n";
print OUT "Errors-To: $mailto\n";
print OUT "To: $mailto\n";
print OUT "From: $email1\n";
$Subject = &decTag($subject); &jis("Subject: $Subject"); print OUT "$msg\n";
print OUT "Date: $date_now\n";
print OUT "Content-Transfer-Encoding: 7bit\n";
print OUT "Content-Type: text/plain\; charset=\"ISO-2022-JP\"\n\n";
&jis("--- ここから ---"); print OUT "$msg\n\n";
$count = @DATA_N;
foreach (0..$count-1) {
if ($DATA_V[$_] =~ /\n/) { &jis("$DATA_N[$_] =\n\n$DATA_V[$_]\n"); print OUT "$msg\n"; }
else { &jis("$DATA_N[$_] = $DATA_V[$_]"); print OUT "$msg\n"; }
}
&jis("--- ここまで ---");
print OUT "\n$msg\n";
close(OUT);
if ($cc eq "on" && $lct ne '') {
print "Content-type: text/html\n\n";
print "<html><head><title>$title</title>\n";
print "<META HTTP-EQUIV=Content-Type CONTENT=\"text/html; charset=Shift_JIS\"></head>\n";
print "$body\n";
print "<h1>送信完了</h1>\n";
print "今<a href=\"mailto:$mailto\">$mailto</a>宛てに送信された内容は以下の通りです.<br>\n";
print "内容の写しとしてお控えください.<p>\n";
print "<form>\n";
print "<blockquote>\n";
print "<textarea cols=70 rows=20>";
&cc;
print "</textarea></form></blockquote><p>\n";
print "<h3>[<a href=\"$lct\" target=\"_top\">コピーしたら次へ</a>]</h3>";
}elsif ($cc eq "on") {
print "Content-type: text/html\n\n";
print "<html><head><title>$title</title>\n";
print "<META HTTP-EQUIV=Content-Type CONTENT=\"text/html; charset=Shift_JIS\"></head>\n";
print "$body\n";
print "<h1>送信完了</h1>\n";
print "今<a href=\"mailto:$mailto\">$mailto</a>宛てに送信された内容は以下の通りです.<br>\n";
print "内容の写しとしてお控えください.<p>\n";
print "<form>\n";
print "<blockquote>\n";
print "<textarea cols=70 rows=20>";
&cc;
print "</textarea></form></blockquote><p>\n";
if ($ref_url ne '' && $ref_name ne '') { &jcode'convert(*ref_name,'sjis');
print "<h3>[<a href=\"$ref_url\" target=\"_top\">$ref_name</a>]</h3>"; }
print "</body></html>\n";
}elsif ($lct ne '') { print "Location: $lct\n\n";
}else {
print "Content-type: text/html\n\n";
print "<html><head><title>$title</title>\n";
print "<META HTTP-EQUIV=Content-Type CONTENT=\"text/html; charset=Shift_JIS\"></head>\n";
print "$body\n";
print "<H1>送信完了</H1>\n";
print "ご記入されたものは<a href=\"mailto:$mailto\">$mailto</a>宛てにメールされました.<br>\n";
print "Thank you for sending comments to $mailto .<p>\n";
if ($ref_url ne '' && $ref_name ne '') { &jcode'convert(*ref_name,'sjis'); print "<h3>[<a href=\"$ref_url\" target=\"_top\">$ref_name</a>]</h3>"; }
print "<p></body></html>\n";
}
exit;
}
sub cc {
print "Date: $date_now\n";
print "To: $mailto\n";
print "Subject: $subject\n\n";
foreach (0..$count-1) {
if ($DATA_VS[$_] =~ /\n/) {
print "$DATA_NS[$_] =\n\n$DATA_VS[$_]\n";
}else{
print "$DATA_NS[$_] = $DATA_VS[$_]\n";
}
}
}
sub jis {
$msg = $_[0];
local(@msg);
@msg = split(/\n/,$msg);
foreach $i (0..$#msg) {
if ($msg[$i] eq '.') {
splice(@msg,$i,1,'..');
}
}
$msg = join("\n",@msg);
&jcode'convert(*msg, 'jis');
}
sub encTag {
local($line) = $_[0];
$line =~ s/"/"/g;
$line =~ s/</</g;
$line =~ s/>/>/g;
$line;
}
sub decTag {
local($line) = $_[0];
$line =~ s/"/"/g;
$line =~ s/</</g;
$line =~ s/>/>/g;
$line;
}
sub error {
print "Content-type: text/html\n\n";
print "<html><head><title>$title</title>\n";
print "<META HTTP-EQUIV=Content-Type CONTENT=\"text/html; charset=Shift_JIS\"></head>\n";
print "$body\n";
print "<h1>$_[0]</h1>\n";
print "<h3>$_[1]</h3>\n";
if ($ref eq '') {
print "※ フォームページが取得できません.<br>\n";
print "※ ブラウザの[戻る]ボタンを押して前の画面に移動してください.<p>\n";
}else{
print "※ フォームページ <a href=\"$ref\">$ref</a><br>\n";
print "※ フォームページ又はブラウザの[戻る]ボタンを押して前の画面に移動してください.<p>\n";
}
print "<p></body></html>\n";
exit;
}
改造は赤で表記の5か所だけです。(メールの送信先と自分のメールアドレスは御自身の環境に合わせてください)
他にはコメントを追加したり、表示の文言を変えたりしておりますが、動作には関係ありません。
<p>の使い方が私のやり方と異なるので変更しようと考えておりますが、現在はそのままです。
1か所でも間違えると、インターナルサーバーエラーが出て動作しないと思います。
送信先を設定できるメールフォームの例
上記のメールフォームでも送信先を自由に設定できるようにするのは容易なのですが、以前から私が使用しているフォームメールソフトがありますので紹介します。
このメールは、私の競馬予想の内容を御自分のメール(携帯電話も可能)に送っていただこと思って作成したものです。
1年近く運用しておりますが、最初にこれを公開した時に迷惑メールの発信源として利用されてしまわないかと私は心配していたのですが、使用したいと思う人はメールアドレスの収集に使われるのではないかと考えるようで利用者は少ないです。
誰でも捨てメールのアドレスの1つや2つは持っているでしょうから、怖がらずにもっと利用していただきたかったです。
(現在は競馬予想を休止しておりますので、メールの利用者はおりません)
このメールフォームは、Friendmail CGIv2.01 を使用させていただいております。
このソフト(フリーソフト)の、利用規約(免責事項)は以下のようになっております。
フリーソフトにつきましては、著作権表示部分を除き、修正してご利用頂いたり、複製、再配布も可能です。 ただし、修正したソフトを再配布するに当たっては、スクリプト内の見やすい場所に修正点と再配布である旨を記載しなければなりません。
条件付ですが、ソフト内容の修正が可能な事と、修正したソフトを再配布する事も出来るようです。
プログラムのファイル数(13)やデータファイル数(8)も多いので、初心者には改造が難しいと思います。
参考にメインとなる form.cgi の内容を記載します。(セキュリティ上の理由から、運用しているソフトの記載と異る部分があります)
実際の運用例
馬ちゃんの競馬予想を メール や 携帯メール に転送する事ができます。(フレームページ用なので、ここではレイアウトが乱れます)
#!/usr/bin/perl
###########################################################################
##------------------- Friendmail CGI(Form) v1.0 -----------------------
## (C)Copyright 2001 by Chama.ne.jp
## E-mail:master@chama.ne.jp
## HP:http://www.chama.ne.jp
###########################################################################
#---------- ↓初期設定項目 -----------------------------------------------#
#保存ファイルの指定---------------------------------
#管理CGIの名前
$kanri_cgi = 'kanri.cgi';
#入力フォーム管理CGI名
$formmake_cgi = 'formmake.cgi';
#入力フォーム表示CGI名
$form_cgi = 'form.cgi';
#メール配信CGI名
$formmail_cgi = 'formmail.cgi';
#管理データファイル名
$k_file = 'data/kihon.cgi';
#CGI情報ファイル名
$cgi_file = 'data/cgi.cgi';
#入力フォームデータ保存ファイル名
$f_file = 'data/def.cgi';
#入力フォームDBファイル名
$fdb_file = 'data/form.cgi';
#IPアドレス情報ファイルの指定
$ip_file = 'data/ip.cgi';
#スタイルシートの指定
$stylehtml = 'style.css';
#---------- ↓プログラム--------------------------------------------------#
require './jcode.pl';
&decode;
#ファイルロック
&o_lock;
#基本ファイルを開く
&k_open;
#CGI情報を取得
&cgi_open;
#投稿・閲覧拒否IPとマッチング
$ip_err = &ip_open;
if($ip_err == 1){
#ロック解除
&c_lock;
⊤
print "
\n";
print "入室できません。\n";
&last;
}
#フォームデータファイルを開く
&f_open;
if($in{'id'}){
&fdb_open;
}
#ロック解除
&c_lock;
#入力フォームの表示
&prev;
#サブルーチン--------------------------------------------------------------#
#デコード処理-------------------------------------------------------------
sub decode{
if ($ENV{'REQUEST_METHOD'} eq "POST") {
read(STDIN, $buff, $ENV{'CONTENT_LENGTH'});
} else {
$buff = $ENV{'QUERY_STRING'};
}
@pairs = split(/&/,$buff);
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/</g;
$value =~ s/>/>/g;
$in{$name} = $value;
}
}
#基本ファイルのOPEN------------------------------------------------------
sub k_open{
open KF,"$k_file" or die "$k_file オープン失敗";
while (){
$_ =~s/[\r\n\t\f]//g;
($mail,$url,$logo,$title,$title_size,$title_color,
$word_size,$word_color,$table_color,$td_color,
$bg_file,$pass,$sendmail,$track_color,
$face_color,$shadow_color,$darkshadow_color,$hightlight_color,
$dlight_color,$arrow_color,$subject_in,
$mail_on,$title_on,$i_url,$i_logo,$i_bgcolor) = split(/<>/,$_);
}
close KF;
}
#CGI情報の取得----------------------------------------------------------
sub cgi_open{
open CGIIN,"$cgi_file" or die "$cgi_file Cannot Open";
while(){
$_ =~ s/[\r\n\t\f]//g;
$copyright = $_;
}
close CGIIN;
}
#入力フォームデータのopen------------------------------------------------
sub f_open{
open FIN,"$f_file" or die "$f_file オープン失敗";
while (){
chomp $_;
($f_max,$f_title,$f_cols,$f_rows,$f_com,$f_last,$f_top,$f_size,$f_color) = split(/<>/,$_);
}
close FIN;
}
#投稿・閲覧拒否IPアドレス情報とマッチング---------------------------------
sub ip_open{
#IPアドレスを$usr_ipに、登録済みのIPを@ipに入れ、マッチしたら1を返すルーチン
$usr_ip = $ENV{'REMOTE_ADDR'};
$ip_err = 0;
open IPIN,"$ip_file" or die "$ip_file オープン失敗";
while (){
$_ =~s/[\r\t\f\n]//g;
if($_ eq $usr_ip){
$ip_err = 1;
}
@ip = (@ip,$_);
}
close IPIN;
return($ip_err);
}
#フォームDBファイルを開く------------------------------------------
sub fdb_open{
open FDBIN,"$fdb_file" or die "$fdb_file Cannot open";
while(){
$_ =~ s/[\r\n\t\f]//g;
($fdb_id[$fdb_cnt],$fdb_title[$fdb_cnt],$fdb_com[$fdb_cnt]) = split(/<>/,$_);
if($in{'id'} eq $fdb_id[$fdb_cnt]){
$v_fdbid = $fdb_id[$fdb_cnt];
$v_fdbtitle = $fdb_title[$fdb_cnt];
$v_fdbcom = $fdb_com[$fdb_cnt]
}
$fdb_cnt++;
}
close FDBIN;
}
#入力画面の表示----------------------------------------------------------
sub prev{
⊤
print "<br><br>\n";
print "<font size=\"$f_size\" color=\"$f_color\">\n";
print $f_top;
print "</font>\n";
print "<FORM action=\"$formmail_cgi\" method=\"post\">\n";
print "<table border=\"0\" width=\"640\" cellpadding=\"0\" cellspacing=\"1\" bgcolor=\"$table_color\">\n";
print "<tbody>\n";
print "<tr bgcolor=\"$td_color\">\n";
print "<td align=\"center\" colspan=\"2\">\n";
print "<font size=\"3\" color=\"$title_color\">\n";
print "<b>\n";
print "メール入力フォーム (最大 $f_maxヶ所迄配信出来ます)";
print "</b>\n";
print "</font>\n";
print "</td>\n";
print "</tr>\n";
print "<tr bgcolor=\"$td_color\">\n";
print "<td width=\"240\" valign=\"top\">\n";
print "<font size=\"$word_size\" color=\"$word_color\">\n";
print "送信先 Mail アドレス\n";
print "</font>\n";
print "</td>\n";
print "<td width=\"400\">\n";
print "<font size=\"$word_size\" color=\"$word_color\">\n";
$fm_cnt = 1;
$f_name = '';
while($f_max >= $fm_cnt){
$f_name = 'in_mailto';
$f_name .= $fm_cnt;
# print "$fm_cnt\:\n";
print "<INPUT type=\"text\" size=\"35\" name=\"$f_name\">\n";
print "<br>\n";
$fm_cnt++;
}
print "</td>\n";
print "</tr>\n";
print "<tr bgcolor=\"$td_color\">\n";
print "<td valign=\"top\">\n";
print "<font size=\"$word_size\" color=\"$word_color\">\n";
print "送信元 Mail アドレス\n";
print "</font>\n";
print "</td>\n";
print "<td>\n";
print "<INPUT type=\"text\" size=\"35\" name=\"in_from\" value=\"yukkenokobeya\@yahoo.co.jp\">\n";
print "</td>\n";
print "</tr>\n";
print "<tr bgcolor=\"$td_color\">\n";
print "<td valign=\"top\">\n";
print "<font size=\"$word_size\" color=\"$word_color\">\n";
print "メールのタイトル\n";
print "</font>\n";
print "</td>\n";
print "<td>\n";
print "<INPUT type=\"text\" size=\"50\" name=\"in_title\" value=\"";
if($v_fdbid){
print $v_fdbtitle;
}else{
print $f_title;
}
print "\">\n";
print "</td>\n";
print "</tr>\n";
print "<tr bgcolor=\"$td_color\">\n";
print "<td valign=\"top\">\n";
print "<font size=\"$word_size\" color=\"$word_color\">\n";
print "メール本文\n";
print "</font>\n";
print "</td>\n";
print "<td>\n";
print "<TEXTAREA cols=\"$f_cols\" rows=\"$f_rows\" name=\"in_com\">\n";
if($v_fdbid){
$v_fdbcom =~ s/<br>/\n/g;
print $v_fdbcom;
}else{
$f_com =~ s/<br>/\n/g;
print $f_com;
}
print "</TEXTAREA>\n";
print "<font size=\"$word_size\" color=\"$word_color\">\n";
print $f_last;
print "</font>\n";
print "</td>\n";
print "</tr>\n";
print "<tr bgcolor=\"$td_color\">\n";
print "<td align=\"center\" colspan=\"2\">\n";
print "<br><br>\n";
print "<INPUT type=\"submit\" value=\"確認画面\">\n";
print "<INPUT type=\"reset\" value=\"リセット\">\n";
print "<br><br>\n";
print "</td>\n";
print "</tr>\n";
print "</tbody>\n";
print "</table>\n";
print "<INPUT type=\"hidden\" name=\"in_pass\" value=\"$in_pass\">\n";
print "<INPUT type=\"hidden\" name=\"in_flag\" value=\"1\">\n";
print "</FORM>\n";
print "<br><br>\n";
print "<center>\n";
#print "<A href=\"$url\">\n";
#print "【ホームページに戻る】\n";
#print "</A>\n";
print "</center>\n";
print "<br><br>\n";
&last;
}
#HTMLprintサブルーチン---------------------------------------------------
sub top{
print "Content-type:text/html\n\n";
print "<html><head><title>$title</title>\n";
print "<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\">\n";
#print "<STYLE type=text/css>\n";
#print '<!--',"\n";
#print 'body {scrollbar-Track-Color:',$track_color,';',"\n";
#print 'scrollbar-Face-Color:',$face_color,';',"\n";
#print 'scrollbar-Shadow-Color:',$shadow_color,';',"\n";
#print 'scrollbar-DarkShadow-Color:',$darkshadow_color,';',"\n";
#print 'scrollbar-Highlight-Color:',$hightlight_color,';',"\n";
#print 'scrollbar-3dLight-Color:',$dlight_color,';',"\n";
#print 'scrollbar-Arrow-Color:',$arrow_color,';}',"\n";
#print 'INPUT{',"\n";
#print 'color : blown;border-width : 1px 1px 1px 1px;border-style : solid solid solid solid;border-color : navy navy navy navy;}',"\n";
#print '-->',"\n";
#print "</STYLE>\n";
print "</head>\n";
if($bg_file){
print "<body background=$bg_file>\n";
}else{
print "<body bgcolor=$bg_color>\n";
}
print "<center>\n";
print "<font size=$word_size color=$word_color>\n";
if($logo){
print "<IMG src=$logo>\n";
print "<br>\n";
}
unless($title_on == 2){
print "<table border=\"0\" cellpadding=\"0\" cellspacing=\"1\" bgcolor=\"$table_color\">\n";
print "<tbody>\n";
print "<tr bgcolor=\"$td_color\">\n";
print "<td align=center>\n";
print "<font size=$title_size color=$title_color>\n";
print "$title\n";
print "</font>\n";
print "</td>\n";
print "</tr>\n";
print "</tbody>\n";
print "</table>\n";
}
}
sub last{
print "<HR width=\"90%\" color=\"$word_color\">\n";
print "<font size=\"$word_size\" color=\"$word_color\">\n";
print $copyright;
print "</font>\n";
print "</center>";
print "</body></html>\n";
exit;
}
#データロック------------------------------------------------
sub o_lock{
open(LOCK,">data.lock");
flock(LOCK,2);
}
#ロック解除--------------------------------------------------
sub c_lock{
close(LOCK);
}