Perl,CGI - サンプル

更新:

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/&/&amp;/g;
	$data =~ s/</&lt;/g;
	$data =~ s/>/&gt;/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://example.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');
このエントリーをはてなブックマークに追加