1 | <?php |
||
2 | /* |
||
3 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||
4 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||
5 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||
6 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||
7 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||
8 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||
9 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||
10 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||
11 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||
12 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||
13 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
14 | * |
||
15 | * This software consists of voluntary contributions made by many individuals |
||
16 | * and is licensed under the MIT license. For more information, see |
||
17 | * <http://www.doctrine-project.org>. |
||
18 | */ |
||
19 | |||
20 | namespace Doctrine\DBAL\Driver\Mysqli; |
||
21 | |||
22 | use Doctrine\DBAL\Driver\Connection as Connection; |
||
23 | use Doctrine\DBAL\Driver\PingableConnection; |
||
24 | use Doctrine\DBAL\Driver\ServerInfoAwareConnection; |
||
25 | |||
26 | /** |
||
27 | * @author Kim Hemsø Rasmussen <[email protected]> |
||
28 | * @author Till Klampaeckel <[email protected]> |
||
29 | */ |
||
30 | class MysqliConnection implements Connection, PingableConnection, ServerInfoAwareConnection |
||
31 | { |
||
32 | /** |
||
33 | * Name of the option to set connection flags |
||
34 | */ |
||
35 | const OPTION_FLAGS = 'flags'; |
||
36 | |||
37 | /** |
||
38 | * @var \mysqli |
||
39 | */ |
||
40 | private $_conn; |
||
41 | |||
42 | /** |
||
43 | * @param array $params |
||
44 | * @param string $username |
||
45 | * @param string $password |
||
46 | * @param array $driverOptions |
||
47 | * |
||
48 | * @throws \Doctrine\DBAL\Driver\Mysqli\MysqliException |
||
49 | */ |
||
50 | 5 | public function __construct(array $params, $username, $password, array $driverOptions = []) |
|
51 | { |
||
52 | 5 | $port = isset($params['port']) ? $params['port'] : ini_get('mysqli.default_port'); |
|
53 | |||
54 | // Fallback to default MySQL port if not given. |
||
55 | 5 | if ( ! $port) { |
|
56 | $port = 3306; |
||
57 | } |
||
58 | |||
59 | 5 | $socket = isset($params['unix_socket']) ? $params['unix_socket'] : ini_get('mysqli.default_socket'); |
|
60 | 5 | $dbname = isset($params['dbname']) ? $params['dbname'] : null; |
|
61 | |||
62 | 5 | $flags = isset($driverOptions[static::OPTION_FLAGS]) ? $driverOptions[static::OPTION_FLAGS] : null; |
|
63 | |||
64 | 5 | $this->_conn = mysqli_init(); |
|
65 | |||
66 | 5 | $this->setSecureConnection($params); |
|
67 | 1 | $this->setDriverOptions($driverOptions); |
|
68 | |||
69 | set_error_handler(function () {}); |
||
70 | try { |
||
71 | 1 | if ( ! $this->_conn->real_connect($params['host'], $username, $password, $dbname, $port, $socket, $flags)) { |
|
72 | 1 | throw new MysqliException($this->_conn->connect_error, $this->_conn->sqlstate ?? 'HY000', $this->_conn->connect_errno); |
|
73 | } |
||
74 | } finally { |
||
75 | 1 | restore_error_handler(); |
|
76 | } |
||
77 | |||
78 | if (isset($params['charset'])) { |
||
79 | $this->_conn->set_charset($params['charset']); |
||
80 | } |
||
81 | } |
||
82 | |||
83 | /** |
||
84 | * Retrieves mysqli native resource handle. |
||
85 | * |
||
86 | * Could be used if part of your application is not using DBAL. |
||
87 | * |
||
88 | * @return \mysqli |
||
89 | */ |
||
90 | public function getWrappedResourceHandle() |
||
91 | { |
||
92 | return $this->_conn; |
||
93 | } |
||
94 | |||
95 | /** |
||
96 | * {@inheritdoc} |
||
97 | */ |
||
98 | public function getServerVersion() |
||
99 | { |
||
100 | $majorVersion = floor($this->_conn->server_version / 10000); |
||
101 | $minorVersion = floor(($this->_conn->server_version - $majorVersion * 10000) / 100); |
||
102 | $patchVersion = floor($this->_conn->server_version - $majorVersion * 10000 - $minorVersion * 100); |
||
103 | |||
104 | return $majorVersion . '.' . $minorVersion . '.' . $patchVersion; |
||
105 | } |
||
106 | |||
107 | /** |
||
108 | * {@inheritdoc} |
||
109 | */ |
||
110 | 1 | public function requiresQueryForServerVersion() |
|
111 | { |
||
112 | 1 | return false; |
|
113 | } |
||
114 | |||
115 | /** |
||
116 | * {@inheritdoc} |
||
117 | */ |
||
118 | public function prepare($prepareString) |
||
119 | { |
||
120 | return new MysqliStatement($this->_conn, $prepareString); |
||
121 | } |
||
122 | |||
123 | /** |
||
124 | * {@inheritdoc} |
||
125 | */ |
||
126 | View Code Duplication | public function query() |
|
0 ignored issues
–
show
|
|||
127 | { |
||
128 | $args = func_get_args(); |
||
129 | $sql = $args[0]; |
||
130 | $stmt = $this->prepare($sql); |
||
131 | $stmt->execute(); |
||
132 | |||
133 | return $stmt; |
||
134 | } |
||
135 | |||
136 | /** |
||
137 | * {@inheritdoc} |
||
138 | */ |
||
139 | public function quote($input, $type=\PDO::PARAM_STR) |
||
140 | { |
||
141 | return "'". $this->_conn->escape_string($input) ."'"; |
||
142 | } |
||
143 | |||
144 | /** |
||
145 | * {@inheritdoc} |
||
146 | */ |
||
147 | public function exec($statement) |
||
148 | { |
||
149 | if (false === $this->_conn->query($statement)) { |
||
150 | throw new MysqliException($this->_conn->error, $this->_conn->sqlstate, $this->_conn->errno); |
||
151 | } |
||
152 | |||
153 | return $this->_conn->affected_rows; |
||
154 | } |
||
155 | |||
156 | /** |
||
157 | * {@inheritdoc} |
||
158 | */ |
||
159 | public function lastInsertId($name = null) |
||
160 | { |
||
161 | return $this->_conn->insert_id; |
||
162 | } |
||
163 | |||
164 | /** |
||
165 | * {@inheritdoc} |
||
166 | */ |
||
167 | public function beginTransaction() |
||
168 | { |
||
169 | $this->_conn->query('START TRANSACTION'); |
||
170 | |||
171 | return true; |
||
172 | } |
||
173 | |||
174 | /** |
||
175 | * {@inheritdoc} |
||
176 | */ |
||
177 | public function commit() |
||
178 | { |
||
179 | return $this->_conn->commit(); |
||
180 | } |
||
181 | |||
182 | /** |
||
183 | * {@inheritdoc}non-PHPdoc) |
||
184 | */ |
||
185 | public function rollBack() |
||
186 | { |
||
187 | return $this->_conn->rollback(); |
||
188 | } |
||
189 | |||
190 | /** |
||
191 | * {@inheritdoc} |
||
192 | */ |
||
193 | public function errorCode() |
||
194 | { |
||
195 | return $this->_conn->errno; |
||
196 | } |
||
197 | |||
198 | /** |
||
199 | * {@inheritdoc} |
||
200 | */ |
||
201 | public function errorInfo() |
||
202 | { |
||
203 | return $this->_conn->error; |
||
0 ignored issues
–
show
The expression
return $this->_conn->error returns the type string which is incompatible with the return type mandated by Doctrine\DBAL\Driver\Connection::errorInfo() of array .
In the issue above, the returned value is violating the contract defined by the mentioned interface. Let's take a look at an example: interface HasName {
/** @return string */
public function getName();
}
class Name {
public $name;
}
class User implements HasName {
/** @return string|Name */
public function getName() {
return new Name('foo'); // This is a violation of the ``HasName`` interface
// which only allows a string value to be returned.
}
}
Loading history...
|
|||
204 | } |
||
205 | |||
206 | /** |
||
207 | * Apply the driver options to the connection. |
||
208 | * |
||
209 | * @param array $driverOptions |
||
210 | * |
||
211 | * @throws MysqliException When one of of the options is not supported. |
||
212 | * @throws MysqliException When applying doesn't work - e.g. due to incorrect value. |
||
213 | */ |
||
214 | 1 | private function setDriverOptions(array $driverOptions = []) |
|
215 | { |
||
216 | $supportedDriverOptions = [ |
||
217 | 1 | \MYSQLI_OPT_CONNECT_TIMEOUT, |
|
218 | \MYSQLI_OPT_LOCAL_INFILE, |
||
219 | \MYSQLI_INIT_COMMAND, |
||
220 | \MYSQLI_READ_DEFAULT_FILE, |
||
221 | \MYSQLI_READ_DEFAULT_GROUP, |
||
222 | ]; |
||
223 | |||
224 | 1 | if (defined('MYSQLI_SERVER_PUBLIC_KEY')) { |
|
225 | 1 | $supportedDriverOptions[] = \MYSQLI_SERVER_PUBLIC_KEY; |
|
226 | } |
||
227 | |||
228 | 1 | $exceptionMsg = "%s option '%s' with value '%s'"; |
|
229 | |||
230 | 1 | foreach ($driverOptions as $option => $value) { |
|
231 | |||
232 | if ($option === static::OPTION_FLAGS) { |
||
233 | continue; |
||
234 | } |
||
235 | |||
236 | if (!in_array($option, $supportedDriverOptions, true)) { |
||
237 | throw new MysqliException( |
||
238 | sprintf($exceptionMsg, 'Unsupported', $option, $value) |
||
239 | ); |
||
240 | } |
||
241 | |||
242 | if (@mysqli_options($this->_conn, $option, $value)) { |
||
243 | continue; |
||
244 | } |
||
245 | |||
246 | $msg = sprintf($exceptionMsg, 'Failed to set', $option, $value); |
||
247 | $msg .= sprintf(', error: %s (%d)', mysqli_error($this->_conn), mysqli_errno($this->_conn)); |
||
248 | |||
249 | throw new MysqliException( |
||
250 | $msg, |
||
251 | $this->_conn->sqlstate, |
||
252 | $this->_conn->errno |
||
253 | ); |
||
254 | } |
||
255 | 1 | } |
|
256 | |||
257 | /** |
||
258 | * Pings the server and re-connects when `mysqli.reconnect = 1` |
||
259 | * |
||
260 | * @return bool |
||
261 | */ |
||
262 | public function ping() |
||
263 | { |
||
264 | return $this->_conn->ping(); |
||
265 | } |
||
266 | |||
267 | /** |
||
268 | * Establish a secure connection |
||
269 | * |
||
270 | * @param array $params |
||
271 | * @throws MysqliException |
||
272 | */ |
||
273 | 5 | private function setSecureConnection(array $params) |
|
274 | { |
||
275 | 5 | if (! isset($params['ssl_key']) && |
|
276 | 5 | ! isset($params['ssl_cert']) && |
|
277 | 5 | ! isset($params['ssl_ca']) && |
|
278 | 5 | ! isset($params['ssl_capath']) && |
|
279 | 5 | ! isset($params['ssl_cipher']) |
|
280 | ) { |
||
281 | 1 | return; |
|
282 | } |
||
283 | |||
284 | 4 | if (! isset($params['ssl_key']) || ! isset($params['ssl_cert'])) { |
|
285 | 4 | $msg = '"ssl_key" and "ssl_cert" parameters are mandatory when using secure connection parameters.'; |
|
286 | 4 | throw new MysqliException($msg); |
|
287 | } |
||
288 | |||
289 | $this->_conn->ssl_set( |
||
290 | $params['ssl_key'], |
||
291 | $params['ssl_cert'], |
||
292 | $params['ssl_ca'] ?? null, |
||
293 | $params['ssl_capath'] ?? null, |
||
294 | $params['ssl_cipher'] ?? null |
||
295 | ); |
||
296 | } |
||
297 | } |
||
298 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.