Search A.I.
Menu
ホーム

メールマガジン ホームページプログラミングテク

Windowsテク
Javaアプレット サンプル
Java Q & A
JavaScript Q & A
Perl Q & A
Perl レッスン
PHP レッスン
PHPテク
MS-DOS コマンド集
UNIX コマンド集
SQL コマンド集
SEの基礎講座
WEBシステム開発受注します
]無料フォームメール送信サービス
リンク集
Perl レッスン

1. Perl の基礎
2. Perlの文法、条件式
3. Perlの文法、条件式 - 続き
4. 配列について
5. ハッシュ配列について
6. Perlの基礎 - 続き
7. 関数について
8. 関数について - 続き
9. 文字列操作関数
10. 配列操作関数
11. ファイル操作
12. ファイル操作 - 続き
13. パラメータの受け渡し
14. クッキーについて
15. 総合練習
16. メール送信
17. ファイルアップロード
18. パッケージの使用方法
19. MySQL
20. MySQL - 続き(1)
21. MySQL - 続き(2)
22. PostgreSQL
23. 総合練習
24. 総合練習解答



14. クッキーについて

今日は、クッキーについてご説明いたします。

■クッキーについて
クッキーとは、アクセスしてきたユーザのローカルマシンにテキストデータ
を保存できる機能のことを言います。

例えば、アクセスカウンターなどで同じ人がアクセスしてきた場合は、カウント
しないようにしたり、会員サイトなどで、ログイン情報をユーザに持たせて、
会員のみ表示できるページを表示させるなどといった使い方があります。

■クッキーの書き込み方法
ユーザマシンのクッキーに書き込むには、HTTPヘッダと呼ばれる領域に書き込み
ます。HTTPヘッダについては、レッスン6で少し説明していますので、参照して
みてください。

このHTTPヘッダに以下のような書式で記述します。

Set-Cookie: 名前=値;名前=値;・・・ expires=有効期限;

この、"名前=値;名前=値;・・・"の部分にテキストデータを書き込みます。
名前は何でも構いません。

また、有効期限というのは、クッキーの有効期限になり、任意に設定することが
できます。

例を以下に記述します。

-----------------------------------------------------------------
($secg, $ming, $hourg, $mdayg, $mong, $yearg, $wdayg) = localtime(time + 3600);
@mons = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
@week = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
$dt = sprintf("%s\, %02d-%s-%04d %02d:%02d:%02d GMT", $week[$wdayg], $mdayg, $mons[$mong], $yearg+1900, $hourg, $ming, $secg);
print "Content-type: text/html\n";
print "Set-Cookie: name=test;pass=sample; expires=$dt;\n\n";
-----------------------------------------------------------------

Perlの場合、少々面倒なのですが、このようにします。

最初の 4行は、有効期限の文字列を作成するための処理です。
expires=の部分に記述するフォーマットは、

expires=Sun, 01-Jan-2005 18:00:00 GMT

のようになりますので、これに合わせたフォーマットを作成します。

まず、現在時刻と有効にしたい時間を足して、localtimeで年月日と時間を
取得します。ここで、timeは、現在時刻をUNIXタイムスタンプにしたもの
ですので、これに3600秒をプラスすると、現在時刻から 1時間後の年月日と
時間が得られます。

次に、月の配列と曜日の配列を作成し、sprintfでフォーマットを整えます。

最後にHTTPヘッダを出力します。Content-typeの前にSet-Cookieがきても
構いませんが、HTTPヘッダの終わりには、\n\nと、改行を 2つ続けます。

上記のサンプルでは、"name"というクッキー名に、"test"、"pass"という
クッキー名に"sample"というデータを格納しています。

これで、クライアントにレスポンスを返せば、クッキーに書き込まれます。

■クッキーの取り出し方
一度、ユーザのマシンに書き込んだクッキーを取り出す方法をご説明します。

クッキーを取り出すには、前回もお話した環境変数から取り出せます。
環境変数$ENV{'HTTP_COOKIE'}に格納されています。

