MediaWiki  master
DatabaseMysqli.php
Go to the documentation of this file.
1 <?php
23 namespace Wikimedia\Rdbms;
24 
25 use mysqli;
26 use mysqli_result;
27 use Wikimedia\AtEase\AtEase;
28 use Wikimedia\IPUtils;
29 
47  protected function doQuery( $sql ) {
48  AtEase::suppressWarnings();
49  $res = $this->getBindingHandle()->query( $sql );
50  AtEase::restoreWarnings();
51 
52  return $res instanceof mysqli_result ? new MysqliResultWrapper( $this, $res ) : $res;
53  }
54 
63  protected function mysqlConnect( $server, $user, $password, $db ) {
64  if ( !function_exists( 'mysqli_init' ) ) {
65  throw $this->newExceptionAfterConnectError(
66  "MySQLi functions missing, have you compiled PHP with the --with-mysqli option?"
67  );
68  }
69 
70  // PHP 8.1.0+ throws exceptions by default. Turn that off for consistency.
71  mysqli_report( MYSQLI_REPORT_OFF );
72 
73  // Other than mysql_connect, mysqli_real_connect expects an explicit port number
74  // e.g. "localhost:1234" or "127.0.0.1:1234"
75  // or Unix domain socket path
76  // e.g. "localhost:/socket_path" or "localhost:/foo/bar:bar:bar"
77  // colons are known to be used by Google AppEngine,
78  // see <https://cloud.google.com/sql/docs/mysql/connect-app-engine>
79  //
80  // We need to parse the port or socket path out of $realServer
81  $port = null;
82  $socket = null;
83  $hostAndPort = IPUtils::splitHostAndPort( $server );
84  if ( $hostAndPort ) {
85  $realServer = $hostAndPort[0];
86  if ( $hostAndPort[1] ) {
87  $port = $hostAndPort[1];
88  }
89  } elseif ( substr_count( $server, ':/' ) == 1 ) {
90  // If we have a colon slash instead of a colon and a port number
91  // after the ip or hostname, assume it's the Unix domain socket path
92  list( $realServer, $socket ) = explode( ':', $server, 2 );
93  } else {
94  $realServer = $server;
95  }
96 
97  $mysqli = mysqli_init();
98  // Make affectedRows() for UPDATE reflect the number of matching rows, regardless
99  // of whether any column values changed. This is what callers want to know and is
100  // consistent with what Postgres, SQLite, and SQL Server return.
101  $flags = MYSQLI_CLIENT_FOUND_ROWS;
102  if ( $this->getFlag( self::DBO_SSL ) ) {
103  $flags |= MYSQLI_CLIENT_SSL;
104  $mysqli->ssl_set(
105  $this->sslKeyPath,
106  $this->sslCertPath,
107  $this->sslCAFile,
108  $this->sslCAPath,
109  $this->sslCiphers
110  );
111  }
112  if ( $this->getFlag( self::DBO_COMPRESS ) ) {
113  $flags |= MYSQLI_CLIENT_COMPRESS;
114  }
115  if ( $this->getFlag( self::DBO_PERSISTENT ) ) {
116  $realServer = 'p:' . $realServer;
117  }
118 
119  if ( $this->utf8Mode ) {
120  // Tell the server we're communicating with it in UTF-8.
121  // This may engage various charset conversions.
122  $mysqli->options( MYSQLI_SET_CHARSET_NAME, 'utf8' );
123  } else {
124  $mysqli->options( MYSQLI_SET_CHARSET_NAME, 'binary' );
125  }
126  $mysqli->options( MYSQLI_OPT_CONNECT_TIMEOUT, 3 );
127 
128  // @phan-suppress-next-line PhanTypeMismatchArgumentNullableInternal socket seems set when used
129  $ok = $mysqli->real_connect( $realServer, $user, $password, $db, $port, $socket, $flags );
130 
131  return $ok ? $mysqli : null;
132  }
133 
137  protected function closeConnection() {
138  $conn = $this->getBindingHandle();
139 
140  return $conn->close();
141  }
142 
146  public function insertId() {
147  $conn = $this->getBindingHandle();
148 
149  return (int)$conn->insert_id;
150  }
151 
155  public function lastErrno() {
156  if ( $this->conn instanceof mysqli ) {
157  return $this->conn->errno;
158  } else {
159  return mysqli_connect_errno();
160  }
161  }
162 
166  protected function fetchAffectedRowCount() {
167  $conn = $this->getBindingHandle();
168 
169  return $conn->affected_rows;
170  }
171 
176  protected function mysqlError( $conn = null ) {
177  if ( $conn === null ) {
178  return mysqli_connect_error();
179  } else {
180  return $conn->error;
181  }
182  }
183 
189  protected function mysqlRealEscapeString( $s ) {
190  $conn = $this->getBindingHandle();
191 
192  return $conn->real_escape_string( (string)$s );
193  }
194 
198  protected function getBindingHandle() {
199  return parent::getBindingHandle();
200  }
201 }
202 
206 class_alias( DatabaseMysqli::class, 'DatabaseMysqli' );
Database abstraction object for MySQL.
Database abstraction object for PHP extension mysqli.
mysqlRealEscapeString( $s)
Escapes special characters in a string for use in an SQL statement.
mysqlConnect( $server, $user, $password, $db)
string null $password
Password used to establish the current connection.
Definition: Database.php:87
object resource null $conn
Database connection.
Definition: Database.php:77
newExceptionAfterConnectError( $error)
Definition: Database.php:1756
int $flags
Current bit field of class DBO_* constants.
Definition: Database.php:106
string null $server
Server that this instance is currently connected to.
Definition: Database.php:83
getFlag( $flag)
Returns a boolean whether the flag $flag is set for this connection.
Definition: Database.php:777
string null $user
User that this instance is currently connected under the name of.
Definition: Database.php:85
foreach( $mmfl['setupFiles'] as $fileName) if( $queue) if(empty( $mmfl['quiet'])) $s
const DBO_COMPRESS
Definition: defines.php:18
const DBO_SSL
Definition: defines.php:17
const DBO_PERSISTENT
Definition: defines.php:14