mysqliのコンストラクタで"No such file or directory"のエラー
mysqli::__construct() で以下のエラーが発生。
mysqli::mysqli(): (HY000/2002): No such file or directory
調べてみると、MySQLのソケットファイル(mysql.sock)が見当たらない場合にこのエラーが発生することがあるようです。
パッケージでインストールした場合はよしなに設定してくれるはずですが、順序によるものか、MySQLの設定とPHPの設定でソケットファイルのパスが異なってしまうケースもあるとのこと。
(そういえば某レンタルサーバの初期設定で同様の問題が起きていました…)
参考
mysqliモジュールの設定をコマンドで確認してみます。
$ php --ri mysqli mysqli MysqlI Support => enabled Client API library version => mysqlnd 5.0.11-dev - 20120503 - $Id: bf9ad53b11c9a57efdb1057292d73b928b8c5c77 $ Active Persistent Links => 0 Inactive Persistent Links => 0 Active Links => 0 Directive => Local Value => Master Value mysqli.max_links => Unlimited => Unlimited mysqli.max_persistent => Unlimited => Unlimited mysqli.allow_persistent => On => On mysqli.default_host => no value => no value mysqli.default_user => no value => no value mysqli.default_pw => no value => no value mysqli.default_port => 3306 => 3306 mysqli.default_socket => /var/lib/mysql/mysql.sock => /var/lib/mysql/mysql.sock mysqli.reconnect => Off => Off mysqli.allow_local_infile => On => On
pdo_mysqlの方も念のため。
$ php --ri pdo_mysql pdo_mysql PDO Driver for MySQL => enabled Client API version => mysqlnd 5.0.11-dev - 20120503 - $Id: bf9ad53b11c9a57efdb1057292d73b928b8c5c77 $ Directive => Local Value => Master Value pdo_mysql.default_socket => /var/lib/mysql/mysql.sock => /var/lib/mysql/mysql.sock
どちらも /var/lib/mysql/mysql.sock
になっています。
findコマンドで探してみても見つからない…それもそのはず、今回はWebサーバとDBサーバを分離していて、PHPが動作しているWebサーバにはMySQLを入れてなかったのです。
(それなのにMySQLソケットファイルを探しに行ってる時点で、おかしいと気付くべきでしたが…)
なお、MySQLソケットファイルの変更は php.ini や ini_set()関数 でこれらの設定値を変更するほか、以下の方法でも可能です。
mysqli::__construct() の第6引数でMySQLソケットファイルのパスを指定する
PHPマニュアルの mysqli::__construct() の通り、コンストラクタの引数はこうなってます。
mysqli::__construct (
string $host = ini_get("mysqli.default_host"),
string $username = ini_get("mysqli.default_user"),
string $passwd = ini_get("mysqli.default_pw"),
string $dbname = "",
int $port = ini_get("mysqli.default_port"),
string $socket = ini_get("mysqli.default_socket")
)
第6引数でソケットファイルへのパスを指定できます。
注意: socket 引数を指定しても、MySQL サーバーへの 接続時の型を明示的に定義することにはなりません。MySQL サーバーへの 接続方法については host 引数で定義されます
この注意書きはちょっと分かりづらいのですが、「接続時の型」とはUNIXドメインソケットで接続するか、それともTCPソケットで接続するか、という意味でしょうか。
MySQLでは "localhost" と "127.0.0.1" が別物というのは有名な話で、"localhost" ではUNIXドメインソケット、"127.0.0.1" ではTCPソケットが利用されるという違いがあり、MySQLのユーザー権限もそれぞれ個別に設定する必要があります。
あとよく引っかかるものとして、MySQLの設定で skip-networking が有効にされている場合、ネットワーク経由の接続を禁止=UNIXドメインソケットしか受け付けなくなるので、host=127.0.0.1
を指定してると接続できない、ということがあります。
しかし、今回の場合はLAN内の別のホストで動いているDBサーバに接続しようとしているはずで、No such file or directory
がソケットファイルを探した結果のエラーだとすると、そんなエラーが発生すること自体がおかしいわけで。
あっ、と思ってアプリケーション側の設定ファイルを確認してみると、いつもの癖で接続先ホストを "localhost" って書いてしまってたという単純なオチでした…。
PDO::__construct() の第1引数でMySQLソケットファイルのパスを指定する
もうオチはついたんですが、せっかくなのでPDOの場合も書いておきます。
PHPマニュアルの PDO::__construct の通り、コンストラクタの引数はこうなってます。
public PDO::__construct ( string $dsn, string $username, string $password, array $driver_options )
第1引数のDSNに受け付ける内容は使用するPDOドライバによって異なりますが、MYSQLの場合は PDO_MYSQL DSN に書かれており、ソケットを指定する例があります。
unix_socket MySQL の unix ソケットを指定します (host あるいは port と同時に使用することはできません)。
こんな風にDSNでソケットを指定できます。
mysql:unix_socket=/tmp/mysql.sock;dbname=testdb
なお前述した通り、unix_socket=...
と指定していなくても、host=localhost
と指定している場合、UNIXドメインソケットを使った接続が行われます。
注意: Unix のみ ホスト名を "localhost" にすると、 サーバーへの接続はドメインソケットを使って行われます。 libmysqlclient を使って PDO_MYSQL をコンパイルした場合は、 ソケットファイルの場所は libmysqlclient のコンパイル時の場所になります。 mysqlnd を使って PDO_MYSQL をコンパイルした場合は、デフォルトのソケットは pdo_mysql.default_socket の設定を使って作られます。
PDO関数だけでなくmysql、mysqli等のエクステンションでは旧来libmysqlclientライブラリを標準で利用していましたが、PHP5.4以降はPHP拡張として実装された mysqlnd (MySQL native driver for PHP) を標準で利用するように変わりましたので、今回の環境でPDO_MYSQLを利用する場合は前述の通り pdo_mysql.default_socket => /var/lib/mysql/mysql.sock
を参照することになります。