宿題14

1. show_list.cgi

list.txtは、番号、名前、性別がコンマで区切られたCSVファイルである。 list.txtの内容を読み取って、各行の項目の値をタブで区切って、webページで表示するCGIスクリプトshowlist.cgiをサブルーチン化して、show_list.cgiを作成してみた。

  1. show_list.cgiとlist.txtを~/public_html/cgi中にアップロードせよ。
  2. chmod 755 show_list.cgiとパーミッションを設定せよ(FFFTPでも設定可)。

サンプル

[show_list.cgi]
#! /usr/bin/perl


my $top_page = "index.html";
my $filename = "list.txt";

my @data =();

read_records();
show_list();
exit;



################### subroutines ##################

sub show_list
{
	print "Content-Type: text/html;charset=Shift_JIS;\n\n";
	print "<html><head>\n";
	print "<title>CGI sample</title>\n";
	print "<link href=\"homework.css\" rel=\"stylesheet\"  type=\"text/css\">\n";
	print "</head>\n<body>\n";
	print "<h2>リストの表\示</h2>\n";
	print "<table>";


	foreach (@data){
		print "<tr><td>$_->{number}</td><td>$_->{name}</td><td>$_->{gender}</td></tr>\n";
	}
	print "</table>";
	print "</body></html>\n";
}


sub read_records
{
	my( $number, $name, $gender);

	# 読み取りモードでファイルを開く
	open(IN, "<$filename") || &error("Cannot read $filename: $!");

	while(<IN>){
		chomp;
		( $number, $name, $gender) = split(/,/, $_);
		# 無名ハッシュを配列にする
		push  @data, 
		{ 
			'number'=>$number, 
			'name'=>$name, 
			'gender' =>$gender
		};
	}
	# ファイルを閉じる
	close(IN);

}


# エラー表示
sub error
{
	print "Content-Type: text/html\n\n";
	print <<"---EOF---";
<html><head><title>Information</title></head>
<body>
<span sylte="color: red;"> $_[0]</span>
<form method="GET" action="$top_page">
<input type=SUBMIT value="最初のページに戻る">
</form>
</body></html>
---EOF---
	exit;
}

2. edit_record.html

show_list.cgiを改造して、新しいデータを追加できるようにしたい。そのために、新しいデータを追加するための入力フォームを、edit_record.htmlという名前のHTMLファイルとして作成しておこう。

フォームのパラメータは以下の通りとした:

サンプル

[edit_record.html]
<html>
<head>
<title>レコードの編集</title>
</head>
<body>
<form  method="POST" action="add_record.cgi" >
番号:<input type="text" name="NUMBER"><br>
名前:<input type="text" name="NAME">(空欄にすると、そのデータは削除されます)<br>
性別:
<label><input type="radio" name="GENDER" value="男">男性 </label>
<label><input type="radio" name="GENDER" value="女">女性</label>
<br>
<input type="submit" value="送信">
</form>
</body>
</html>

3. add_record.cgi

show_list.cgiを改造してadd_record.cgiという名前で、新しいデータの入力やデータの削除ができるようしよう。このCGIスクリプトは、上で作成したedit_record.htmlから呼び出すものとする。

  1. edit_record.htmlを~/public_html/cgi中にアップロードせよ。
  2. add_record.cgiを~/public_html/cgi中にアップロードせよ。
  3. chmod 755 add_record.cgiとパーミッションを設定せよ(FFFTPでも設定可)。
[add_record.cgi]
#! /usr/bin/perl

my $top_page = "index.html";
my $filename = "list.txt";

my %param;
my @data;

%param = get_param();

if( $param{NUMBER} ne "" || $param{NAME} ne "" ){
    @data =();	# @dataを初期化
    read_records();
    update_data($param{NUMBER}, $param{NAME}, $param{GENDER});
}

@data =();	# @dataを初期化
read_records();
show_list();
exit;



################### subroutines ##################
sub update_data
{
	my $Number =$_[0];
	$Number =~ s/\s+//g;	# 空白は削除
	$Number =~ s/\D+//g;	# 数字以外は削除
	my $Name = $_[1];
	my $Gender = $_[2];
	
	my $flag = 0;
	
	foreach (@data){
		if( $_->{number} eq $Number ){
			$flag = 1;
			$_->{name} = $Name;
			$_->{gender} = $Gender;
			if( $Name eq "" ){
				delete $_->{number};
				delete $_->{name};
				delete $_->{gender};
			}
		}
	}
	if($flag == 0 && $Number ne "" && $Name ne "" && $Gender ne ""){
		push  @data, { 'number'=>$Number, 'name'=>$Name, 'gender' =>$Gender };
	
	}

	# 書き込みモードでファイルを開く
	open(OUT, ">$filename") || &error("Cannot open $filename: $!");

	foreach (@data){
		if($_->{number} eq ""){ next;}	# データがNULLの場合は書き出さない。
		print OUT "$_->{number},$_->{name},$_->{gender}\n";
	}
	# ファイルを閉じる
	close(OUT);
}


sub read_records
{
	my( $number, $name, $gender);

	# 読み取りモードでファイルを開く
	open(IN, "<$filename") || &error("Cannot read $filename: $!");

	while(<IN>){
		chomp;
		( $number, $name, $gender) = split(/,/, $_);
		# 無名ハッシュを配列にする
		push  @data, 
		{ 
			'number'=>$number, 
			'name'=>$name, 
			'gender' =>$gender
		};
	}
	# ファイルを閉じる
	close(IN);

}


