- 締切済み
バイナリファイルのアップロードに関して
今回質問させて頂くことに関連した問題を、現在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にはバイナリデータがちゃんと入っていないのでしょうか?間違っているところがあれば、どのように直したらいいか教えてください。どうぞよろしくお願いします。
- みんなの回答 (11)
- 専門家の回答
みんなの回答
- root139
- ベストアンサー率60% (488/809)
IEが送受信しているHTTPヘッダを表示するツール(フリー)もあります。 詳しくは参考URLをどうぞ。
- hikomin
- ベストアンサー率63% (40/63)
ヘッダが正しく送信されていて、ブラウザがPDF閲覧可能であれば、データが壊れてない限り大丈夫だと思うのですが。Winの事は良く分かりませんけれど。ブラウザは何をお使いですか?他のブラウザでは、何と表示されますか? ヘッダがどのように送信されているかは、もしブラウザにヘッダを確認出来る機能なんかがあればそれで確認出来るかと思います。(Mozilla系だとプラグインでそういった機能を加えられたと思います。)そういう機能を持ったブラウザなりユーティリティなりを使うほうがずっと手軽だろうとは思いますが、ブラウザなどに頼りたくなくても、telnetでサーバの80番ポートにアクセスし、自分でHTTPリクエストを打ってみれば分かります。(或いはそういうプログラムを自作すると言う手もありますが。) 簡易的には、自分で出しているヘッダの直前で別のヘッダを出してしまえば、サーバに渡されるデータは見れます。 print "Content-type: text/plain?n?n"; # 他のヘッダに先駆けてtext/plainを出し、空行を加えてヘッダとして認識させれば、以降の出力は本文と見なされるので閲覧可能である。 print "Content-Length: ",length $img,"?n"; print "Content-type: application/pdf?n?n"; print $img; しかし、ヘッダは最終的にサーバで再処理(必要なヘッダを追加)された後に出力されているので、そのまま信用する事は出来ません。(が、参考にはなります。) まずヘッダが正しく(思った通りに)出力されているかどうか、正しければブラウザがPDFを正しく読み取れるかどうか、確認してみてください。
- hikomin
- ベストアンサー率63% (40/63)
出来上がったHTTPヘッダを調べたところ、lengthの後ろの改行が有効にならないようです。(何故だかはちょっと分からないですが。)結合している文字列を、結合ではなくリストとして渡せば解決出来そうです。 print "Content-Length: ".length $img."?n"; ↓ print "Content-Length: ",length $img,"?n"; (ピリオドがコンマに変わっています。) それは良いのですが、ブラウザにCGIからのPDF出力を表示する事が目的ではないので、次に何を調べるかも考えましょう。恐らく$imgにバイナリが入っているだろう事は分かったと思うので、それ以外、DBへのINSERTや、そもそもTABLE定義が正しいか等も確認してみてください。
お礼
hikomin様、どうもありがとうございます。 binmode(STDOUT); print "Content-Length: ",length $img,"\n"; print "Content-type: application/pdf\n\n"; print $img; にしまして、やってみたのですが、ブラウザにはなにも表示されませんでした。更新を押しても今回は何も変わりませんでした。 現在平行して、MySQLのカテゴリでこの$imgをDBに格納することについて教えて頂きお世話になっています。このことも目的なのですが、格納したバイナリデータを取り出す際に、ブラウザに表示させたいとも考えておりまして、今回アップロードしたときにブラウザに表示させるのを成功したいと思っております。色々な方法を教えていただいて本当に感謝しております。すみませんが、もう少しアドバイス頂けませんでしょうか。よろしくお願いします。 http://oshiete1.goo.ne.jp/kotaeru.php3?q=1156195 テーブルやSQLはこちらで書かせて頂いております。テーブル定義は問題ないようです。
- hikomin
- ベストアンサー率63% (40/63)
ヘッダの書き方が変です。HTTPヘッダと本文の区切りが空行です。以下のようなイメージです。 Content-Length: xxx Content-Type: xxx xxx ヘッダの並べ方の順番はどうでも良いし、他にヘッダを追加しても構わないのですが、ヘッダと本文の間に空行があるわけです。空行を作る為に、二回改行を出力しています。 さて、前のコードではどうでしょうか。確認してみてください。 後一つ、$img = join undef, <$fH>;ですが、この意味は『<$fH>から配列でデータを取り出し、undef(つまり何も区切り無し)でそれらを繋いで$imgに代入』です。ファイルハンドル$fHは、その前のwhileで全てreadしているので、そこからさらに何かとり出そうとしても、何も出て来ません。私のサンプルコードは、スタンドアロンで動く事を前提に書いた(つまりサンプルだけでプログラムとした時に動く)のでこうした読み込みの記述がありますが、while readのところで$imgに読み込むなら不要です。もしも$img = join undef, <$fH>;の効果を試したいのであれば、seek $fH, 0, 0;でファイルポインタを冒頭に戻してやれば、恐らく読めると思います。
お礼
hikomin様、お忙しいところ本当にありがとうございます。また、ご親切にわかりやすく解説していただきまして、ありがとうございました。理解できました。 ヘッダの書き方を確認してみましたところ、やはり空行を入れてませんでした。それで下で記載させていただいたスクリプトの下行を次のように書き直しました。 ----------------- binmode(STDOUT); print "Content-Length: ".length $img."\n"; print "Content-Type: application/pdf\n\n"; print $img; ----------------- これはそのままスクリプトからコピーしてきました。 なので行間もスクリプトと同じです。 このスクリプトを実行しましたところ、ブラウザには何も出力されませんでした。更新(F5)を押すと、例の画面左上にアイコン(赤の□と緑の○と青の△の3つが入っているアイコン)が表示されました。エラーなども出ておりません。何かアドバイスいただけると助かります。何度も申し訳ありませんが、よろしくお願いいたします。
- hikomin
- ベストアンサー率63% (40/63)
アップロードデータを保存しているファイルの方は、ちゃんと大丈夫なんですよね?$imgのデータは保存されているものと双子のようなものなので、そっちが大丈夫であれば$imgも大丈夫であろうと推測出来ます。(ちなみにバイナリで出力した時に%PDF-1.4 %…とかと出たと言う事ですが、これはPDFのソースなので、全て確認出来ているわけではないですがPDFは入っていると思われます。) ちょっと気掛かりなのは、Content-Lengthヘッダが出ていない事です。text以外だと、Lengthが必要だったりもします。 my $q = new CGI; my $ufh = $q->upload('filename'); my $bin = join undef, <$ufh>; $binにバイナリを取り込み=$imgと読み替えて良し print "Content-Length:".length $bin."?n"; #lengthでサイズを取得してヘッダ出力 print "Content-Type:".$q->uploadInfo($ufh)."?n?n"; #uploadInfoからMIMEを取得:application/pdfで良い print $bin; 以上を参考に、Lengthを出してみてください。
お礼
hikomin様、ご回答本当にありがとうございます。 >アップロードデータを保存しているファイルの方は、>ちゃんと大丈夫なんですよね? はい、そちらの方は大丈夫です。 教えていただいた方法でやってみました。 #!C:\Perl use CGI; $PCMOJPATH='C:\ディレクトリ'; my ($buffer); my $query = new CGI; $uniqid = time . "_" . $$; $newfile = "upload_$uniqid"; #ファイル名 my $fH = $query->upload('filename'); 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"); binmode(STDOUT); print "Content-type: application/pdf\n\n"; print "Content-Length:".length $img."\n"; print $img; というように書いて行ったのですが、アップロードは成功しましたが、ブラウザには、 Content-Length:26926%PDF-1.4 %粤マモ 7 0 obj << /Type/FontDescriptor /CapHeight 709 : : startxref 49727 %%EOF という感じで、以前とは違いきれいに整列した形で表示されましたが、Adobe Readerは起動しませんでした。 また、$img .= $buffer;をコメントして chmod (0666, "$PCMOJPATH/$newfile");の後で、 my $img = join undef, <$fH>;とすると、ブラウザにはContent-Length:1としか表示されませんでした。 まだ未熟なため、見当違いのことをしているかもしれませんが、どうぞご教授おねがいいたします。
- t140
- ベストアンサー率39% (59/150)
my $mimetype = $query->uploadInfo($fH)->{'Content-Type'}; これもなんのためにあるんですか? 使ってないようですが・・・。 とりあえずコメントにしておいてください。
お礼
t140様、度々ありがとうございます。 そうですね、すみません。コメントにしました。 すると、何も表示されなかったのですが、更新(F5)をまた押してみると、Acrobatが起動しかけました(起動時にでる画面がでました)。しかしそのあとは何も表示されません。 その後もう一度アップロードからやって、また更新してみても、今度はAcrobatは起動しませんでした。 アパッチのlogをみても今度はエラーが出ていません。 どうしたらよいのでしょうか。ご教授いただけると助かります。お願いいたします。
- t140
- ベストアンサー率39% (59/150)
>print "Content-type: text/html\n\n"; >print "<html><body>\n"; この部分は何のため?? 消したらできるようになると思います。
お礼
ありがとうございます。 すみません、間違えました。 消してやってみましたら、ブラウザには何も表示されなくなってしまいました。 特にエラーなども出ていないのですが、これは$imgにバイナリデータが入っていないということなのでしょうか?どうしたらよいか教えてください。お願いいたします。
補足
アップロード後、何も表示されないブラウザで、更新(F5)を押してみると、画面左上にアイコン(赤の□と緑の○と青の△の3つが入っているアイコン)が表示されます。そして、logで次のようなエラーが出ています。 Premature end of script headers: c:/・・・/・・・/cgi-bin/upload_test.pl [Thu Jan 13 15:54:05 2005] [error] Can't use an undefined value as a HASH reference at c:\・・・\cgi-bin\UPLOAD~4.PL line 13. line 13は、my $mimetype = $query->uploadInfo($fH)->{'Content-Type'}; なのですが、どうすればいいでしょうか。
- t140
- ベストアンサー率39% (59/150)
まず、ヘッダの終端には改行が2つ必要です。 また、ソースからWindows環境みたいなのでバイナリモード で出力しないといけません。 binmode(STDOUT); print "Content-type: application/pdf\n\n"; print $img;
お礼
t140様、どうもありがとうございます。 私の環境は、Windows XpでActivePerl5.8.4です。 上記の通り書いたのですが、ブラウザにはContent-type:application/pdf %PDF-1.4 %âãÏÓ 7 0 obj << /Type/Encoding /Differences・・・という形式で表示されます。何か足りないのでしょうか?もう一度ソースを載せさせて頂きますので、よろしければ見ていただけないでしょうか。よろしくお願いします。 #!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"); binmode(STDOUT); print "Content-type:application/pdf\n\n"; print $img; どうすれば、PDFの形でブラウザに表示できますでしょうか?
補足
print "Content-type: text/html\n\n"; print "<html><body>\n"; を消してみても、同じ結果でした。
- hikomin
- ベストアンサー率63% (40/63)
$imgにバイナリが入っているかどうかは、出力してみれば分かる事です。適切な場所でprint $img;してみれば良いです。(ファイル保存に成功と言う事なら、多分うまく行っているだろうと推測出来ますが、心配なら出せば良いわけです。)必要に応じてContent-Typeヘッダも出しておけば、CGIでブラウザを介しても表示可能です。 疑うべきポイントは、$imgにバイナリデータが入っているか、DBへのINSERT等のSQL文が正しいか、DBのテーブル定義が正しいか、そんなところでしょうか。それぞれ該当のポイントでデータをダンプするなりすれば、何らかの手がかりになります。
お礼
hikomin様、早速の回答ありがとうございます。 print $img;で出力させると、 %PDF-1.4 %âãÏÓ 7 0 obj << /Type/Encoding /Differences[33/exclam/quotedblright/numbersign/dollar/percent/ampersand/quoteright・・・249.6 458.6 458.6 458.6 458.6 458.6 ・・・という感じで出力されます。 ------------ しかし、 print "Content-type:application/pdf\n"; print $img; というように記述してブラウザで表示させようとしても、Content-type:application/pdf %PDF-1.4 %âãÏÓ ・・・というように始めにContent-type:application/pdfが付くだけです。この方法は間違っているでしょうか?よろしくお願いします。
- t140
- ベストアンサー率39% (59/150)
そのソース見たところ、 $query->upload('filename') という箇所があるけど、この upload というサブルーチン は CGI.pm のver2.47 という新しいものだからもしかした ら upload を 以前の param に変えるだけでいけるかも 知れない。 $fH= $query->param('filename');
お礼
t140様、ご回答どうもありがとうございます。 uploadをparamに変えてみたのですが、バイナリデータをDBに格納できませんでした。 現在、サイズの大きくないPDFをアップロードしてみて試しているのですが、アップロードは指定したディレクトリにファイルが作成されていて成功しております。心配なのが、$imgにちゃんとしたバイナリデータが格納されているのかということなのですが、記載させていただいた書き方でよいのでしょうか? どうぞよろしくお願いいたします。
- 1
- 2
お礼
hikomin様、お忙しいところどうもありがとうございます。 ブラウザはIEを使っています。それ以外は使用したことがありません。 昨日までの段階で、アップロードはある1つのPDFについて行っていました。今日違うPDFをアップロードしましたら、ブラウザに表示できました。しかし、その表示できたファイルをもう一度アップロードすると、表示できなくなり、他のもう1つのPDFでも同じ結果でした。また、PDFによっては、初めから(一回目から)表示できないのもありました。 >まずヘッダが正しく(思った通りに)出力されてい>るかどうか、正しければブラウザがPDFを正しく読み>取れるかどうか、確認してみてください。 すみません、まずはこの上記のことをお礼とともに 早く報告させていただきたく投稿いたしました。確 認次第、結果について投稿させて頂きますのでよろ しくお願いします。