-----------------------------------------------------------------
$cookie = $ENV{'HTTP_COOKIE'};

#// クッキー取得
@cookie = split(/ /, $cookie);
foreach(@cookie)
{
($key, $val) = split(/=/);
$data{$key} = $val;
}
-----------------------------------------------------------------

クッキーにデータを書き込む時は、";"区切りでしたが、取り出す時は、" "
(半角スペース)区切りになるようです。

これで、"名前=値"の形式になりますので、さらに"="で分解して、それぞれを
取得します。

ハッシュ配列に格納すれば、常にキーで値を取りだせるようになります。

-----------------------------------------------------------------
print $data{'name'};
print $data{'pass'};
-----------------------------------------------------------------

また、クッキーに書き込むときに、データに","や" "(半角スペース)があると、
区切り文字と判断されてしまうので、変換する必要があります。

この当りの処理を、今日のまとめサンプルで関数化しましたので、参考に
してください。

■クッキーの削除
クッキーのデータを削除、もしくはデータをクリアしたい場合は、有効期限を
過去にしてセットします。

■クッキーの制限について
クッキーは、テキストデータのみ保存可能となっております。
また、クッキーは、全体で 4Kバイトまでしか書き込めません。

"名前=値;名前=値;・・・"
の繰り返しも、20個までとなっております。

ユーザのマシンなのに何でもかんでも書き込めてしまうと、ハードディスクを
いっぱいにしたりできてしまいますので、制限は当然必要ですね。

また、クッキーに書き込んだ後、レスポンスをまだ返していない状態で、すぐに
クッキーを取り出すことはできないので、注意してください。

クッキーは、HTTPヘッダに記述するので、レスポンスを一度も返していないと、
クッキーには何も書かれていないためです。

 

★今日のまとめサンプルプログラム
-----------------------------------------------------------------
#!/usr/local/bin/perl

use strict;

my ($cookie_name, %cook_data, $str_cookie, $count);

# クッキー名
$cookie_name = "cname";

# クッキーを取得する関数
%cook_data = GetCookie();

# クッキーの内容を取得
$count = $cook_data{$cookie_name};
if ($count eq '')
{
$count = 1;
}
else
{
$count++;
}

# クッキーに書き込む文字列を作成
$str_cookie = $cookie_name . "=" . $count . ";";

# クッキーに書き込む関数
SetCookie($str_cookie, 3600);

print "Content-type: text/html\n\n";
print << "END_OF_HTML";
<html>
<body>
END_OF_HTML

print $count;

print << "END_OF_HTML";
回目の訪問ありがとうございます。
</body>
</html>
END_OF_HTML

#------------------------------------------------------------------
# 関数 : SetCookie
# 説明 : クッキー設定
# 引数 : 保存する文字列
# : クッキーの有効時間(秒)
# 戻値 : なし
#------------------------------------------------------------------
sub SetCookie
{
my($data, %data, $str_cookie, $cookie_time);
my($sec, $min, $hour, $mday, $mon, $year, $wday);
my(@mons, @week, $dt);

$str_cookie = @_[0];
$cookie_time = @_[1];

#// 文字列のエスケープ
$str_cookie =~ s/\,/%2C/g;
$str_cookie =~ s/ /%20/g;
$str_cookie =~ s/;//g;
$str_cookie =~ s/([^\w\=\& ])/'%' . unpack("H2", $1)/eg;

#// 有効期限設定
($sec, $min, $hour, $mday, $mon, $year, $wday) = localtime(time + $cookie_time);
@mons = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
@week = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
$dt = sprintf("%s\, %02d-%s-%04d %02d:%02d:%02d GMT", $week[$wday], $mday, $mons[$mon], $year+1900, $hour, $min, $sec);

#// ヘッダ出力
print "Set-Cookie: $str_cookie expires=$dt;\n";
}

