binmode

binmodeは、C言語で扱ったsetmodeと同じで、指定のファイルハンドルをバイナリモードにする。

Perlの組み込み関数 binmode の翻訳 - perldoc.jp

また、Windows上のApacheで試すのだが、今回はPerlCGIなので、Perlを入れないといけない。

Windows版ApacheでCGI(Perl)を使用する方法 ActivePerl - [Windows/サーバー] ぺんたん info

ここを参考に、

Download & Install Perl | ActiveState

ActivePerlをダウンロード。

最近はmsiダウンロードじゃなくてPowerShellで入れさせようとするの・・・。
最近はmsiダウンロードじゃなくてPowerShellで入れさせようとするの・・・。

最近はmsiダウンロードじゃなくてPowerShellで入れさせようとするの・・・。

さっきのコマンドをコピペしてPowerShellで打つとこうなる
さっきのコマンドをコピペしてPowerShellで打つとこうなる

さっきのコマンドをコピペしてPowerShellで打つとこうなる。
Yを入力。

で、こうなって
で、こうなって

で、こうなって、

入ったかな
入ったかな

入ったかな。

コマンドプロンプトからもperlは呼べるのでパスは通ってるみたい
コマンドプロンプトからもperlは呼べるのでパスは通ってるみたい

コマンドプロンプトからもperlは呼べるのでパスは通ってるみたい。
ただ、PerlCGIスクリプトの先頭に書くperlコマンドのパスがわからんのよね。
いろいろ探し回った結果、

ここっぽいのかなとおもったんだけど
ここっぽいのかなとおもったんだけど

ここっぽいのかなとおもったんだけど、

さっきのperl.batの中身を見たら
さっきのperl.batの中身を見たら

さっきの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が動いたので、これでようやくできそう。
上記の試しCGIが動いたので、これでようやくできそう。

上記の試し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に成功

いろいろ試してなんとかsearchに成功。

searchできるのになんでinstall失敗するの
searchできるのになんでinstall失敗するの

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を選択して送信
こっからtest1.txtを選択して送信

こっから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を付けなくても成功してしまう
binmodeを付けなくても成功してしまう

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が出来てる。

しかし開けない
しかし開けない

しかし開けない。

送信元のimage1.bmp
送信元のimage1.bmp

送信元のimage1.bmp

送信先のimage1.bmpのサイズを見ると違うのがわかる。
送信先のimage1.bmpのサイズを見ると違うのがわかる。

送信先のimage1.bmpのサイズを見ると違うのがわかる。

そこでbinmodeでSTDINとOUTをバイナリモードにする。

今度はimage1.bmpが開けた。
今度はimage1.bmpが開けた。

今度はimage1.bmpが開けたし、サイズも同じになった。

Sample/perl/binmode/binmode/src at master · bg1bgst333/Sample · GitHub