blog20100901

2013/08/20 - プログラミング言語 Perl にまつわる etc. - Perl monger
参考 : perldoc, perldoc.jp, search.cpan.org, perldoc.perl.org ...
「 初めての Perl 第 6 版 」(オライリー・ジャパン発行 ISBN978-4-87311-567-2) 」
「 続・初めての Perl 改訂版 」(オライリー・ジャパン発行 ISBN4-87311-305-9) 」
「 Effective Perl 第 2 版 」(翔泳社発行 ISBN978-4-7981-3981-4) 」 ... etc,.

Perl Perl_2

Perl 「 モジュール 」 CGI 実用的なファイルアップロード 16 書き込み処理 詳細 (0x11d)

Perl 「 モジュール 」 CGI 実用的なファイルアップロード 16 書き込み処理 詳細 (0x11d)

目次 - Perl Index



Theme



Perl について、復習を兼ねて断片的な情報を掲載して行く連載その 0x11d 回。

CGI.pm で、実用的なファイルアップロードの処理を確認する。その 15 回。データ書き込み処理の詳細を確認する。



ファイルアップロードのためのコード



ファイルアップロードのためのプログラムコードを改めて確認します。原理的には (0x109) の基本処理と変わりありません。


# 書き込みモードでファイルハンドルをオープン
open ( OUTFILE, ">", "$file" ) or die "Couldn't open $file for writing: $!";

# 関数 read() でファイルを読み込み
while ( $bytesread = read( $filename, $buffer, $num_bytes )) {

# $totalbytes = $totalbytes + $bytesread
$totalbytes += $bytesread;

# バッファの内容を書き込み
print OUTEFILE $buffer;
}

# もし $bytesread の値が undef なら die
die "Read failure" unless defined( $bytesread );

# もし $totalbytes の値が undef なら
unless ( defined ( $totalbytes )) {

# エラーメッセージ
print "<p>Error: Could not read file ${untainted_finename},";
print "or the file was zero length.";
} else {

# $totalbytes の値が undef でなければ完了のメッセージ
print "<p>Done. File $filename uploaded to $file ($totalbytes bytes)";
}

# ファイルハンドルをクローズ
close OUTFILE or die "Couldn't close $file: $!";




今回は上記の処理をひとつずつ確認します。


書き込みモードでファイルハンドルをオープン



まず、ファイルハンドルを、書き込みモードでオープンします。ここでは (0x44) で確認した 3 引数の open 演算子を利用しています。これは、旧来型の 2 引数の open に比較して安全です。

書き込みモードには「 > 」を利用しているため、同名のファイルがあった場合は上書きします。既存のファイルに追加で書き込みたい場合は、「 >> 」を利用します。これらの機能は、シェルの「 リダイレクション 」( リダイレクト ) 機能に準拠しています。


open ( OUTFILE, ">", "$file" ) or die "Couldn't open $file for writing: $!";



関数 die のメッセージに含まれる「 $! 」は、(0x48) で確認した通り、システムからのメッセージが格納されています。


ファイルの読み込みと書き込み



関数「 read() 」を利用したファイルの読み込みと、ファイルハンドルを利用したデータの書き込みを行います。

(0x118) で予め "宣言 / 初期化" しておいた変数を利用します。基本的な処理は (0x109) と変わりありません。


while ( $bytesread = read( $filename, $buffer, $num_bytes )) {

$totalbytes += $bytesread;
print OUTEFILE $buffer;
}


基本的な処理と異なる部分は、関数 read() が返す値 ( $num_bytes のバイト数 ) を、1 ループ毎に累算していることです。

これによって、ループが終了 ( ファイルの読み込みが完了 ) した際に、合計読み込みバイト数、つまり、読み込んだファイルのデータサイズが分かります。データサイズを格納したスカラ変数「 $totalbytes 」は、アップロード処理完了時のメッセージに利用します。

累算に利用している「 二項代入演算子 」( binary assignment operator) は、(0x86) で確認しました。


読み込みエラーの検知



読み込みんだファイルのバイト数を逐次格納するスカラ変数「 $bytesread 」を関数「 define 」でチェックして、データの読み込みエラーを検知しています。

