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. 総合練習解答



17. ファイルアップロード

今日はファイルアップロードについて、ご説明いたします。

■ファイルアップロードの概要
ユーザから、画像などのファイルをアップロードして保存したい場合などが
あるかと思います。Perlを使用すれば、こういった場合でもブラウザから
ユーザのローカルマシンに入っているファイルをサーバへアップロードして
もらうことができます。

■HTMLの記述
まず、ファイルアップロードをしてもらうためのページを作成します。
ファイルアップロードをするには、通常のフォームではできません。

<form>タグのenctypeに、multipart/form-dataを指定し、ファイル名を指定する
ボックスを用意します。

-----------------------------------------------------------------
<HTML>
<BODY>
<FORM action="upload.cgi" enctype="multipart/form-data" method="post">
ファイル: <INPUT type="file" name="upload_file" size="32"><BR>
<INPUT type="submit" value="送信">
</FORM>
</BODY>
</HTML>
-----------------------------------------------------------------

enctypeに、multipart/form-dataを指定しない場合は、テキストを送るという
ことになりますが、上記のように記述すると、テキスト以外のバイナリファイル
をアップロードできます。

<input>タグのtypeにfileを指定すると、ファイルの参照ボタンの付いたテキスト
ボックスが表示されます。これにより、ユーザが自分のローカルマシンのファイルを
選んで、アップロードすることができます。

また、ファイルをアップロードしてもらう場合は、必ずPOST送信にしてください。

■受け取り側の処理
アップロードされたファイルを受け取る処理をご説明します。

Perlでファイルを受け取るには、CGI.pmというパッケージを使用すると楽です。
CGI.pmパッケージは、Perlのインストール時にライブラリに入っているので、
特にインストールは必要ないと思います。

-----------------------------------------------------------------
use CGI;
$query = new CGI;
-----------------------------------------------------------------

上記のように、まずnewをして、パッケージを使用できる状態にします。
次に、ファイル名を取得します。

-----------------------------------------------------------------
# ファイル名の取得
$filename = $query->param('upload_file');
-----------------------------------------------------------------

upload_fileという文字列は、前のHTMLで<input>タグで指定したnameになります。
次に、ファイル読み込みと同じ要領で、バイナリ形式で読み込みます。

-----------------------------------------------------------------
# ファイルの受け取り
while($bytesread = read($filename, $buffer, 2048)) {
$file .= $buffer;
}
-----------------------------------------------------------------

2キロバイトずつ読み込んで、$file変数に格納します。$file変数は、テキスト
データではなく、バイナリ形式になっているので、ご注意ください。

-----------------------------------------------------------------
※バイナリ形式とは?
バイナリ形式を一言では説明できないのですが、簡単に言うと、テキスト形式
ではない、画像(.jpgなど)や音声(.wavなど)、プログラムの実行ファイル
(.exeなど)などを指します。
このため、テキストエディタでバイナリ形式を開くと、文字化けしたような
表示になります。
実際には、ファイルの先頭部分に、そのファイルがどんな形式(jpgやexeなど)
なのかが定義されていて、プログラムがそれを見て判断しています。(拡張子で
判断する場合もありますが、拡張子は変更できるので、正確ではありません。)
-----------------------------------------------------------------

受け取ったファイルを保存する場合は、以下のようにします。

-----------------------------------------------------------------
# ファイルの保存
open(OUT, "> ./tmp.dat") or die("ファイルの保存に失敗しました。");
binmode(OUT);
print(OUT $file);
close(OUT);
-----------------------------------------------------------------

書き込みモードで、保存したいファイル名でファイルオープンしますが、
binmode関数を使用して、バイナリ形式であることを明示する必要があります。

■アップロードファイルの情報
アップロードされたファイルが画像なのか、音声ファイルなのかの情報が
必要な場合があります。以下の方法でMIMEタイプという、ファイル形式の
分かる文字列が取得できます。

-----------------------------------------------------------------
# ファイル形式の取得
$type = $query->uploadInfo($filename)->{'Content-Type'};
-----------------------------------------------------------------

拡張子で判断しても良いですが、MIMEタイプで判定した方が確実と言えます。

 

★今日のまとめサンプルプログラム

index.html
-----------------------------------------------------------------
<HTML>
<BODY>
<FORM action="upload.cgi" enctype="multipart/form-data" method="post">
画像ファイル: <INPUT type="file" name="upload_file" size="32"><BR>
<INPUT type="submit" value="送信">
</FORM>
</BODY>
</HTML>
-----------------------------------------------------------------

