ファイルアップロード方法とデータの受信方法について

このQ&Aのポイント
  • ファイルアップロードに関する方法と、データの受信方法について解説します。
  • ファイルアップロードの際に、ファイル名と一緒にデータを取得する方法について詳しく説明します。
  • とほほさんの書かれたコードを参考に、ファイルアップロードとデータの受信方法を実装する方法を解説します。
回答を見る
  • ベストアンサー

とほほさんのファイルのアップロードのことで

http://tohoho.wakusei.ne.jp/wwwxx034.htm のファイルのアップローダーを使用しています。 私は普段postのデータを受け取るのに、 read(STDIN,$buffer,$ENV{'content_length'}); のように指定していますが、ここでは $buf = ""; $read_data = ""; $remain = $ENV{'CONTENT_LENGTH'}; binmode(STDIN); while ($remain) { $remain -= sysread(STDIN, $buf, $remain); $read_data .= $buf; } としているみたいです。 ファイルをアップロードするだけなら上記をそのまま使用すればいいのですが、 ファイル名とともに取得したいデータをファイルアップロードの画面でユーザーに指定してもらうので、 そのデータをどのように取得すればいいのかわかりません。 このとほほさんが書いたコードはどのようにデータを受信しているのでしょうか? おわかりの方ご説明お願いします。

  • Perl
  • 回答数3
  • ありがとう数3

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

  • ベストアンサー
  • damejan
  • ベストアンサー率30% (58/192)
回答No.1

質問の内容は、 while ($remain) { $remain -= sysread(STDIN, $buf, $remain); $read_data .= $buf; } この部分の内容を解説してくださいということでしょうか? ちなみに、分かりやすく書き換えるとこんな感じです。 while($remain) { $read_len = sysread(STDIN, $buf, $remain); $read_data = $read_data.$buf; $remain = $remain - $read_len; } whileループを回しているのは、sysreadは必ずしも$remain分だけのデータを読み込むことを保証していないからです(これはエラーではありません)。読み残しを防ぐためです。もし、読み残しがあれば、読み残しの長さを新たに$remainにセットし、再度sysreadします。あとは読み残しが0になるまで同様に繰り返します。

KODAMAR
質問者

お礼

回答ありがとうございます。 while($remain) { $read_len = sysread(STDIN, $buf, $remain); $read_data = $read_data.$buf; $remain = $remain - $read_len; } 受信したデータを、 $read_lenに代入 ($read_len = sysread(STDIN, $buf, $remain); は $read_len = sysread(SITDIN,$buf,$ENV{'CONTENT_LENGTH'});ってことですよね?) $read_dataはどこから出てきたのでしょうか? それと下記のようにしたいのですが、どのようにしたらいいでしょうか? よろしくお願いします。 ┌───┐ ┌──┐ │    │ │参照│ └───┘ └──┘  ○ フォルダ1 ○フォルダ2 ・参照ボタンでアップロードするファイルを選択 ・ラジオボタンで入れるフォルダを選択 ・受信したデータからフォルダを変数に読み込み、そのフォルダに入れるようにする

その他の回答 (2)

  • damejan
  • ベストアンサー率30% (58/192)
回答No.3

誤解を与えるかも知れませんので、$read_dataについての補足です。 >まずプログラムの頭のあたりで初期化していますよね。 これは、「とほほさんのオリジナルプログラムの頭」といいう意味です。 また、$read_lenは、私が勝手に作った変数です。

  • damejan
  • ベストアンサー率30% (58/192)
回答No.2

>受信したデータを、$read_lenに代入 違います。 $read_len = sysread(STDIN, $buf, $remain); では、$bufに読み込んだデータが、$read_lenに読み込んだデータ長がそれぞれ代入されます。 「$remain分だけデータを読み込んでんじゃないの?」と疑問をお持ちかも知れませんが、この関数は、最大で$remain分のデータを$bufに読み込めと命令しえいるだけで、必ずしも$remain分を読み込むとは限らないのです(データの遅延などのため)。 >$read_dataはどこから出てきたのでしょうか? まずプログラムの頭のあたりで初期化していますよね。 $read_data = $read_data.$buf; では、$buf(sysreadで読み込んだデータが入っている)の内容を$read_dataにどんどん継ぎ足していっています。(「.」演算子は文字列を連結します) >それと下記のようにしたいのですが、どのようにしたらいいでしょうか? 私はperlプログラミングをちょっとかじっているだけで、CGIやhtmlについては知りません(使ったことないです)。このあたりの質問は、別の人にお願いします。 すみませんね。

KODAMAR
質問者

お礼

回答ありがとうございます。 なんとなくは理解したような気がするんですが、意図したことを行う、というところまで 行き着きませんでした。 教えていただいたのにスイマセン。 もうちょっとがんばってみます。 ありがとうございました。

