1 | <?php |
||
30 | class MysqliConnection implements PingableConnection, ServerInfoAwareConnection |
||
31 | { |
||
32 | /** |
||
33 | * Name of the option to set connection flags |
||
34 | */ |
||
35 | public const OPTION_FLAGS = 'flags'; |
||
36 | |||
37 | /** @var mysqli */ |
||
38 | private $conn; |
||
39 | |||
40 | /** |
||
41 | * @param array<string, mixed> $params |
||
42 | * @param array<int, mixed> $driverOptions |
||
43 | * |
||
44 | * @throws MysqliException |
||
45 | */ |
||
46 | 368 | public function __construct(array $params, string $username, string $password, array $driverOptions = []) |
|
47 | { |
||
48 | 368 | $port = $params['port'] ?? (int) ini_get('mysqli.default_port'); |
|
49 | |||
50 | // Fallback to default MySQL port if not given. |
||
51 | 368 | if (! $port) { |
|
52 | $port = 3306; |
||
53 | } |
||
54 | |||
55 | 368 | $socket = $params['unix_socket'] ?? ini_get('mysqli.default_socket'); |
|
56 | 368 | $dbname = $params['dbname'] ?? ''; |
|
57 | 368 | $host = $params['host']; |
|
58 | |||
59 | 368 | if (! empty($params['persistent'])) { |
|
60 | $host = 'p:' . $host; |
||
61 | } |
||
62 | |||
63 | 368 | $flags = $driverOptions[static::OPTION_FLAGS] ?? 0; |
|
64 | |||
65 | 368 | $this->conn = mysqli_init(); |
|
|
|||
66 | |||
67 | 368 | $this->setSecureConnection($params); |
|
68 | 368 | $this->setDriverOptions($driverOptions); |
|
69 | |||
70 | set_error_handler(static function () : bool { |
||
71 | 48 | return true; |
|
72 | 360 | }); |
|
73 | try { |
||
74 | 360 | if (! $this->conn->real_connect($host, $username, $password, $dbname, $port, $socket, $flags)) { |
|
75 | 48 | throw ConnectionError::new($this->conn); |
|
76 | } |
||
77 | 320 | } finally { |
|
78 | 360 | restore_error_handler(); |
|
79 | } |
||
80 | |||
81 | 320 | if (! isset($params['charset'])) { |
|
82 | 312 | return; |
|
83 | } |
||
84 | |||
85 | 8 | $this->conn->set_charset($params['charset']); |
|
86 | 8 | } |
|
87 | |||
88 | /** |
||
89 | * Retrieves mysqli native resource handle. |
||
90 | * |
||
91 | * Could be used if part of your application is not using DBAL. |
||
92 | */ |
||
93 | public function getWrappedResourceHandle() : mysqli |
||
94 | { |
||
95 | return $this->conn; |
||
96 | } |
||
97 | |||
98 | /** |
||
99 | * {@inheritdoc} |
||
100 | * |
||
101 | * The server version detection includes a special case for MariaDB |
||
102 | * to support '5.5.5-' prefixed versions introduced in Maria 10+ |
||
103 | * |
||
104 | * @link https://jira.mariadb.org/browse/MDEV-4088 |
||
105 | */ |
||
106 | 167 | public function getServerVersion() : string |
|
107 | { |
||
108 | 167 | $serverInfos = $this->conn->get_server_info(); |
|
109 | 167 | if (stripos($serverInfos, 'mariadb') !== false) { |
|
110 | 63 | return $serverInfos; |
|
111 | } |
||
112 | |||
113 | 104 | $majorVersion = floor($this->conn->server_version / 10000); |
|
114 | 104 | $minorVersion = floor(($this->conn->server_version - $majorVersion * 10000) / 100); |
|
115 | 104 | $patchVersion = floor($this->conn->server_version - $majorVersion * 10000 - $minorVersion * 100); |
|
116 | |||
117 | 104 | return $majorVersion . '.' . $minorVersion . '.' . $patchVersion; |
|
118 | } |
||
119 | |||
120 | /** |
||
121 | * {@inheritdoc} |
||
122 | */ |
||
123 | 169 | public function requiresQueryForServerVersion() : bool |
|
124 | { |
||
125 | 169 | return false; |
|
126 | } |
||
127 | |||
128 | /** |
||
129 | * {@inheritdoc} |
||
130 | */ |
||
131 | 2781 | public function prepare(string $sql) : DriverStatement |
|
132 | { |
||
133 | 2781 | return new MysqliStatement($this->conn, $sql); |
|
134 | } |
||
135 | |||
136 | /** |
||
137 | * {@inheritdoc} |
||
138 | */ |
||
139 | 1829 | public function query(string $sql) : ResultStatement |
|
140 | { |
||
141 | 1829 | $stmt = $this->prepare($sql); |
|
142 | 1805 | $stmt->execute(); |
|
143 | |||
144 | 1805 | return $stmt; |
|
145 | } |
||
146 | |||
147 | /** |
||
148 | * {@inheritdoc} |
||
149 | */ |
||
150 | 16 | public function quote(string $input) : string |
|
151 | { |
||
152 | 16 | return "'" . $this->conn->escape_string($input) . "'"; |
|
153 | } |
||
154 | |||
155 | /** |
||
156 | * {@inheritdoc} |
||
157 | */ |
||
158 | 1557 | public function exec(string $statement) : int |
|
166 | |||
167 | /** |
||
168 | * {@inheritdoc} |
||
169 | */ |
||
170 | 16 | public function lastInsertId(?string $name = null) : string |
|
174 | |||
175 | /** |
||
176 | * {@inheritdoc} |
||
177 | */ |
||
178 | 136 | public function beginTransaction() : void |
|
179 | { |
||
180 | 136 | $this->conn->query('START TRANSACTION'); |
|
181 | 136 | } |
|
182 | |||
183 | /** |
||
184 | * {@inheritdoc} |
||
185 | */ |
||
186 | 56 | public function commit() : void |
|
192 | |||
193 | /** |
||
194 | * {@inheritdoc} |
||
195 | */ |
||
196 | 88 | public function rollBack() : void |
|
202 | |||
203 | /** |
||
204 | * Apply the driver options to the connection. |
||
205 | * |
||
206 | * @param array<int, mixed> $driverOptions |
||
207 | * |
||
208 | * @throws MysqliException When one of of the options is not supported. |
||
209 | * @throws MysqliException When applying doesn't work - e.g. due to incorrect value. |
||
210 | */ |
||
211 | 368 | private function setDriverOptions(array $driverOptions = []) : void |
|
245 | |||
246 | /** |
||
247 | * Pings the server and re-connects when `mysqli.reconnect = 1` |
||
248 | * |
||
249 | * {@inheritDoc} |
||
250 | */ |
||
251 | 8 | public function ping() : void |
|
257 | |||
258 | /** |
||
259 | * Establish a secure connection |
||
260 | * |
||
261 | * @param array<string, mixed> $params |
||
262 | * |
||
263 | * @throws MysqliException |
||
264 | */ |
||
265 | 368 | private function setSecureConnection(array $params) : void |
|
284 | } |
||
285 |
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.
Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..