1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Interface to the MySQL Improved extension (MySQLi) |
4
|
|
|
* |
5
|
|
|
* @package PhpMyAdmin-DBI |
6
|
|
|
* @subpackage MySQLi |
7
|
|
|
*/ |
8
|
|
|
declare(strict_types=1); |
9
|
|
|
|
10
|
|
|
namespace PhpMyAdmin\Dbi; |
11
|
|
|
|
12
|
|
|
use mysqli; |
13
|
|
|
use mysqli_result; |
14
|
|
|
use mysqli_stmt; |
15
|
|
|
use PhpMyAdmin\DatabaseInterface; |
16
|
|
|
use stdClass; |
17
|
|
|
use function mysqli_init; |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* Interface to the MySQL Improved extension (MySQLi) |
21
|
|
|
* |
22
|
|
|
* @package PhpMyAdmin-DBI |
23
|
|
|
* @subpackage MySQLi |
24
|
|
|
*/ |
25
|
|
|
class DbiMysqli implements DbiExtension |
26
|
|
|
{ |
27
|
|
|
/** |
28
|
|
|
* @var array |
29
|
|
|
*/ |
30
|
|
|
private static $pma_mysqli_flag_names = [ |
31
|
|
|
MYSQLI_NUM_FLAG => 'num', |
32
|
|
|
MYSQLI_PART_KEY_FLAG => 'part_key', |
33
|
|
|
MYSQLI_SET_FLAG => 'set', |
34
|
|
|
MYSQLI_TIMESTAMP_FLAG => 'timestamp', |
35
|
|
|
MYSQLI_AUTO_INCREMENT_FLAG => 'auto_increment', |
36
|
|
|
MYSQLI_ENUM_FLAG => 'enum', |
37
|
|
|
MYSQLI_ZEROFILL_FLAG => 'zerofill', |
38
|
|
|
MYSQLI_UNSIGNED_FLAG => 'unsigned', |
39
|
|
|
MYSQLI_BLOB_FLAG => 'blob', |
40
|
|
|
MYSQLI_MULTIPLE_KEY_FLAG => 'multiple_key', |
41
|
|
|
MYSQLI_UNIQUE_KEY_FLAG => 'unique_key', |
42
|
|
|
MYSQLI_PRI_KEY_FLAG => 'primary_key', |
43
|
|
|
MYSQLI_NOT_NULL_FLAG => 'not_null', |
44
|
|
|
]; |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* connects to the database server |
48
|
|
|
* |
49
|
|
|
* @param string $user mysql user name |
50
|
|
|
* @param string $password mysql user password |
51
|
|
|
* @param array $server host/port/socket/persistent |
52
|
|
|
* |
53
|
|
|
* @return mysqli|bool false on error or a mysqli object on success |
54
|
|
|
*/ |
55
|
|
|
public function connect($user, $password, array $server) |
56
|
|
|
{ |
57
|
|
|
if ($server) { |
|
|
|
|
58
|
|
|
$server['host'] = empty($server['host']) |
59
|
|
|
? 'localhost' |
60
|
|
|
: $server['host']; |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
$mysqli = mysqli_init(); |
64
|
|
|
|
65
|
|
|
$client_flags = 0; |
66
|
|
|
|
67
|
|
|
/* Optionally compress connection */ |
68
|
|
|
if ($server['compress'] && defined('MYSQLI_CLIENT_COMPRESS')) { |
69
|
|
|
$client_flags |= MYSQLI_CLIENT_COMPRESS; |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
/* Optionally enable SSL */ |
73
|
|
|
if ($server['ssl']) { |
74
|
|
|
$client_flags |= MYSQLI_CLIENT_SSL; |
75
|
|
|
if (! empty($server['ssl_key']) || |
76
|
|
|
! empty($server['ssl_cert']) || |
77
|
|
|
! empty($server['ssl_ca']) || |
78
|
|
|
! empty($server['ssl_ca_path']) || |
79
|
|
|
! empty($server['ssl_ciphers']) |
80
|
|
|
) { |
81
|
|
|
if (! isset($server['ssl_key']) || is_null($server['ssl_key'])) { |
82
|
|
|
$server['ssl_key'] = ''; |
83
|
|
|
} |
84
|
|
|
if (! isset($server['ssl_cert']) || is_null($server['ssl_cert'])) { |
85
|
|
|
$server['ssl_cert'] = ''; |
86
|
|
|
} |
87
|
|
|
if (! isset($server['ssl_ca']) || is_null($server['ssl_ca'])) { |
88
|
|
|
$server['ssl_ca'] = ''; |
89
|
|
|
} |
90
|
|
|
if (! isset($server['ssl_ca_path']) || is_null($server['ssl_ca_path'])) { |
91
|
|
|
$server['ssl_ca_path'] = ''; |
92
|
|
|
} |
93
|
|
|
if (! isset($server['ssl_ciphers']) || is_null($server['ssl_ciphers'])) { |
94
|
|
|
$server['ssl_ciphers'] = ''; |
95
|
|
|
} |
96
|
|
|
$mysqli->ssl_set( |
97
|
|
|
$server['ssl_key'], |
98
|
|
|
$server['ssl_cert'], |
99
|
|
|
$server['ssl_ca'], |
100
|
|
|
$server['ssl_ca_path'], |
101
|
|
|
$server['ssl_ciphers'] |
102
|
|
|
); |
103
|
|
|
} |
104
|
|
|
/* |
105
|
|
|
* disables SSL certificate validation on mysqlnd for MySQL 5.6 or later |
106
|
|
|
* @link https://bugs.php.net/bug.php?id=68344 |
107
|
|
|
* @link https://github.com/phpmyadmin/phpmyadmin/pull/11838 |
108
|
|
|
*/ |
109
|
|
|
if (! $server['ssl_verify']) { |
110
|
|
|
$mysqli->options( |
111
|
|
|
MYSQLI_OPT_SSL_VERIFY_SERVER_CERT, |
112
|
|
|
$server['ssl_verify'] |
113
|
|
|
); |
114
|
|
|
$client_flags |= MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT; |
115
|
|
|
} |
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
if ($GLOBALS['cfg']['PersistentConnections']) { |
119
|
|
|
$host = 'p:' . $server['host']; |
120
|
|
|
} else { |
121
|
|
|
$host = $server['host']; |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
$return_value = $mysqli->real_connect( |
125
|
|
|
$host, |
126
|
|
|
$user, |
127
|
|
|
$password, |
128
|
|
|
'', |
129
|
|
|
$server['port'], |
130
|
|
|
(string) $server['socket'], |
131
|
|
|
$client_flags |
132
|
|
|
); |
133
|
|
|
|
134
|
|
|
if ($return_value === false || $return_value === null) { |
135
|
|
|
/* |
136
|
|
|
* Switch to SSL if server asked us to do so, unfortunately |
137
|
|
|
* there are more ways MySQL server can tell this: |
138
|
|
|
* |
139
|
|
|
* - MySQL 8.0 and newer should return error 3159 |
140
|
|
|
* - #2001 - SSL Connection is required. Please specify SSL options and retry. |
141
|
|
|
* - #9002 - SSL connection is required. Please specify SSL options and retry. |
142
|
|
|
*/ |
143
|
|
|
$error_number = $mysqli->connect_errno; |
144
|
|
|
$error_message = $mysqli->connect_error; |
145
|
|
|
if (! $server['ssl'] && ($error_number == 3159 || |
146
|
|
|
(($error_number == 2001 || $error_number == 9002) && stripos($error_message, 'SSL Connection is required') !== false)) |
147
|
|
|
) { |
148
|
|
|
trigger_error( |
149
|
|
|
__('SSL connection enforced by server, automatically enabling it.'), |
150
|
|
|
E_USER_WARNING |
151
|
|
|
); |
152
|
|
|
$server['ssl'] = true; |
153
|
|
|
return self::connect($user, $password, $server); |
|
|
|
|
154
|
|
|
} |
155
|
|
|
return false; |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
if (defined('PMA_ENABLE_LDI')) { |
159
|
|
|
$mysqli->options(MYSQLI_OPT_LOCAL_INFILE, true); |
160
|
|
|
} else { |
161
|
|
|
$mysqli->options(MYSQLI_OPT_LOCAL_INFILE, false); |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
return $mysqli; |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
/** |
168
|
|
|
* selects given database |
169
|
|
|
* |
170
|
|
|
* @param string $databaseName database name to select |
171
|
|
|
* @param mysqli $mysqli the mysqli object |
172
|
|
|
* |
173
|
|
|
* @return boolean |
174
|
|
|
*/ |
175
|
|
|
public function selectDb($databaseName, $mysqli) |
176
|
|
|
{ |
177
|
|
|
return $mysqli->select_db($databaseName); |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
/** |
181
|
|
|
* runs a query and returns the result |
182
|
|
|
* |
183
|
|
|
* @param string $query query to execute |
184
|
|
|
* @param mysqli $mysqli mysqli object |
185
|
|
|
* @param int $options query options |
186
|
|
|
* |
187
|
|
|
* @return mysqli_result|bool |
188
|
|
|
*/ |
189
|
|
|
public function realQuery($query, $mysqli, $options) |
190
|
|
|
{ |
191
|
|
|
if ($options == ($options | DatabaseInterface::QUERY_STORE)) { |
192
|
|
|
$method = MYSQLI_STORE_RESULT; |
193
|
|
|
} elseif ($options == ($options | DatabaseInterface::QUERY_UNBUFFERED)) { |
194
|
|
|
$method = MYSQLI_USE_RESULT; |
195
|
|
|
} else { |
196
|
|
|
$method = 0; |
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
return $mysqli->query($query, $method); |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
/** |
203
|
|
|
* Run the multi query and output the results |
204
|
|
|
* |
205
|
|
|
* @param mysqli $mysqli mysqli object |
206
|
|
|
* @param string $query multi query statement to execute |
207
|
|
|
* |
208
|
|
|
* @return bool |
209
|
|
|
*/ |
210
|
|
|
public function realMultiQuery($mysqli, $query) |
211
|
|
|
{ |
212
|
|
|
return $mysqli->multi_query($query); |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
/** |
216
|
|
|
* returns array of rows with associative and numeric keys from $result |
217
|
|
|
* |
218
|
|
|
* @param mysqli_result $result result set identifier |
219
|
|
|
* |
220
|
|
|
* @return array|null |
221
|
|
|
*/ |
222
|
|
|
public function fetchArray($result) |
223
|
|
|
{ |
224
|
|
|
if (! $result instanceof mysqli_result) { |
|
|
|
|
225
|
|
|
return null; |
226
|
|
|
} |
227
|
|
|
return $result->fetch_array(MYSQLI_BOTH); |
228
|
|
|
} |
229
|
|
|
|
230
|
|
|
/** |
231
|
|
|
* returns array of rows with associative keys from $result |
232
|
|
|
* |
233
|
|
|
* @param mysqli_result $result result set identifier |
234
|
|
|
* |
235
|
|
|
* @return array|null |
236
|
|
|
*/ |
237
|
|
|
public function fetchAssoc($result) |
238
|
|
|
{ |
239
|
|
|
if (! $result instanceof mysqli_result) { |
|
|
|
|
240
|
|
|
return null; |
241
|
|
|
} |
242
|
|
|
return $result->fetch_array(MYSQLI_ASSOC); |
243
|
|
|
} |
244
|
|
|
|
245
|
|
|
/** |
246
|
|
|
* returns array of rows with numeric keys from $result |
247
|
|
|
* |
248
|
|
|
* @param mysqli_result $result result set identifier |
249
|
|
|
* |
250
|
|
|
* @return array|null |
251
|
|
|
*/ |
252
|
|
|
public function fetchRow($result) |
253
|
|
|
{ |
254
|
|
|
if (! $result instanceof mysqli_result) { |
|
|
|
|
255
|
|
|
return null; |
256
|
|
|
} |
257
|
|
|
return $result->fetch_array(MYSQLI_NUM); |
258
|
|
|
} |
259
|
|
|
|
260
|
|
|
/** |
261
|
|
|
* Adjusts the result pointer to an arbitrary row in the result |
262
|
|
|
* |
263
|
|
|
* @param mysqli_result $result database result |
264
|
|
|
* @param integer $offset offset to seek |
265
|
|
|
* |
266
|
|
|
* @return bool true on success, false on failure |
267
|
|
|
*/ |
268
|
|
|
public function dataSeek($result, $offset) |
269
|
|
|
{ |
270
|
|
|
return $result->data_seek($offset); |
271
|
|
|
} |
272
|
|
|
|
273
|
|
|
/** |
274
|
|
|
* Frees memory associated with the result |
275
|
|
|
* |
276
|
|
|
* @param mysqli_result $result database result |
277
|
|
|
* |
278
|
|
|
* @return void |
279
|
|
|
*/ |
280
|
|
|
public function freeResult($result) |
281
|
|
|
{ |
282
|
|
|
if ($result instanceof mysqli_result) { |
|
|
|
|
283
|
|
|
$result->close(); |
284
|
|
|
} |
285
|
|
|
} |
286
|
|
|
|
287
|
|
|
/** |
288
|
|
|
* Check if there are any more query results from a multi query |
289
|
|
|
* |
290
|
|
|
* @param mysqli $mysqli the mysqli object |
291
|
|
|
* |
292
|
|
|
* @return bool true or false |
293
|
|
|
*/ |
294
|
|
|
public function moreResults($mysqli) |
295
|
|
|
{ |
296
|
|
|
return $mysqli->more_results(); |
297
|
|
|
} |
298
|
|
|
|
299
|
|
|
/** |
300
|
|
|
* Prepare next result from multi_query |
301
|
|
|
* |
302
|
|
|
* @param mysqli $mysqli the mysqli object |
303
|
|
|
* |
304
|
|
|
* @return bool true or false |
305
|
|
|
*/ |
306
|
|
|
public function nextResult($mysqli) |
307
|
|
|
{ |
308
|
|
|
return $mysqli->next_result(); |
309
|
|
|
} |
310
|
|
|
|
311
|
|
|
/** |
312
|
|
|
* Store the result returned from multi query |
313
|
|
|
* |
314
|
|
|
* @param mysqli $mysqli the mysqli object |
315
|
|
|
* |
316
|
|
|
* @return mysqli_result|bool false when empty results / result set when not empty |
317
|
|
|
*/ |
318
|
|
|
public function storeResult($mysqli) |
319
|
|
|
{ |
320
|
|
|
return $mysqli->store_result(); |
321
|
|
|
} |
322
|
|
|
|
323
|
|
|
/** |
324
|
|
|
* Returns a string representing the type of connection used |
325
|
|
|
* |
326
|
|
|
* @param mysqli $mysqli mysql link |
327
|
|
|
* |
328
|
|
|
* @return string type of connection used |
329
|
|
|
*/ |
330
|
|
|
public function getHostInfo($mysqli) |
331
|
|
|
{ |
332
|
|
|
return $mysqli->host_info; |
333
|
|
|
} |
334
|
|
|
|
335
|
|
|
/** |
336
|
|
|
* Returns the version of the MySQL protocol used |
337
|
|
|
* |
338
|
|
|
* @param mysqli $mysqli mysql link |
339
|
|
|
* |
340
|
|
|
* @return string version of the MySQL protocol used |
341
|
|
|
*/ |
342
|
|
|
public function getProtoInfo($mysqli) |
343
|
|
|
{ |
344
|
|
|
return $mysqli->protocol_version; |
|
|
|
|
345
|
|
|
} |
346
|
|
|
|
347
|
|
|
/** |
348
|
|
|
* returns a string that represents the client library version |
349
|
|
|
* |
350
|
|
|
* @param mysqli $mysqli mysql link |
351
|
|
|
* |
352
|
|
|
* @return string MySQL client library version |
353
|
|
|
*/ |
354
|
|
|
public function getClientInfo($mysqli) |
355
|
|
|
{ |
356
|
|
|
return $mysqli->get_client_info(); |
357
|
|
|
} |
358
|
|
|
|
359
|
|
|
/** |
360
|
|
|
* returns last error message or false if no errors occurred |
361
|
|
|
* |
362
|
|
|
* @param mysqli $mysqli mysql link |
363
|
|
|
* |
364
|
|
|
* @return string|bool error or false |
365
|
|
|
*/ |
366
|
|
|
public function getError($mysqli) |
367
|
|
|
{ |
368
|
|
|
$GLOBALS['errno'] = 0; |
369
|
|
|
|
370
|
|
|
if (null !== $mysqli && false !== $mysqli) { |
371
|
|
|
$error_number = $mysqli->errno; |
372
|
|
|
$error_message = $mysqli->error; |
373
|
|
|
} else { |
374
|
|
|
$error_number = $mysqli->connect_errno; |
375
|
|
|
$error_message = $mysqli->connect_error; |
376
|
|
|
} |
377
|
|
|
if (0 == $error_number) { |
378
|
|
|
return false; |
379
|
|
|
} |
380
|
|
|
|
381
|
|
|
// keep the error number for further check after |
382
|
|
|
// the call to getError() |
383
|
|
|
$GLOBALS['errno'] = $error_number; |
384
|
|
|
|
385
|
|
|
return $GLOBALS['dbi']->formatError($error_number, $error_message); |
386
|
|
|
} |
387
|
|
|
|
388
|
|
|
/** |
389
|
|
|
* returns the number of rows returned by last query |
390
|
|
|
* |
391
|
|
|
* @param mysqli_result $result result set identifier |
392
|
|
|
* |
393
|
|
|
* @return string|int |
394
|
|
|
*/ |
395
|
|
|
public function numRows($result) |
396
|
|
|
{ |
397
|
|
|
// see the note for tryQuery(); |
398
|
|
|
if (is_bool($result)) { |
|
|
|
|
399
|
|
|
return 0; |
400
|
|
|
} |
401
|
|
|
|
402
|
|
|
return $result->num_rows; |
403
|
|
|
} |
404
|
|
|
|
405
|
|
|
/** |
406
|
|
|
* returns the number of rows affected by last query |
407
|
|
|
* |
408
|
|
|
* @param mysqli $mysqli the mysqli object |
409
|
|
|
* |
410
|
|
|
* @return int |
411
|
|
|
*/ |
412
|
|
|
public function affectedRows($mysqli) |
413
|
|
|
{ |
414
|
|
|
return $mysqli->affected_rows; |
415
|
|
|
} |
416
|
|
|
|
417
|
|
|
/** |
418
|
|
|
* returns meta info for fields in $result |
419
|
|
|
* |
420
|
|
|
* @param mysqli_result $result result set identifier |
421
|
|
|
* |
422
|
|
|
* @return array|bool meta info for fields in $result |
423
|
|
|
*/ |
424
|
|
|
public function getFieldsMeta($result) |
425
|
|
|
{ |
426
|
|
|
if (! $result instanceof mysqli_result) { |
|
|
|
|
427
|
|
|
return false; |
428
|
|
|
} |
429
|
|
|
// Build an associative array for a type look up |
430
|
|
|
$typeAr = []; |
431
|
|
|
$typeAr[MYSQLI_TYPE_DECIMAL] = 'real'; |
432
|
|
|
$typeAr[MYSQLI_TYPE_NEWDECIMAL] = 'real'; |
433
|
|
|
$typeAr[MYSQLI_TYPE_BIT] = 'int'; |
434
|
|
|
$typeAr[MYSQLI_TYPE_TINY] = 'int'; |
435
|
|
|
$typeAr[MYSQLI_TYPE_SHORT] = 'int'; |
436
|
|
|
$typeAr[MYSQLI_TYPE_LONG] = 'int'; |
437
|
|
|
$typeAr[MYSQLI_TYPE_FLOAT] = 'real'; |
438
|
|
|
$typeAr[MYSQLI_TYPE_DOUBLE] = 'real'; |
439
|
|
|
$typeAr[MYSQLI_TYPE_NULL] = 'null'; |
440
|
|
|
$typeAr[MYSQLI_TYPE_TIMESTAMP] = 'timestamp'; |
441
|
|
|
$typeAr[MYSQLI_TYPE_LONGLONG] = 'int'; |
442
|
|
|
$typeAr[MYSQLI_TYPE_INT24] = 'int'; |
443
|
|
|
$typeAr[MYSQLI_TYPE_DATE] = 'date'; |
444
|
|
|
$typeAr[MYSQLI_TYPE_TIME] = 'time'; |
445
|
|
|
$typeAr[MYSQLI_TYPE_DATETIME] = 'datetime'; |
446
|
|
|
$typeAr[MYSQLI_TYPE_YEAR] = 'year'; |
447
|
|
|
$typeAr[MYSQLI_TYPE_NEWDATE] = 'date'; |
448
|
|
|
$typeAr[MYSQLI_TYPE_ENUM] = 'unknown'; |
449
|
|
|
$typeAr[MYSQLI_TYPE_SET] = 'unknown'; |
450
|
|
|
$typeAr[MYSQLI_TYPE_TINY_BLOB] = 'blob'; |
451
|
|
|
$typeAr[MYSQLI_TYPE_MEDIUM_BLOB] = 'blob'; |
452
|
|
|
$typeAr[MYSQLI_TYPE_LONG_BLOB] = 'blob'; |
453
|
|
|
$typeAr[MYSQLI_TYPE_BLOB] = 'blob'; |
454
|
|
|
$typeAr[MYSQLI_TYPE_VAR_STRING] = 'string'; |
455
|
|
|
$typeAr[MYSQLI_TYPE_STRING] = 'string'; |
456
|
|
|
// MySQL returns MYSQLI_TYPE_STRING for CHAR |
457
|
|
|
// and MYSQLI_TYPE_CHAR === MYSQLI_TYPE_TINY |
458
|
|
|
// so this would override TINYINT and mark all TINYINT as string |
459
|
|
|
// see https://github.com/phpmyadmin/phpmyadmin/issues/8569 |
460
|
|
|
//$typeAr[MYSQLI_TYPE_CHAR] = 'string'; |
461
|
|
|
$typeAr[MYSQLI_TYPE_GEOMETRY] = 'geometry'; |
462
|
|
|
$typeAr[MYSQLI_TYPE_BIT] = 'bit'; |
463
|
|
|
$typeAr[MYSQLI_TYPE_JSON] = 'json'; |
464
|
|
|
|
465
|
|
|
$fields = $result->fetch_fields(); |
466
|
|
|
|
467
|
|
|
if (! is_array($fields)) { |
|
|
|
|
468
|
|
|
return false; |
469
|
|
|
} |
470
|
|
|
|
471
|
|
|
foreach ($fields as $k => $field) { |
472
|
|
|
$fields[$k]->_type = $field->type; |
473
|
|
|
$fields[$k]->type = $typeAr[$field->type]; |
474
|
|
|
$fields[$k]->_flags = $field->flags; |
475
|
|
|
$fields[$k]->flags = $this->fieldFlags($result, $k); |
476
|
|
|
|
477
|
|
|
// Enhance the field objects for mysql-extension compatibility |
478
|
|
|
//$flags = explode(' ', $fields[$k]->flags); |
479
|
|
|
//array_unshift($flags, 'dummy'); |
480
|
|
|
$fields[$k]->multiple_key |
481
|
|
|
= (int) (bool) ($fields[$k]->_flags & MYSQLI_MULTIPLE_KEY_FLAG); |
482
|
|
|
$fields[$k]->primary_key |
483
|
|
|
= (int) (bool) ($fields[$k]->_flags & MYSQLI_PRI_KEY_FLAG); |
484
|
|
|
$fields[$k]->unique_key |
485
|
|
|
= (int) (bool) ($fields[$k]->_flags & MYSQLI_UNIQUE_KEY_FLAG); |
486
|
|
|
$fields[$k]->not_null |
487
|
|
|
= (int) (bool) ($fields[$k]->_flags & MYSQLI_NOT_NULL_FLAG); |
488
|
|
|
$fields[$k]->unsigned |
489
|
|
|
= (int) (bool) ($fields[$k]->_flags & MYSQLI_UNSIGNED_FLAG); |
490
|
|
|
$fields[$k]->zerofill |
491
|
|
|
= (int) (bool) ($fields[$k]->_flags & MYSQLI_ZEROFILL_FLAG); |
492
|
|
|
$fields[$k]->numeric |
493
|
|
|
= (int) (bool) ($fields[$k]->_flags & MYSQLI_NUM_FLAG); |
494
|
|
|
$fields[$k]->blob |
495
|
|
|
= (int) (bool) ($fields[$k]->_flags & MYSQLI_BLOB_FLAG); |
496
|
|
|
} |
497
|
|
|
return $fields; |
498
|
|
|
} |
499
|
|
|
|
500
|
|
|
/** |
501
|
|
|
* return number of fields in given $result |
502
|
|
|
* |
503
|
|
|
* @param mysqli_result $result result set identifier |
504
|
|
|
* |
505
|
|
|
* @return int field count |
506
|
|
|
*/ |
507
|
|
|
public function numFields($result) |
508
|
|
|
{ |
509
|
|
|
return $result->field_count; |
510
|
|
|
} |
511
|
|
|
|
512
|
|
|
/** |
513
|
|
|
* returns the length of the given field $i in $result |
514
|
|
|
* |
515
|
|
|
* @param mysqli_result $result result set identifier |
516
|
|
|
* @param int $i field |
517
|
|
|
* |
518
|
|
|
* @return int|bool length of field |
519
|
|
|
*/ |
520
|
|
|
public function fieldLen($result, $i) |
521
|
|
|
{ |
522
|
|
|
if ($i >= $this->numFields($result)) { |
523
|
|
|
return false; |
524
|
|
|
} |
525
|
|
|
/** @var stdClass $fieldDefinition */ |
526
|
|
|
$fieldDefinition = $result->fetch_field_direct($i); |
527
|
|
|
if ($fieldDefinition !== false) { |
|
|
|
|
528
|
|
|
return $fieldDefinition->length; |
529
|
|
|
} |
530
|
|
|
return false; |
531
|
|
|
} |
532
|
|
|
|
533
|
|
|
/** |
534
|
|
|
* returns name of $i. field in $result |
535
|
|
|
* |
536
|
|
|
* @param mysqli_result $result result set identifier |
537
|
|
|
* @param int $i field |
538
|
|
|
* |
539
|
|
|
* @return string|bool name of $i. field in $result |
540
|
|
|
*/ |
541
|
|
|
public function fieldName($result, $i) |
542
|
|
|
{ |
543
|
|
|
if ($i >= $this->numFields($result)) { |
544
|
|
|
return false; |
|
|
|
|
545
|
|
|
} |
546
|
|
|
/** @var stdClass $fieldDefinition */ |
547
|
|
|
$fieldDefinition = $result->fetch_field_direct($i); |
548
|
|
|
if ($fieldDefinition !== false) { |
|
|
|
|
549
|
|
|
return $fieldDefinition->name; |
550
|
|
|
} |
551
|
|
|
return false; |
552
|
|
|
} |
553
|
|
|
|
554
|
|
|
/** |
555
|
|
|
* returns concatenated string of human readable field flags |
556
|
|
|
* |
557
|
|
|
* @param mysqli_result $result result set identifier |
558
|
|
|
* @param int $i field |
559
|
|
|
* |
560
|
|
|
* @return string|false field flags |
561
|
|
|
*/ |
562
|
|
|
public function fieldFlags($result, $i) |
563
|
|
|
{ |
564
|
|
|
if ($i >= $this->numFields($result)) { |
565
|
|
|
return false; |
|
|
|
|
566
|
|
|
} |
567
|
|
|
/** @var stdClass $fieldDefinition */ |
568
|
|
|
$fieldDefinition = $result->fetch_field_direct($i); |
569
|
|
|
if ($fieldDefinition !== false) { |
|
|
|
|
570
|
|
|
$type = $fieldDefinition->type; |
571
|
|
|
$charsetNumber = $fieldDefinition->charsetnr; |
572
|
|
|
$fieldDefinitionFlags = $fieldDefinition->flags; |
573
|
|
|
$flags = []; |
574
|
|
|
foreach (self::$pma_mysqli_flag_names as $flag => $name) { |
575
|
|
|
if ($fieldDefinitionFlags & $flag) { |
576
|
|
|
$flags[] = $name; |
577
|
|
|
} |
578
|
|
|
} |
579
|
|
|
// See https://dev.mysql.com/doc/refman/6.0/en/c-api-datatypes.html: |
580
|
|
|
// to determine if a string is binary, we should not use MYSQLI_BINARY_FLAG |
581
|
|
|
// but instead the charsetnr member of the MYSQL_FIELD |
582
|
|
|
// structure. Watch out: some types like DATE returns 63 in charsetnr |
583
|
|
|
// so we have to check also the type. |
584
|
|
|
// Unfortunately there is no equivalent in the mysql extension. |
585
|
|
|
if (($type == MYSQLI_TYPE_TINY_BLOB || $type == MYSQLI_TYPE_BLOB |
586
|
|
|
|| $type == MYSQLI_TYPE_MEDIUM_BLOB || $type == MYSQLI_TYPE_LONG_BLOB |
587
|
|
|
|| $type == MYSQLI_TYPE_VAR_STRING || $type == MYSQLI_TYPE_STRING) |
588
|
|
|
&& 63 == $charsetNumber |
589
|
|
|
) { |
590
|
|
|
$flags[] = 'binary'; |
591
|
|
|
} |
592
|
|
|
return implode(' ', $flags); |
593
|
|
|
} else { |
594
|
|
|
return ''; |
595
|
|
|
} |
596
|
|
|
} |
597
|
|
|
|
598
|
|
|
/** |
599
|
|
|
* returns properly escaped string for use in MySQL queries |
600
|
|
|
* |
601
|
|
|
* @param mysqli $mysqli database link |
602
|
|
|
* @param string $string string to be escaped |
603
|
|
|
* |
604
|
|
|
* @return string a MySQL escaped string |
605
|
|
|
*/ |
606
|
|
|
public function escapeString($mysqli, $string) |
607
|
|
|
{ |
608
|
|
|
return $mysqli->real_escape_string($string); |
609
|
|
|
} |
610
|
|
|
|
611
|
|
|
/** |
612
|
|
|
* Prepare an SQL statement for execution. |
613
|
|
|
* |
614
|
|
|
* @param mysqli $mysqli database link |
615
|
|
|
* @param string $query The query, as a string. |
616
|
|
|
* |
617
|
|
|
* @return mysqli_stmt|false A statement object or false. |
618
|
|
|
*/ |
619
|
|
|
public function prepare($mysqli, string $query) |
620
|
|
|
{ |
621
|
|
|
return $mysqli->prepare($query); |
622
|
|
|
} |
623
|
|
|
} |
624
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.