binmodeは、C言語で扱ったsetmodeと同じで、指定のファイルハンドルをバイナリモードにする。
Perlの組み込み関数 binmode の翻訳 - perldoc.jp
また、Windows上のApacheで試すのだが、今回はPerlのCGIなので、Perlを入れないといけない。
Windows版ApacheでCGI(Perl)を使用する方法 ActivePerl - [Windows/サーバー] ぺんたん info
ここを参考に、
Download & Install Perl | ActiveState
ActivePerlをダウンロード。
最近はmsiダウンロードじゃなくてPowerShellで入れさせようとするの・・・。
さっきのコマンドをコピペしてPowerShellで打つとこうなる。
Yを入力。
で、こうなって、
入ったかな。
コマンドプロンプトからもperlは呼べるのでパスは通ってるみたい。
ただ、PerlのCGIスクリプトの先頭に書くperlコマンドのパスがわからんのよね。
いろいろ探し回った結果、
ここっぽいのかなとおもったんだけど、
さっきのperl.batの中身を見たら、
ここっぽいのよね。
#!C:\Users\bg1\AppData\Local\activestate\d0653c90\bin\perl print "Content-type: text/plain\n"; print "\n"; print "perl cgi hello";
こういう試しのCGI置いて試してたら、
C:\Apache24\cgi-binの下にこういうのも作られてよくわからないのだけど、
上記の試しCGIが動いたので、これでようやくできそう。
#!C:\Users\bg1\AppData\Local\activestate\d0653c90\bin\perl use strict; # 厳密な文法チェック. use CGI; # CGI # CGIオブジェクトの作成. my $q = CGI->new; # CGI::newでCGIオブジェクトを生成し, $qに格納. # パラメータの有無. if ($ENV{'REQUEST_METHOD'} eq 'POST'){ # 'POST'の時. # CGIヘッダの出力. print "Content-type: image/bmp\n"; # "Content-type: image/bmp\n"を出力. print "\n"; # "\n"を出力. # リクエストの読み込み. my $file = $q->upload('uploadedfile'); # アップロード対象のファイルが返る. #print '$file = '."$file\n"; # printだとファイル名. my $buf; # バッファ. my $numbytes = 1024; # 1回で読み込むバイト数を1024とする. my $bytesread; # 実際に読み込んだバイト数. #print "-----file begin-----\n"; # 開始. while ($bytesread = read($file, $buf, $numbytes)){ # 全部読み込む. print $buf; # バッファ出力. } #print "-----file end-----\n"; # 終了. #print 'ref($file) = '.ref($file)."\n"; # ref($file)を出力. } else{ # 'POST'以外.('GET'など.) # HTTPヘッダの出力. print $q->header; # HTMLヘッダの出力. print $q->start_html("binmode"); # <html>タグなどの出力. # HTMLフォームの出力. print $q->start_form; # <form>タグの出力. print "\n"; # 改行の出力. print $q->filefield(-name => 'uploadedfile'); # ファイル選択. print $q->submit; # submit print $q->end_form; # </form>タグの出力. # HTMLフッタの出力. print $q->end_html; # </html>タグなどの出力. }
前回までのCGIをContent-typeをimage/bmpにして、余計なprintをコメントアウトして、試す。
そうするとエラー。
C:\Apache24\logs\error.logを見ると、
[Xxx Xxx xx xx:xx:xx.xxxxxx 2021] [cgi:error] [pid 6788:tid 536] [client ::1:60733] AH01215: Can't locate CGI.pm in @INC (you may need to install the CGI module) (@INC contains: C:/Users/bg1/AppData/Local/activestate/d0653c90/site/lib C:/Users/bg1/AppData/Local/activestate/d0653c90/lib) at C:/Apache24/cgi-bin/binmode.cgi line 4.\r: C:/Apache24/cgi-bin/binmode.cgi
やっぱCGI.pmか。
モジュールの入れ方がわからん。
cpan使えるのかわからんし、ppmというものがあったらしいけど、stateに置き換えになったらしい。
(ActivePerlの情報、最近のが全然無い・・・。)
いろいろ試してなんとかsearchに成功。
searchできるのになんでinstall失敗するの・・・。
この後、管理者権限でコマンドプロンプトを起動し直して、もう一度installコマンドしたら、今度は成功した。
でもその後、一般ユーザでinstallコマンドしても、成功した。
意味わからんけど入ったからいいか。
#!C:\Users\bg1\AppData\Local\activestate\d0653c90\bin\perl use strict; # 厳密な文法チェック. use CGI; # CGI # CGIオブジェクトの作成. my $q = CGI->new; # CGI::newでCGIオブジェクトを生成し, $qに格納. # パラメータの有無. if ($ENV{'REQUEST_METHOD'} eq 'POST'){ # 'POST'の時. # CGIヘッダの出力. print "Content-type: text/plain\n"; # "Content-type: text/plain\n"を出力. print "\n"; # "\n"を出力. # リクエストの読み込み. my $file = $q->upload('uploadedfile'); # アップロード対象のファイルが返る. print '$file = '."$file\n"; # printだとファイル名. my $buf; # バッファ. my $numbytes = 1024; # 1回で読み込むバイト数を1024とする. my $bytesread; # 実際に読み込んだバイト数. print "-----file begin-----\n"; # 開始. while ($bytesread = read($file, $buf, $numbytes)){ # 全部読み込む. print $buf; # バッファ出力. } print "-----file end-----\n"; # 終了. print 'ref($file) = '.ref($file)."\n"; # ref($file)を出力. } else{ # 'POST'以外.('GET'など.) # HTTPヘッダの出力. print $q->header; # HTMLヘッダの出力. print $q->start_html("CGI::upload(uploadedfile)"); # <html>タグなどの出力. # HTMLフォームの出力. print $q->start_form; # <form>タグの出力. print "\n"; # 改行の出力. print $q->filefield(-name => 'uploadedfile'); # ファイル選択. print $q->submit; # submit print $q->end_form; # </form>タグの出力. # HTMLフッタの出力. print $q->end_html; # </html>タグなどの出力. }
さっきのimage/bmp版じゃなくて以前のtext/plain版(余計なprintもあり)を試す。
こっからtest1.txtを選択して送信すると、
成功。
問題は画像の場合。
#!C:\Users\bg1\AppData\Local\activestate\d0653c90\bin\perl use strict; # 厳密な文法チェック. use CGI; # CGI # CGIオブジェクトの作成. my $q = CGI->new; # CGI::newでCGIオブジェクトを生成し, $qに格納. # パラメータの有無. if ($ENV{'REQUEST_METHOD'} eq 'POST'){ # 'POST'の時. # CGIヘッダの出力. print "Content-type: image/jpg\n"; # "Content-type: image/jpg\n"を出力. print "\n"; # "\n"を出力. # リクエストの読み込み. my $file = $q->upload('uploadedfile'); # アップロード対象のファイルが返る. #print '$file = '."$file\n"; # printだとファイル名. my $buf; # バッファ. my $numbytes = 1024; # 1回で読み込むバイト数を1024とする. my $bytesread; # 実際に読み込んだバイト数. #print "-----file begin-----\n"; # 開始. while ($bytesread = read($file, $buf, $numbytes)){ # 全部読み込む. print $buf; # バッファ出力. } #print "-----file end-----\n"; # 終了. #print 'ref($file) = '.ref($file)."\n"; # ref($file)を出力. } else{ # 'POST'以外.('GET'など.) # HTTPヘッダの出力. print $q->header; # HTMLヘッダの出力. print $q->start_html("binmode"); # <html>タグなどの出力. # HTMLフォームの出力. print $q->start_form; # <form>タグの出力. print "\n"; # 改行の出力. print $q->filefield(-name => 'uploadedfile'); # ファイル選択. print $q->submit; # submit print $q->end_form; # </form>タグの出力. # HTMLフッタの出力. print $q->end_html; # </html>タグなどの出力. }
image/bmp版でもimage/jpg版でも、
こっから送信で、
binmodeを付けなくても成功してしまう。
もしかして、CGI.pmは中でbinmodeセットしてるんかな。
ということで方針を変えて、HttpClientプログラムを作成し、マルチパートではなく画像バイナリをCGI.pmを使わないbinmode.cgiに直接送信し、binmode.cgiでそれを読み込み、ファイルに書き出した時に問題が起きるかどうかを試す。
HttpClient側は、
とする。
binmode.cgiは、
#!C:\Users\bg1\AppData\Local\activestate\d0653c90\bin\perl use strict; # 厳密な文法チェック. # パラメータの有無. if ($ENV{'REQUEST_METHOD'} eq 'POST'){ # 'POST'の時. # CGIヘッダの出力. print "Content-type: image/bmp\n"; # "Content-type: image/bmp\n"を出力. print "\n"; # "\n"を出力. # リクエストの読み込み. my $buf; # バッファ. read(STDIN, $buf, $ENV{'CONTENT_LENGTH'}); # ファイルへの書き出し. my $ret = open(OUT, ">", "image1.bmp"); # test.txtを開く. if ($ret){ # trueの時. print OUT $buf; # OUTに$bufを書き込む. } }
最初こうする。
送信。
image1.bmpが出来てる。
しかし開けない。
送信元のimage1.bmp。
送信先のimage1.bmpのサイズを見ると違うのがわかる。
そこでbinmodeでSTDINとOUTをバイナリモードにする。
今度はimage1.bmpが開けたし、サイズも同じになった。
Sample/perl/binmode/binmode/src at master · bg1bgst333/Sample · GitHub