[wp-trac] [WordPress Trac] #54877: Occasional PHP exception being thrown on WPDB/MySQLi connections
WordPress Trac
noreply at wordpress.org
Fri Jan 21 19:09:21 UTC 2022
#54877: Occasional PHP exception being thrown on WPDB/MySQLi connections
-----------------------------+---------------------
Reporter: johnjamesjacoby | Owner: (none)
Type: enhancement | Status: new
Priority: normal | Milestone: 6.0
Component: Database | Version: 1.5
Severity: normal | Resolution:
Keywords: 2nd-opinion | Focuses:
-----------------------------+---------------------
Description changed by johnjamesjacoby:
Old description:
> ** PHP Debug Notice **
> {{{
> mysqli::real_connect() expects parameter 5 to be integer, string given -
> wpdb::_do_query /wp-includes/wp-db.php:2056
> }}}
>
> The above notice appears in logs once for approximately every 250k
> requests. I have a hunch it's happening on reconnection attempts (using
> `$this->dbh`) but don't have any hard evidence to back up that claim.
>
> My `DB_HOST` is `localhost`, and I've also seen this happen with RDS
> (`xxx.rds.amazonaws.com`).
>
> ----
>
> I've spent a few hours researching this, and am including that research
> below:
>
> **WordPress DB_HOST Documentation**
> * https://wordpress.org/support/article/editing-wp-config-php/#set-
> database-host
>
> The above docs confirm that `localhost:3306` is the recommended way of
> adding a port number.
>
> **CodeIgniter example & fix**
> * https://github.com/bcit-ci/CodeIgniter/issues/5627
> * https://github.com/bcit-
> ci/CodeIgniter/commit/41bba2fea6fafa315db0a21093722f920455e3b1
>
> The above links confirm that CodeIgniter was defaulting to a string
> (causing the same issue) instead of null or int, and patched it
> internally.
>
> **Facebook, HHVM, HACK**
> * https://github.com/facebook/hhvm/issues/2482
> *
> https://github.com/facebook/hhvm/commit/f03f434e2eacda604b32bc7e4aa3334ed956a83a
>
> The above issue confirms that Facebook saw the same issue, and decided to
> patch it inside of HHVM.
>
> **Tangential WordPress tickets**
> * #41722 - Adding IPv6 support
> * #42496 - Improving MySQL 8.0 support
> * #21663 - Adding mysqli support
>
> The above tickets show an abbreviated timeline of surrounding changes to
> wpdb. No regressions. No bug introductions. Simply some related research.
>
> **PHP MySQL unit tests**
> * https://github.com/php/pecl-database-
> mysql/blob/6ca4fa4b509819ecc4c8ff2b28080d60ad64acc6/tests/mysql_connect.phpt
>
> The above link shows how PHP itself tests MySQL (not MySQLi) database
> connections.
>
> **PHP MySQLi Docs**
> * https://www.php.net/manual/en/class.mysqli.php
>
> The above link is my favorite. Specifically:
>
> {{{
> class mysqli {
> (...)
> public __construct(
> string $hostname = ini_get("mysqli.default_host"),
> string $username = ini_get("mysqli.default_user"),
> string $password = ini_get("mysqli.default_pw"),
> string $database = "",
> int $port = ini_get("mysqli.default_port"),
> string $socket = ini_get("mysqli.default_socket")
> )
> (...)
> public real_connect(
> string $host = ?,
> string $username = ?,
> string $passwd = ?,
> string $dbname = ?,
> int $port = ?,
> string $socket = ?,
> int $flags = ?
> ): bool
> }
> }}}
>
> `ini_get()` always returns a string, and PHP's mysqli class constructs &
> defaults its `$port` using it. In the PHP source, it does not appear to
> be type cast into an integer.
>
> ----
>
> **Hypothesis**
>
> I believe this small and random-feeling annoyance can be fixed quite
> easily in WordPress in much the same way it's been fixed in HHVM &
> CodeIgniter.
>
> I have a hunch that: web hosts silence or ignore these notices; they've
> been happening for a very long time; the problem is small enough where it
> wasn't worth anyone else digging too deep into.
>
> ----
>
> **Conclusion**
>
> * `wpdb::parse_db_host()` parses `$this->dbhost` looking for IPv4/IPv6,
> port number, sockets, etc...
> * `$this->dbhost` is gotten from `DB_HOST`
> * Casting `$post` to `(int)` when non-null will ensure
> `mysqli_real_connect()` will only ever see `null` or `int` type values
>
> Something like:
> {{{
> $port = $port ? absint( $port ) : null;
> }}}
New description:
** PHP Debug Notice **
{{{
mysqli::real_connect() expects parameter 5 to be integer, string given -
wpdb::_do_query /wp-includes/wp-db.php:2056
}}}
The above notice appears in logs once for approximately every 250k
requests. I have a hunch it's happening on reconnection attempts (using
`$this->dbh`) but don't have any hard evidence to back up that claim.
My `DB_HOST` is `localhost`, and I've also seen this happen with RDS
(`xxx.rds.amazonaws.com`).
----
I've spent a few hours researching this, and am including that research
below:
**WordPress DB_HOST Documentation**
* https://wordpress.org/support/article/editing-wp-config-php/#set-
database-host
The above docs confirm that `localhost:3306` is the recommended way of
adding a port number.
**CodeIgniter example & fix**
* https://github.com/bcit-ci/CodeIgniter/issues/5627
* https://github.com/bcit-
ci/CodeIgniter/commit/41bba2fea6fafa315db0a21093722f920455e3b1
The above links confirm that CodeIgniter was defaulting to a string
(causing the same issue) instead of null or int, and patched it
internally.
**Facebook, HHVM, HACK**
* https://github.com/facebook/hhvm/issues/2482
*
https://github.com/facebook/hhvm/commit/f03f434e2eacda604b32bc7e4aa3334ed956a83a
The above issue confirms that Facebook saw the same issue, and decided to
patch it inside of HHVM.
**Tangential WordPress tickets**
* #41722 - Adding IPv6 support
* #42496 - Improving MySQL 8.0 support
* #21663 - Adding mysqli support
The above tickets show an abbreviated timeline of surrounding changes to
wpdb. No regressions. No bug introductions. Simply some related research.
**PHP MySQL unit tests**
* https://github.com/php/pecl-database-
mysql/blob/6ca4fa4b509819ecc4c8ff2b28080d60ad64acc6/tests/mysql_connect.phpt
The above link shows how PHP itself tests MySQL (not MySQLi) database
connections.
**PHP MySQLi Docs**
* https://www.php.net/manual/en/class.mysqli.php
The above link is my favorite. Specifically:
{{{
class mysqli {
(...)
public __construct(
string $hostname = ini_get("mysqli.default_host"),
string $username = ini_get("mysqli.default_user"),
string $password = ini_get("mysqli.default_pw"),
string $database = "",
int $port = ini_get("mysqli.default_port"),
string $socket = ini_get("mysqli.default_socket")
)
(...)
public real_connect(
string $host = ?,
string $username = ?,
string $passwd = ?,
string $dbname = ?,
int $port = ?,
string $socket = ?,
int $flags = ?
): bool
}
}}}
`ini_get()` always returns a string, and PHP's mysqli class constructs &
defaults its `$port` using it. In the PHP source, it does not appear to be
type cast into an integer.
----
**Hypothesis**
I believe this small and random-feeling annoyance can be fixed quite
easily in WordPress in much the same way it's been fixed in HHVM &
CodeIgniter.
I have a hunch that: web hosts silence or ignore these notices; they've
been happening for a very long time; the problem is small enough where it
wasn't worth anyone else digging too deep into.
----
**Conclusion**
* `wpdb::parse_db_host()` parses `$this->dbhost` looking for IPv4/IPv6,
port number, sockets, etc...
* `$this->dbhost` is gotten from `DB_HOST`
* Casting `$port` to `(int)` when non-null will ensure
`mysqli_real_connect()` will only ever see `null` or `int` type values
Something like:
{{{
$port = $port ? absint( $port ) : null;
}}}
--
--
Ticket URL: <https://core.trac.wordpress.org/ticket/54877#comment:1>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list