M.C.P.C.

―むり・くり―プラスコミュニケーション(更新終了)


| トップページ |

2007年10月 8日 16:17

CGI.pmのアップロード後のファイル処理を高速に行う

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

とりあえず手っ取り早くファイルアップローダを作らなくちゃならなくなったとき用の汎用ルーチンとしてCGI.pmを使ったアップローダのソースをあげておこうと思いました。自分用のメモだけど単純にアップロード後の処理が高速なので参考にされるといいかと思います。

fillename:upload.cgi

#!/usr/bin/perl
use strict;
use warnings;
use CGI;
use CGI::Carp qw(fatalsToBrowser);
use File::Copy;
use File::Basename;
 
my $upload_dir  = 'upload';      # 保存先のディレクトリ
 
my $q  = CGI->new();             # CGIオブジェクト
my $fh = $q->upload('filename'); # ファイルハンドル兼ファイル名
my $temp_path = $q->tmpFileName($fh); # アップロードされた
                                      #ファイルのフルパス
fileparse_set_fstype('MSDOS');   # WinIE用パス文字設定
my $filename    = basename($fh); # アップロードされたファイルの
                                 # ファイル名
my $upload_path
  = "$upload_dir/$filename";     # 保存先フルパス
 
move ($temp_path, $upload_path)  # File::Copy の moveメソッドで
  or die $!;                     # 移動
close($fh);                      # おまじない
 
print $q->header( -type=>'text/html', -charset=>'UTF-8', );
print <<"END_OF_HTML";
<body><p>done.</p></body>
END_OF_HTML
 
exit;
 
__END__

filename: upload.html

<html>
  <body>
    <form action="upload.cgi" method="post"
      enctype="multipart/form-data">
      <p>
        <label for="filename">file</label>
        <br>
        <input type="file" name="filename" id="filename">
      </p>
      <p>
        <input type="submit" name="submit" value="submit">
      </p>
    </form>
    </p>
  </body>
</html>


~~~

よく、CGI,pmによるアップローダの説明で、

:: Cepheid :: - ファイルのアップロード その1

# ファイル取得
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;
}
close (OUT);
close ($fH) if ($CGI::OS ne 'UNIX'); # Windowsプラットフォーム用

なんてコードを見ますけれども、いまどき印刷業界は1GB超のファイルも平気で飛び交うのですから、これはかなり効率が悪い。ガソリンスタンドでしょうゆちゅるちゅるを使っているような感覚です。

次に、

ファイルアップロードの仕方 [www.hidekik.com]

my $fh = $q->upload('upfile');
copy ($fh, "$newfile");
close($fh);

ですが、なるほどFile::Copy [search.cpan.org] モジュールのcopyメソッド、これは頭がいいなーと思うわけですけれども、これとて1GBのファイルだったりしたら、アップロード済みのテンポラリファイルから、アップロード先へのベタコピーをしているわけで、なんだか無駄っぽいです。実際ユーザから見ると、アップロードが終わってから何10秒も待たないと処理が終わらないわけです。

つうわけで、普通にmoveメソッドでやっちゃえばいいってことになります。

そして、アップロード済みで、廃棄予定のテンポラリファイルのファイル名を

$q->tmpFileName($q->upload('filename') )

で取れてしまうこともポイント。これにより、簡単にmoveできるようになりましたとさ。これ探り当てるまで3年かかっている。そのあいだ、アップロードファイルが直接対象ディレクトリに保存される、CGI::Liteモジュール使っていたわけです。長くかかったねー

moveなので、同じファイルシステム上にあれば、高速に処理が終わりますので、とてもいいと思いますがいかがでしょうか。

※アップロードされたファイルのファイル名の取り扱いについては、また変なノウハウがいるので今回は割愛。

M.C.P.C.: CGI.pmのuploadメソッドでファイル名取得したらフルパスからファイル名を取り出す処理を入れる
M.C.P.C.: Safari の ファイル送信フォームのファイル名のデコード

投稿 大野 義貴 [Perl] | |

トラックバック(0)

トラックバックURL: http://blog.dtpwiki.jp/MTOS/mt-tb.cgi/2241

コメント(2)

ファイルアップロードのCGIを参考にさせていただきましたが、残念なことにうまく動きませんでした。
Windows 2003 Server // IIS // Perl 5.8使用で、moveの時点で dieが発生します。
どうも、cgi.pmがファイルを掴んだままなのか「Permission denied」のエラーが出てしまいますね。
IISのスクリプト実行ユーザーをAdministrator権限のユーザーでテストしてみましたが同じでした。
ファイルのアクセス権に関しての設定は問題無いので、moveを、copyにすれば問題無く処理が完了します。
しかしながら、copyだと・・・・( ^^) _旦~~

すずめちゃん さん:

[Perl] CGI.pm の TMPDIRECTORY isoya9の日記/ウェブリブログ

にある、一時ファイルがアップロードされるディレクトリを指定するのを入れてみたらどうでしょうか。

コメントする