#------------------------------------------------------------------
# 関数 : GetCookie
# 概要 : クッキー取得
# 引数 : なし
# 戻値 : クッキーのハッシュ値
#------------------------------------------------------------------
sub GetCookie
{
my($cookie) = $ENV{'HTTP_COOKIE'};
my($key, $val, %data);
my(@cookie);

#// クッキー取得
@cookie = split(/ /, $cookie);
foreach(@cookie)
{
($key, $val) = split(/=/);

#// 文字列をデコードする
$val =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C",hex($1))/eg;
$val =~ s/%2C/\,/g;
$val =~ s/%20/ /g;
$data{$key} = $val;
}

#// 戻り値セット
return %data;
}

exit(0);
-----------------------------------------------------------------

■解説
ユーザがこのページを訪れた回数を表示するサンプルです。

最初にアクセスした時はクッキーに何も保存されていないので、デフォルトの値を
表示しますが、2回目からは、クッキーからデータを取得します。

クッキーを利用してユーザのローカルマシンに保存するので、アクセスカウンタと
違い、ユーザ毎に違うカウントが表示されます。

SetCookieは、第一引数に、クッキー名とデータを含めた文字列、第二引数に
クッキーの有効期限を渡します。また、SetCookieという関数で、","や" "などの
文字をエスケープしています。";"は、区切り文字となってしまうので、削除します。

さらに、そのままだと日本語が文字化けしてしまうので、unpack関数を使用して
%〜の文字に変換しています。

GetCookieの方で、クッキーを取得し、変換された文字列を元に戻して、ハッシュ
配列のデータで返します。SetCookieの方で、区切り文字の";"を消しているので、
この場合の区切りは、" "(半角スペース)になります。

クッキーの設定については少し難しいので、この関数をそのまま利用すると良いと
思います。

サンプルでは、クッキーの有効期限を 1時間(3600秒)に設定しています。
クッキーを削除したい場合は、有効期限を 0以下にして保存させればOKです。

 

★課題
1. クッキーに接続した日時(YYYY/MM/DD HH:MM:SS)を保存し、取り出すプログラムを
作成してください。取り出した日時は、「前回のアクセス日時」として、HTML上に
表示してください。1つのプログラムにまとめてしまっても結構です。

2. HTML上に、名前の入力ボックスを作成し、これをPOSTで受け取り、クッキーに
保存し、次回のアクセス時からは、この名前が表示されるプログラムを作成して
ください。1つのプログラムにまとめてしまっても結構です。

 

★前回の課題の解答
1. 以下のテキスト情報をPOSTで受け取って、HTML上に受け取ったデータを表示する
プログラムを作成してください。また、()の条件に合わない場合は、エラー
メッセージを表示するようにしてください。

 ・名前 (50バイトまで)
  ・郵便番号 (8バイトまで、半角数字・ハイフンのみ)
  ・住所 (255バイトまで)
  ・電話番号 (13バイトまで、半角数字・ハイフンのみ)
  ・メールアドレス (50バイトまで、"@"と"."が含まれている)
  ・コメント (255バイトまで)

→下のサンプルを参照してください。

2. 1の問題で受け取った情報をファイルに追加書き込みしていくプログラムを作成
してください。(カンマ区切り)

→下のサンプルを参照してください。

-----------------------------------------------------------------
#! /usr/local/bin/perl

print "Content-type:text/html\n\n";

print << "END_OF_HTML";
<HTML>
<BODY>
END_OF_HTML

# 1. パラメータの受け取り
%data = GetPara();
$err_msg = "";

# エラーチェック
# 名前のチェック
if (length($data{'name'}) > 50) {
$err_msg .= "名前は、50バイト以内で入力してください。<br>\n";
}

# 郵便番号のチェック
if (length($data{'post_code'}) > 8) {
$err_msg .= "郵便番号は、8バイト以内で入力してください。<br>\n";
}
elsif ($data{'post_code'} !~ /^[0-9\-]/) {
$err_msg .= "郵便番号は、半角数字かハイフンで入力してください。<br>\n";
}

