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_optionsMYSQL_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