Could not open input file

一見よさそうだけど、引数の処理がうまくいかないので、この記事は前面削除です。

症状

Cygwin+bash 上で、次のような php スクリプトを実行するとエラーになりました。

#! php
<?php
  print "Hello";
?>
$ hello.php
Could not open input file: /home/egc/bin/hello.php

原因

「きっと」ですが、実行されるPHPwindows用のものなのに、パスがcygwin(unix)ものだということだと思います。

対策

本当のphpインタプリタ(c:/php/php.exe)のダミー php(.sh)を作って、ダミーを経由させて、パス形式を変換して実行させます。

まず path を確認しておきます。

例えば、phpインタプリタが c:/php/php.exe、ユーザ用のbinフォルダが /home/egc/bin として、

$ echo $PATH
・・・:/home/egc/bin:・・・:/cygdrive/c/php:・・・

のように path の並びは、ユーザー用の/home/egc/binが先行しているはずです。ダミーのphpはユーザー用のbinに置きます。

ダミー「phpスクリプト

本物のphpインタプリタ(c:/php/php.exe)よりも優先されるパスに置きます(/home/egc/bin/php)。

#! /usr/bin/sh
php.exe $(cygpath -m "$1")

実行すると...

$ hello.php
Hello

えーと、

  1. bashのシェルコマンドから、hello.php を実行すると、
  2. 1行目の#! phpに従ってシェルが php を起動しますが、
  3. パスで先行するダミーの php が起動されて
  4. cygwin風のパスをミックス(-m)形式に変換し、
  5. 本当のphpインタプリタ(php.exe)を実行

というからくりになります。
ちなみに、hello.php はここでは、/home/egc/bin に置いてますが、どこにおいても問題はありません。そのときは、./hello.php などと起動します。

うーん。もっと上手い方法がないものでしょうか・・・

補足 php.ini

軽量化した php.ini を使う場合、環境変数で「PHPRC=c:/home/egc/bin」として、php.ini のサーチフォルダを指定することができますが、それだと常に「c:/home/egc/bin/php.ini」が使われることになります。そこで、各々のスクリプトでべつの INIファイルが使えるようにする方法を検討します。
軽量化した独自のCLI用のINIファイルのパスを「c:/home/egc/bin/my.php.ini」とします。このINIファイルの内容は次のようだとします。

[PHP]
extension_dir = "c:/php/ext"
extension=php_sockets.dll
extension=php_mbstring.dll

PHPスクリプト(c:/home/egc/bin/hello.php)は次のように書きます。

#! php -c my.php.ini
<?php
  print "Hello";
?>

関連するファイルの構成は次のようになります。

c:/
├ php/
│ ├ dev/
│ ├ ext/
│ ├ PEAR/
│ ├ php.exe     <=本物のphpインタプリタ実行ファイル
│ └ php.ini     <=デフォルトのINIファイル
│
├ home/egc/bin 
│ ├ php         <=ダミーのphp。CLI専用 bash スクリプト
│ ├ my.php.ini  <=軽量化したINIファイル
│ └ hello.php   <=任意のPHPスクリプト

この hello.php は、「my.php.ini」が置かれている「c:/home/egc/bin」フォルダでしか実行できません。どのフォルダからでも実行できるようにするには、INIファイルを絶対パスで指定する必要があります。つまり、「#! php -c c:/home/egc/bin/my.php.ini」とするのですが、これはうれしくないので、phpを改変します。

#! /usr/bin/sh

function argproc {
    while [[ $# -gt 1 ]]
    do
	case $1 in
	    -c)
		echo "$1"
		shift
		echo $(cygpath -m "$(dirname $0)/$1")
		;;
	    *)
		echo -n "$1 "
		;;
	esac
	shift
    done
    echo $(cygpath -m "$1")
}

args=$(argproc $@)
php.exe $args