いけむランド

はてダからやってきました

cygwin の PHP や MySQL から VertrigoServ の MySQL に接続する方法

誰もこんなことをやろうとしていないのか、ぐぐってもわからず、結局ソースまで調べて、解決したことをまとめておく。


cygwinPHP および MySQLCygwin Ports から入手することができるため、それをインストールする。

CLI

普通に MySQL のクライアントから接続しようとすると、ソケットがないと怒られてしまう。

% mysql
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
%


マニュアルを確認すると、--protocol というオプションがあるため、それで TCP を指定すると、接続することができる。

% mysql --protocol=TCP -uroot -pvertrigo
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.0.51b-community MySQL Community Edition (GPL)

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> status
--------------
mysql  Ver 14.12 Distrib 5.0.75, for pc-cygwin (i686) using readline 5.2

Connection id:          2
Current database:
Current user:           root@localhost
SSL:                    Not in use
Current pager:          stdout
Using outfile:          ''
Using delimiter:        ;
Server version:         5.0.51b-community MySQL Community Edition (GPL)
Protocol version:       10
Connection:             localhost via TCP/IP
Server characterset:    latin1
Db     characterset:    latin1
Client characterset:    latin1
Conn.  characterset:    latin1
TCP port:               3306
Uptime:                 50 sec

Threads: 1  Questions: 4  Slow queries: 0  Opens: 12  Flush tables: 1  Open tables: 6  Queries per second avg: 0.080
--------------

mysql>

PDO (MySQL)

一方で PHP の PDO で接続する場合は DSN で指定すれば良いように思われるが、普通に指定しても、CLI の場合と同様にソケットを使用しようとしてしまい、やはり怒られてしまう。

<?php
$dsn = 'mysql:dbname=hogehoge;host=localhost';
$user = 'root';
$password = 'vertrigo';
try {
    $dbh = new PDO($dsn, $user, $password);
} catch (PDOException $e) {
    echo 'Connection failed: ' . $e->getMessage();
}
?>


ポート番号を指定しないといけないのかな?と思い 'port=3306' とか、ソケット名を無効にすればいいのかな?と思い 'unix_socket=' とか指定してみるが、駄目。


しかし、MySQL CLI と同じメッセージが表示されるということは --protocol=TCP 相当の情報を渡せば、接続できるはずと思い、PHP の pdo_mysql のソースを調べているうちに以下のコードを発見した。

static int pdo_mysql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC)
{
	pdo_mysql_db_handle *H;
	int i, ret = 0;
	char *host = NULL, *unix_socket = NULL;
	unsigned int port = 3306;
	char *dbname;
	struct pdo_data_src_parser vars[] = {
		{ "charset",  NULL,	0 },
		{ "dbname",   "",	0 },
		{ "host",   "localhost",	0 },
		{ "port",   "3306",	0 },
		{ "unix_socket",  MYSQL_UNIX_ADDR,	0 },
	};
// snip
	php_pdo_parse_data_source(dbh->data_source, dbh->data_source_len, vars, 5); // PDO の第一引数 ($dsn) を parse する関数っぽい。
// snip
	dbname = vars[1].optval;
	host = vars[2].optval;	
	if(vars[3].optval) {
		port = atoi(vars[3].optval);
	}
	if (vars[2].optval && !strcmp("localhost", vars[2].optval)) {
		unix_socket = vars[4].optval;  
	}
// snip
}


どうも 'host=localhost' があると、強制的に 'unix_socket=MYSQL_UNIX_ADDR' (おそらく '/tmp/mysql.sock') が指定されるようになっている感じだったため、試しに 'host=127.0.0.1' に変更してみたところ、接続できることを確認した。


まあ、Windowscygwin と VertrigoServ を併用している人くらいしかこんなことではまらないとは思いますけどね...。