upload.cgi
-----------------------------------------------------------------
#! /usr/local/bin/perl

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

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

use CGI;
$query = new CGI;

# ファイル名の取得
$filename = $query->param('upload_file');
# MIMEタイプの取得
$type = $query->uploadInfo($filename)->{'Content-Type'};

# ファイルの受け取り
while($bytesread = read($filename, $buffer, 2048)) {
$file .= $buffer;
}

# ファイルの保存
open(OUT, "> ./tmp.dat") or die("ファイルの保存に失敗しました。");
binmode(OUT);
print(OUT $file);
close(OUT);

print << "END_OF_HTML";

<img src="./tmp.dat"><br>
ファイル名 : $filename<br>
MIMEタイプ : $type<br>

</BODY>
</HTML>
END_OF_HTML

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

■解説
このサンプルは、画像ファイルをアップロードし、アップロードされたファイルを
表示するプログラムです。

このプログラムを実行すると、CGIの置いてあるディレクトリにアップロードした
ファイルがコピーされます。

取得したファイル名とMIMEタイプも表示されるので、確認してください。

実際にプログラムを組むときは、ファイル名がすでに存在していて、上書きされる
場合もありますので、上書きされないようにする工夫も必要です。

 

★課題
1. サンプルプログラムを改良し、ファイルサイズが100キロバイトを超えたら、
エラーメッセージを表示するプログラムを作成してください。

2. サンプルプログラムを改良し、アップロードファイルのMIMEタイプが、
JPEG以外の形式だった場合に、エラーメッセージを表示するプログラムを作成して
ください。

 

★前回の課題の解答
1. HTML上に、メール送信者(text)、件名(text)、本文(textarea)のフォームを
作成し、自分のメールアドレスへ送信されるプログラムを作成してください。

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

index.html
-----------------------------------------------------------------
<HTML>
<BODY>
<FORM action="send_mail.cgi" method="POST">
あなたのメールアドレス <INPUT type="text" name="mail_from"><br>
件名 <INPUT type="text" name="subject"><br>
本文 <textarea name="body" rows="5" cols="30"></textarea><br>
<INPUT type="submit" value="送信">
</FORM>
</BODY>
</HTML>
-----------------------------------------------------------------

send_mail.cgi
-----------------------------------------------------------------
#! /usr/local/bin/perl

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

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

# メールエージェントのパス指定
$mailer = '/usr/lib/sendmail';

#// パラメタ取得
%data = &GetPara();

# 送信者のメールアドレス
$mlfr = $data{'mail_from'};

# 宛先のメールアドレス
$mlto = 'info@searchai.jp';

# 件名
$mlsb = $data{'subject'};

# 本文
$mlms = $data{'body'};

# 日本語ライブラリの読み込み
require "./jcode.pl";

# JISコードへ変換
jcode::convert(\$mlsb, "jis");
jcode::convert(\$mlms, "jis");

# メールヘッダ作成
$mlhd = "From: $mlfr" . "\n" . "To: $mlto" . "\n" . "Subject: $mlsb" . "\n\n";

# メール送信処理
$err = 0;
open(MAIL, "| $mailer -t -f'$mlfr'") or $err = 1;
if ($err == 0) {
print MAIL $mlhd;
print MAIL $mlms;
print MAIL "\n";
close(MAIL);
print 'メール送信正常に処理しました。';
}
else {
print 'メール送信エラー';
}

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

#------------------------------------------------------------------
# 関数 : GetPara
# 概要 : パラメータ取得
# 引数 : なし
# 戻値 : パラメータハッシュ配列
#------------------------------------------------------------------
sub GetPara
{
my $self = shift;
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;
#// 後で使用するため,$in{'パラメータ名'} に代入しておく
$in{$name} = $value;
}

return %in;
}

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

■解説
以前、作成したGetPara関数を使用して、パラメータを取得しています。

日本語変換ライブラリのjcode.plを使用しているので、同じディレクトリに
入れておく必要があります。

宛先の$mltoは、自分のメールアドレスを指定してください。

メールエージェントのパスが異なる場合は、$mailerのパスを変更してください。

前回のレッスンのサンプルに、パラメータを渡すだけですので、それ以外の
説明はなくても分かるかと思います。




前の章へ 次の章へ


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


OfficeLance

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