Perl,CGI - サンプル
作成:2005-11-07、更新:2008-04-24
Perl,CGI - サンプル。
==================== Perl/CGI 基本 ====================
■環境変数
ユーザエージェント $ENV{'HTTP_USER_AGENT'}
リモートIPアドレス $ENV{'REMOTE_ADDR'}
リモートホスト名 $ENV{'REMOTE_HOST'}
参照元URL $ENV{'HTTP_REFERER'}
リクエストメソッド $ENV{'REQUEST_METHOD'}
データの長さ $ENV{'CONTENT_LENGTH'}
データのMIME $ENV{'CONTENT_TYPE'}
エンコードデータ $ENV{'QUERY_STRING'}
■Content-type
HTML Content-type: text/html
HDML Content-type: text/x-hdml; charset=SHIFT_JIS
GIF Content-type: image/gif
JPEG Content-type: image/jpeg
PNG Content-type: image/png
BMP Content-type: image/bmp
MPEG Content-type: video/mpeg
WAVE Content-type: audio/x-wav
PDF Content-type: application/pdf
一般的なバイナリ Content-type: application/octet-stream
SMAF形式着信メロディ Content-type: application/x-smaf
EZwebダウンロード形式 Content-type: application/x-up-download
■制御文
・if
if($i >= 1 && $i <= 5){
}elsif($i < 1 || ($i > 5 && $i < 10)){
}else{
}
if($i == 1)
if($i != 1)
if($i eq 1)
if($i ne 1)
・for
for($i=0;$i<10;$i++){
}
・while
while($i < 10){
$i++;
}
・ループの最初に戻る
next;
・ループを終了する
last;
==================== Perl/CGI ページ・ファイル出力 ====================
■ページ出力
#!/usr/bin/perl
print "Content-type: text/html\n\n";
print "<HTML><BODY>サンプル</BODY></HTML>";
■画像出力、データ出力
・HTMLサンプル
<IMG SRC="./cgi/imgview.cgi?param=50">
・CGIサンプル
#!/usr/bin/perl
$buffer = $ENV{'QUERY_STRING'};
@pairs=split(/&/,$buffer);
foreach $pair (@pairs){
($name,$value) = split(/=/,$pair);
$value =~ tr/+/ /;
$value =~ s/%(..)/pack("C",hex($1))/eg;
$cgi{$name} = $value;
}
$param = $cgi{'param'};
$imagefile = "img/image" . $param . ".gif";
$filesize = -s $imagefile;
print "Content-type: image/gif\n";
print "Content-Length: $filesize\n\n";
open(DATA,"$imagefile");
print <DATA>;
close(DATA);
exit;
■出力
・ソース内で出力
print "文字";
・まとめて出力(ヒアドキュメント)
print <<EOD;
<html>
<body>
表示
</body>
<html>
EOD
■ファイル
・読み書き
open(FILE,"$filename");#読み込み
open(FILE,"<$filename");#読み込み
open(FILE,">$filename");#書き込み(上書き)
open(FILE,">>$filename");#書き込み(追加書き込み)
close(FILE);#閉じる
・ファイルサイズ
$filename = "./data/test1.txt";
$filesize = -s $filename;
・サンプル1
#!/usr/bin/perl
$filename = "./data/test.txt";
open(DATA, "<$filename");
while($filedata = <DATA>){
@splitdata = split(/\t/, $filedata);
print "$splitdata[0]\t$splitdata[1]\n";
}
close(DATA);
exit;
・サンプル2
#!/usr/bin/perl
$filename1 = "./data/test1.txt";
$filename2 = "./data/test2.txt";
open(FILE1, "<$filename1");
open(FILE2, ">>$filename2");
while($filedata = <FILE1>){
@splitdata = split(/\t/, $filedata);
print FILE2 "$splitdata[3]\t$splitdata[0]\n";
}
close(FILE2);
close(FILE1);
exit;
■ディレクトリ
opendir(DIRH, "./$dirname");#開く
readdir(DIRH);#読み取る
closedir(DIRH);#閉じる
・サンプル
#!/usr/bin/perl
$dirname = "./";
$filename = "";
print "Content-type: text/html\n\n";
print "<HTML><BODY>";
opendir(DIRH, "./$dirname");
while($filename = readdir(DIRH)){
if($filename eq "." || $filename eq ".."){
next;
}
print "<A HREF=$filename>$filename</A><BR>\n";
}
closedir(DIRH);
print "</BODY></HTML>";
exit;
==================== Perl/CGI 文字列 ====================
■文字列連結
・連結
$str3 = $str1 . " : " . $str2;
$str4 = "$str1 : $str2";
・追加で連結
$str5 .= $str1;
$str5 .= $str2;
$str5 .= $str3;
$str5 .= $str4;
■文字列分割
・文字列の先頭0(1,2,・・・)後ろが-1(-2,-3,・・・)
$str = substr($str, 取り出し開始位置, 取り出す長さ);
$str = substr($str, 5);
$str = substr($str, 5, 2);
$str = substr($str, 5, -1);
■文字列検索
・前方から検索
index(対象文字列, 検索文字列, 先頭0として検索開始位置)
・後方から検索
rindex(対象文字列, 検索文字列, 末尾0として検索開始位置)
・サンプル
$str = "ABCDEFG";
$a = index($str, "E", 2);
$c = rindex($str, "B", 6);
■文字列のサイズ(バイト数)
$str = "ABCDEFG";
$b = length $str;
■パターンマッチ
$ENV{'HTTP_USER_AGENT'} =~ /Windows/;#一致
$ENV{'HTTP_USER_AGENT'} !~ /Windows/;#不一致
・複数の場合は|で区切る
$ENV{'HTTP_USER_AGENT'} =~ /Windows|Mac/;
・サンプル
#!/usr/bin/perl
$userAgent = $ENV{'HTTP_USER_AGENT'};
print "Content-type: text/html\n\n";
print "<HTML><BODY>";
if($userAgent =~ /Windows/){
print "Windows<BR>";
}else{
print "Windows以外<BR>";
}
print $userAgent;
print "</BODY></HTML>";
exit;
==================== Perl/CGI 正規表現・一致・置換 ====================
■正規表現の修飾子
・修飾子
g:一致するものを全て探す
o:1回だけ一致するものを探す
i:大文字小文字の区別なし
s:文字列を1行とみなす
m:文字列を複数行とみなす
e:文字列を式とみなす
x:拡張正規表現(空白が無効)
・メタ文字
.:任意の1文字
*:直前パターン0回以上繰り返し
+:直前パターン1回以上繰り返し
?:直前パターン0または1回以上繰り返し
^:文字列の先頭([]内で使った場合、~以外になる)
$:文字列の最後
\:エスケープ(/などをエスケープするときに使う)
|:論理輪
\d:数字。[0-9]
\D:数字以外。[^0-9]
\w:英数字。[_a-zA-Z0-9]
\W:英数字以外。[^_a-zA-Z0-9]
\s:空白。[ \t\n\r\f]
\S:空白以外。[^ \t\n\r\f]
\A:文字列の先頭。^と同じ。
\Z:文字列の最後。$と同じ。または\z。
-:[]内で範囲を示す。
■正規表現
^は、文字列の先頭
$は、文字列の最後
+は、1回以上の繰り返し
メールアドレスチェック
$filedata = "oshima\@sample.com";
if($filedata =~ /^[0-9,a-z,A-Z][0-9,a-z,A-Z,_,\.,-]+@[0-9,a-z,A-Z][0-9,a-z,A-Z,_,\.,-]+\.[a-z,A-Z]+$/){
#一致
}else{
#不一致
}
・URL:^http://[0-9,a-z,A-Z,_,\.,/,:,~,-]+$
・半角数字:^[0-9]+$
・電話番号:^[0-9][0-9,-]+[0-9]$
・URLを取り出す(URLを判別してリンクを張る)
$filedata =~ s/(https?:\/\/[-\w.!~*'" ();\/?:@&=+\$,%\#]+)/<A TARGET="_blank" HREF="$1">$1<\/A>/ig;
・メールアドレスを取り出す(メールアドレスを判別してリンクを張る)
$filedata =~ s/([\w\.\-]+\@[\w\-]+\.[\w\.\-]+)/<A HREF="mailto:$1">$1<\/A>/ig;
・HTMLタグを除去する
^は、[]内で使うと~以外。
[^>]だと>以外の全ての文字
$filedata =~ s/<[^>]*>//gs;
・大文字を小文字にする
$filedata =~ tr/A-Z/a-z/;
・小文字を大文字にする
$filedata =~ tr/a-z/A-Z/;
■置換、変換
$data =~ s/置換したい文字(正規表現可)/置換後の文字/g;
$data =~ s/変換対象のリスト/変換後の文字リスト/g;
・HTMLタグの回避
$data =~ s/&/&/g;
$data =~ s/</</g;
$data =~ s/>/>/g;
・5C(\)を含む文字の処理(表ソ十構能予申噂暴などの文字化け対策)
$data =~ s/\\/\\\\/g;
ファイル、フォーム、DBなどソース外部から取得した文字列のみ変換できる。
表示→表\示など
ソース内の文字は、実行と同時に化けてしまう(\がエスケープ処理される)
5Cがたくさんある例文
十月発売予定の暴走レースゲームソフトの表示性能は、結構すごいという噂なので、ネットで申し込んだ。
・SQLでエラーになりそうな文字
$data =~ s/\'/\\'/g;
$data =~ s/,/\,/g;
$data =~ s/\(/\\(/g;
$data =~ s/\)/\\)/g;
$data =~ s/\;/\\;/g;
・改行コードを<BR>に変換
$data =~ s/\r\n/<BR>/g;
$data =~ s/\r/<BR>/g;
$data =~ s/\n/<BR>/g;
または
$data =~ s/\015\012/<BR>/g;
$data =~ s/\015/<BR>/g;
$data =~ s/\012/<BR>/g;
・大文字を小文字にする
$filedata =~ tr/A-Z/a-z/;
・小文字を大文字にする
$filedata =~ tr/a-z/A-Z/;
==================== Perl/CGI 配列・ハッシュ ====================
■配列
@str = ("AB","CDE","F","G","HIJK");
・配列数取得
$i = $#str;
・サンプル
@str = ("AB","CDE","F","G","HIJK");
for($i=0;$i<=$#str;$i++){
$strtotal .= $str[$i];
}
print "$strtotal\n";
・2次元配列、多次元配列
@list = (["a", "あ"],
["b", "い"],
["c", "う"],
["d", "え"],
["e", "お"]);
for($i=0;$i<=$#list;$i++){
print $list[$i][0] . " : " . $list[$i][1];
}
■連想配列(ハッシュ)
・サンプル
%list = ("a" => "1",
"b" => "2",
"c" => "3",
"d" => "4",
"e" => "5");
while(($key, $value) = each %list){
print $key . " : " . $value;
}
#連想配列のkeyとvalueを取り出す
#この場合、連想配列に書いた順には表示されない
#上記の2次元配列か以下のサンプルを使えば順番に表示される
・ハッシュのキーでソートして表示する場合
foreach $key (sort keys %list){
$value = $list{$key};
print $key . " : " . $value;
}
・ハッシュのvalueの値が大きい方から逆順ソートする場合
#reverseがなければ昇順、あれば降順
foreach $key (reverse sort {$list{$a} <=> $list{$b}} keys %list){
$value = $list{$key};
print $key . " : " . $value;
}
■スプリット(配列に分割)
@splitdata = split(/分割の基準の文字/,$filedata);
@splitdata = split(/\t/,$filedata);
@splitdata = split(/,/,$filedata);
■語尾切り取り
・文字列の最後の文字を切り取る
chop $str;
・文字列の最後の改行コードを切り取る
chomp $str;
==================== Perl/CGI 日付 ====================
■日付・曜日取得、閏年、月末日計算
#曜日
@wday_array = ('<FONT COLOR="#FF0000">[日]</FONT>','[月]','[火]','[水]','[木]','[金]','[土]');
#日付の取得
#戻り値:年月日時分秒曜日
sub GetDate{
($sec, $min, $hour, $mday, $month, $year, $wday) = localtime;
$wday = $wday_array[$wday];
$month ++;
$year = $year + 1900;
my $ymm = sprintf("%02d/%02d/%02d", $year, $month, $mday);
my $hms = sprintf("%02d:%02d:%02d", $hour, $min, $sec);
return "$ymm $hms $wday";
}
#曜日の取得
#年月日を渡す
#戻り値:曜日
sub GetWday{
my $wday_num;
my($year, $month, $day) = @_;
if($month == 1 || $month == 2){
$year --;
$month += 12;
}
$wday_num = int($year + int($year / 4)
- int($year / 100)
+ int($year / 400)
+ int((13 * $month + 8) / 5) + $day) % 7;
return $wday_array[$wday_num];
}
#月末日計算
#年月を渡す
#戻り値:末尾の日数
sub GetLastDay{
my($month, $year) = @_;
my @last_day_array = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
if($month < 1 || $month > 12){
$month = (localtime)[4] + 1;
}
if($year == 0){
$year = 1900 + (localtime)[5];
}
if($month == 2 && GetLeapYear($year)){
return 29;
}else{
return $last_day_array[$month - 1];
}
}
#閏年取得
#戻り値:閏年なら1、偽なら空
sub GetLeapYear{
my $year = shift;
return ((($year % 4 == 0) && ($year % 100 != 0) || ($year % 400 == 0)) ? 1 : '');
}
==================== Perl/CGI メール送信 ====================
■メール送信 / sendmail / メールヘッダ情報
#jcode.plのパス
require "./jcode.pl";
#sendmailのパス
$mail_path = '/usr/sbin/sendmail';
#管理者情報
#宛先のメールアドレス
$mail_to = 'mailto@sample.jp';
#メールのタイトル
$mail_subject = 'ご意見・ご質問';
#送信先のメールアドレスが存在しなかった場合の返送先
$mail_return_path = 'yahoo@yahoo.co.jp';
#本文
$mail_body = 'テスト';
#送信者のメールアドレス
$mail_from = 'mailfrom@sample.com';
#JISに変換
jcode::convert(\$mail_subject, 'jis');
jcode::convert(\$mail_body, 'jis');
#メール送信
#-tは、メールのToヘッダを宛先とみなすオプション。
#通常sendmailコマンドは、宛先も同時に指定する必要がある。「sendmail test@sample.com」など。
#-iは、メール本文中に「.(ピリオド)」だけの行があってもメールの終端とみなさないオプション。
#smtpでは、ピリオドだけの行はメールの終端を意味するため、それを回避する。
#-fは、エラーメールの宛先(Return-Pathヘッダ)を付加するオプション。
if($mail_return_path ne ""){
open(MAIL, "| $mail_path -t -i -f $mail_return_path") or &Disp_Error;
}else{
open(MAIL, "| $mail_path -t -i") or &Disp_Error;
}
#print MAIL "X-Mailer: Mailer\n";
#print MAIL "Reply-To: $mail_from\n";
#print MAIL "From: $mail_subject <$mail_from>\n";
print MAIL "From: $mail_from\n";
print MAIL "To: $mail_to\n";
print MAIL "Subject: $mail_subject\n";
print MAIL "MIME-Version: 1.0\n";
print MAIL "Content-type: text/plain; charset=ISO-2022-JP\n";
print MAIL "Content-Transfer-Encoding: 7bit\n";
print MAIL "\n";
print MAIL "$mail_body\n";
print MAIL "\n";
close(MAIL);
print "Content-type: text/html\n\n";
print "送信しました。";
#エラー表示
sub Disp_Error{
print "Content-type: text/html\n\n";
print "メール送信エラー";
}
==================== Perl/CGI その他 ====================
■サブルーチン
・サンプル
#!/usr/bin/perl
$i = 0;
&count;
exit;
sub count{
for($i=0;$i<1000;$i++){
print "$i\n";
}
}
■Location
・サンプル
#!/usr/bin/perl
$filename = "image.gif";
print "Location: http://www.inunote.com/cgi/$filename\n\n";
exit;
■URLエンコード
$url = "あいうえお";
$url_enc = $url;
$url_dec = "";
#type1
#エンコード
#$url_enc =~ s/(\W)/'%' . unpack('H2', $1)/eg;
#デコード
#$url_dec = $url_enc;
#$url_dec =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack('H2', $1)/eg;
#type2
#エンコード
$url_enc =~ s/([^\w ])/'%'.unpack('H2', $1)/eg;
$url_enc =~ tr/ /+/;
#デコード
$url_dec = $url_enc;
$url_dec =~ tr/+/ /;
$url_dec =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack('H2', $1)/eg;
#type3
#デコード
#$url_dec =~ s/%(..)/pack("C", hex($1))/eg;
print $url . "\n";
print $url_enc . "\n";
print $url_dec . "\n";
■Base64
・サンプル
#!/usr/bin/perl
use MIME::Base64;
$string = "oshima";
$encoded = encode_base64($string,'');
$decoded = decode_base64($encoded);
print "元の文字 : $string\n";
print "Base64エンコード後 : $encoded\n";
print "Base64デコード後 : $decoded\n";
exit;
■日本語処理 jcode.pl
・最新版
ftp://ftp.iij.ad.jp/pub/IIJ/dist/utashiro/perl/
・書き方(\マーク忘れに注意)
&jcode'convert(*value,'sjis');#Perl4タイプ
jcode::convert(\$data,'sjis');#Perl5タイプ
・SJISにする(元の文字は自動判定)
jcode::convert(\$data,'sjis');
・EUCからSJISにする(逆ならコード指定を入れ替える)
jcode::convert(\$data,'sjis','euc');
・全角半角変換
jcode::z2h_euc(\$data); #全角カタカナを半角カタカナに(EUC)
jcode::h2z_euc(\$data); #半角カタカナを全角カタカナに(EUC)
jcode::z2h_sjis(\$data);#全角カタカナを半角カタカナに(SJIS)
jcode::h2z_sjis(\$data);#半角カタカナを全角カタカナに(SJIS)
・置換
jcode::tr(\$data,'0-9A-za-z','0-9A-za-z');#全角英数を半角英数に
jcode::tr(\$data,'!$%&','!$%&');#全角記号を半角記号に
・フォームからの日本語をSJISにする
#!/usr/bin/perl
#jcode.pl
require "./jcode.pl";
#POSTやGETを大文字に統一
$ENV{'REQUEST_METHOD'} =~ tr/a-z/A-Z/;
#フォームの内容を受け取る
if($ENV{'REQUEST_METHOD'} eq "POST"){
#POSTの場合
read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
}else{
#GETの場合
$buffer = $ENV{'QUERY_STRING'};
}
@pairs = split(/&/, $buffer);
foreach $pair(@pairs){
($name, $value) = split(/=/, $pair);
$value =~ tr/+/ /;
$value =~ s/%(..)/pack("C", hex($1))/eg;
jcode::convert(\$value, 'sjis');
$cgi{$name} = $value;
}
$text = $cgi{'text'};
■フォームデータ、リンク引数取得(POST、GET)サンプル
#!/usr/bin/perl
#jcode.pl
#require "./jcode.pl";
#POSTやGETを大文字に統一
$ENV{'REQUEST_METHOD'} =~ tr/a-z/A-Z/;
#フォームの内容を受け取る
if($ENV{'REQUEST_METHOD'} eq "POST"){
#POSTの場合
read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
}else{
#GETの場合
$buffer = $ENV{'QUERY_STRING'};
}
@pairs = split(/&/, $buffer);
foreach $pair (@pairs){
($name, $value) = split(/=/, $pair);
$value =~ tr/+/ /;
$value =~ s/%(..)/pack("C", hex($1))/eg;
# jcode::convert(\$value, 'sjis');
$cgi{$name} = $value;
}
$textbox = $cgi{'textbox'};
$textarea = $cgi{'textarea'};
$radio = $cgi{'radio'};
$select = $cgi{'select'};
$check[0] = $cgi{'check0'};
$check[1] = $cgi{'check1'};
■引数処理 cgi-lib.pl
・最新版
http://cgi-lib.berkeley.edu/
・サンプル
require "./cgi-lib.pl";
&ReadParse(*cgi);
$name = $cgi{'name'};
$mail = $cgi{'mail'};
■引数処理 CGI.pm
・サンプル
use CGI;
$cgi = new CGI;
$name = $cgi->param('name');
$mail = $cgi->param('mail');
■システムコマンド実行
・コマンド実行
system("javac -classpath $SRC_ROOT\;$SERVLET_JAR $SRC_FILE");
・パイプ利用
open(FP, "| javac -classpath $SRC_ROOT\;$SERVLET_JAR $SRC_FILE");
close(FP);
■ライブラリ、モジュール利用
・ライブラリ
CGI側
require "./sample1.pl";
require "./sample2.pl";
&Get_Date;
&Time::Get_Time
sample1.pl
$i = 0;
sub Get_Date{
}
1;
sample2.pl
package Time;
sub Get_Time{
}
1;
・モジュール
CGI側
use CGI;
$cgi = new CGI;
$name = $cgi->param('name');
$mail = $cgi->param('mail');
==================== SSI ====================
■SSI
・サンプル
<HTML>
<BODY>
現在の時刻は、
<!--#exec cmd="date"-->
です。
</BODY>
</HTML>
・時間情報
現在の日時 <!--#echo var="DATE_LOCAL"-->
ファイルの最終更新日時 <!--#echo var="LAST_MODIFIED"-->
任意ファイルの最終更新日時 <!--#flastmod file="sample.htm"-->
<HTML>
<BODY>
現在の日時は
<!--#echo var="DATE_LOCAL"-->
です。
</BODY>
</HTML>
・時間フォーマット
%y 年(00~99)
%m 月(01~12)
%d 日(01~31)
%H 時(00~23)
%M 分(00~59)
%S 秒(00~59)
%A 曜日(Monday~Sunday)
%p 午前・午後(AM・PM)
%B 月(January~December)
%h 略月(Jan~Dec)
%a 略曜日(Mon~Sun)
<HTML>
<BODY>
今日は
<!--#config timefmt="%m月%d日"-->
<!--#echo var="DATE_LOCAL"-->
です。
</BODY>
</HTML>
・ファイル情報
ファイル名 <!--#echo var="DOCUMENT_NAME"-->
ファイルのURL <!--#echo var="DOCUMENT_URI"-->
任意ファイルのサイズ <!--#fsize file="sample.htm"-->
<HTML>
<BODY>
このファイルのURLは
<!--#echo var="DOCUMENT_URI"-->
です。
</BODY>
</HTML>
・ファイルサイズフォーマット
bytes バイト
abbrev キロまたはメガバイト
<HTML>
<BODY>
この(sample_ssi_docformat.html)ファイルサイズは
<!--#config sizefmt="bytes"-->
<!--#fsize file="sample_ssi_docformat.html"-->
です。
</BODY>
</HTML>
・ファイルの取り込み
<!--#include file="sample.htm"-->
<!--#include virtual="/~cylas/sample.htm"-->
file 相対パス
virtual ルートからのパス
<HTML>
<BODY>
<!--#include file="sample_ssi_fileinclude.html"-->
</BODY>
</HTML>
・Perlプログラム実行
・Perl側
#!/usr/bin/perl
$cntlog = "sample_ssi_counter.txt";
open(LOG,"$cntlog");
while(<LOG>){
$cnt=$_;
}
$cnt++;
close(LOG);
open(LOG,">$cntlog");
print LOG "$cnt\n";
close(LOG);
print $cnt;
exit;
・HTML側
<HTML>
<BODY>
あなたは
<!--#exec cmd="./sample_ssi_counter.pl"-->
人目の訪問者です。
</BODY>
</HTML>