# 住所のチェック
if (length($data{'address'}) > 255) {
$err_msg .= "住所は、255バイト以内で入力してください。<br>\n";
}

# 電話番号のチェック
if (length($data{'tel'}) > 13) {
$err_msg .= "電話番号は、13バイト以内で入力してください。<br>\n";
}
elsif ($data{'tel'} !~ /^[0-9\-]/) {
$err_msg .= "電話番号は、半角数字かハイフンで入力してください。<br>\n";
}

# メールアドレスのチェック
if (length($data{'email'}) > 50) {
$err_msg .= "メールアドレスは、50バイト以内で入力してください。<br>\n";
}
elsif ($data{'email'} !~ /@.*\./) {
$err_msg .= "メールアドレスの形式が正しくありません。<br>\n";
}

# コメントのチェック
if (length($data{'comment'}) > 255) {
$err_msg .= "コメントは、255バイト以内で入力してください。<br>\n";
}

if ($err_msg ne '') {
# エラーメッセージの表示
print $err_msg;
}
else {
# パラメータの表示
print "名前 : " . $data{'name'} . "<br>";
print "郵便番号 : " . $data{'post_code'} . "<br>";
print "住所 : " . $data{'address'} . "<br>";
print "電話番号 : " . $data{'tel'} . "<br>";
print "メールアドレス : " . $data{'email'} . "<br>";
print "コメント : " . $data{'comment'} . "<br>";

# 2. ファイル書き込み
$filename = "data.txt";
if (!open(FH, ">> $filename")) {
print "ファイルオープンに失敗しました。($filename)";
exit;
}

# ファイルロック
flock(FH, LOCK_EX);

# データの書き込み
print FH $data{'name'} . ",";
print FH $data{'post_code'} . ",";
print FH $data{'address'} . ",";
print FH $data{'tel'} . ",";
print FH $data{'email'} . ",";
print FH $data{'comment'} . "\n";

# ファイルロック解除
flock(FH, LOCK_UN);

# ファイルクローズ
close(FH);
}

print << "END_OF_HTML";
</BODY>
</HTML>

END_OF_HTML

#------------------------------------------------------------------
# 関数 : GetPara
# 概要 : パラメータ取得
# 引数 : なし
# 戻値 : パラメータハッシュ配列
#------------------------------------------------------------------
sub GetPara
{
my($query_string); #// エンコードされたパラメータ全体
my(@a, $a); #// エンコードされたパラメータを分解したもの
my($name, $value); #// デコードされたパラメータ
my(%in);

#// パラメータの読み込み
if ($ENV{ "REQUEST_METHOD" } eq "POST")
{
#// POSTなら標準入力から読み込む
read(STDIN, $query_string, $ENV{ "CONTENT_LENGTH"});
}
else
{
#// GETなら環境変数から読み込む
$query_string = $ENV{"QUERY_STRING"};
}

#// 「変数名1=値1&変数名2=値2」の形式をアンパサンド(&)で分解
@a = split(/&/, $query_string);

# パラメータの取得
foreach $a (@a)
{
#// =(イコール)で分解
($name, $value) = split(/=/, $a);
#// + や %8A などのデコード
$value =~ tr/+/ /;
$value =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex( $1 ))/eg;
$value =~ s/\t/ /g;
$value =~ s/\r//g;
$value =~ s/\n/<br>/g;
#// 後で使用するため,$in{'パラメータ名'} に代入しておく
$in{ $name } = $value;
}

return %in;
}

exit;
-----------------------------------------------------------------

■解説
前回のサンプルで記述したGetPara()関数をそのまま持ってきています。

長さをチェックするときは、length()関数を使用します。

上の解答例では、エラーが発生した場合は、エラーメッセージを変数に入れ、
その変数が空でない場合は、メッセージを表示して終了します。

エラーがない場合は、 2問目のファイル書き込みを行います。
ファイル書き込み時は、ファイルロックを行っています。




前の章へ 次の章へ


このエントリーをはてなブックマークに追加


OfficeLance

お問い合わせはこちらから