sub show_list
{
	print "Content-Type: text/html;charset=Shift_JIS;\n\n";
	print "<html><head>\n";
	print "<title>CGI sample</title>\n";
	print "<link href=\"homework.css\" rel=\"stylesheet\"  type=\"text/css\">\n";
	print "</head>\n<body>\n";
	print "<h2>リストの表\示</h2>\n";
	print "<table>";

	foreach (@data){
		print "<tr><td>$_->{number}</td><td>$_->{name}</td><td>$_->{gender}</td></tr>\n";
	}
	print "</table>";
	print "<a href=\"edit_record.html\">入力フォーム</a>";
	print "</body></html>\n";
}


# 入力データの取得
sub get_param
{
	my($query, $key, $value, %param);

	if($ENV{REQUEST_METHOD} eq "GET"){
		$query = $ENV{QUERY_STRING};
	}else{
		read(STDIN, $query, $ENV{CONTENT_LENGTH});
	}


	foreach(split(/&/, $query)){
		($key, $value) = split(/=/, $_);
		$value =~ s/\+/ /g;
		$value =~ s/%([\da-f][\da-f])/pack("C", hex($1))/egi;
##		&jcode'convert($value, 'euc');
		$value =~ s/\r//g;
		$param{$key} = $value;
	}
	return %param;
}


# エラー表示
sub error
{
	print "Content-Type: text/html\n\n";
	print <<"---EOF---";
<html><head><title>Information</title></head>
<body>
<span sylte="color: red;"> $_[0]</span>
<form method="GET" action="$top_page">
<input type=SUBMIT value="最初のページに戻る">
</form>
</body></html>
---EOF---
	exit;
}

4. add_record.cgi --- ヒアドキュメント(教科書p. 157)

add_record.cgiのshow_listサブルーチンをヒアドキュメントという方法で書き換える。ヒアドキュメントは、print関数でHTMLのソースを出力するとき、ラベルで指定した範囲までを出力するという書き方をしたもので、HTMLのソースコードが読みやすくなるという利点がある。

[add_record.cgi]
#! /usr/bin/perl

my $top_page = "index.html";
my $filename = "list.txt";

my %param;
my @data;

%param = get_param();

if( $param{NUMBER} ne "" || $param{NAME} ne "" ){
    @data =();	# @dataを初期化
    read_records();
    update_data($param{NUMBER}, $param{NAME}, $param{GENDER});
}

@data =();	# @dataを初期化
read_records();
show_list();
exit;



################### subroutines ##################
sub update_data
{
	my $Number =$_[0];
	$Number =~ s/\s+//g;	# 空白は削除
	$Number =~ s/\D+//g;	# 数字以外は削除
	my $Name = $_[1];
	my $Gender = $_[2];
	
	my $flag = 0;
	
	foreach (@data){
		if( $_->{number} eq $Number ){
			$flag = 1;
			$_->{name} = $Name;
			$_->{gender} = $Gender;
			if( $Name eq "" ){
				delete $_->{number};
				delete $_->{name};
				delete $_->{gender};
			}
		}
	}
	if($flag == 0 && $Number ne "" && $Name ne "" && $Gender ne ""){
		push  @data, { 'number'=>$Number, 'name'=>$Name, 'gender' =>$Gender };
	
	}

	# 書き込みモードでファイルを開く
	open(OUT, ">$filename") || &error("Cannot open $filename: $!");

	foreach (@data){
		if($_->{number} eq ""){ next;}	# データがNULLの場合は書き出さない。
		print OUT "$_->{number},$_->{name},$_->{gender}\n";
	}
	# ファイルを閉じる
	close(OUT);
}


sub read_records
{
	my( $number, $name, $gender);

	# 読み取りモードでファイルを開く
	open(IN, "<$filename") || &error("Cannot read $filename: $!");

	while(<IN>){
		chomp;
		( $number, $name, $gender) = split(/,/, $_);
		# 無名ハッシュを配列にする
		push  @data, 
		{ 
			'number'=>$number, 
			'name'=>$name, 
			'gender' =>$gender
		};
	}
	# ファイルを閉じる
	close(IN);

}


sub show_list
{
	print "Content-Type: text/html;charset=Shift_JIS;\n\n";
	print <<"_HTML_";
<html>
<head>
<title>CGI sample</title>
<link href="homework.css" rel="stylesheet"  type="text/css">
</head>
<body>
<h2>リストの表\示</h2>
<table>
_HTML_

	foreach (@data){
		print "<tr><td>$_->{number}</td><td>$_->{name}</td><td>$_->{gender}</td></tr>\n";
	}

	print <<"_HTML_";
</table>
<a href="edit_record.html">入力フォーム</a>
</body>
</html>
_HTML_

}


# 入力データの取得
sub get_param
{
	my($query, $key, $value, %param);

	if($ENV{REQUEST_METHOD} eq "GET"){
		$query = $ENV{QUERY_STRING};
	}else{
		read(STDIN, $query, $ENV{CONTENT_LENGTH});
	}


	foreach(split(/&/, $query)){
		($key, $value) = split(/=/, $_);
		$value =~ s/\+/ /g;
		$value =~ s/%([\da-f][\da-f])/pack("C", hex($1))/egi;
##		&jcode'convert($value, 'euc');
		$value =~ s/\r//g;
		$param{$key} = $value;
	}
	return %param;
}


# エラー表示
sub error
{
	print "Content-Type: text/html\n\n";
	print <<"---EOF---";
<html><head><title>Information</title></head>
<body>
<span sylte="color: red;"> $_[0]</span>
<form method="GET" action="$top_page">
<input type=SUBMIT value="最初のページに戻る">
</form>
</body></html>
---EOF---
	exit;
}

戻る