拡張モジュールの読み込みエラーでApacheを起動できない
PHPを5.2.13から5.2.14に上げるついでに、面倒になって拡張モジュールを全部インストールしました。ところが、まあ以前からそうだったんだけど、特定の拡張モジュールの読み込みでApacheがエラーになって再起動できない。以前はphp.iniの当該箇所をコメントアウトしてお茶を濁したものの、今回は使いたいモジュール(cURL)だったのでようやくちゃんと調べました。
どうやらPHP4の頃にインストールしたときのphp.iniがsystem32にずっと残っていて(日付は五年前……)、それが悪さをしていた模様。
うーん。こんなところにあったとは知らなんだ。インストールしたPHPフォルダ直下のしかいじってなかったよ。
とりあえずPHP4も残してはあるので、system32直下のphp.iniはそっちに移動、代わりにPHP5のほうのphp.iniをコピーしました。でもコピーじゃエラーは解消しなかったのでダメみたい。
試しにコピーじゃなく移動したらエラーは消えたようで、Apacheを再起動できました。良かった、良かった。
エラーは続く
う。いざプログラムを実行しようとしたら、
Fatal error: Call to undefined function curl_init()
Fatal error: Class 'PDO' not found
調べてみるとsystem32にPHP4のDLLが他にもあるようだったので、面倒になってPHP4自体を削除。その後PHP5も削除→再インストール。でもだめ……。
「
Windows php curlを使う。 」にある方法も全滅。そもそもphpinfo()でcURLもPDOも出てこない。
考えてみればhttpd.confのPHPIniDirにもPHPのパスが指定してあるし、PHPRC 環境変数の内容も同じなのに、system32にphp.iniを置かないと作動しないのがおかしい。マニュアルによると最優先はPHPIniDirで、system32のようなフォルダは優先度最低なのに。
で、php_ini_loaded_file() を実行してみたらパスを取得できない。phpinfo()の「Configuration File (php.ini) Path」の値を確認すると「C:\WINDOWS」。ディレクトリのみの場合はphp.iniが読み込まれていないということらしいけど、ここにもphp.iniがあったんだよね。もしかしてこれも以前からあって、system32とも被ったかな。紛らわしいんで、とりあえず削除したけど。
ただしphp.iniを読み込まないのは「C:\WINDOWS」もsystem32に置いても同じ。いちおうレジストリにも手動でIniFilePathを登録してみたけど、症状は変わらず。何だろう……。
ググると、php.iniを作り直したら認識されたとの例を発見、念のために他にphp.iniがないことを確認した上で、PHPのインストールフォルダのphp.iniのみにし、拡張モジュール以降を削除してApacheを再起動したところ正常終了。
うーむ。どうやら認識してなかったのではなく、途中でエラーになって読み込みが完了していなかったらしい。そしてphpinfo()を見る限りデフォルトのパスはC:\WINDOWSだから、元からsystem32のは読み込んでもいなかったんじゃ……。
検証したところextensionの指定でいくつかエラーになっていたことが判明し、それをコメントアウトしたところ、とりあえずはApacheは起動、「Configuration File (php.ini) Path」の値は変わらないながらも、noneだった「Loaded Configuration File」にphp.iniのパスが。php_ini_loaded_file() の結果も同じパス。
extensionの指定がアルファベット順に並んでいたため、最初のほう(肝心のcURL……)でエラーになってPDOまでたどりつけず、PDOクラスが見つからなかったようです。
cURLに必要なDLL
とりあえずPDOを再度使えるようになったのはいいとして、どうしてcURLのモジュールをロードできないんだろう? その他にも指定するとエラーになるモジュールはいくつかあって、一覧は以下の通り。
extension=php_curl.dll
extension=php_oci8.dll
extension=php_pdo_oci.dll
extension=php_pdo_oci8.dll
extension=php_pdo_sqlite_external.dll
extension=php_pspell.dll
extension=php_sybase_ct.dll
まあ、機械的に全部インストールしたから使わないものも含まれていて、それはコメントアウトしたままでもいいけど、cURLはなぁ。これを使いたくてモジュールをインストールし直したわけだし、どうにか原因を突きとめたいなぁ。一部のDLLだけってことは、「
指定されたモジュールが見つからないとか言われる 」と同じく、そのDLLからロードするDLLを見つけられないということかなぁ。
「
Windows用PHP拡張モジュール 」によると、一部のモジュールには外部DLLが必要で、非バンドルの場合もあるらしい。例としてOracleモジュールが挙げられていたから、php_oci8.dllとかがエラーになるのはこれが原因だな。
でもなあ、cURLはなぁ。同ページの別途必要なDLLを見ても、パスの通ったところにあるバンドルDLL2個しか書いてないしなぁ。それにたとえばMySQL用のモジュールもバンドルDLLが必要だとあるけど、こっちについてはエラーになってないから、パスを認識できていないとは考えにくい……。
他に必要なDLLがあるのでは?と検索してみたら、こんなページが→「
win+apache+phpでcurlを使えるようにするのに一苦労 」
PHPのマニュアルに書いてあるDLL以外に、zlib.dll、wldap32.dllが必要だとあり、wldap32.dllはsystem32にあったものの、zlib.dllがなかったため(個々のアプリケーションフォルダにあったりしたけど)、最新版をダウンロードしてsystem32に入れたら動きました。phpinfo() にもやっと「curl」の項が出現。一日がかりだよ、長かった……。
Windows XP、7とも同じ
なお今回試行錯誤したのは Windows XP。でも Windows 7(Home Premium)にもzlib.dllはsystem32になかったですね。しかも Windows 7 の場合はよくわからない……。system32に入れただけだと動作しなかったので、管理者権限で何かやる必要がありそうだけど、XPのほうではzlib.dllって複数のアプリケーションフォルダにまったくサイズの違うものが入っていたため、同名の異なるdllもあるかも。
ってことで、XPも最終的にそうしたけど、7の場合もsystem32ではなくphpのインストールフォルダ直下に入れました。ここもパスが通っているので。
それと今回ググっていて混乱したのは、「コメントアウト」をコメント化することではなく、なぜか「コメントになっているコードを有効に戻すこと」という逆の意味で使っている人が複数いたこと。実際のコードを見る限り逆になっていたので、斜め読みしたときは「??」でした。
それにしてもDelphi使ってたときはリソースビューアがあったと思ったけど、どこだったかなぁ。あれでdllを覗けば、ロードしている外部dllの名前を綺麗に見られるんじゃないかな。見づらいながらもバイナリエディタで覗いたところ、こんな名前があったのは確認したけど。
KERNEL32.dll
MSVCRT.dll
WLDAP32.dll
WS2_32.dll
secur32.dll
security.dll
LIBEAY32.dll
SSLEAY32.dll
php5ts.dll
zlib.dll
この中でKERNEL32.dll~security.dllはもともとsystem32にあったようだし(Windows 7 で確認)、LIBEAY32.dll~php5ts.dllはPHPのインストールフォルダ直下にあるわけだから、なかったのは、やはりzlib.dllだけです。
まとめ
複数のバージョンのPHPを入れるのを避ける
複数のバージョンのPHP、特にPHP4以前をインストールしている場合、それらをさっくり削除したほうが面倒がない。入れたままにする場合は、php.iniやdllが取り違えてロードされないよう削除するなり退避するなりし、誤動作の原因にならないよう対処しておく。特に%systemroot%や%systemroot%\system32はきっちり調べること。
PHP4だとインストールフォルダのサブフォルダに使用dllがまとめて入っているようなので、それのコピーがないか確認するといいかも。全部同じ更新日時のようだから、それで検索してもいいけど。
php.iniが複数ないことを確認する
全ドライブを検索して、php.iniが複数ないか確認する。
ちなみに複数ある場合、どれがロードされるかという優先度がマニュアルの「
設定ファイル 」項に書いてある。
Apacheが起動しなかったら、php.iniなしで起動させてみる
Apacheが起動しなかったら、唯一だと確認したphp.iniをリネームして再度試してみる。php.iniが見つからないと、たぶん全部初期値で起動されるだろうから、それで phpinfo() の結果確認ができる(コマンドラインから確認してもいいけど見づらいので)。
PHPをインストールしただけだとApacheが起動しない、でもsystem32(等のシステムフォルダ)にphp.iniを移動させると起動する場合、そもそもsystem32のphp.iniを認識していないと思われる。だからエラーが起きなくなり、一見、解決したように見える(コピーした場合にエラーになるのは、コピー元のファイルをちゃんと認識してロードしようとしているためかと)。
PHPプログラム内で phpinfo()、またはコマンドラインから php -i を実行して「Configuration File (php.ini) Path」を確認する。そこが「C:\Windows」となっていた場合、「C:\Windows\system32」は単純にphp.iniの検索パスにないと思われるので、system32に置いてもたぶん無駄。そして「Loaded Configuration File」が「(none)」になっていた場合は、php.iniがロードされていない、あるいはロード途中でエラーになって完了していない。
拡張モジュールのロード箇所をコメント化してみる
Apacheを起動できなかった場合、php.ini末尾にある「extension=dll名」の羅列のどこかでエラーになっている可能性が高い。
とりあえずその部分をすべて削除するかコメントアウトし、Apacheが起動すること、「Loaded Configuration File」に当該php.iniのパスがあることを確認する。その後、先頭から一行ずつ元に戻しながらApacheが起動するか試す(php_pdo.dllの後に記載しなければいけないPDO関連dllのように、順番が重要なdllもあるため記載順自体は変えない)。
そうやってエラーが発生した行をコメントアウトすればとりあえずは動作するし、エラー箇所を特定できたことになる。当該dllでエラーが起きる理由は外部dllが足りないということだろうから、詳細をあとで調査する。
そもそもちゃんとパスが通ってる?
パスの通った場所に各外部dllを置いてあるなら、正常に設定がされていればsystem32にコピーする必要はない。もしコピーしなければ動作しないなら、そもそもどこかがおかしいわけで、それを解決することが肝要。
なおユーザ環境変数ではなく、システム環境変数に設定しないとパスを認識しないという報告もあり(インストーラー版でインストールすれば、勝手にシステム環境変数にPHPのインストールパスが入る気がするけど、zip版で手動インストールする場合に注意)。
zlib.dllのダウンロード
2010/10/04 21:26:17
最終更新:2010年10月04日 21:26