もし、$bytesread が「 undef 」だった場合は、関数 die によってプログラムを終了しつつ「 Read failure 」( 読み込み失敗 ) のメッセージを表示します。


die "Read failure" unless defined( $bytesread );



このチェックは「 define 」を使っているのがポイントです。なぜなら、「 define 」は、未定義値「 undef 」を確認した場合のみ 偽 を返すからです。

つまり、通常の条件式では 偽 が返される「 空文字 」や数値「 0 」が対象であっても「 define 」を使えば 真 を返します。

実際に、ここで検査されている変数 $bytesread は、正常にデータを読み込んでいた場合でも、最終的には値「 0 」を持っているはずです。

それによって、while 文の条件式を抜けてきているので ( (0x109) )、式修飾子 ( (0x82) ) unless で異常をチェックするには、関数「 define 」が相応しいという訳です。

仮に、$bytesread の値が「 undef 」だった場合は、もとから何もデータを読み込めていないことを意味するので、それはエラーと判断出来ます。

関数「 define 」は、(0x1a) で確認しました。


読み込みエラーの検知 その 2



続いてもうひとつ、エラー検知のための記述があります。ここではファイルサイズを格納する変数 $totalbytes の値が「 undef 」だった場合をチェックしています。


unless ( defined ( $totalbytes )) {

print "<p>Error: Could not read file ${untainted_finename},";
print "or the file was zero length.";



変数 $totalbytes は、上述した通り、読み込んだデータの合計バイト数を持っています。

変数 $bytesread が undef ではない ( ひとつ前のチェックを通過した ) 状況で、どのようにすれば $totalbytes が undef になりえるのかは、今の僕では分かりませんが、現時点では多角的なチェックということで理解します。

仮にここで undef を確認した場合は、「 Could not read file, or the file was zero length. 」( ファイルが読み取れませんでした, または ファイルの長さがゼロです. ) と言うメッセージを表示します。

ここでは関数 die によるプログラムの強制終了はしません。何故なら、続く処理はファイルハンドルのクローズのみだからだと理解しています。


データ読み込みに問題がなかった場合



変数 $totalbytes を検査しても問題がない場合は、次の様にして、メッセージ「 ファイルのアップロードが完了した 」を表示します。


} else {

print "<p>Done. File $filename uploaded to $file ($totalbytes bytes)";

}



変数「 $filename 」で元のファイル名を、変数「 $file 」でアップロード後のファイル名を、変数「 $totalbytes 」によって、ファイルサイズを表示しています。

ちょっとした親切ですね。


ファイルハンドルをクローズする



最後の処理は、ファイルハンドルのクローズです。正常にクローズ出来なかった場合に備えて、関数 die をセットで記述しています。


close OUTFILE or die "Couldn't close $file: $!";




0x11d -> 0x11e へ



次回は、Cgi upload - perlmeme.org の例示をローカライズしつつ、全体のコードとその動作を確認します。


参考情報は書籍「 初めての Perl 第 6 版 」を中心に perldoc, Wikipedia および各 Web サイト。それと詳しい先輩。

目次 - Perl Index
















同じカテゴリー(Perl)の記事
 Perl mp2 翻訳 Web コンテンツ圧縮の FAQ (d228) (2023-10-11 23:49)
 Perl mp2 翻訳 既知のブラウザのバグの回避策をいくつか (d227) (2023-05-26 15:41)
 Perl mp2 翻訳 Perl と Apache でのキュートなトリック (d226) (2023-05-19 17:05)
 Perl mp2 翻訳 テンプレートシステムの選択 (d225) (2022-08-15 22:23)
 Perl mp2 翻訳 大規模 E コマースサイトの構築 (d224) (2022-06-15 20:43)
 Perl mp2 翻訳 チュートリアル (d223) (2022-06-15 20:42)
上の画像に書かれている文字を入力して下さい
 
<ご注意>
書き込まれた内容は公開され、ブログの持ち主だけが削除できます。

Llama
リャマ
TI-DA
てぃーだブログ
プロフィール
セラ (perlackline)
セラ (perlackline)
QRコード
QRCODE
オーナーへメッセージ

PAGE TOP ▲