こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

cgi(perl)でアップロードされたファイルを保存する方法について

ファイルをアップロードするフォーム"form.html"(method="POST" action="/cgi-bin/form.cgi")を書きました。
ファイルを保存する方法について疑問があるので教えて下さい。
http://www.ss.iij4u.or.jp/~somali/web/_perl_upload.html
上記URLを参考にしました。


下記の変数"$filename"には、アップロードしたファイル名(image.jpgなど)が入っています。
(アップロードされたファイル名と保存するファイル名を同じにしました。)
#------------------------------------------------------------
open (OUT, ">$filename") || die "cannot open";
binmode (OUT);
$i=1;#ループ回数とアップロードされたファイルのサイズの比較の為。
while(read($filename, $buffer, 1024)){
print OUT $buffer;
$i++;
}
close (OUT);
close ($filename) if ($CGI::OS ne 'UNIX'); # Windowsプラットフォーム用
print "whileループの数: $i<BR>";
#------------------------------------------------------------


while文について。
while(read($filename, $buffer, 1024)){
print OUT $buffer;
上記の2行は、1024バイトづつ$filename(アップロードしたファイル名)から読み込み、$bufferに格納。
$bufferに格納されたデータをOUTで指定した部分に書き込む、そしてそれを繰り返す。
こう理解していますが間違いないでしょうか?

ファイルサイズが予想できれば、whlie文を使わずに
read($filename,$temp,10000);
print OUT $temp;
このようにしても問題ありませんか?


read関数について教えて下さい。
書籍などには、
read(FILEHANDLE,$data,1024);
こう書いてありますが、上記例でFILEHANDLEを変数名$filenameにしても問題なく動作しました。
FILEHANDLEでなく、変数$filenameでも問題無いのでしょうか?
FILEHANDLEと$filenameは何を示しているんですか?
ファイルの先頭アドレスでしょうか?
$filenameにはアップロードしたファイル名が入っているのにどうして動くのだろうと疑問に思っています。

乱文で申し訳ありませんがご教授下さい。
宜しくお願い致します。

投稿日時 - 2008-04-28 01:31:01

QNo.3981406

暇なときに回答ください

質問者が選んだベストアンサー

> print "$filename<BR>";
> print "$fh";
> この部分で出力結果を確認したら、どちらもアップロードした画像ファイル名だったので、
> ファイル名とファイルハンドルはどう違うのだろう?と思っていました。

ああ、なるほど。
それは "" で括ってるせいでしょう。たぶん。
つまり、"$fh" と書くことによって、
ruby でいうところの
$fh.to_s 見たいな操作が行われていて、その結果がprintで出力されているのです。

$fh が保持しているのはファイル名を表す文字列ではなく、ただ単に上記のような変換の結果、
ファイル名を表す文字列になってしまっているだけです。

Data::Dump モジュールの dump() 等を使って出力してみれば
違いが明確に現れると思います。

投稿日時 - 2008-04-28 16:34:32

お礼

アドバイスどおり、
print Dumper($fh);
を実行すると
bless( \*{'Fh::fh00001be.jpg'}, 'Fh' );
と出力されました。
意味は分かりませんが、特殊な変数が入っている事だけは確認できました。

回答だけでなく、聞いた事の無いキーワード"dump"を教えて頂きありがとうございます。

投稿日時 - 2008-04-30 17:51:58

このQ&Aは役に立ちましたか?

3人が「このQ&Aが役に立った」と投票しています

回答(2)

ANo.1

> 上記の2行は、1024バイトづつ$filename(アップロードしたファイル名)から読み込み、$bufferに格納。
> $bufferに格納されたデータをOUTで指定した部分に書き込む、そしてそれを繰り返す。
> こう理解していますが間違いないでしょうか?

readの第一引数はあくまでもファイルハンドル(openで取得した値など)であり、
ファイル名を引数に取ることはありません。
「OUTで指定した部分」という表現に引っかかりを感じますがまあこちらはおおむねそんなところです。

> こう書いてありますが、上記例でFILEHANDLEを変数名$filenameにしても問題なく動作しました。
> FILEHANDLEでなく、変数$filenameでも問題無いのでしょうか?

上で書いたように問題大有りです。
問題なく動作したというのは多分勘違いだと思います。

> FILEHANDLEと$filenameは何を示しているんですか?
スクリプト全体を見ないとなんともいえませんが、名前から判断すると、
$filneameはファイルの名前を保持していて、その中身を操作するための
ファイルハンドルが FILEHANDLEでしょう。

ってリンク先見たらぜんぜん違うこと書いてるじゃないですか

# ファイル取得
my $fH = $query->upload('filename');

# MIMEタイプ取得
my $mimetype = $query->uploadInfo($fH)->{'Content-Type'};

# ファイル保存
open (OUT, ">Savefile") || die "Can't open Savefile!";
binmode (OUT);
while(read($fH, $buffer, 1024)){
print OUT $buffer;
}

この例でreadの第一引数に使われている $fH は、ファイルハンドルを保持しているはずですよ。

To be safe, use the *upload()* function (new in version 2.47). When
called with the name of an upload field, *upload()* returns a
filehandle, or undef if the parameter is not a valid filehandle.

$fh = $query->upload('uploaded_file');
while (<$fh>) {
print;
}

と、CGI::upload() は filehandle を返すと明記されています。
ファイル名だなんてどこに載ってたんですか?

それと
> ファイルサイズが予想できれば、whlie文を使わずに
> read($filename,$temp,10000);
> print OUT $temp;
> このようにしても問題ありませんか?

あまりでかいサイズを一気に読もうとしなければ大丈夫でしょう。
1024はいかにも小さすぎるきらいがありますし。
というか、そのファイルサイズの予想が問題なんですけどね :)

