[wp-trac] [WordPress Trac] #54877: Occasional PHP exception being thrown on WPDB/MySQLi connections

WordPress Trac noreply at wordpress.org
Fri Jan 21 19:06:32 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           |   Keywords:  2nd-opinion
  Focuses:                   |
-----------------------------+-------------------------
 ** 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;
 }}}

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/54877>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list