関連するQ&A

  • CGIファイル1つで掲示板

    1つだけのファイルで一覧型の掲示板を作っています。 HTMLを表示するのもそれです。 フォームで送信すると、自分のファイル自身にアクセスします。 $ENV{'CONTENT_LENGTH'}は受け取ることができたけど read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); では$bufferは空っぽでした。 1つのファイルでPOSTデータの送受信をするのは requireを使わないと無理ですか?

    • ベストアンサー
    • CGI
  • STDINから何度も読み込むことはできますか?

    Perlはかじっている程度の者です。 STDINから全てのデータを read( STDIN, $strRead, $ENV{CONTENT_LENGTH} ); として読み込んで、次に read( STDIN, $strRead, $ENV{CONTENT_LENGTH} ); とすると、もう読み込めませんよね。 なので、 seek( STDIN, 0, 0 ); を毎回呼び出して、ポントを先頭にもっていってから読もうとしたのですが・・だめでした。 そこで質問なのですが、CGIプログラムでSTDINから何度も重複してデータを読み込む方法はありませんか?

    • ベストアンサー
    • Perl
  • Windows2000サーバーでは動いていたCGIがWindowsサーバー2003で動きません

    ファイルのアップロードをするCGIです。 Windows2000サーバーでは問題なく動いていました。 先日Windows2003に乗り換えたとたん、動かなくなりました。 色々調べて、とりあえずエラーにはならなくなったのですが、正常に実行されないのです。 あやしいところは・・・ binmode(STDIN); while($remain){$remain-=sysread(STDIN,$buf,$remain);$read_data.=$buf;} $pos1=$pos2=$pos3=0; $delimiter=""; $max_count=0; $sendfilecnt=0; while(1){ $pos2=index($read_data,"\r\n\r\n",$pos1)+4; @headers=split("\r\n",substr($read_data,$pos1,$pos2-$pos1)); $filename=''; $name=''; foreach(@headers){ if($delimiter eq''){ $delimiter=$_; }elsif(/^Content-Disposition: ([^;]*); name="([^;]*)"; filename="([^;]*)"/i){ if($3){ $filename=$3; if($filename=~/([^\\\/]+$)/){$filename=$1;} } }elsif(/^Content-Disposition: ([^;]*); name="([^;]*)"/i){$name=$2;} } このへんです。 どうも、$filenameが''(ヌル)のままなので、この後正常にファイルのアップが動かないようなのです。 どなたか詳しい方、ぜひ教えてください。

    • ベストアンサー
    • CGI
  • リクエストパラメタを一括置き換え

    リクエストパラメタを一括置き換え if( $ENV{'REQUEST_METHOD'} eq "GET" ) { $buffer = $ENV{'QUERY_STRING'}; } else { read( STDIN, $buffer, $ENV{'CONTENT_LENGTH'} ); } %req_params = map { /([^=]+)=(.+)/ } split /&/, $buffer; 上記のように書いていて、リクエストされたものを置き換える時は次のように一個一個書いています。 $req_params{name} =~ s/&/&/g; $req_params{mail} =~ s/&/&/g; $req_params{url} =~ s/&/&/g; このリクエストされたパラメタを一括で置き換えするにはどうすればいいのでしょうか? 例えば、上記の書き方で以下のようなことをしたいです。よろしくお願いいたします。 if ($ENV{'REQUEST_METHOD'} eq "POST") { read(STDIN, $buf, $ENV{'CONTENT_LENGTH'}); } else { $buf = $ENV{'QUERY_STRING'}; } foreach ( split(/&/, $buf) ) { ($key, $val) = split(/=/); $val =~ tr/+/ /; $val =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("H2", $1)/eg; $val =~ s/&/&/g; $req_params{$key} .= "\0" if (defined($req_params{$key})); $req_params{$key} .= $val; }

    • ベストアンサー
    • Perl
  • cgiでのデータ受信

    すみません、これで最後にします・・・ http://okwave.jp/qa/q7445617.html 結局getによるデータ受信の方もできませんでした。 やはりPOSTに戻ってやってみると、$ENV{'CONTENT_LENGTH'}の値は入っています。 文字の長さが入っているということは、文字列が入っているだろうということなので、 後は文字を読み込むだけのはずです。 となると read(STDIN, $alldata, $ENV{'CONTENT_LENGTH'}); このコードが間違っているのでしょうか?

    • ベストアンサー
    • CGI
  • バイナリファイルのアップロードに関して

    今回質問させて頂くことに関連した問題を、現在MySQLのカテゴリで質問させていただいているのですが、 バイナリファイルをアップロードし、そのファイルのバイナリデータを変数($img)に格納し、それをDBに格納するという形を目指しています。しかし、DBにどうしても格納できません。もしやバイナリデータを変数に格納する時点で、既におかしいのかと思いまして、その部分についてこちらでご教授頂きたく書き込ませていただきました。 #!C:\Perl use CGI; use DBI; $PCMOJPATH='C:\パス名'; #ディレクトリ指定 my ($buffer); my $query = new CGI; $uniqid = time . "_" . $$; $newfile = "upload_$uniqid"; #ファイル名 print "Content-type: text/html\n\n"; print "<html><body>\n"; my $fH = $query->upload('filename'); my $mimetype = $query->uploadInfo($fH)->{'Content-Type'}; open (OUT, ">$PCMOJPATH/$newfile"); binmode (OUT); while(read($fH, $buffer, 1024)){ print OUT $buffer; $img .= $buffer;   #バイナリデータを$imgに格納 } close (OUT); close ($fH) if ($CGI::OS ne 'UNIX'); chmod (0666, "$PCMOJPATH/$newfile"); ------------------------- と書いているのですが、$imgにはバイナリデータがちゃんと入っていないのでしょうか?間違っているところがあれば、どのように直したらいいか教えてください。どうぞよろしくお願いします。

  • ファイルのアップロードについて

    PERLでファイルのアップロード機能を作成しています。 アップロードと言っても、サーバへのコピーではなく、 データベースへバイナリで格納しなければならないのです。 とりあえず2パターン作成してみたのですが、 OPEN関数を使ってやるとうまくいきません。 -----パターン1(OPEN関数使用)------------- $query = new CGI; $filename = $query->param('msds'); # ファイル名(フルパス)取得 if($filename ne "") { open(ATT, $filename);# or die "Could not open atachment file:"; binmode(ATT); while($bytesread = read(ATT, $buffer, $BUFSZ)){ $file .= $buffer; # ファイルサイズ制限 $file_size ++; if($file_size > 300){ exitError("ファイルサイズが大きすぎます。600KB 以下にして下さい。"); } } close(ATT); } -----パターン2(OPEN関数未使用)------------- $query = new CGI; $filename = $query->param('temp1'); # ファイル名(フルパス)取得 if($filename ne "") { while($bytesread = read($filename, $buffer, $BUFSZ)){ $file .= $buffer; # ファイルサイズ制限 $file_size ++; if($file_size > 300){ exitError("ファイルサイズが大きすぎます。600KB 以下にして下さい。"); } } print "FILE DATA:" . $file . "<BR>"; } パターン2でprint $fileをすると、ファイルの内容が 画面表示されるのですが、パターン1だと、While文に 入ってくれませんでした。 原因がさっぱりわかりません。。。 お分かりになる方が見えましたらご教授願います。

    • ベストアンサー
    • CGI
  • utf-8環境で標準入力からの全角文字にマッチさせる方法

    utf-8でフォーム処理のコードを書いてます。 euc-jpで動作していた全角文字の正規表現がutf-8で動作しません。 単純な「$str =~ /あ/」のような書き方ではなく、別な指定方法が必要なのでしょうか? ・perl5.8 文字コードutf-8 標準入力側文字コードutf-8 use utf8; my(%POST,$buffer,$key,$value,@data_s); if ($ENV{'REQUEST_METHOD'} eq 'POST') { if ($ENV{'CONTENT_TYPE'} =~ /application\/x-www-form-urlencoded/i) { binmode STDIN; read(STDIN,$buffer,$ENV{'CONTENT_LENGTH'}); @data_s = split(/&/,$buffer); foreach $buffer (@data_s) { ($key,$value) = split(/=/,$buffer); $value =~ tr/+/ /; $value =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("C",hex($1))/eg; if ( exists ($POST{$key}) ) { $POST{$key} .= '<>' . $value; } else { $POST{$key} = $value; } } } } binmode STDOUT,":encoding(utf8)"; print "Content-type: text/html; charset=utf-8\n\n"; print "<br>\n"; foreach $key (keys %POST) { if ($POST{$key} =~ /[0-9]/) { print "全角数字にマッチ<br>\n"; }###### print "$key = $POST{$key}<br>\n"; } exit;

    • ベストアンサー
    • Perl
  • 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にはアップロードしたファイル名が入っているのにどうして動くのだろうと疑問に思っています。 乱文で申し訳ありませんがご教授下さい。 宜しくお願い致します。

    • ベストアンサー
    • Perl
  • フォームからアップロードされた画像ファイルの処理

    フォームからアップロードされてきた画像ファイルを、適当なファイル名を付けてJPGあるいはGIFの拡張子で保存し、HTMLファイルで保存した画像を一覧表示させようというCGIスクリプトを作りたいと考えています。 質問1 <FORM action="xxxx.cgi" method="post" enctype="multipart/form-data"> <INPUT type="file" name="gazo"> <INPUT type="submit"> </FORM> とこんな具合のフォームから画像ファイル(JPGやGIF)をアップロードした時、 受け手のxxxx.cgiでは、この画像ファイルのデータをどのように受けたらよいのでしょうか? read(STDIN,$_,$ENV{'CONTENT_LENGTH'});としたり、 あるいは cgi-lib.plを読み込んで、$in{'gazo'} というような形で画像ファイルのデータを受け取ればよいのでしょうか? 質問2 画像ファイルを受け取ったとして、フォームから送られてきた画像ファイルがJPGなのかGIFなのかを判別することは可能でしょうか? 可能ならば、判別するためのスクリプトはどんなものが考えられるでしょうか? (フォームから送られてくる画像ファイルのデータの何をチェックすれば、JPGかGIFかを判別できるのでしょうか?) もしご回答頂ける方がおられればご教授ください。よろしくお願いします。 なお、「既存のスクリプトを利用しなさい」というような回答やアドバイスならば不要でございます。

    • ベストアンサー
    • Perl