|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace voku\db; |
|
4
|
|
|
|
|
5
|
|
|
use voku\cache\Cache; |
|
6
|
|
|
use voku\helper\UTF8; |
|
7
|
|
|
|
|
8
|
|
|
/** |
|
9
|
|
|
* DB: this handles DB queries via MySQLi |
|
10
|
|
|
* |
|
11
|
|
|
* @package voku\db |
|
12
|
|
|
*/ |
|
13
|
|
|
class DB |
|
14
|
|
|
{ |
|
15
|
|
|
|
|
16
|
|
|
/** |
|
17
|
|
|
* @var int |
|
18
|
|
|
*/ |
|
19
|
|
|
public $query_count = 0; |
|
20
|
|
|
|
|
21
|
|
|
/** |
|
22
|
|
|
* @var bool |
|
23
|
|
|
*/ |
|
24
|
|
|
protected $exit_on_error = true; |
|
25
|
|
|
|
|
26
|
|
|
/** |
|
27
|
|
|
* @var bool |
|
28
|
|
|
*/ |
|
29
|
|
|
protected $echo_on_error = true; |
|
30
|
|
|
|
|
31
|
|
|
/** |
|
32
|
|
|
* @var string |
|
33
|
|
|
*/ |
|
34
|
|
|
protected $css_mysql_box_border = '3px solid red'; |
|
35
|
|
|
|
|
36
|
|
|
/** |
|
37
|
|
|
* @var string |
|
38
|
|
|
*/ |
|
39
|
|
|
protected $css_mysql_box_bg = '#FFCCCC'; |
|
40
|
|
|
|
|
41
|
|
|
/** |
|
42
|
|
|
* @var \mysqli |
|
43
|
|
|
*/ |
|
44
|
|
|
protected $link = false; |
|
45
|
|
|
|
|
46
|
|
|
/** |
|
47
|
|
|
* @var bool |
|
48
|
|
|
*/ |
|
49
|
|
|
protected $connected = false; |
|
50
|
|
|
|
|
51
|
|
|
/** |
|
52
|
|
|
* @var array |
|
53
|
|
|
*/ |
|
54
|
|
|
protected $mysqlDefaultTimeFunctions; |
|
55
|
|
|
|
|
56
|
|
|
/** |
|
57
|
|
|
* @var string |
|
58
|
|
|
*/ |
|
59
|
|
|
private $logger_class_name; |
|
60
|
|
|
|
|
61
|
|
|
/** |
|
62
|
|
|
* @var string |
|
63
|
|
|
* |
|
64
|
|
|
* 'TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL' |
|
65
|
|
|
*/ |
|
66
|
|
|
private $logger_level; |
|
67
|
|
|
|
|
68
|
|
|
/** |
|
69
|
|
|
* @var string |
|
70
|
|
|
*/ |
|
71
|
|
|
private $hostname = ''; |
|
72
|
|
|
|
|
73
|
|
|
/** |
|
74
|
|
|
* @var string |
|
75
|
|
|
*/ |
|
76
|
|
|
private $username = ''; |
|
77
|
|
|
|
|
78
|
|
|
/** |
|
79
|
|
|
* @var string |
|
80
|
|
|
*/ |
|
81
|
|
|
private $password = ''; |
|
82
|
|
|
|
|
83
|
|
|
/** |
|
84
|
|
|
* @var string |
|
85
|
|
|
*/ |
|
86
|
|
|
private $database = ''; |
|
87
|
|
|
|
|
88
|
|
|
/** |
|
89
|
|
|
* @var int |
|
90
|
|
|
*/ |
|
91
|
|
|
private $port = 3306; |
|
92
|
|
|
|
|
93
|
|
|
/** |
|
94
|
|
|
* @var string |
|
95
|
|
|
*/ |
|
96
|
|
|
private $charset = 'utf8'; |
|
97
|
|
|
|
|
98
|
|
|
/** |
|
99
|
|
|
* @var string |
|
100
|
|
|
*/ |
|
101
|
|
|
private $socket = ''; |
|
102
|
|
|
|
|
103
|
|
|
/** |
|
104
|
|
|
* @var array |
|
105
|
|
|
*/ |
|
106
|
|
|
private $_errors = array(); |
|
107
|
|
|
|
|
108
|
|
|
/** |
|
109
|
|
|
* @var bool |
|
110
|
|
|
*/ |
|
111
|
|
|
private $session_to_db = false; |
|
112
|
|
|
|
|
113
|
|
|
/** |
|
114
|
|
|
* @var bool |
|
115
|
|
|
*/ |
|
116
|
|
|
private $_in_transaction = false; |
|
117
|
|
|
|
|
118
|
|
|
/** |
|
119
|
|
|
* __construct() |
|
120
|
|
|
* |
|
121
|
|
|
* @param string $hostname |
|
122
|
|
|
* @param string $username |
|
123
|
|
|
* @param string $password |
|
124
|
|
|
* @param string $database |
|
125
|
|
|
* @param int $port |
|
126
|
|
|
* @param string $charset |
|
127
|
|
|
* @param boolean|string $exit_on_error use a empty string "" or false to disable it |
|
128
|
|
|
* @param boolean|string $echo_on_error use a empty string "" or false to disable it |
|
129
|
|
|
* @param string $logger_class_name |
|
130
|
|
|
* @param string $logger_level 'TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL' |
|
131
|
|
|
* @param boolean|string $session_to_db use a empty string "" or false to disable it |
|
132
|
|
|
*/ |
|
133
|
10 |
|
protected function __construct($hostname, $username, $password, $database, $port, $charset, $exit_on_error, $echo_on_error, $logger_class_name, $logger_level, $session_to_db) |
|
134
|
|
|
{ |
|
135
|
10 |
|
$this->connected = false; |
|
136
|
|
|
|
|
137
|
10 |
|
$this->_loadConfig( |
|
138
|
10 |
|
$hostname, |
|
139
|
10 |
|
$username, |
|
140
|
10 |
|
$password, |
|
141
|
10 |
|
$database, |
|
142
|
10 |
|
$port, |
|
143
|
10 |
|
$charset, |
|
144
|
10 |
|
$exit_on_error, |
|
145
|
10 |
|
$echo_on_error, |
|
146
|
10 |
|
$logger_class_name, |
|
147
|
10 |
|
$logger_level, |
|
148
|
|
|
$session_to_db |
|
149
|
10 |
|
); |
|
150
|
|
|
|
|
151
|
7 |
|
$this->connect(); |
|
152
|
|
|
|
|
153
|
4 |
|
$this->mysqlDefaultTimeFunctions = array( |
|
154
|
|
|
// Returns the current date. |
|
155
|
4 |
|
'CURDATE()', |
|
156
|
|
|
// CURRENT_DATE | Synonyms for CURDATE() |
|
157
|
4 |
|
'CURRENT_DATE()', |
|
158
|
|
|
// CURRENT_TIME | Synonyms for CURTIME() |
|
159
|
4 |
|
'CURRENT_TIME()', |
|
160
|
|
|
// CURRENT_TIMESTAMP | Synonyms for NOW() |
|
161
|
4 |
|
'CURRENT_TIMESTAMP()', |
|
162
|
|
|
// Returns the current time. |
|
163
|
4 |
|
'CURTIME()', |
|
164
|
|
|
// Synonym for NOW() |
|
|
|
|
|
|
165
|
4 |
|
'LOCALTIME()', |
|
166
|
|
|
// Synonym for NOW() |
|
|
|
|
|
|
167
|
4 |
|
'LOCALTIMESTAMP()', |
|
168
|
|
|
// Returns the current date and time. |
|
169
|
4 |
|
'NOW()', |
|
170
|
|
|
// Returns the time at which the function executes. |
|
171
|
4 |
|
'SYSDATE()', |
|
172
|
|
|
// Returns a UNIX timestamp. |
|
173
|
4 |
|
'UNIX_TIMESTAMP()', |
|
174
|
|
|
// Returns the current UTC date. |
|
175
|
4 |
|
'UTC_DATE()', |
|
176
|
|
|
// Returns the current UTC time. |
|
177
|
4 |
|
'UTC_TIME()', |
|
178
|
|
|
// Returns the current UTC date and time. |
|
179
|
4 |
|
'UTC_TIMESTAMP()', |
|
180
|
|
|
); |
|
181
|
4 |
|
} |
|
182
|
|
|
|
|
183
|
|
|
/** |
|
184
|
|
|
* Load the config from the constructor. |
|
185
|
|
|
* |
|
186
|
|
|
* @param string $hostname |
|
187
|
|
|
* @param string $username |
|
188
|
|
|
* @param string $password |
|
189
|
|
|
* @param string $database |
|
190
|
|
|
* @param int $port |
|
191
|
|
|
* @param string $charset |
|
192
|
|
|
* @param boolean|string $exit_on_error use a empty string "" or false to disable it |
|
193
|
|
|
* @param boolean|string $echo_on_error use a empty string "" or false to disable it |
|
194
|
|
|
* @param string $logger_class_name |
|
195
|
|
|
* @param string $logger_level |
|
196
|
|
|
* @param boolean|string $session_to_db use a empty string "" or false to disable it |
|
197
|
|
|
* |
|
198
|
|
|
* @return bool |
|
199
|
|
|
*/ |
|
200
|
10 |
|
private function _loadConfig($hostname, $username, $password, $database, $port, $charset, $exit_on_error, $echo_on_error, $logger_class_name, $logger_level, $session_to_db) |
|
201
|
|
|
{ |
|
202
|
10 |
|
$this->hostname = (string)$hostname; |
|
203
|
10 |
|
$this->username = (string)$username; |
|
204
|
10 |
|
$this->password = (string)$password; |
|
205
|
10 |
|
$this->database = (string)$database; |
|
206
|
|
|
|
|
207
|
10 |
|
if ($charset) { |
|
208
|
4 |
|
$this->charset = (string)$charset; |
|
209
|
4 |
|
} |
|
210
|
|
|
|
|
211
|
10 |
|
if ($port) { |
|
212
|
4 |
|
$this->port = (int)$port; |
|
213
|
4 |
|
} else { |
|
214
|
|
|
/** @noinspection PhpUsageOfSilenceOperatorInspection */ |
|
215
|
7 |
|
$this->port = @ini_get('mysqli.default_port'); |
|
216
|
|
|
} |
|
217
|
|
|
|
|
218
|
10 |
|
if (!$this->socket) { |
|
219
|
|
|
/** @noinspection PhpUsageOfSilenceOperatorInspection */ |
|
220
|
10 |
|
$this->socket = @ini_get('mysqli.default_socket'); |
|
221
|
10 |
|
} |
|
222
|
|
|
|
|
223
|
10 |
|
if ($exit_on_error === true || $exit_on_error === false) { |
|
224
|
10 |
|
$this->exit_on_error = (boolean)$exit_on_error; |
|
225
|
10 |
|
} |
|
226
|
|
|
|
|
227
|
10 |
|
if ($echo_on_error === true || $echo_on_error === false) { |
|
228
|
10 |
|
$this->echo_on_error = (boolean)$echo_on_error; |
|
229
|
10 |
|
} |
|
230
|
|
|
|
|
231
|
10 |
|
$this->logger_class_name = (string)$logger_class_name; |
|
232
|
10 |
|
$this->logger_level = (string)$logger_level; |
|
233
|
|
|
|
|
234
|
10 |
|
$this->session_to_db = (boolean)$session_to_db; |
|
235
|
|
|
|
|
236
|
10 |
|
return $this->showConfigError(); |
|
237
|
|
|
} |
|
238
|
|
|
|
|
239
|
|
|
/** |
|
240
|
|
|
* Show config errors by throw exceptions. |
|
241
|
|
|
* |
|
242
|
|
|
* @return bool |
|
243
|
|
|
* |
|
244
|
|
|
* @throws \Exception |
|
245
|
|
|
*/ |
|
246
|
10 |
|
public function showConfigError() |
|
247
|
|
|
{ |
|
248
|
|
|
|
|
249
|
|
|
if ( |
|
250
|
10 |
|
!$this->hostname |
|
251
|
10 |
|
|| |
|
252
|
9 |
|
!$this->username |
|
253
|
9 |
|
|| |
|
254
|
8 |
|
!$this->database |
|
255
|
10 |
|
) { |
|
256
|
|
|
|
|
257
|
3 |
|
if (!$this->hostname) { |
|
258
|
1 |
|
throw new \Exception('no-sql-hostname'); |
|
259
|
|
|
} |
|
260
|
|
|
|
|
261
|
2 |
|
if (!$this->username) { |
|
262
|
1 |
|
throw new \Exception('no-sql-username'); |
|
263
|
|
|
} |
|
264
|
|
|
|
|
265
|
1 |
|
if (!$this->database) { |
|
266
|
1 |
|
throw new \Exception('no-sql-database'); |
|
267
|
|
|
} |
|
268
|
|
|
|
|
269
|
|
|
return false; |
|
270
|
|
|
} |
|
271
|
|
|
|
|
272
|
7 |
|
return true; |
|
273
|
|
|
} |
|
274
|
|
|
|
|
275
|
|
|
/** |
|
276
|
|
|
* Open a new connection to the MySQL server. |
|
277
|
|
|
* |
|
278
|
|
|
* @return boolean |
|
279
|
|
|
*/ |
|
280
|
8 |
|
public function connect() |
|
281
|
|
|
{ |
|
282
|
8 |
|
if ($this->isReady()) { |
|
283
|
1 |
|
return true; |
|
284
|
|
|
} |
|
285
|
|
|
|
|
286
|
8 |
|
mysqli_report(MYSQLI_REPORT_STRICT); |
|
287
|
|
|
try { |
|
288
|
|
|
/** @noinspection PhpUsageOfSilenceOperatorInspection */ |
|
289
|
8 |
|
$this->link = @mysqli_connect( |
|
290
|
8 |
|
$this->hostname, |
|
291
|
8 |
|
$this->username, |
|
292
|
8 |
|
$this->password, |
|
293
|
8 |
|
$this->database, |
|
294
|
8 |
|
$this->port, |
|
295
|
8 |
|
$this->socket |
|
296
|
8 |
|
); |
|
297
|
8 |
|
} catch (\Exception $e) { |
|
298
|
3 |
|
$this->_displayError('Error connecting to mysql server: ' . $e->getMessage(), true); |
|
299
|
|
|
} |
|
300
|
5 |
|
mysqli_report(MYSQLI_REPORT_OFF); |
|
301
|
|
|
|
|
302
|
5 |
|
if (!$this->link) { |
|
303
|
|
|
$this->_displayError('Error connecting to mysql server: ' . mysqli_connect_error(), true); |
|
304
|
|
|
} else { |
|
305
|
5 |
|
$this->set_charset($this->charset); |
|
306
|
5 |
|
$this->connected = true; |
|
307
|
|
|
} |
|
308
|
|
|
|
|
309
|
5 |
|
return $this->isReady(); |
|
310
|
|
|
} |
|
311
|
|
|
|
|
312
|
|
|
/** |
|
313
|
|
|
* Check if db-connection is ready. |
|
314
|
|
|
* |
|
315
|
|
|
* @return boolean |
|
316
|
|
|
*/ |
|
317
|
29 |
|
public function isReady() |
|
318
|
|
|
{ |
|
319
|
29 |
|
return $this->connected ? true : false; |
|
320
|
|
|
} |
|
321
|
|
|
|
|
322
|
|
|
/** |
|
323
|
|
|
* Display SQL-Errors or throw Exceptions (for dev). |
|
324
|
|
|
* |
|
325
|
|
|
* @param string $error |
|
326
|
|
|
* @param null|boolean $force_exception_after_error |
|
327
|
|
|
* |
|
328
|
|
|
* @throws \Exception |
|
329
|
|
|
*/ |
|
330
|
18 |
|
private function _displayError($error, $force_exception_after_error = null) |
|
331
|
|
|
{ |
|
332
|
18 |
|
$fileInfo = $this->getFileAndLineFromSql(); |
|
333
|
|
|
|
|
334
|
18 |
|
$this->logger( |
|
335
|
|
|
array( |
|
336
|
18 |
|
'error', |
|
337
|
18 |
|
'<strong>' . date( |
|
338
|
|
|
'd. m. Y G:i:s' |
|
339
|
18 |
|
) . ' (' . $fileInfo['file'] . ' line: ' . $fileInfo['line'] . ') (sql-error):</strong> ' . $error . '<br>', |
|
340
|
|
|
) |
|
341
|
18 |
|
); |
|
342
|
|
|
|
|
343
|
18 |
|
$this->_errors[] = $error; |
|
344
|
|
|
|
|
345
|
18 |
|
if ($this->checkForDev() === true) { |
|
346
|
|
|
|
|
347
|
18 |
|
if ($this->echo_on_error) { |
|
348
|
4 |
|
$box_border = $this->css_mysql_box_border; |
|
349
|
4 |
|
$box_bg = $this->css_mysql_box_bg; |
|
350
|
|
|
|
|
351
|
|
|
echo ' |
|
352
|
4 |
|
<div class="OBJ-mysql-box" style="border:' . $box_border . '; background:' . $box_bg . '; padding:10px; margin:10px;"> |
|
353
|
|
|
<b style="font-size:14px;">MYSQL Error:</b> |
|
354
|
|
|
<code style="display:block;"> |
|
355
|
4 |
|
file / line: ' . $fileInfo['file'] . ' / ' . $fileInfo['line'] . ' |
|
356
|
4 |
|
' . $error . ' |
|
357
|
|
|
</code> |
|
358
|
|
|
</div> |
|
359
|
4 |
|
'; |
|
360
|
4 |
|
} |
|
361
|
|
|
|
|
362
|
18 |
|
if ($force_exception_after_error === true) { |
|
363
|
4 |
|
throw new \Exception($error); |
|
364
|
14 |
|
} elseif ($force_exception_after_error === false) { |
|
365
|
|
|
// nothing |
|
366
|
14 |
|
} elseif ($force_exception_after_error === null) { |
|
367
|
|
|
// default |
|
368
|
11 |
|
if ($this->exit_on_error === true) { |
|
369
|
2 |
|
throw new \Exception($error); |
|
370
|
|
|
} |
|
371
|
9 |
|
} |
|
372
|
12 |
|
} |
|
373
|
12 |
|
} |
|
374
|
|
|
|
|
375
|
|
|
/** |
|
376
|
|
|
* Try to get the file & line from the current sql-query. |
|
377
|
|
|
* |
|
378
|
|
|
* @return array will return array['file'] and array['line'] |
|
379
|
|
|
*/ |
|
380
|
19 |
|
private function getFileAndLineFromSql() |
|
381
|
|
|
{ |
|
382
|
|
|
// init |
|
383
|
19 |
|
$return = array(); |
|
384
|
19 |
|
$file = ''; |
|
385
|
19 |
|
$line = ''; |
|
386
|
|
|
|
|
387
|
19 |
|
$referrer = debug_backtrace(); |
|
388
|
|
|
|
|
389
|
19 |
|
foreach ($referrer as $key => $ref) { |
|
390
|
|
|
|
|
391
|
|
|
if ( |
|
392
|
19 |
|
$ref['function'] == 'query' |
|
393
|
19 |
|
|| |
|
394
|
19 |
|
$ref['function'] == 'qry' |
|
395
|
19 |
|
) { |
|
396
|
11 |
|
$file = $referrer[$key]['file']; |
|
397
|
11 |
|
$line = $referrer[$key]['line']; |
|
398
|
19 |
|
} else if ($ref['function'] == 'execSQL') { |
|
399
|
1 |
|
$file = $referrer[$key]['file']; |
|
400
|
1 |
|
$line = $referrer[$key]['line']; |
|
401
|
1 |
|
} |
|
402
|
|
|
|
|
403
|
19 |
|
} |
|
404
|
|
|
|
|
405
|
19 |
|
$return['file'] = $file; |
|
406
|
19 |
|
$return['line'] = $line; |
|
407
|
|
|
|
|
408
|
19 |
|
return $return; |
|
409
|
|
|
} |
|
410
|
|
|
|
|
411
|
|
|
/** |
|
412
|
|
|
* Wrapper-Function for a "Logger"-Class. |
|
413
|
|
|
* |
|
414
|
|
|
* INFO: |
|
415
|
|
|
* The "Logger"-ClassName is set by "$this->logger_class_name",<br /> |
|
416
|
|
|
* the "Logger"-Method is the [0] element from the "$log"-parameter,<br /> |
|
417
|
|
|
* the text you want to log is the [1] element and<br /> |
|
418
|
|
|
* the type you want to log is the next [2] element. |
|
419
|
|
|
* |
|
420
|
|
|
* @param string[] $log [method, text, type]<br />e.g.: array('error', 'this is a error', 'sql') |
|
421
|
|
|
*/ |
|
422
|
20 |
|
private function logger(array $log) |
|
423
|
|
|
{ |
|
424
|
20 |
|
$logMethod = ''; |
|
425
|
20 |
|
$logText = ''; |
|
426
|
20 |
|
$logType = ''; |
|
427
|
20 |
|
$logClass = $this->logger_class_name; |
|
428
|
|
|
|
|
429
|
20 |
|
if (isset($log[0])) { |
|
430
|
20 |
|
$logMethod = $log[0]; |
|
431
|
20 |
|
} |
|
432
|
20 |
|
if (isset($log[1])) { |
|
433
|
20 |
|
$logText = $log[1]; |
|
434
|
20 |
|
} |
|
435
|
20 |
|
if (isset($log[2])) { |
|
436
|
1 |
|
$logType = $log[2]; |
|
437
|
1 |
|
} |
|
438
|
|
|
|
|
439
|
|
|
if ( |
|
440
|
|
|
$logClass |
|
441
|
20 |
|
&& |
|
442
|
|
|
class_exists($logClass) |
|
443
|
20 |
|
&& |
|
444
|
|
|
method_exists($logClass, $logMethod) |
|
445
|
20 |
|
) { |
|
446
|
|
|
$logClass::$logMethod($logText, $logType); |
|
447
|
|
|
} |
|
448
|
20 |
|
} |
|
449
|
|
|
|
|
450
|
|
|
/** |
|
451
|
|
|
* Check is the current user is a developer. |
|
452
|
|
|
* |
|
453
|
|
|
* INFO: |
|
454
|
|
|
* By default we will return "true" if the remote-ip-address is localhost or |
|
455
|
|
|
* if the script is called via CLI. But you can also overwrite this method or |
|
456
|
|
|
* you can implement a global "checkForDev()"-function. |
|
457
|
|
|
* |
|
458
|
|
|
* @return bool |
|
459
|
|
|
*/ |
|
460
|
18 |
|
protected function checkForDev() |
|
461
|
|
|
{ |
|
462
|
|
|
// init |
|
463
|
18 |
|
$return = false; |
|
464
|
|
|
|
|
465
|
18 |
|
if (function_exists('checkForDev')) { |
|
466
|
|
|
$return = checkForDev(); |
|
467
|
|
|
} else { |
|
468
|
|
|
|
|
469
|
|
|
// for testing with dev-address |
|
470
|
18 |
|
$noDev = isset($_GET['noDev']) ? (int)$_GET['noDev'] : 0; |
|
471
|
18 |
|
$remoteIpAddress = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : false; |
|
472
|
|
|
|
|
473
|
|
|
if ( |
|
474
|
|
|
$noDev != 1 |
|
475
|
18 |
|
&& |
|
476
|
|
|
( |
|
477
|
|
|
$remoteIpAddress == '127.0.0.1' |
|
478
|
18 |
|
|| |
|
479
|
|
|
$remoteIpAddress == '::1' |
|
480
|
18 |
|
|| |
|
481
|
18 |
|
PHP_SAPI == 'cli' |
|
482
|
18 |
|
) |
|
483
|
18 |
|
) { |
|
484
|
18 |
|
$return = true; |
|
485
|
18 |
|
} |
|
486
|
|
|
} |
|
487
|
|
|
|
|
488
|
18 |
|
return $return; |
|
489
|
|
|
} |
|
490
|
|
|
|
|
491
|
|
|
/** |
|
492
|
|
|
* Execute a sql-query and return the result-array for select-statements. |
|
493
|
|
|
* |
|
494
|
|
|
* @param $query |
|
495
|
|
|
* |
|
496
|
|
|
* @return mixed |
|
497
|
|
|
* @deprecated |
|
498
|
|
|
* @throws \Exception |
|
499
|
|
|
*/ |
|
500
|
|
|
public static function qry($query) |
|
501
|
|
|
{ |
|
502
|
|
|
$db = self::getInstance(); |
|
503
|
|
|
|
|
504
|
|
|
$args = func_get_args(); |
|
505
|
|
|
$query = array_shift($args); |
|
506
|
|
|
$query = str_replace('?', '%s', $query); |
|
507
|
|
|
$args = array_map( |
|
508
|
|
|
array( |
|
509
|
|
|
$db, |
|
510
|
|
|
'escape', |
|
511
|
|
|
), |
|
512
|
|
|
$args |
|
513
|
|
|
); |
|
514
|
|
|
array_unshift($args, $query); |
|
515
|
|
|
$query = call_user_func_array('sprintf', $args); |
|
516
|
|
|
$result = $db->query($query); |
|
517
|
|
|
|
|
518
|
|
|
if ($result instanceof Result) { |
|
519
|
|
|
$return = $result->fetchAllArray(); |
|
520
|
|
|
} else { |
|
521
|
|
|
$return = $result; |
|
522
|
|
|
} |
|
523
|
|
|
|
|
524
|
|
|
if ($return || is_array($return)) { |
|
525
|
|
|
return $return; |
|
526
|
|
|
} else { |
|
527
|
|
|
return false; |
|
528
|
|
|
} |
|
529
|
|
|
} |
|
530
|
|
|
|
|
531
|
|
|
/** |
|
532
|
|
|
* getInstance() |
|
533
|
|
|
* |
|
534
|
|
|
* @param string $hostname |
|
535
|
|
|
* @param string $username |
|
536
|
|
|
* @param string $password |
|
537
|
|
|
* @param string $database |
|
538
|
|
|
* @param string $port default is (int)3306 |
|
539
|
|
|
* @param string $charset default is 'utf8', but if you need 4-byte chars, then your tables need |
|
540
|
|
|
* the 'utf8mb4'-charset |
|
541
|
|
|
* @param bool|string $exit_on_error use a empty string "" or false to disable it |
|
542
|
|
|
* @param bool|string $echo_on_error use a empty string "" or false to disable it |
|
543
|
|
|
* @param string $logger_class_name |
|
544
|
|
|
* @param string $logger_level |
|
545
|
|
|
* @param bool|string $session_to_db use a empty string "" or false to disable it |
|
546
|
|
|
* |
|
547
|
|
|
* @return \voku\db\DB |
|
548
|
|
|
*/ |
|
549
|
39 |
|
public static function getInstance($hostname = '', $username = '', $password = '', $database = '', $port = '', $charset = '', $exit_on_error = '', $echo_on_error = '', $logger_class_name = '', $logger_level = '', $session_to_db = '') |
|
550
|
|
|
{ |
|
551
|
|
|
/** |
|
552
|
|
|
* @var $instance DB[] |
|
553
|
|
|
*/ |
|
554
|
39 |
|
static $instance = array(); |
|
555
|
|
|
|
|
556
|
|
|
/** |
|
557
|
|
|
* @var $firstInstance DB |
|
558
|
|
|
*/ |
|
559
|
39 |
|
static $firstInstance = null; |
|
560
|
|
|
|
|
561
|
|
|
if ( |
|
562
|
39 |
|
$hostname . $username . $password . $database . $port . $charset == '' |
|
563
|
39 |
|
&& |
|
564
|
7 |
|
null !== $firstInstance |
|
565
|
39 |
|
) { |
|
566
|
7 |
|
return $firstInstance; |
|
567
|
|
|
} |
|
568
|
|
|
|
|
569
|
39 |
|
$connection = md5( |
|
570
|
39 |
|
$hostname . $username . $password . $database . $port . $charset . (int)$exit_on_error . (int)$echo_on_error . $logger_class_name . $logger_level . (int)$session_to_db |
|
571
|
39 |
|
); |
|
572
|
|
|
|
|
573
|
39 |
|
if (!isset($instance[$connection])) { |
|
574
|
10 |
|
$instance[$connection] = new self( |
|
575
|
10 |
|
$hostname, |
|
576
|
10 |
|
$username, |
|
577
|
10 |
|
$password, |
|
578
|
10 |
|
$database, |
|
579
|
10 |
|
$port, |
|
580
|
10 |
|
$charset, |
|
581
|
10 |
|
$exit_on_error, |
|
582
|
10 |
|
$echo_on_error, |
|
583
|
10 |
|
$logger_class_name, |
|
584
|
10 |
|
$logger_level, |
|
585
|
|
|
$session_to_db |
|
586
|
10 |
|
); |
|
587
|
|
|
|
|
588
|
4 |
|
if (null === $firstInstance) { |
|
589
|
1 |
|
$firstInstance = $instance[$connection]; |
|
590
|
1 |
|
} |
|
591
|
4 |
|
} |
|
592
|
|
|
|
|
593
|
39 |
|
return $instance[$connection]; |
|
594
|
|
|
} |
|
595
|
|
|
|
|
596
|
|
|
/** |
|
597
|
|
|
* Execute a sql-query. |
|
598
|
|
|
* |
|
599
|
|
|
* @param string $sql sql-query |
|
600
|
|
|
* |
|
601
|
|
|
* @param array|boolean $params "array" of sql-query-parameters |
|
602
|
|
|
* "false" if you don't need any parameter (default) |
|
603
|
|
|
* |
|
604
|
|
|
* @return bool|int|Result "Result" by "<b>SELECT</b>"-queries<br /> |
|
605
|
|
|
* "int" (insert_id) by "<b>INSERT / REPLACE</b>"-queries<br /> |
|
606
|
|
|
* "int" (affected_rows) by "<b>UPDATE / DELETE</b>"-queries<br /> |
|
607
|
|
|
* "true" by e.g. "DROP"-queries<br /> |
|
608
|
|
|
* "false" on error |
|
609
|
|
|
* |
|
610
|
|
|
* @throws \Exception |
|
611
|
|
|
*/ |
|
612
|
22 |
|
public function query($sql = '', $params = false) |
|
613
|
|
|
{ |
|
614
|
22 |
|
if (!$this->isReady()) { |
|
615
|
|
|
return false; |
|
616
|
|
|
} |
|
617
|
|
|
|
|
618
|
22 |
|
if (!$sql || $sql === '') { |
|
619
|
4 |
|
$this->_displayError('Can\'t execute an empty Query', false); |
|
620
|
|
|
|
|
621
|
4 |
|
return false; |
|
622
|
|
|
} |
|
623
|
|
|
|
|
624
|
|
|
if ( |
|
625
|
|
|
$params !== false |
|
626
|
20 |
|
&& |
|
627
|
1 |
|
is_array($params) |
|
628
|
20 |
|
&& |
|
629
|
1 |
|
count($params) > 0 |
|
630
|
20 |
|
) { |
|
631
|
1 |
|
$sql = $this->_parseQueryParams($sql, $params); |
|
632
|
1 |
|
} |
|
633
|
|
|
|
|
634
|
20 |
|
$query_start_time = microtime(true); |
|
635
|
20 |
|
$result = mysqli_query($this->link, $sql); |
|
636
|
20 |
|
$query_duration = microtime(true) - $query_start_time; |
|
637
|
20 |
|
$this->query_count++; |
|
638
|
|
|
|
|
639
|
20 |
|
$resultCount = 0; |
|
640
|
20 |
|
if ($result instanceof \mysqli_result) { |
|
641
|
17 |
|
$resultCount = (int)$result->num_rows; |
|
642
|
17 |
|
} |
|
643
|
20 |
|
$this->_logQuery($sql, $query_duration, $resultCount); |
|
644
|
|
|
|
|
645
|
|
|
if ( |
|
646
|
|
|
$result !== null |
|
647
|
20 |
|
&& |
|
648
|
|
|
$result instanceof \mysqli_result |
|
649
|
20 |
|
) { |
|
650
|
|
|
|
|
651
|
|
|
// return query result object |
|
652
|
17 |
|
return new Result($sql, $result); |
|
653
|
|
|
|
|
654
|
|
|
} else { |
|
655
|
|
|
// is the query successful |
|
656
|
17 |
|
if ($result === true) { |
|
657
|
|
|
|
|
658
|
15 |
|
if (preg_match('/^\s*"?(INSERT|UPDATE|DELETE|REPLACE)\s+/i', $sql)) { |
|
659
|
|
|
|
|
660
|
|
|
// it is an "INSERT" || "REPLACE" |
|
661
|
15 |
|
if ($this->insert_id() > 0) { |
|
662
|
14 |
|
return (int)$this->insert_id(); |
|
663
|
|
|
} |
|
664
|
|
|
|
|
665
|
|
|
// it is an "UPDATE" || "DELETE" |
|
666
|
6 |
|
if ($this->affected_rows() > 0) { |
|
667
|
6 |
|
return (int)$this->affected_rows(); |
|
668
|
|
|
} |
|
669
|
|
|
} |
|
670
|
|
|
|
|
671
|
|
|
return true; |
|
672
|
|
|
} else { |
|
673
|
8 |
|
$this->queryErrorHandling(mysqli_error($this->link), $sql, $params); |
|
674
|
|
|
} |
|
675
|
|
|
} |
|
676
|
|
|
|
|
677
|
8 |
|
return false; |
|
678
|
|
|
} |
|
679
|
|
|
|
|
680
|
|
|
/** |
|
681
|
|
|
* _parseQueryParams |
|
682
|
|
|
* |
|
683
|
|
|
* @param string $sql |
|
684
|
|
|
* @param array $params |
|
685
|
|
|
* |
|
686
|
|
|
* @return string |
|
687
|
|
|
*/ |
|
688
|
1 |
|
private function _parseQueryParams($sql, array $params) |
|
689
|
|
|
{ |
|
690
|
|
|
|
|
691
|
|
|
// is there anything to parse? |
|
692
|
1 |
|
if (strpos($sql, '?') === false) { |
|
693
|
|
|
return $sql; |
|
694
|
|
|
} |
|
695
|
|
|
|
|
696
|
1 |
|
if (count($params) > 0) { |
|
697
|
1 |
|
$parseKey = md5(uniqid(mt_rand(), true)); |
|
698
|
1 |
|
$sql = str_replace('?', $parseKey, $sql); |
|
699
|
|
|
|
|
700
|
1 |
|
$k = 0; |
|
701
|
1 |
|
while (strpos($sql, $parseKey) !== false) { |
|
702
|
1 |
|
$value = $this->secure($params[$k]); |
|
703
|
1 |
|
$sql = preg_replace("/$parseKey/", $value, $sql, 1); |
|
704
|
1 |
|
$k++; |
|
705
|
1 |
|
} |
|
706
|
1 |
|
} |
|
707
|
|
|
|
|
708
|
1 |
|
return $sql; |
|
709
|
|
|
} |
|
710
|
|
|
|
|
711
|
|
|
/** |
|
712
|
|
|
* Try to secure a variable, so can you use it in sql-queries. |
|
713
|
|
|
* |
|
714
|
|
|
* int: (also strings that contains only an int-value) |
|
715
|
|
|
* 1. parse into (int) |
|
716
|
|
|
* |
|
717
|
|
|
* strings: |
|
718
|
|
|
* 1. check if the string isn't a default mysql-time-function e.g. 'CURDATE()' |
|
719
|
|
|
* 2. trim whitespace |
|
720
|
|
|
* 3. trim ' |
|
721
|
|
|
* 4. escape the string (and remove non utf-8 chars) |
|
722
|
|
|
* 5. trim ' again (because we maybe removed some chars) |
|
723
|
|
|
* 6. add ' around the new string |
|
724
|
|
|
* |
|
725
|
|
|
* @param mixed $var |
|
726
|
|
|
* |
|
727
|
|
|
* @return string | null |
|
728
|
|
|
*/ |
|
729
|
14 |
|
public function secure($var) |
|
730
|
|
|
{ |
|
731
|
|
|
// save the current value as int (for later usage) |
|
732
|
14 |
|
if (!is_object($var)) { |
|
733
|
14 |
|
$varInt = (int)$var; |
|
734
|
14 |
|
} |
|
735
|
|
|
|
|
736
|
14 |
|
if ((isset($varInt) && "$varInt" == $var) || is_int($var) || is_bool($var)) { |
|
|
|
|
|
|
737
|
|
|
|
|
738
|
|
|
// "int" || int || bool |
|
739
|
|
|
|
|
740
|
12 |
|
$var = (int)$var; |
|
741
|
|
|
|
|
742
|
14 |
|
} elseif (is_string($var)) { |
|
743
|
|
|
|
|
744
|
|
|
// "string" |
|
745
|
|
|
|
|
746
|
14 |
|
if (!in_array($var, $this->mysqlDefaultTimeFunctions, true)) { |
|
747
|
14 |
|
$var = "'" . trim($this->escape(trim(trim((string)$var), "'")), "'") . "'"; |
|
748
|
14 |
|
} |
|
749
|
|
|
|
|
750
|
14 |
View Code Duplication |
} elseif (is_float($var)) { |
|
|
|
|
|
|
751
|
|
|
|
|
752
|
|
|
// float |
|
753
|
|
|
|
|
754
|
2 |
|
$var = number_format((float)str_replace(',', '.', $var), 8, '.', ''); |
|
755
|
|
|
|
|
756
|
2 |
|
} elseif (is_array($var)) { |
|
757
|
|
|
|
|
758
|
|
|
// array |
|
759
|
|
|
|
|
760
|
1 |
|
$var = null; |
|
761
|
|
|
|
|
762
|
1 |
|
} elseif ($var instanceof \DateTime) { |
|
763
|
|
|
|
|
764
|
|
|
// "DateTime"-object |
|
765
|
|
|
|
|
766
|
|
|
try { |
|
767
|
1 |
|
$var = "'" . $this->escape($var->format('Y-m-d H:i:s'), false, false) . "'"; |
|
768
|
1 |
|
} catch (\Exception $e) { |
|
769
|
|
|
$var = null; |
|
770
|
|
|
} |
|
771
|
|
|
|
|
772
|
1 |
|
} else { |
|
773
|
|
|
|
|
774
|
|
|
// fallback ... |
|
775
|
|
|
|
|
776
|
|
|
$var = "'" . trim($this->escape(trim(trim((string)$var), "'")), "'") . "'"; |
|
777
|
|
|
|
|
778
|
|
|
} |
|
779
|
|
|
|
|
780
|
14 |
|
return $var; |
|
781
|
|
|
} |
|
782
|
|
|
|
|
783
|
|
|
/** |
|
784
|
|
|
* Escape |
|
785
|
|
|
* |
|
786
|
|
|
* @param mixed $var boolean: convert into "integer"<br /> |
|
787
|
|
|
* int: convert into "integer"<br /> |
|
788
|
|
|
* float: convert into "float" and replace "," with "."<br /> |
|
789
|
|
|
* array: run escape() for every key => value<br /> |
|
790
|
|
|
* string: run UTF8::cleanup() and mysqli_real_escape_string()<br /> |
|
791
|
|
|
* @param bool $stripe_non_utf8 |
|
792
|
|
|
* @param bool $html_entity_decode |
|
793
|
|
|
* @param bool $array_to_string |
|
794
|
|
|
* |
|
795
|
|
|
* @return array|bool|float|int|string |
|
796
|
|
|
*/ |
|
797
|
17 |
|
public function escape($var = '', $stripe_non_utf8 = true, $html_entity_decode = true, $array_to_string = false) |
|
798
|
|
|
{ |
|
799
|
|
|
// save the current value as int (for later usage) |
|
800
|
17 |
|
if (!is_object($var)) { |
|
801
|
17 |
|
$varInt = (int)$var; |
|
802
|
17 |
|
} |
|
803
|
|
|
|
|
804
|
17 |
|
if ((isset($varInt) && "$varInt" == $var) || is_int($var) || is_bool($var)) { |
|
|
|
|
|
|
805
|
|
|
|
|
806
|
|
|
// "int" || int || bool |
|
807
|
|
|
|
|
808
|
3 |
|
return (int)$var; |
|
809
|
|
|
|
|
810
|
17 |
View Code Duplication |
} elseif (is_float($var)) { |
|
811
|
|
|
|
|
812
|
|
|
// float |
|
813
|
|
|
|
|
814
|
1 |
|
return number_format((float)str_replace(',', '.', $var), 8, '.', ''); |
|
815
|
|
|
|
|
816
|
17 |
|
} elseif (is_array($var)) { |
|
817
|
|
|
|
|
818
|
|
|
// array |
|
819
|
|
|
|
|
820
|
1 |
|
$varCleaned = array(); |
|
821
|
1 |
|
foreach ($var as $key => $value) { |
|
822
|
|
|
|
|
823
|
1 |
|
$key = (string)$this->escape($key, $stripe_non_utf8, $html_entity_decode); |
|
824
|
1 |
|
$value = (string)$this->escape($value, $stripe_non_utf8, $html_entity_decode); |
|
825
|
|
|
|
|
826
|
1 |
|
$varCleaned[$key] = $value; |
|
827
|
1 |
|
} |
|
828
|
|
|
|
|
829
|
1 |
|
if ($array_to_string === true) { |
|
830
|
1 |
|
$varCleaned = implode(',', $varCleaned); |
|
831
|
|
|
|
|
832
|
1 |
|
return $varCleaned; |
|
833
|
|
|
} else { |
|
834
|
1 |
|
return (array)$varCleaned; |
|
835
|
|
|
} |
|
836
|
|
|
} |
|
837
|
|
|
|
|
838
|
17 |
|
if (is_string($var)) { |
|
839
|
|
|
|
|
840
|
|
|
// "string" |
|
841
|
|
|
|
|
842
|
17 |
|
if ($stripe_non_utf8 === true) { |
|
843
|
17 |
|
$var = UTF8::cleanup($var); |
|
844
|
17 |
|
} |
|
845
|
|
|
|
|
846
|
17 |
|
if ($html_entity_decode === true) { |
|
847
|
|
|
// use no-html-entity for db |
|
848
|
17 |
|
$var = UTF8::html_entity_decode($var); |
|
849
|
17 |
|
} |
|
850
|
|
|
|
|
851
|
17 |
|
$var = get_magic_quotes_gpc() ? stripslashes($var) : $var; |
|
852
|
|
|
|
|
853
|
17 |
|
$var = mysqli_real_escape_string($this->getLink(), $var); |
|
854
|
|
|
|
|
855
|
17 |
|
return (string)$var; |
|
856
|
|
|
} else { |
|
857
|
|
|
return false; |
|
858
|
|
|
} |
|
859
|
|
|
} |
|
860
|
|
|
|
|
861
|
|
|
/** |
|
862
|
|
|
* Get the mysqli-link (link identifier returned by mysqli-connect). |
|
863
|
|
|
* |
|
864
|
|
|
* @return \mysqli |
|
865
|
|
|
*/ |
|
866
|
17 |
|
public function getLink() |
|
867
|
|
|
{ |
|
868
|
17 |
|
return $this->link; |
|
869
|
|
|
} |
|
870
|
|
|
|
|
871
|
|
|
/** |
|
872
|
|
|
* Log the current query via "$this->logger". |
|
873
|
|
|
* |
|
874
|
|
|
* @param string $sql sql-query |
|
875
|
|
|
* @param int $duration |
|
876
|
|
|
* @param int $results result counter |
|
877
|
|
|
* |
|
878
|
|
|
* @return bool |
|
879
|
|
|
*/ |
|
880
|
21 |
|
private function _logQuery($sql, $duration, $results) |
|
881
|
|
|
{ |
|
882
|
21 |
|
$logLevelUse = strtolower($this->logger_level); |
|
883
|
|
|
|
|
884
|
|
|
if ( |
|
885
|
|
|
$logLevelUse != 'trace' |
|
886
|
21 |
|
&& |
|
887
|
|
|
$logLevelUse != 'debug' |
|
888
|
21 |
|
) { |
|
889
|
20 |
|
return false; |
|
890
|
|
|
} |
|
891
|
|
|
|
|
892
|
1 |
|
$info = 'time => ' . round( |
|
893
|
1 |
|
$duration, |
|
894
|
|
|
5 |
|
895
|
1 |
|
) . ' - ' . 'results => ' . $results . ' - ' . 'SQL => ' . UTF8::htmlentities($sql); |
|
896
|
|
|
|
|
897
|
1 |
|
$fileInfo = $this->getFileAndLineFromSql(); |
|
898
|
1 |
|
$this->logger( |
|
899
|
|
|
array( |
|
900
|
1 |
|
'debug', |
|
901
|
1 |
|
'<strong>' . date( |
|
902
|
|
|
'd. m. Y G:i:s' |
|
903
|
1 |
|
) . ' (' . $fileInfo['file'] . ' line: ' . $fileInfo['line'] . '):</strong> ' . $info . '<br>', |
|
904
|
1 |
|
'sql', |
|
905
|
|
|
) |
|
906
|
1 |
|
); |
|
907
|
|
|
|
|
908
|
1 |
|
return true; |
|
909
|
|
|
} |
|
910
|
|
|
|
|
911
|
|
|
/** |
|
912
|
|
|
* Returns the auto generated id used in the last query. |
|
913
|
|
|
* |
|
914
|
|
|
* @return int|string |
|
915
|
|
|
*/ |
|
916
|
15 |
|
public function insert_id() |
|
917
|
|
|
{ |
|
918
|
15 |
|
return mysqli_insert_id($this->link); |
|
919
|
|
|
} |
|
920
|
|
|
|
|
921
|
|
|
/** |
|
922
|
|
|
* Gets the number of affected rows in a previous MySQL operation. |
|
923
|
|
|
* |
|
924
|
|
|
* @return int |
|
925
|
|
|
*/ |
|
926
|
6 |
|
public function affected_rows() |
|
927
|
|
|
{ |
|
928
|
6 |
|
return mysqli_affected_rows($this->link); |
|
929
|
|
|
} |
|
930
|
|
|
|
|
931
|
|
|
/** |
|
932
|
|
|
* Error-handling for the sql-query. |
|
933
|
|
|
* |
|
934
|
|
|
* @param string $errorMsg |
|
935
|
|
|
* @param string $sql |
|
936
|
|
|
* @param array|bool $sqlParams false if there wasn't any parameter |
|
937
|
|
|
* |
|
938
|
|
|
* @throws \Exception |
|
939
|
|
|
*/ |
|
940
|
9 |
|
protected function queryErrorHandling($errorMsg, $sql, $sqlParams = false) |
|
941
|
|
|
{ |
|
942
|
9 |
|
if ($errorMsg == 'DB server has gone away' || $errorMsg == 'MySQL server has gone away') { |
|
943
|
1 |
|
static $reconnectCounter; |
|
944
|
|
|
|
|
945
|
|
|
// exit if we have more then 3 "DB server has gone away"-errors |
|
946
|
1 |
|
if ($reconnectCounter > 3) { |
|
947
|
|
|
$this->mailToAdmin('SQL-Fatal-Error', $errorMsg . ":\n<br />" . $sql, 5); |
|
948
|
|
|
throw new \Exception($errorMsg); |
|
949
|
|
|
} else { |
|
950
|
1 |
|
$this->mailToAdmin('SQL-Error', $errorMsg . ":\n<br />" . $sql); |
|
951
|
|
|
|
|
952
|
|
|
// reconnect |
|
953
|
1 |
|
$reconnectCounter++; |
|
954
|
1 |
|
$this->reconnect(true); |
|
955
|
|
|
|
|
956
|
|
|
// re-run the current query |
|
957
|
1 |
|
$this->query($sql, $sqlParams); |
|
958
|
|
|
} |
|
959
|
1 |
|
} else { |
|
960
|
8 |
|
$this->mailToAdmin('SQL-Warning', $errorMsg . ":\n<br />" . $sql); |
|
961
|
|
|
|
|
962
|
|
|
// this query returned an error, we must display it (only for dev) !!! |
|
963
|
8 |
|
$this->_displayError($errorMsg . ' | ' . $sql); |
|
964
|
|
|
} |
|
965
|
9 |
|
} |
|
966
|
|
|
|
|
967
|
|
|
/** |
|
968
|
|
|
* send a error mail to the admin / dev |
|
969
|
|
|
* |
|
970
|
|
|
* @param string $subject |
|
971
|
|
|
* @param string $htmlBody |
|
972
|
|
|
* @param int $priority |
|
973
|
|
|
*/ |
|
974
|
9 |
|
private function mailToAdmin($subject, $htmlBody, $priority = 3) |
|
975
|
|
|
{ |
|
976
|
9 |
|
if (function_exists('mailToAdmin')) { |
|
977
|
|
|
mailToAdmin($subject, $htmlBody, $priority); |
|
978
|
|
|
} else { |
|
979
|
|
|
|
|
980
|
9 |
|
if ($priority == 3) { |
|
981
|
9 |
|
$this->logger( |
|
982
|
|
|
array( |
|
983
|
9 |
|
'debug', |
|
984
|
9 |
|
$subject . ' | ' . $htmlBody, |
|
985
|
|
|
) |
|
986
|
9 |
|
); |
|
987
|
9 |
|
} elseif ($priority > 3) { |
|
988
|
|
|
$this->logger( |
|
989
|
|
|
array( |
|
990
|
|
|
'error', |
|
991
|
|
|
$subject . ' | ' . $htmlBody, |
|
992
|
|
|
) |
|
993
|
|
|
); |
|
994
|
|
|
} elseif ($priority < 3) { |
|
995
|
|
|
$this->logger( |
|
996
|
|
|
array( |
|
997
|
|
|
'info', |
|
998
|
|
|
$subject . ' | ' . $htmlBody, |
|
999
|
|
|
) |
|
1000
|
|
|
); |
|
1001
|
|
|
} |
|
1002
|
|
|
|
|
1003
|
|
|
} |
|
1004
|
9 |
|
} |
|
1005
|
|
|
|
|
1006
|
|
|
/** |
|
1007
|
|
|
* Reconnect to the MySQL-Server. |
|
1008
|
|
|
* |
|
1009
|
|
|
* @param bool $checkViaPing |
|
1010
|
|
|
* |
|
1011
|
|
|
* @return bool |
|
1012
|
|
|
*/ |
|
1013
|
2 |
|
public function reconnect($checkViaPing = false) |
|
1014
|
|
|
{ |
|
1015
|
2 |
|
$ping = false; |
|
1016
|
|
|
|
|
1017
|
2 |
|
if ($checkViaPing === true) { |
|
1018
|
2 |
|
$ping = $this->ping(); |
|
1019
|
2 |
|
} |
|
1020
|
|
|
|
|
1021
|
2 |
|
if ($ping !== true) { |
|
1022
|
2 |
|
$this->connected = false; |
|
1023
|
2 |
|
$this->connect(); |
|
1024
|
2 |
|
} |
|
1025
|
|
|
|
|
1026
|
2 |
|
return $this->isReady(); |
|
1027
|
|
|
} |
|
1028
|
|
|
|
|
1029
|
|
|
/** |
|
1030
|
|
|
* Pings a server connection, or tries to reconnect |
|
1031
|
|
|
* if the connection has gone down. |
|
1032
|
|
|
* |
|
1033
|
|
|
* @return boolean |
|
1034
|
|
|
*/ |
|
1035
|
3 |
|
public function ping() |
|
1036
|
|
|
{ |
|
1037
|
|
|
if ( |
|
1038
|
3 |
|
$this->link |
|
1039
|
3 |
|
&& |
|
1040
|
3 |
|
$this->link instanceof \mysqli |
|
1041
|
3 |
|
) { |
|
1042
|
|
|
/** @noinspection PhpUsageOfSilenceOperatorInspection */ |
|
1043
|
3 |
|
return @mysqli_ping($this->link); |
|
1044
|
|
|
} else { |
|
1045
|
|
|
return false; |
|
1046
|
|
|
} |
|
1047
|
|
|
} |
|
1048
|
|
|
|
|
1049
|
|
|
/** |
|
1050
|
|
|
* Execute select/insert/update/delete sql-queries. |
|
1051
|
|
|
* |
|
1052
|
|
|
* @param string $query sql-query |
|
1053
|
|
|
* @param bool $useCache use cache? |
|
1054
|
|
|
* @param int $cacheTTL cache-ttl in seconds |
|
1055
|
|
|
* |
|
1056
|
|
|
* @return mixed "array" by "<b>SELECT</b>"-queries<br /> |
|
1057
|
|
|
* "int" (insert_id) by "<b>INSERT</b>"-queries<br /> |
|
1058
|
|
|
* "int" (affected_rows) by "<b>UPDATE / DELETE</b>"-queries<br /> |
|
1059
|
|
|
* "true" by e.g. "DROP"-queries<br /> |
|
1060
|
|
|
* "false" on error |
|
1061
|
|
|
* |
|
1062
|
|
|
*/ |
|
1063
|
3 |
|
public static function execSQL($query, $useCache = false, $cacheTTL = 3600) |
|
1064
|
|
|
{ |
|
1065
|
3 |
|
$db = self::getInstance(); |
|
1066
|
|
|
|
|
1067
|
3 |
|
if ($useCache === true) { |
|
1068
|
1 |
|
$cache = new Cache(null, null, false, $useCache); |
|
1069
|
1 |
|
$cacheKey = 'sql-' . md5($query); |
|
1070
|
|
|
|
|
1071
|
|
|
if ( |
|
1072
|
1 |
|
$cache->getCacheIsReady() === true |
|
1073
|
1 |
|
&& |
|
1074
|
1 |
|
$cache->existsItem($cacheKey) |
|
1075
|
1 |
|
) { |
|
1076
|
1 |
|
return $cache->getItem($cacheKey); |
|
1077
|
|
|
} |
|
1078
|
|
|
|
|
1079
|
1 |
|
} else { |
|
1080
|
3 |
|
$cache = false; |
|
1081
|
|
|
} |
|
1082
|
|
|
|
|
1083
|
3 |
|
$result = $db->query($query); |
|
1084
|
|
|
|
|
1085
|
3 |
|
if ($result instanceof Result) { |
|
1086
|
|
|
|
|
1087
|
1 |
|
$return = $result->fetchAllArray(); |
|
1088
|
|
|
|
|
1089
|
|
|
if ( |
|
1090
|
1 |
|
isset($cacheKey) |
|
1091
|
1 |
|
&& |
|
1092
|
|
|
$useCache === true |
|
1093
|
1 |
|
&& |
|
1094
|
|
|
$cache instanceof Cache |
|
1095
|
1 |
|
&& |
|
1096
|
1 |
|
$cache->getCacheIsReady() === true |
|
1097
|
1 |
|
) { |
|
1098
|
1 |
|
$cache->setItem($cacheKey, $return, $cacheTTL); |
|
1099
|
1 |
|
} |
|
1100
|
|
|
|
|
1101
|
1 |
|
} else { |
|
1102
|
2 |
|
$return = $result; |
|
1103
|
|
|
} |
|
1104
|
|
|
|
|
1105
|
3 |
|
return $return; |
|
1106
|
|
|
} |
|
1107
|
|
|
|
|
1108
|
|
|
/** |
|
1109
|
|
|
* Get the current charset. |
|
1110
|
|
|
* |
|
1111
|
|
|
* @return string |
|
1112
|
|
|
*/ |
|
1113
|
1 |
|
public function get_charset() |
|
1114
|
|
|
{ |
|
1115
|
1 |
|
return $this->charset; |
|
1116
|
|
|
} |
|
1117
|
|
|
|
|
1118
|
|
|
/** |
|
1119
|
|
|
* Set the current charset. |
|
1120
|
|
|
* |
|
1121
|
|
|
* @param string $charset |
|
1122
|
|
|
* |
|
1123
|
|
|
* @return bool |
|
1124
|
|
|
*/ |
|
1125
|
6 |
|
public function set_charset($charset) |
|
1126
|
|
|
{ |
|
1127
|
6 |
|
$this->charset = (string)$charset; |
|
1128
|
|
|
|
|
1129
|
6 |
|
$return = mysqli_set_charset($this->link, $charset); |
|
1130
|
|
|
/** @noinspection PhpUsageOfSilenceOperatorInspection */ |
|
1131
|
6 |
|
@mysqli_query($this->link, 'SET CHARACTER SET ' . $charset); |
|
1132
|
|
|
/** @noinspection PhpUsageOfSilenceOperatorInspection */ |
|
1133
|
6 |
|
@mysqli_query($this->link, "SET NAMES '" . ($charset == 'utf8' ? 'utf8mb4' : $charset) . "'"); |
|
1134
|
|
|
|
|
1135
|
6 |
|
return $return; |
|
1136
|
|
|
} |
|
1137
|
|
|
|
|
1138
|
|
|
/** |
|
1139
|
|
|
* __wakeup |
|
1140
|
|
|
* |
|
1141
|
|
|
* @return void |
|
1142
|
|
|
*/ |
|
1143
|
1 |
|
public function __wakeup() |
|
1144
|
|
|
{ |
|
1145
|
1 |
|
$this->reconnect(); |
|
1146
|
1 |
|
} |
|
1147
|
|
|
|
|
1148
|
|
|
/** |
|
1149
|
|
|
* Get all table-names via "SHOW TABLES". |
|
1150
|
|
|
* |
|
1151
|
|
|
* @return array |
|
1152
|
|
|
*/ |
|
1153
|
1 |
|
public function getAllTables() |
|
1154
|
|
|
{ |
|
1155
|
1 |
|
$query = 'SHOW TABLES'; |
|
1156
|
1 |
|
$result = $this->query($query); |
|
1157
|
|
|
|
|
1158
|
1 |
|
return $result->fetchAllArray(); |
|
1159
|
|
|
} |
|
1160
|
|
|
|
|
1161
|
|
|
/** |
|
1162
|
|
|
* Execute a sql-multi-query. |
|
1163
|
|
|
* |
|
1164
|
|
|
* @param string $sql |
|
1165
|
|
|
* |
|
1166
|
|
|
* @return false|Result[] "Result"-Array by "<b>SELECT</b>"-queries<br /> |
|
1167
|
|
|
* "boolean" by only "<b>INSERT</b>"-queries<br /> |
|
1168
|
|
|
* "boolean" by only (affected_rows) by "<b>UPDATE / DELETE</b>"-queries<br /> |
|
1169
|
|
|
* "boolean" by only by e.g. "DROP"-queries<br /> |
|
1170
|
|
|
* |
|
1171
|
|
|
* @throws \Exception |
|
1172
|
|
|
*/ |
|
1173
|
1 |
|
public function multi_query($sql) |
|
1174
|
|
|
{ |
|
1175
|
1 |
|
if (!$this->isReady()) { |
|
1176
|
|
|
return false; |
|
1177
|
|
|
} |
|
1178
|
|
|
|
|
1179
|
1 |
|
if (!$sql || $sql === '') { |
|
1180
|
1 |
|
$this->_displayError('Can\'t execute an empty Query', false); |
|
1181
|
|
|
|
|
1182
|
1 |
|
return false; |
|
1183
|
|
|
} |
|
1184
|
|
|
|
|
1185
|
1 |
|
$query_start_time = microtime(true); |
|
1186
|
1 |
|
$resultTmp = mysqli_multi_query($this->link, $sql); |
|
1187
|
1 |
|
$query_duration = microtime(true) - $query_start_time; |
|
1188
|
|
|
|
|
1189
|
1 |
|
$this->_logQuery($sql, $query_duration, 0); |
|
1190
|
|
|
|
|
1191
|
1 |
|
$returnTheResult = false; |
|
1192
|
1 |
|
$result = array(); |
|
1193
|
1 |
|
if ($resultTmp) { |
|
1194
|
|
|
do { |
|
1195
|
1 |
|
$resultTmpInner = mysqli_store_result($this->link); |
|
1196
|
|
|
|
|
1197
|
|
|
if ( |
|
1198
|
1 |
|
null !== $resultTmpInner |
|
1199
|
1 |
|
&& |
|
1200
|
|
|
$resultTmpInner instanceof \mysqli_result |
|
1201
|
1 |
|
) { |
|
1202
|
1 |
|
$returnTheResult = true; |
|
1203
|
1 |
|
$result[] = new Result($sql, $resultTmpInner); |
|
1204
|
1 |
|
} else { |
|
1205
|
1 |
|
$errorMsg = mysqli_error($this->link); |
|
1206
|
|
|
|
|
1207
|
|
|
// is the query successful |
|
1208
|
1 |
|
if ($resultTmpInner === true || !$errorMsg) { |
|
1209
|
1 |
|
$result[] = true; |
|
1210
|
1 |
|
} else { |
|
1211
|
|
|
$result[] = false; |
|
1212
|
|
|
|
|
1213
|
|
|
$this->queryErrorHandling($errorMsg, $sql); |
|
1214
|
|
|
} |
|
1215
|
|
|
} |
|
1216
|
1 |
|
} while (mysqli_more_results($this->link) === true ? mysqli_next_result($this->link) : false); |
|
1217
|
|
|
|
|
1218
|
1 |
|
} else { |
|
1219
|
|
|
|
|
1220
|
|
|
$errorMsg = mysqli_error($this->link); |
|
1221
|
|
|
|
|
1222
|
|
|
if ($this->checkForDev() === true) { |
|
1223
|
|
|
echo "Info: maybe you have to increase your 'max_allowed_packet = 30M' in the config: 'my.conf' \n<br />"; |
|
1224
|
|
|
echo 'Error:' . $errorMsg; |
|
1225
|
|
|
} |
|
1226
|
|
|
|
|
1227
|
|
|
$this->mailToAdmin('SQL-Error in mysqli_multi_query', $errorMsg . ":\n<br />" . $sql); |
|
1228
|
|
|
} |
|
1229
|
|
|
|
|
1230
|
|
|
// return the result only if there was a "SELECT"-query |
|
1231
|
1 |
|
if ($returnTheResult === true) { |
|
1232
|
1 |
|
return $result; |
|
1233
|
|
|
} |
|
1234
|
|
|
|
|
1235
|
1 |
|
if (!in_array(false, $result, true)) { |
|
1236
|
1 |
|
return true; |
|
1237
|
|
|
} else { |
|
1238
|
|
|
return false; |
|
1239
|
|
|
} |
|
1240
|
|
|
} |
|
1241
|
|
|
|
|
1242
|
|
|
/** |
|
1243
|
|
|
* alias: "beginTransaction()" |
|
1244
|
|
|
*/ |
|
1245
|
1 |
|
public function startTransaction() |
|
1246
|
|
|
{ |
|
1247
|
1 |
|
$this->beginTransaction(); |
|
1248
|
1 |
|
} |
|
1249
|
|
|
|
|
1250
|
|
|
/** |
|
1251
|
|
|
* Begins a transaction, by turning off auto commit. |
|
1252
|
|
|
* |
|
1253
|
|
|
* @return boolean this will return true or false indicating success of transaction |
|
1254
|
|
|
*/ |
|
1255
|
4 |
|
public function beginTransaction() |
|
1256
|
|
|
{ |
|
1257
|
4 |
|
$this->clearErrors(); |
|
1258
|
|
|
|
|
1259
|
4 |
|
if ($this->inTransaction() === true) { |
|
1260
|
1 |
|
$this->_displayError('Error mysql server already in transaction!', true); |
|
1261
|
|
|
|
|
1262
|
|
|
return false; |
|
1263
|
4 |
|
} elseif (mysqli_connect_errno()) { |
|
1264
|
|
|
$this->_displayError('Error connecting to mysql server: ' . mysqli_connect_error(), true); |
|
1265
|
|
|
|
|
1266
|
|
|
return false; |
|
1267
|
|
|
} else { |
|
1268
|
4 |
|
$this->_in_transaction = true; |
|
1269
|
4 |
|
mysqli_autocommit($this->link, false); |
|
1270
|
|
|
|
|
1271
|
4 |
|
return true; |
|
1272
|
|
|
|
|
1273
|
|
|
} |
|
1274
|
|
|
} |
|
1275
|
|
|
|
|
1276
|
|
|
/** |
|
1277
|
|
|
* Clear the errors in "$this->_errors". |
|
1278
|
|
|
* |
|
1279
|
|
|
* @return bool |
|
1280
|
|
|
*/ |
|
1281
|
4 |
|
public function clearErrors() |
|
1282
|
|
|
{ |
|
1283
|
4 |
|
$this->_errors = array(); |
|
1284
|
|
|
|
|
1285
|
4 |
|
return true; |
|
1286
|
|
|
} |
|
1287
|
|
|
|
|
1288
|
|
|
/** |
|
1289
|
|
|
* Check if we are in a transaction. |
|
1290
|
|
|
* |
|
1291
|
|
|
* @return boolean |
|
1292
|
|
|
*/ |
|
1293
|
4 |
|
public function inTransaction() |
|
1294
|
|
|
{ |
|
1295
|
4 |
|
return $this->_in_transaction; |
|
1296
|
|
|
} |
|
1297
|
|
|
|
|
1298
|
|
|
/** |
|
1299
|
|
|
* Ends a transaction and commits if no errors, then ends autocommit. |
|
1300
|
|
|
* |
|
1301
|
|
|
* @return boolean this will return true or false indicating success of transactions |
|
1302
|
|
|
*/ |
|
1303
|
2 |
|
public function endTransaction() |
|
1304
|
|
|
{ |
|
1305
|
|
|
|
|
1306
|
2 |
|
if (!$this->errors()) { |
|
1307
|
1 |
|
mysqli_commit($this->link); |
|
1308
|
1 |
|
$return = true; |
|
1309
|
1 |
|
} else { |
|
1310
|
1 |
|
$this->rollback(); |
|
1311
|
1 |
|
$return = false; |
|
1312
|
|
|
} |
|
1313
|
|
|
|
|
1314
|
2 |
|
mysqli_autocommit($this->link, true); |
|
1315
|
2 |
|
$this->_in_transaction = false; |
|
1316
|
|
|
|
|
1317
|
2 |
|
return $return; |
|
1318
|
|
|
} |
|
1319
|
|
|
|
|
1320
|
|
|
/** |
|
1321
|
|
|
* Get all errors from "$this->_errors". |
|
1322
|
|
|
* |
|
1323
|
|
|
* @return array|false false === on errors |
|
1324
|
|
|
*/ |
|
1325
|
2 |
|
public function errors() |
|
1326
|
|
|
{ |
|
1327
|
2 |
|
return count($this->_errors) > 0 ? $this->_errors : false; |
|
1328
|
|
|
} |
|
1329
|
|
|
|
|
1330
|
|
|
/** |
|
1331
|
|
|
* Rollback in a transaction. |
|
1332
|
|
|
*/ |
|
1333
|
2 |
|
public function rollback() |
|
1334
|
|
|
{ |
|
1335
|
|
|
// init |
|
1336
|
2 |
|
$return = false; |
|
1337
|
|
|
|
|
1338
|
2 |
|
if ($this->_in_transaction === true) { |
|
1339
|
2 |
|
$return = mysqli_rollback($this->link); |
|
1340
|
2 |
|
mysqli_autocommit($this->link, true); |
|
1341
|
2 |
|
$this->_in_transaction = false; |
|
1342
|
2 |
|
} |
|
1343
|
|
|
|
|
1344
|
2 |
|
return $return; |
|
1345
|
|
|
} |
|
1346
|
|
|
|
|
1347
|
|
|
/** |
|
1348
|
|
|
* Execute a "insert"-query. |
|
1349
|
|
|
* |
|
1350
|
|
|
* @param string $table |
|
1351
|
|
|
* @param array $data |
|
1352
|
|
|
* |
|
1353
|
|
|
* @return false|int false on error |
|
1354
|
|
|
*/ |
|
1355
|
14 |
|
public function insert($table, $data = array()) |
|
1356
|
|
|
{ |
|
1357
|
14 |
|
$table = trim($table); |
|
1358
|
|
|
|
|
1359
|
14 |
|
if ($table === '') { |
|
1360
|
2 |
|
$this->_displayError('invalid-table-name'); |
|
1361
|
|
|
|
|
1362
|
1 |
|
return false; |
|
1363
|
|
|
} |
|
1364
|
|
|
|
|
1365
|
13 |
|
if (count($data) == 0) { |
|
1366
|
3 |
|
$this->_displayError('empty-data-for-INSERT'); |
|
1367
|
|
|
|
|
1368
|
2 |
|
return false; |
|
1369
|
|
|
} |
|
1370
|
|
|
|
|
1371
|
11 |
|
$SET = $this->_parseArrayPair($data); |
|
1372
|
|
|
|
|
1373
|
11 |
|
$sql = 'INSERT INTO ' . $this->quote_string($table) . " SET $SET;"; |
|
1374
|
|
|
|
|
1375
|
11 |
|
return $this->query($sql); |
|
1376
|
|
|
} |
|
1377
|
|
|
|
|
1378
|
|
|
/** |
|
1379
|
|
|
* Parses arrays with value pairs and generates SQL to use in queries. |
|
1380
|
|
|
* |
|
1381
|
|
|
* @param array $arrayPair |
|
1382
|
|
|
* @param string $glue this is the separator |
|
1383
|
|
|
* |
|
1384
|
|
|
* @return string |
|
1385
|
|
|
*/ |
|
1386
|
12 |
|
private function _parseArrayPair($arrayPair, $glue = ',') |
|
1387
|
|
|
{ |
|
1388
|
|
|
// init |
|
1389
|
12 |
|
$sql = ''; |
|
1390
|
12 |
|
$pairs = array(); |
|
1391
|
|
|
|
|
1392
|
12 |
|
if (!empty($arrayPair)) { |
|
1393
|
|
|
|
|
1394
|
12 |
|
foreach ($arrayPair as $_key => $_value) { |
|
1395
|
12 |
|
$_connector = '='; |
|
1396
|
12 |
|
$_key_upper = strtoupper($_key); |
|
1397
|
|
|
|
|
1398
|
12 |
|
if (strpos($_key_upper, ' NOT') !== false) { |
|
1399
|
2 |
|
$_connector = 'NOT'; |
|
1400
|
2 |
|
} |
|
1401
|
|
|
|
|
1402
|
12 |
|
if (strpos($_key_upper, ' IS') !== false) { |
|
1403
|
1 |
|
$_connector = 'IS'; |
|
1404
|
1 |
|
} |
|
1405
|
|
|
|
|
1406
|
12 |
|
if (strpos($_key_upper, ' IS NOT') !== false) { |
|
1407
|
1 |
|
$_connector = 'IS NOT'; |
|
1408
|
1 |
|
} |
|
1409
|
|
|
|
|
1410
|
12 |
|
if (strpos($_key_upper, ' IN') !== false) { |
|
1411
|
1 |
|
$_connector = 'IN'; |
|
1412
|
1 |
|
} |
|
1413
|
|
|
|
|
1414
|
12 |
|
if (strpos($_key_upper, ' NOT IN') !== false) { |
|
1415
|
1 |
|
$_connector = 'NOT IN'; |
|
1416
|
1 |
|
} |
|
1417
|
|
|
|
|
1418
|
12 |
|
if (strpos($_key_upper, ' BETWEEN') !== false) { |
|
1419
|
1 |
|
$_connector = 'BETWEEN'; |
|
1420
|
1 |
|
} |
|
1421
|
|
|
|
|
1422
|
12 |
|
if (strpos($_key_upper, ' NOT BETWEEN') !== false) { |
|
1423
|
1 |
|
$_connector = 'NOT BETWEEN'; |
|
1424
|
1 |
|
} |
|
1425
|
|
|
|
|
1426
|
12 |
|
if (strpos($_key_upper, ' LIKE') !== false) { |
|
1427
|
2 |
|
$_connector = 'LIKE'; |
|
1428
|
2 |
|
} |
|
1429
|
|
|
|
|
1430
|
12 |
|
if (strpos($_key_upper, ' NOT LIKE') !== false) { |
|
1431
|
2 |
|
$_connector = 'NOT LIKE'; |
|
1432
|
2 |
|
} |
|
1433
|
|
|
|
|
1434
|
12 |
View Code Duplication |
if (strpos($_key_upper, ' >') !== false && strpos($_key_upper, ' =') === false) { |
|
1435
|
2 |
|
$_connector = '>'; |
|
1436
|
2 |
|
} |
|
1437
|
|
|
|
|
1438
|
12 |
View Code Duplication |
if (strpos($_key_upper, ' <') !== false && strpos($_key_upper, ' =') === false) { |
|
1439
|
1 |
|
$_connector = '<'; |
|
1440
|
1 |
|
} |
|
1441
|
|
|
|
|
1442
|
12 |
|
if (strpos($_key_upper, ' >=') !== false) { |
|
1443
|
2 |
|
$_connector = '>='; |
|
1444
|
2 |
|
} |
|
1445
|
|
|
|
|
1446
|
12 |
|
if (strpos($_key_upper, ' <=') !== false) { |
|
1447
|
1 |
|
$_connector = '<='; |
|
1448
|
1 |
|
} |
|
1449
|
|
|
|
|
1450
|
12 |
|
if (strpos($_key_upper, ' <>') !== false) { |
|
1451
|
1 |
|
$_connector = '<>'; |
|
1452
|
1 |
|
} |
|
1453
|
|
|
|
|
1454
|
|
|
if ( |
|
1455
|
12 |
|
is_array($_value) |
|
1456
|
12 |
|
&& |
|
1457
|
|
|
( |
|
1458
|
|
|
$_connector == 'NOT IN' |
|
1459
|
1 |
|
|| |
|
1460
|
|
|
$_connector == 'IN' |
|
1461
|
1 |
|
) |
|
1462
|
12 |
|
) { |
|
1463
|
1 |
|
foreach ($_value as $oldKey => $oldValue) { |
|
1464
|
|
|
/** @noinspection AlterInForeachInspection */ |
|
1465
|
1 |
|
$_value[$oldKey] = $this->secure($oldValue); |
|
1466
|
1 |
|
} |
|
1467
|
1 |
|
$_value = '(' . implode(',', $_value) . ')'; |
|
1468
|
1 |
|
} elseif ( |
|
1469
|
12 |
|
is_array($_value) |
|
1470
|
12 |
|
&& |
|
1471
|
|
|
( |
|
1472
|
|
|
$_connector == 'NOT BETWEEN' |
|
1473
|
1 |
|
|| |
|
1474
|
|
|
$_connector == 'BETWEEN' |
|
1475
|
|
|
) |
|
1476
|
12 |
|
) { |
|
1477
|
1 |
|
foreach ($_value as $oldKey => $oldValue) { |
|
1478
|
|
|
/** @noinspection AlterInForeachInspection */ |
|
1479
|
1 |
|
$_value[$oldKey] = $this->secure($oldValue); |
|
1480
|
1 |
|
} |
|
1481
|
1 |
|
$_value = '(' . implode(' AND ', $_value) . ')'; |
|
1482
|
1 |
|
} else { |
|
1483
|
12 |
|
$_value = $this->secure($_value); |
|
1484
|
|
|
} |
|
1485
|
|
|
|
|
1486
|
12 |
|
$quoteString = $this->quote_string(trim(str_ireplace($_connector, '', $_key))); |
|
1487
|
12 |
|
$pairs[] = ' ' . $quoteString . ' ' . $_connector . ' ' . $_value . " \n"; |
|
1488
|
12 |
|
} |
|
1489
|
|
|
|
|
1490
|
12 |
|
$sql = implode($glue, $pairs); |
|
1491
|
12 |
|
} |
|
1492
|
|
|
|
|
1493
|
12 |
|
return $sql; |
|
1494
|
|
|
} |
|
1495
|
|
|
|
|
1496
|
|
|
/** |
|
1497
|
|
|
* Quote && Escape e.g. a table name string. |
|
1498
|
|
|
* |
|
1499
|
|
|
* @param string $str |
|
1500
|
|
|
* |
|
1501
|
|
|
* @return string |
|
1502
|
|
|
*/ |
|
1503
|
14 |
|
public function quote_string($str) |
|
1504
|
|
|
{ |
|
1505
|
14 |
|
return '`' . $this->escape($str, false, false) . '`'; |
|
1506
|
|
|
} |
|
1507
|
|
|
|
|
1508
|
|
|
/** |
|
1509
|
|
|
* Get errors from "$this->_errors". |
|
1510
|
|
|
* |
|
1511
|
|
|
* @return array |
|
1512
|
|
|
*/ |
|
1513
|
1 |
|
public function getErrors() |
|
1514
|
|
|
{ |
|
1515
|
1 |
|
return $this->_errors; |
|
1516
|
|
|
} |
|
1517
|
|
|
|
|
1518
|
|
|
/** |
|
1519
|
|
|
* Execute a "replace"-query. |
|
1520
|
|
|
* |
|
1521
|
|
|
* @param string $table |
|
1522
|
|
|
* @param array $data |
|
1523
|
|
|
* |
|
1524
|
|
|
* @return false|int false on error |
|
1525
|
|
|
*/ |
|
1526
|
1 |
|
public function replace($table, $data = array()) |
|
1527
|
|
|
{ |
|
1528
|
|
|
|
|
1529
|
1 |
|
$table = trim($table); |
|
1530
|
|
|
|
|
1531
|
1 |
|
if ($table === '') { |
|
1532
|
1 |
|
$this->_displayError('invalid table name'); |
|
1533
|
|
|
|
|
1534
|
1 |
|
return false; |
|
1535
|
|
|
} |
|
1536
|
|
|
|
|
1537
|
1 |
|
if (count($data) == 0) { |
|
1538
|
1 |
|
$this->_displayError('empty data for REPLACE'); |
|
1539
|
|
|
|
|
1540
|
1 |
|
return false; |
|
1541
|
|
|
} |
|
1542
|
|
|
|
|
1543
|
|
|
// extracting column names |
|
1544
|
1 |
|
$columns = array_keys($data); |
|
1545
|
1 |
|
foreach ($columns as $k => $_key) { |
|
1546
|
|
|
/** @noinspection AlterInForeachInspection */ |
|
1547
|
1 |
|
$columns[$k] = $this->quote_string($_key); |
|
1548
|
1 |
|
} |
|
1549
|
|
|
|
|
1550
|
1 |
|
$columns = implode(',', $columns); |
|
1551
|
|
|
|
|
1552
|
|
|
// extracting values |
|
1553
|
1 |
|
foreach ($data as $k => $_value) { |
|
1554
|
|
|
/** @noinspection AlterInForeachInspection */ |
|
1555
|
1 |
|
$data[$k] = $this->secure($_value); |
|
1556
|
1 |
|
} |
|
1557
|
1 |
|
$values = implode(',', $data); |
|
1558
|
|
|
|
|
1559
|
1 |
|
$sql = 'REPLACE INTO ' . $this->quote_string($table) . " ($columns) VALUES ($values);"; |
|
1560
|
|
|
|
|
1561
|
1 |
|
return $this->query($sql); |
|
1562
|
|
|
} |
|
1563
|
|
|
|
|
1564
|
|
|
/** |
|
1565
|
|
|
* Execute a "update"-query. |
|
1566
|
|
|
* |
|
1567
|
|
|
* @param string $table |
|
1568
|
|
|
* @param array $data |
|
1569
|
|
|
* @param array|string $where |
|
1570
|
|
|
* |
|
1571
|
|
|
* @return false|int false on error |
|
1572
|
|
|
*/ |
|
1573
|
5 |
|
public function update($table, $data = array(), $where = '1=1') |
|
1574
|
|
|
{ |
|
1575
|
5 |
|
$table = trim($table); |
|
1576
|
|
|
|
|
1577
|
5 |
|
if ($table === '') { |
|
1578
|
1 |
|
$this->_displayError('invalid table name'); |
|
1579
|
|
|
|
|
1580
|
1 |
|
return false; |
|
1581
|
|
|
} |
|
1582
|
|
|
|
|
1583
|
5 |
|
if (count($data) == 0) { |
|
1584
|
1 |
|
$this->_displayError('empty data for UPDATE'); |
|
1585
|
|
|
|
|
1586
|
1 |
|
return false; |
|
1587
|
|
|
} |
|
1588
|
|
|
|
|
1589
|
5 |
|
$SET = $this->_parseArrayPair($data); |
|
1590
|
|
|
|
|
1591
|
5 |
|
if (is_string($where)) { |
|
1592
|
1 |
|
$WHERE = $this->escape($where, false, false); |
|
1593
|
5 |
|
} elseif (is_array($where)) { |
|
1594
|
4 |
|
$WHERE = $this->_parseArrayPair($where, 'AND'); |
|
1595
|
4 |
|
} else { |
|
1596
|
1 |
|
$WHERE = ''; |
|
1597
|
|
|
} |
|
1598
|
|
|
|
|
1599
|
5 |
|
$sql = 'UPDATE ' . $this->quote_string($table) . " SET $SET WHERE ($WHERE);"; |
|
1600
|
|
|
|
|
1601
|
5 |
|
return $this->query($sql); |
|
1602
|
|
|
} |
|
1603
|
|
|
|
|
1604
|
|
|
/** |
|
1605
|
|
|
* Execute a "delete"-query. |
|
1606
|
|
|
* |
|
1607
|
|
|
* @param string $table |
|
1608
|
|
|
* @param string|array $where |
|
1609
|
|
|
* |
|
1610
|
|
|
* @return false|int false on error |
|
1611
|
|
|
*/ |
|
1612
|
1 |
View Code Duplication |
public function delete($table, $where) |
|
1613
|
|
|
{ |
|
1614
|
|
|
|
|
1615
|
1 |
|
$table = trim($table); |
|
1616
|
|
|
|
|
1617
|
1 |
|
if ($table === '') { |
|
1618
|
1 |
|
$this->_displayError('invalid table name'); |
|
1619
|
|
|
|
|
1620
|
1 |
|
return false; |
|
1621
|
|
|
} |
|
1622
|
|
|
|
|
1623
|
1 |
|
if (is_string($where)) { |
|
1624
|
1 |
|
$WHERE = $this->escape($where, false, false); |
|
1625
|
1 |
|
} elseif (is_array($where)) { |
|
1626
|
1 |
|
$WHERE = $this->_parseArrayPair($where, 'AND'); |
|
1627
|
1 |
|
} else { |
|
1628
|
1 |
|
$WHERE = ''; |
|
1629
|
|
|
} |
|
1630
|
|
|
|
|
1631
|
1 |
|
$sql = 'DELETE FROM ' . $this->quote_string($table) . " WHERE ($WHERE);"; |
|
1632
|
|
|
|
|
1633
|
1 |
|
return $this->query($sql); |
|
1634
|
|
|
} |
|
1635
|
|
|
|
|
1636
|
|
|
/** |
|
1637
|
|
|
* Execute a "select"-query. |
|
1638
|
|
|
* |
|
1639
|
|
|
* @param string $table |
|
1640
|
|
|
* @param string|array $where |
|
1641
|
|
|
* |
|
1642
|
|
|
* @return false|Result false on error |
|
1643
|
|
|
*/ |
|
1644
|
13 |
View Code Duplication |
public function select($table, $where = '1=1') |
|
1645
|
|
|
{ |
|
1646
|
|
|
|
|
1647
|
13 |
|
if ($table === '') { |
|
1648
|
1 |
|
$this->_displayError('invalid table name'); |
|
1649
|
|
|
|
|
1650
|
1 |
|
return false; |
|
1651
|
|
|
} |
|
1652
|
|
|
|
|
1653
|
13 |
|
if (is_string($where)) { |
|
1654
|
3 |
|
$WHERE = $this->escape($where, false, false); |
|
1655
|
13 |
|
} elseif (is_array($where)) { |
|
1656
|
11 |
|
$WHERE = $this->_parseArrayPair($where, 'AND'); |
|
1657
|
11 |
|
} else { |
|
1658
|
1 |
|
$WHERE = ''; |
|
1659
|
|
|
} |
|
1660
|
|
|
|
|
1661
|
13 |
|
$sql = 'SELECT * FROM ' . $this->quote_string($table) . " WHERE ($WHERE);"; |
|
1662
|
|
|
|
|
1663
|
13 |
|
return $this->query($sql); |
|
1664
|
|
|
} |
|
1665
|
|
|
|
|
1666
|
|
|
/** |
|
1667
|
|
|
* Get the last sql-error. |
|
1668
|
|
|
* |
|
1669
|
|
|
* @return string false on error |
|
1670
|
|
|
*/ |
|
1671
|
1 |
|
public function lastError() |
|
1672
|
|
|
{ |
|
1673
|
1 |
|
return count($this->_errors) > 0 ? end($this->_errors) : false; |
|
1674
|
|
|
} |
|
1675
|
|
|
|
|
1676
|
|
|
/** |
|
1677
|
|
|
* __destruct |
|
1678
|
|
|
* |
|
1679
|
|
|
*/ |
|
1680
|
1 |
|
public function __destruct() |
|
1681
|
|
|
{ |
|
1682
|
|
|
// close the connection only if we don't save PHP-SESSION's in DB |
|
1683
|
1 |
|
if ($this->session_to_db === false) { |
|
1684
|
1 |
|
$this->close(); |
|
1685
|
1 |
|
} |
|
1686
|
1 |
|
} |
|
1687
|
|
|
|
|
1688
|
|
|
/** |
|
1689
|
|
|
* Closes a previously opened database connection. |
|
1690
|
|
|
*/ |
|
1691
|
3 |
|
public function close() |
|
1692
|
|
|
{ |
|
1693
|
3 |
|
$this->connected = false; |
|
1694
|
|
|
|
|
1695
|
3 |
|
if ($this->link) { |
|
1696
|
3 |
|
mysqli_close($this->link); |
|
1697
|
3 |
|
} |
|
1698
|
3 |
|
} |
|
1699
|
|
|
|
|
1700
|
|
|
/** |
|
1701
|
|
|
* prevent the instance from being cloned |
|
1702
|
|
|
* |
|
1703
|
|
|
* @return void |
|
1704
|
|
|
*/ |
|
1705
|
|
|
private function __clone() |
|
1706
|
|
|
{ |
|
1707
|
|
|
} |
|
1708
|
|
|
|
|
1709
|
|
|
} |
|
1710
|
|
|
|
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.