投稿日時 - 2008-04-28 03:11:11

お礼

回答ありがとうございます。一応どんな事をしたか書いておきます。
HTMLファイル----------------------------------------------
<form action="/cgi-bin/img_upload.cgi" method="post" enctype="multipart/form-data">
画像<input type="file" name="upfile">
<input type="submit" name="send" value="送信">
<input type="reset">
</form>
----------------------------------------------------------
<img_upload.cgi>
#!H:\Perl\bin\perl.exe
print "Content-type: text/html; charset=Shift_JIS\n\n";
use CGI;
$q=new CGI;

$filename=$q->param('upfile'); #ファイル名
$fh=$q->upload('upfile'); #ファイルハンドル
print "$filename";
print "$fh";

# ファイル保存 ファイル名
open(OUT,">filename");
binmode (OUT);
read($filename,$buffer,512000);
print OUT $buffer;
close (OUT);
close ($filename) if ($CGI::OS ne 'UNIX'); # Windowsプラットフォーム用
# ファイル保存 ファイルハンドルの場合
open(OUT,">filehandle");
binmode (OUT);
read($fh,$buffer,512000);
print OUT $buffer;
close (OUT);
close ($fh) if ($CGI::OS ne 'UNIX');
----------------------------------------------------------
上記プログラムを実行すると、"filename"と"filehandle"、2つの画像ファイルを保存する事が出来ました。

>ファイル名だなんてどこに載ってたんですか?
print "$filename<BR>";
print "$fh";
この部分で出力結果を確認したら、どちらもアップロードした画像ファイル名だったので、ファイル名とファイルハンドルはどう違うのだろう?と思っていました。

http://perldoc.jp/docs/modules/CGI.pm-2.89/CGI.pod
上記ページの真ん中辺りに、
#---------------------------------------------------
$filename = $query->param('uploaded_file');
返されるファイル名はファイル・ハンドルでもあります。
#---------------------------------------------------
と書いてあるので、どちらでも問題無く動いたのでは?と思いました。

モジュールをはじめて使うので、理解不足、下調べ不足でした。
長文、乱文お許し下さい。

投稿日時 - 2008-04-28 15:25:04

あなたにオススメの質問