PHP mysqli, pdo_mysql + libmysqlclient + my.cnf の作りはおかしい
PHP mysqli, pdo_mysql + libmysqlclient + my.cnf の作りはおかしい
2025-04-08
(1).何が起きるか
-
my.cnf
に host, socket, user, password 指定 - PHP で
my.cnf
を read させる-
my.cnf
のhost
,socket
,user
,password
の指定値が無視《むし》される
-
[client]
user = xxxx
password = yyyy
host = zzzz
$myi = mysqli_init();
mysqli_options($myi, MYSQLI_READ_DEFAULT_FILE, "/foo/bar/my.cnf");
mysqli_real_connect($myi, NULL, NULL, NULL, NULL, 0, NULL); // ex.1, no effect
mysqli_real_connect($myi); //ex.2, no effect
$pdo = new PDO("mysql:", NULL, NULL,
[PDO::MYSQL_ATTR_READ_DEFAULT_FILE => "/foo/bar/my.cnf"] );
// ex.3 no effect
PHPスクリプトをどのように記述しても my.cnf
の host などの値が渡らない。
PHP *MySQL* ドライバーの中身(C言語)の作りが問題。
(2).PHPソースの何がまちがっているか
- PHP 内で使用されている C の
mysql_real_connect()
引數《ひきすう》にNULL
が渡らない - PHP スクリプト内で引數に
NULL
を與《あた》えてもダメ - PHP 中身(Cソース)の初期値がダメ
- PHP 中身(Cソース)のデフォルト値使用の判定がダメ
直して〜。
しかし PHP 8 が mysqlnd 中心に移行しているため、本家は直さないだろうなぁ。
(3).環境
- Ubuntu 24.04
- PHP 5.6.40, 7.4.33, 8.1.2, 8.4.5
- MySQL 5.0.96, 5.6.36, 8.4.4
(4).もう少し中身をみると
「mysql_real_connect()
の引數《ひきすう》を ""
にすれば my.cnf
使うじゃん!」と安易に考えてはならない。
NULL
なのよ...。
my.cnf
の接續《せつぞく》指定を利用するのは NULL
なのだ。
MySQL 5 までの libmysqlclient の動き
-
mysql_real_connect()
のhost
などにNULL
、port
に0
をセットすると-
my.cnf
の値を利用する -
mysql_options
MYSQL_READ_DEFAULT_FILE
でファイルを指定可能
-
-
NULL
(or0
) 以外の値の場合は、その値を使用する -
NULL
と""
は違う動きをする (除く一部)
libmysqlclient 内の、mysql_real_connect()
の引數《ひきすう》判定のおおよその流れは以下のようになっている。
// my.cnf の値をみる
// check args
if (!host || !host[0]) {
// 引數 host = NULL の時、my.cnf 値セット
// 引數 host = "" の時は、このブロックに入らない。
}
//同じく
if (!user || !user[0]) { ... }
if (!passwd) { .... }
if (!db || !db[0]) { .... }
if (!unix_socket) { ... }
if (!port) { ... }
// port は int につき、0 で判定
C言語において:
-
char *str
において -
str = NULL
の時、if (!str)
はTRUE
-
str = ""
の時、if (!str)
はFALSE
。∵""
がTRUE
-
if (!str)
の記述、個人的に好きになれない理由がこれ。- みんな〜、
if (str != NULL)
って書こうよ〜
- みんな〜、
-
言語によって仕樣《しよう》が違うため、こんがらがる。特にいくつかの言語を行ったりきたりしている時。頭が切りかわらずにハマる。
<?php
var_dump( NULL? "true" : "false" ); //-> string(5) "false"
var_dump( "" ? "true" : "false" ); //-> string(5) "false"
var_dump( "0" ? "true" : "false" ); //-> string(5) "false"
var_dump( 0 ? "true" : "false" ); //-> string(5) "false"
#include <stdio.h>
void main() {
printf("%s\n", NULL? "true" : "false" ); // -> false
printf("%s\n", "" ? "true" : "false" ); // -> true
printf("%s\n", "0" ? "true" : "false" ); // -> true
printf("%s\n", 0 ? "true" : "false" ); // -> false
}
MySQL 8 以上の libmysqlclient の動き
- 中身まで追えていない。MySQL 5 と別物になった。
- MySQL 8.4 マニュアルをみると、
-
NULL
は全てで default (ormy.cnf
値)となるようだ - 引數の一部は
""
でも動くようになっているらしい- 何にせよ
my.cnf
の指定を使いたければ、安パイはNULL
だろう
- 何にせよ
-
If host is NULL or the string "localhost", a connection to the local host is assumed:
If user is NULL or the empty string "", the current user is assumed.
If passwd is NULL, only entries in the user table for the user that have a blank (empty) password field are checked for a match.
If db is not NULL, the connection sets the default database to this value.
If unix_socket is not NULL, the string specifies the socket or named pipe to use.
If port is not 0, the value is used as the port number for the TCP/IP connection.
PHP はどのようにしているか
- mysql, pdo_mysql は、内部で使用する C 變數《へんすう》の初期値が
""
,"/tmp/mysql.sock"
,3306
になっている。- mysqli の内部の變數の初期値は
NULL
だが、その後の處理《しょり》が問題
- mysqli の内部の變數の初期値は
- mysqli_ , pdo:: 函數《かんすう》の arg についての動き
- PHP スクリプト内でセットする arg が
NULL
の場合、-
php.ini
の設定で上書き - あるいは、C 變數の初期値を利用
- ⇒ 結果、PHP スクリプト内で
NULL
指定してもムダになる
-
- PHP スクリプト内で
""
をセットすると- libmysqlclient の
mysql_real_connect()
に""
がセット-
mysql_real_connect()
に値がセットされたと判定され、my.cnf
値は使われない
-
- libmysqlclient の
- PHP スクリプト内でセットする arg が
ということで、
PHPスクリプトをかえようが、php.ini
をかえようが、my.cnf
をよみこませるようにしようが、
host, user, socket などに my.cnf の値は渡らない。
PHP スクリプト内で全てをセットする必要が出てくる。
なお、
-
my.cnf
に書いても無駄なのは、mysql_real_connect()
の引數だけ。他の libmysqlclient オプション (default-character-set
など )は渡る -
php.ini
でほにゃらら =
と値を空にすると、""
になる -
port
はphp.ini
で0
にし、PHP スクリプト内も0
にしておけば良い。これだけは助かる
(5).その他
PHP MySQL は libmysqlclient をリンクする方法が好き。
理由:
-
my.cnf
を使えるから -
my.cnf
を利用できれば、リンクしている libmysqlclient が持つ機能が利用可能になるから
がっかり:
- 最近の PHP は libmysqlclient をリンクさせないように動き始めている
- PHP 8 は configure で libmysqlclient を蹴るようにしている
- PHP 8.4 の mysqli は、ソースからも libmysqlclient 部分をカットしていた
- ⇐ 對策: PHP 8.1.2 の mysqli のソースを利用。PHP 8.4.5 でコンパイルできた
- PHP 8.4 の mysqli は、ソースからも libmysqlclient 部分をカットしていた
- PHP 8 は configure で libmysqlclient を蹴るようにしている
以上
Discussion