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

はじめに

このエントリを公開後,Plackの中の人でもあるmiyagawaさんより,同エントリの内容が現在のバージョンのものにおいて正しくない,という旨のご指摘をいただきました.ありがとうございます.(実際には,0.90*系と0.99_*系との違い,ということで無問題?)

ということで,現時点で最新(ですよね?)の「0.99_5(DEVELOPER RELEASE)」を入れ,同バージョンにおけるPlack::Request,Plack::Request::Uploadのドキュメントを確認し,修正したものを以下に掲載します.

アップロードフォーム

前エントリと同様のものです.

<form action="" method="post"
      enctype="multipart/form-data">
  ファイル 1-1
  <input type="file" name="file1" value="" />
 
  ファイル 1-2
  <input type="file" name="file1" value="" />
 
  ファイル 2
  <input type="file" name="file2" value="" />
 
  <input type="submit" name="submit" value="アップロード!" />
</form>

Plack::Request::Uploadオブジェクトを取得する

アップロードオブジェクトの集合はHash::MultiValueオブジェクトとして

Plack::Requestオブジェクトのuploadsメソッドを呼ぶところは,前と変わりありませんが,得られるものがHash::MultiValueオブジェクトとなりました.

use Data::Dumper;
 
# $req is Plack::Request object
my $uploads = $req->uploads;
print ref $uploads;
Hash::MultiValue

データ構成

今回もスペースの都合上,$VAR1 =な部分は削ってます.

use Data::Dumper;
print Dumper $uploads;
bless( {
         'file2' => bless( {
                             'headers' => bless( {
                                                   'content-disposition' => 'form-data; name="file2"; filename="9a8ba767.jpg"',
                                                   'content-type' => 'image/jpeg'
                                                 }, 'HTTP::Headers' ),
                             'filename' => '9a8ba767.jpg',
                             'tempname' => '/tmp/f2cY6WMe0_',
                             'size' => 102723
                           }, 'Plack::Request::Upload' ),
         'file1' => bless( {
                             'headers' => bless( {
                                                   'content-disposition' => 'form-data; name="file1"; filename="7a98edb3.jpg"',
                                                   'content-type' => 'image/jpeg'
                                                 }, 'HTTP::Headers' ),
                             'filename' => '7a98edb3.jpg',
                             'tempname' => '/tmp/6hLGbxAmym',
                             'size' => 301283
                           }, 'Plack::Request::Upload' )
       }, 'Hash::MultiValue' );

キーにフォームのフィールド名,値にPlack::Request::Uploadオブジェクトが1ファイルにつき1つ,という構成になっているのがわかr...おっと,Data::Dumperでの出力では,キーが重複した分については表示されないんでした.このあたりは次節で確認してみます.

特定のフィールドの要素を取得する

print Dumper $uploads->{file1};
print Dumper $uploads->{file2};
$VAR1 = bless( {
                 'headers' => bless( {
                                       'content-disposition' => 'form-data; name="file1"; filename="7a98edb3.jpg"',
                                       'content-type' => 'image/jpeg'
                                     }, 'HTTP::Headers' ),
                 'filename' => '7a98edb3.jpg',
                 'tempname' => '/tmp/j4gQY8Am6V',
                 'size' => 301283
               }, 'Plack::Request::Upload' );
$VAR1 = bless( {
                 'headers' => bless( {
                                       'content-disposition' => 'form-data; name="file2"; filename="9a8ba767.jpg"',
                                       'content-type' => 'image/jpeg'
                                     }, 'HTTP::Headers' ),
                 'filename' => '9a8ba767.jpg',
                 'tempname' => '/tmp/GbG3P_7Fhp',
                 'size' => 102723
               }, 'Plack::Request::Upload' );
print Dumper $uploads->get_all('file1');
print Dumper $uploads->get_all('file2');
$VAR1 = bless( {
                 'headers' => bless( {
                                       'content-disposition' => 'form-data; name="file1"; filename="6ac3d070.jpg"',
                                       'content-type' => 'image/jpeg'
                                     }, 'HTTP::Headers' ),
                 'filename' => '6ac3d070.jpg',
                 'tempname' => '/tmp/E63LJB8y1s',
                 'size' => 59307
               }, 'Plack::Request::Upload' );
$VAR2 = bless( {
                 'headers' => bless( {
                                       'content-disposition' => 'form-data; name="file1"; filename="7a98edb3.jpg"',
                                       'content-type' => 'image/jpeg'
                                     }, 'HTTP::Headers' ),
                 'filename' => '7a98edb3.jpg',
                 'tempname' => '/tmp/38aWzTxmFv',
                 'size' => 301283
               }, 'Plack::Request::Upload' );
$VAR1 = bless( {
                 'headers' => bless( {
                                       'content-disposition' => 'form-data; name="file2"; filename="9a8ba767.jpg"',
                                       'content-type' => 'image/jpeg'
                                     }, 'HTTP::Headers' ),
                 'filename' => '9a8ba767.jpg',
                 'tempname' => '/tmp/jFgvreL2Ol',
                 'size' => 102723
               }, 'Plack::Request::Upload' );

Data::Dumperでは確認できなかった分についてもしっかり取得できていますね.

Plack::Request::Uploadオブジェクトのメソッド

こちらにも変更がありますね.

size

アップロードされたファイルのサイズが得られます.

my ($up) = $uploads->get_all('file1');
print Dumper $up->size;
$VAR1 = 59307;

path

ファイルは自動的に一時ファイルとして保存されるわけですが,このメソッドは,その保存先のパスを取得できます.

print Dumper $up->path;
$VAR1 = '/tmp/FmOgLKzAZQ';

content_type

アップロードされたファイルのContent-Typeが得られます.

print Dumper $up->content_type;
$VAR1 = 'image/jpeg';

filename,basename

それぞれ,「original filename in the client」「basename for “filename”」ということですが,まだよくわかっていません><

print Dumper $up->filename;
print Dumper $up->basename;
$VAR1 = '6ac3d070.jpg';
$VAR1 = '6ac3d070.jpg';

参考

おわりに

以上,Plackにおけるファイルアップロード処理のための準備(というか,もうファイル自体はアップロードされてしまっていますがw)に関するメモの修正版でした.

All parameter-related methods such as parameters, body_parameters, query_parameters and uploads now contains Hash::MultiValue objects, rather than scalar or an array reference depending on the user input which is insecure. See Hash::MultiValue for more about this change.
INCOMPATIBILITIES – Plack::Request – search.cpan.org

ということなので,Hash::MultiValueオブジェクトの扱いに慣れておいて損はないかと思います.