Win Apacheでperlを1行目無視でcgi実行するには
執筆:2006.12.27
編集:2007.01.04
普通に実行するには、httpd.confに
Options +ExecCGI
AddHandler cgi-script .cgi
を書くだけで使えるでしょう。
そういう人は、これを読んでも意味がありません。
私のような、開発はWin 、サーバーはunix系だと
困ったことになるのです。
・Cygwin(Win上で動くLinux)のApache
・Anhttpdサーバー
・仮想OSを使ってApache
・Win Apacheで無理矢理変換
などの選択がありますが、ここでは、無理矢理変換をやってみましょう。
Winでは、
CygwinのApacheやAnhttpdサーバー
を使えばなんの苦労もなく実行できるのですが
Win Apacheを使うと スクリプトの最初が
#!/usr/local/bin/perl
#!c:/prog..../perl.exe
と指定の仕方がちがうのでーす
※CygwinのApacheつかえって つっこみは抜きでお願いします。
それで 、直接ハンドラを変更してみると 内部エラー・・・・
unix系で できるのになぜ?
Anhttpdサーバー的な使い方をしたいのですよ!!
いろいろ条件を変え、試して、
どうもWinのperl.exeは、環境変数をよんでくれない?
という結論にいたりました
直接perl.exeにおくらず
仲介ソフト+リダイレクトを通すことにしました。
やっていることは、
カレントディレクトリを変更して
STDINをファイルに書き出して
PATH_INFO
PATH_TRANSLATED
から
単に、コマンド実行させて結果をファイルに保存して、
そのファイルをコンソールにはきだすだけです。
ここで問題になるのが実行の同期問題です。
コマンド実行がくせもので、Win32アプリですと
言語はなんでもいいのですが
Shellexecでは「実行待ち無し」にしかできないので
「実行待ちができる」Shellコマンドを使うのですが、なぜかVBにしかないのです。
VBはもっていないので
Delphi2005でコンパイルできる VB.netで作ってみました。
(ShellがないためにDelphi → Delphi.net → VB.net という経過をたどりました。)
つい慣れている環境で作ろうとしてしまうので・・・おもわぬところでつまづきました。
VB.netはコード支援が働かないのでヘルプを見ながらコピペでペタペタと・・・
実行ファイルも7KBと小さいので、問題なしです。
本気でWin運用するには、
Win apacheではなく、仮想OSかCygwin上の方が
全角文字問題やmodrewriteの動作異常につきあわずに済みます。
またそのほうがセキュリティ的にいいと思います。
しかし、記憶容量やメモリや、実行速度の問題で
テストにしか使わないのに、いちいちそんなことできませんよー
というときに この技は 便利なんです。
ScriptAlias /perl_MyCgi/ "c:/。。。/Perl/bin/"
Action cgi-script "/perl_MyCgi/perl.exe"
これで 動けば一番いいのですが動かないのです。
※この方法で最近のphpは、動くようです。(php-cgi.exe)。
※perl.exeが馬鹿なので仕方がないです
そこで
※CygwinのApacheつかえって つっこみは抜きでお願いします。
やり方は、非常に簡単です。
●ハンドラのオーバーライト(httpd.conf)
ScriptAlias /perl_MyCgi/ "c:/。。。/Perl/bin/"
AddHandler perl_cgi .cgi
Action perl_cgi "/perl_MyCgi/perl_cgi_vb/perl_cgi_vb.exe"
●仲介ソフトの設置(ここでは、perl_cgi_vb.exe)
(※パスの全角文字は壊れるようなので、全角を含む場合は、Cygwinを検討しましょう)
ついでに、スクリプト内でのOSの確認は
if (index($^O,'Win')
みたいな感じで分岐できます。MSWin32
わぁ。やったぁ・・・
そ の ま ま
う ・ ご ・ い ・ た
しつこいですが、
※CygwinのApacheつかえって つっこみは抜きでお願いします。
※本気で使う場合は、CygwinのApacheか、仮想OS上で普通に使うほうが安全です。
仲介ソフト |
のコード(一部)
VB.net (Shellを利用するため) |
PerlのPath |
dim rk as Microsoft.Win32.RegistryKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("SOFTWARE\Perl")
if Not(IsNothing(rk)) then
Perl_exe_Path = rk.GetValue("BinDir","")
End if |
環境変数
の取得 |
PATH_INFO = Environment.GetEnvironmentVariable("PATH_INFO")
PATH_TRANSLATED = Environment.GetEnvironmentVariable("PATH_TRANSLATED") |
コマンドの
エスケープ用 |
Function QuotedStr(S as String)
Dim c as Char
c = """" ' ややこしくなるので単純化
Return c + S.Replace(c, c+c) + c
End Function |
|
Sub MakeStdinFile()
dim AFileStream as FileStream
Dim standardInput as Stream
dim b as byte
dim i as integer
' STDIN の内容を書き出す
Temp_IN_FileName = getTempFileName()
AFileStream = new FileStream(Temp_IN_FileName,FileMode.Create)
standardInput = Console.OpenStandardInput()
' Seekをサポートしていないので 最後にきたかを判定。
' ReadByte() 終わりだと -1
Try
i = standardInput.ReadByte()
While (i>-1)
if (i = -1) then exit While
b = Cbyte(i)
AFileStream.WriteByte(b)
i = standardInput.ReadByte()
End While ' Wend
Finally
AFileStream.Flush()
AFileStream.Close()
End Try
End Sub |
作成関数 |
Sub MakeStdinFile()
Sub DeleteStdinFile()
Sub DeleteTempFile()
Function getTempFileName() as string
Function cmd() as string
Function QuotedStr(S as String)
Sub ExecCGI() ' shell |
その他
使用したクラス |
FileStream
Console.OpenStandardInput()
Console.OpenStandardOutput()
|
概要
Stdinの内容をstandardInput.ReadByte()でファイルに納め、
コマンドとともにリダイレクトし、
結果ファイルを、FileStreamでreadbyteで読み込みながら
Console.OpenStandardOutput()へwitebyteで出力します。
CygwinやLinuxの場合。
普通に、
httpd.confに
Options +ExecCGI
AddHandler cgi-script .cgi
を書くだけで使えるでしょう。
/usr/bin/perl
と
/usr/local/bin/perl
の場合に対応できるように
perlが入っていることを確認して
/usr/binと/usr/local/binにシンボリックリンクがあるか確認しましょう。
Cygwinの場合、ln -s /usr/bin/perl /usr/local/bin/ perl
で、リンクを追加しておけば、特に困ることはないと思います。