時々、Webサーバからシェルのコマンドを呼び出したくなることがあります。 例えば、GraphVizでグラフを自動生成してWebページに貼り付けたい場合、 内部的にはdotコマンドが実行されます。 おそらく、現実的にはPerlのGraphVizモジュールを利用するなど、 外部ライブラリを使ってPerlなどのスクリプトを書いて実装すると思いますが、 内部的にはdotコマンドが呼び出されているはずです。
さて、シェルから実行したときと同じように動作すれば問題ないのですが、 必ずしもコマンドラインからの実行と同じようにWebサーバからコマンドを呼び出せるとは限りません。 理由は、Webサーバの環境変数PATHが普段のシェルの実行環境と同じとは限らないからです。 例えば、自分のFreeBSDのユーザ環境でのPATHの中身は、
/sbin:/bin:/usr/sbin:/usr/bin:/usr/games:/usr/local/sbin:/usr/local/bin
となっています。 一方、Apacheの環境変数PATHの中身は、
/sbin:/bin:/usr/sbin:/usr/bin
と、シェルの実行環境と異なります。 例えば、FreeBSDにGraphVizをpkg経由でインストールすると、 dotコマンドは/usr/local/bin/dotにインストールされます。 すると、通常のシェルからはpathが通っているので、問題なくdotコマンドを呼び出すことが出来ますが、 ApacheのWebサーバからはpathが通っていないので、単純には呼び出せません。
最も単純な解決方法は、Webサーバ上のpathが通っているディレクトリに 使いたいコマンドへのシンボリックリンクを張ることが挙げられます。 例えば、/usr/binに/usr/local/bin/dotのシンボリックリンクを張ることで、 Webサーバからdotコマンドを実行できるようになります。
ln -s /usr/local/bin/dot /usr/bin
しかし、簡易的なプログラムのためだけに、シンボリックリンクを張りたくない場合や、 MacのSIP(System Integrity Protection)のように、root権限でも特定のディレクトリを変更できない場合、 Apacheの環境変数PATHを書き換える必要があります。
Apacheの設定ファイルに、以下の内容を記述することでpathを変更します。
SetEnv PATH /path/to/target/dir:${PATH}
.htaccessファイルに記述することで、記述した設定ファイルの存在するディレクトリ以下のpathを変更出来ます。 例えば、/usr/local/binをPATHに加える場合は以下の通りになります。
SetEnv PATH /usr/local/bin:${PATH}
純粋にシェルコマンドをWebから使うことはそこまで多くないとは思いますが、 GraphVizをPerlのモジュールから利用するように、プログラマが意識しないところでコマンドを呼び出すことは意外とあるのかもしれません。 基本的にはシンボリックリンクを張ればおそらく解決すると思いますが、Macみたいに、 ディレクトリが保護されている場合は、環境変数を書き換えられると解決出来ると思います。 実際に、MacでGraphVizを使って自動生成したグラフを張るCGIプログラムを動かそうとして、 なかなかうまく動かなくて悩んでいましたが、Apacheの環境変数PATHを書き換えて解決しました。 多分、Nginxでも同じようなことは出来ると思います。Nginx使ったことないけど... そんな感じで、今回はここまで。