Completed
Push — master ( b4f983...cea542 )
by Nazar
04:20
created

_Abstract::connecting_time()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 3
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
/**
3
 * @package   CleverStyle CMS
4
 * @author    Nazar Mokrynskyi <[email protected]>
5
 * @copyright Copyright (c) 2011-2016, Nazar Mokrynskyi
6
 * @license   MIT License, see license.txt
7
 */
8
namespace cs\DB;
9
abstract class _Abstract {
10
	/**
11
	 * Is connection established
12
	 *
13
	 * @var bool
14
	 */
15
	protected $connected = false;
16
	/**
17
	 * DB type, may be used for constructing requests, accounting particular features of current DB (lowercase name)
18
	 *
19
	 * @var string
20
	 */
21
	protected $db_type = '';
22
	/**
23
	 * Current DB
24
	 *
25
	 * @var string
26
	 */
27
	protected $database;
28
	/**
29
	 * Current prefix
30
	 *
31
	 * @var string
32
	 */
33
	protected $prefix;
34
	/**
35
	 * Total time of requests execution
36
	 *
37
	 * @var int
38
	 */
39
	protected $time;
40
	/**
41
	 * Array for storing of data of the last executed request
42
	 *
43
	 * @var array
44
	 */
45
	protected $query = [
46
		'time' => '',
47
		'text' => ''
48
	];
49
	/**
50
	 * Array for storing data of all executed requests
51
	 *
52
	 * @var array
53
	 */
54
	protected $queries = [
55
		'num'  => '',
56
		'time' => [],
57
		'text' => []
58
	];
59
	/**
60
	 * Connection time
61
	 *
62
	 * @var float
63
	 */
64
	protected $connecting_time;
65
	/**
66
	 * Asynchronous request
67
	 *
68
	 * @var bool
69
	 */
70
	protected $async = false;
71
	/**
72
	 * Connecting to the DB
73
	 *
74
	 * @param string $database
75
	 * @param string $user
76
	 * @param string $password
77
	 * @param string $host
78
	 * @param string $charset
79
	 * @param string $prefix
80
	 */
81
	abstract function __construct ($database, $user = '', $password = '', $host = 'localhost', $charset = 'utf8', $prefix = '');
82
	/**
83
	 * Query
84
	 *
85
	 * SQL request into DB
86
	 *
87
	 * @abstract
88
	 *
89
	 * @param string|string[] $query  SQL query string or array, may be a format string in accordance with the first parameter of sprintf() function
90
	 * @param string|string[] $params May be array of arguments for formatting of <b>$query</b><br>
91
	 *                                or string - in this case it will be first argument for formatting of <b>$query</b>
92
	 * @param string          $_      if <b>$params</s> is string - this parameter will be second argument for formatting of <b>$query</b>.
93
	 *                                If you need more arguments - add them after this one, function will accept them.
94
	 *
95
	 * @return false|object|resource
96
	 */
97
	function q ($query, $params = [], $_ = null) {
98
		$normalized = $this->prepare_and_normalize_arguments($query, func_get_args());
99
		if (!$normalized) {
100
			return false;
101
		}
102
		list($query, $params) = $normalized;
103
		/**
104
		 * Executing multiple queries
105
		 */
106
		if (is_array($query)) {
107
			return $this->execute_multiple($query, $params);
108
		}
109
		return $this->execute_single($query, $params);
110
	}
111
	/**
112
	 * @param string|string[] $query
113
	 * @param array           $arguments
114
	 *
115
	 * @return array|false
1 ignored issue
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use false|array.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
116
	 */
117
	protected function prepare_and_normalize_arguments ($query, $arguments) {
118
		if (!$query || !$arguments) {
119
			return false;
120
		}
121
		$query = str_replace('[prefix]', $this->prefix, $query);
122
		switch (count($arguments)) {
123
			default:
124
				$params = array_slice($arguments, 1);
125
				break;
126
			case 1:
127
				$params = [];
128
				break;
129
			case 2:
130
				$params = (array)$arguments[1];
131
				break;
132
		}
133
		foreach ($params as &$param) {
134
			$param = $this->s($param, false);
135
		}
136
		return [
137
			$query,
138
			$params
139
		];
140
	}
141
	/**
142
	 * @param string[] $queries
143
	 * @param string[] $params
144
	 *
145
	 * @return false|object|resource
146
	 */
147
	protected function execute_multiple ($queries, $params) {
148
		$time_from = microtime(true);
149
		foreach ($queries as &$q) {
150
			$q = $params ? vsprintf($q, $params) : $q;
151
		}
152
		unset($q);
153
		$this->queries['num'] += count($queries);
154
		$result = $this->q_multi_internal($queries);
155
		$this->time += round(microtime(true) - $time_from, 6);
156
		return $result;
157
	}
158
	/**
159
	 * @param string   $query
160
	 * @param string[] $params
161
	 *
162
	 * @return false|object|resource
163
	 */
164
	protected function execute_single ($query, $params) {
165
		$time_from           = microtime(true);
166
		$this->query['text'] = empty($params) ? $query : vsprintf($query, $params);
167
		if (DEBUG) {
168
			$this->queries['text'][] = $this->query['text'];
169
		}
170
		$result              = $this->q_internal($this->query['text']);
171
		$this->query['time'] = round(microtime(true) - $time_from, 6);
172
		$this->time += $this->query['time'];
173
		if (DEBUG) {
174
			$this->queries['time'][] = $this->query['time'];
175
		}
176
		++$this->queries['num'];
177
		return $result;
178
	}
179
	/**
180
	 * Asynchronous, Query
181
	 *
182
	 * Asynchronous SQL request into DB (if is not supported - ordinary request will me executed).
183
	 * Result of execution can't be obtained, so, use it, for example, for deleting some non-critical data
184
	 *
185
	 * @abstract
186
	 *
187
	 * @param string|string[] $query          SQL query string, may be a format string in accordance with the first parameter of sprintf() function
188
	 * @param string|string[] $params         May be array of arguments for formatting of <b>$query</b><br>
189
	 *                                        or string - in this case it will be first argument for formatting of <b>$query</b>
190
	 * @param string          $param          if <b>$params</s> is string - this parameter will be second argument for formatting of <b>$query</b>.
191
	 *                                        If you need more arguments - add them after this one, function will accept them.
192
	 *
193
	 * @return false|object|resource
194
	 */
195
	function aq ($query, $params = [], $param = null) {
196
		$this->async = true;
197
		$result      = call_user_func_array([$this, 'q'], func_get_args());
198
		$this->async = false;
199
		return $result;
200
	}
201
	/**
202
	 * SQL request to DB
203
	 *
204
	 * @abstract
205
	 *
206
	 * @param string|string[] $query
207
	 *
208
	 * @return false|object|resource
209
	 */
210
	abstract protected function q_internal ($query);
211
	/**
212
	 * Multiple SQL request to DB
213
	 *
214
	 * @abstract
215
	 *
216
	 * @param string[] $query
217
	 *
218
	 * @return false|object|resource
219
	 */
220
	abstract protected function q_multi_internal ($query);
221
	/**
222
	 * Number
223
	 *
224
	 * Getting number of selected rows
225
	 *
226
	 * @abstract
227
	 *
228
	 * @param object|resource $query_result
229
	 *
230
	 * @return false|int
231
	 */
232
	abstract function n ($query_result);
233
	/**
234
	 * Fetch
235
	 *
236
	 * Fetch a result row as an associative array
237
	 *
238
	 * @abstract
239
	 *
240
	 * @param false|object|resource $query_result
241
	 * @param bool                  $single_column If <b>true</b> function will return not array with one element, but directly its value
242
	 * @param bool                  $array         If <b>true</b> returns array of associative arrays of all fetched rows
243
	 * @param bool                  $indexed       If <b>false</b> - associative array will be returned
244
	 *
245
	 * @return array[]|false|int|int[]|string|string[]
246
	 */
247
	abstract function f ($query_result, $single_column = false, $array = false, $indexed = false);
248
	/**
249
	 * Fetch, Array
250
	 *
251
	 * Similar to ::f() method, with parameter <b>$array</b> = true
252
	 *
253
	 * @param false|object|resource $query_result
254
	 * @param bool                  $single_column If <b>true</b> function will return not array with one element, but directly its value
255
	 * @param bool                  $indexed       If <b>false</b> - associative array will be returned
256
	 *
257
	 * @return array[]|false
0 ignored issues
show
Documentation introduced by
Should the return type not be array[]|false|integer|integer[]|string|string[]?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
258
	 */
259
	function fa ($query_result, $single_column = false, $indexed = false) {
260
		return $this->f($query_result, $single_column, true, $indexed);
261
	}
262
	/**
263
	 * Fetch, Single
264
	 *
265
	 * Similar to ::f() method, with parameter <b>$single_column</b> = true
266
	 *
267
	 * @param false|object|resource $query_result
268
	 * @param bool                  $array If <b>true</b> returns array of associative arrays of all fetched rows
269
	 *
270
	 * @return false|int|int[]|string|string[]
0 ignored issues
show
Documentation introduced by
Should the return type not be array[]|false|integer|integer[]|string|string[]?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
271
	 */
272
	function fs ($query_result, $array = false) {
273
		return $this->f($query_result, true, $array);
274
	}
275
	/**
276
	 * Fetch, Array, Single
277
	 *
278
	 * Combination of ::fa() and ::fs() methods
279
	 *
280
	 * @param false|object|resource $query_result
281
	 *
282
	 * @return false|int[]|string[]
0 ignored issues
show
Documentation introduced by
Should the return type not be array[]|false|integer|integer[]|string|string[]?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
283
	 */
284
	function fas ($query_result) {
285
		return $this->fa($query_result, true);
286
	}
287
	/**
288
	 * Query, Fetch
289
	 *
290
	 * Combination of ::q() and ::f() methods
291
	 *
292
	 * @param array|string $query         SQL query string, or you can put all parameters, that ::q() function can accept in form of array
293
	 * @param bool         $single_column If <b>true</b> function will return not array with one element, but directly its value
294
	 * @param bool         $array         If <b>true</b> returns array of associative arrays of all fetched rows
295
	 * @param bool         $indexed       If <b>false</b> - associative array will be returned
296
	 *
297
	 * @return array[]|false|int|int[]|string|string[]
298
	 */
299
	function qf ($query, $single_column = false, $array = false, $indexed = false) {
300
		list($query, $params) = $this->q_prepare($query);
301
		if (!$query) {
302
			return false;
303
		}
304
		return $this->f($this->q($query, $params), $single_column, $array, $indexed);
305
	}
306
	/**
307
	 * Query, Fetch, Array
308
	 *
309
	 * Combination of ::q() and ::fa() methods
310
	 *
311
	 * @param array|string $query         SQL query string, or you can put all parameters, that ::q() function can accept in form of array
312
	 * @param bool         $single_column If <b>true</b> function will return not array with one element, but directly its value
313
	 * @param bool         $indexed       If <b>false</b> - associative array will be returned
314
	 *
315
	 * @return array[]|false
0 ignored issues
show
Documentation introduced by
Should the return type not be false|array[]|integer|integer[]|string|string[]?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
316
	 */
317
	function qfa ($query, $single_column = false, $indexed = false) {
318
		list($query, $params) = $this->q_prepare($query);
319
		if (!$query) {
320
			return false;
321
		}
322
		return $this->fa($this->q($query, $params), $single_column, $indexed);
323
	}
324
	/**
325
	 * Query, Fetch, Single
326
	 *
327
	 * Combination of ::q() and ::fs() methods
328
	 *
329
	 * @param array|string $query SQL query string, or you can put all parameters, that ::q() function can accept in form of array
330
	 * @param bool         $array If <b>true</b> returns array of associative arrays of all fetched rows
331
	 *
332
	 * @return false|int|int[]|string|string[]
0 ignored issues
show
Documentation introduced by
Should the return type not be false|array[]|integer|integer[]|string|string[]?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
333
	 */
334
	function qfs ($query, $array = false) {
335
		list($query, $params) = $this->q_prepare($query);
336
		if (!$query) {
337
			return false;
338
		}
339
		return $this->fs($this->q($query, $params), $array);
340
	}
341
	/**
342
	 * Query, Fetch, Array, Single
343
	 *
344
	 * Combination of ::q() and ::fas() methods
345
	 *
346
	 * @param array|string $query SQL query string, or you can put all parameters, that ::q() function can accept in form of array
347
	 *
348
	 * @return false|int[]|string[]
0 ignored issues
show
Documentation introduced by
Should the return type not be false|array[]|integer|integer[]|string|string[]?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
349
	 */
350
	function qfas ($query) {
351
		list($query, $params) = $this->q_prepare($query);
352
		if (!$query) {
353
			return false;
354
		}
355
		return $this->fas($this->q($query, $params));
356
	}
357
	/**
358
	 * Query preparing for ::q*() methods
359
	 *
360
	 * @param array|string|string[] $query
361
	 *
362
	 * @return array|false [<b>$query</b>, <b>$params</b>]
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use false|array.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
363
	 */
364
	protected function q_prepare ($query) {
365
		if (!$query) {
366
			return false;
367
		}
368
		$params = [];
369
		if (is_array($query)) {
370
			if (count($query) == 2) {
371
				$params = $query[1];
372
			} elseif (count($query) > 2) {
373
				$params = array_slice($query, 1);
374
			}
375
			$query = $query[0];
376
		}
377
		return [
378
			$query,
379
			$params
380
		];
381
	}
382
	/**
383
	 * Method for simplified inserting of several rows
384
	 *
385
	 * @param string        $query
386
	 * @param array|array[] $params   Array of array of parameters for inserting
387
	 * @param bool          $join     If true - inserting of several rows will be combined in one query. For this, be sure, that your query has keyword
388
	 *                                <i>VALUES</i> in uppercase. Part of query after this keyword will be multiplied with coma separator.
389
	 *
390
	 * @return bool
391
	 */
392
	function insert ($query, $params, $join = true) {
393
		if (!$query || !$params) {
394
			return false;
395
		}
396
		if ($join) {
397
			$query    = explode('VALUES', $query, 2);
398
			$query[1] = explode(')', $query[1], 2);
399
			$query    = [
400
				$query[0],
401
				$query[1][0].')',
402
				$query[1][1]
403
			];
404
			if (!isset($query[1]) || !$query[1]) {
405
				return false;
406
			}
407
			$query[1] .= str_repeat(",$query[1]", count($params) - 1);
408
			$query = $query[0].'VALUES'.$query[1].$query[2];
409
			return (bool)$this->q(
410
				$query,
411
				call_user_func_array(
412
					'array_merge',
413
					array_map(
414
						'array_values',
415
						_array($params)
416
					)
417
				)
418
			);
419
		} else {
420
			$result = true;
421
			foreach ($params as $p) {
422
				$result = $result && (bool)$this->q($query, $p);
423
			}
424
			return $result;
425
		}
426
	}
427
	/**
428
	 * Id
429
	 *
430
	 * Get id of last inserted row
431
	 *
432
	 * @abstract
433
	 *
434
	 * @return int
435
	 */
436
	abstract function id ();
437
	/**
438
	 * Affected
439
	 *
440
	 * Get number of affected rows during last query
441
	 *
442
	 * @abstract
443
	 *
444
	 * @return int
445
	 */
446
	abstract function affected ();
447
	/**
448
	 * Free result memory
449
	 *
450
	 * @abstract
451
	 *
452
	 * @param object|resource $query_result
453
	 */
454
	abstract function free ($query_result);
455
	/**
456
	 * Get columns list of table
457
	 *
458
	 * @param string       $table
459
	 * @param false|string $like
460
	 *
461
	 * @return string[]
1 ignored issue
show
Documentation introduced by
Should the return type not be false|integer|string|array? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
462
	 */
463
	function columns ($table, $like = false) {
464
		if (!$table) {
465
			return false;
466
		}
467
		if ($like) {
468
			$like    = $this->s($like);
469
			$columns = $this->qfa("SHOW COLUMNS FROM `$table` LIKE $like") ?: [];
470
		} else {
471
			$columns = $this->qfa("SHOW COLUMNS FROM `$table`") ?: [];
472
		}
473
		foreach ($columns as &$column) {
1 ignored issue
show
Bug introduced by
The expression $columns of type integer|string|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
474
			$column = $column['Field'];
475
		}
476
		return $columns;
477
	}
478
	/**
479
	 * Get tables list
480
	 *
481
	 * @param false|string $like
482
	 *
483
	 * @return string[]
1 ignored issue
show
Documentation introduced by
Should the return type not be integer|string|array? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
484
	 */
485
	function tables ($like = false) {
486
		if ($like) {
487
			$like = $this->s($like);
488
			return $this->qfas("SHOW TABLES FROM `$this->database` LIKE $like") ?: [];
489
		} else {
490
			return $this->qfas("SHOW TABLES FROM `$this->database`") ?: [];
491
		}
492
	}
493
	/**
494
	 * Safe
495
	 *
496
	 * Preparing string for using in SQL query
497
	 * SQL Injection Protection
498
	 *
499
	 * @param string|string[] $string
500
	 * @param bool            $single_quotes_around
501
	 *
502
	 * @return string|string[]
503
	 */
504
	function s ($string, $single_quotes_around = true) {
505
		if (is_array($string)) {
506
			foreach ($string as &$s) {
507
				$s = $this->s_internal($s, $single_quotes_around);
508
			}
509
			return $string;
510
		}
511
		return $this->s_internal($string, $single_quotes_around);
512
	}
513
	/**
514
	 * Preparing string for using in SQL query
515
	 * SQL Injection Protection
516
	 *
517
	 * @param string $string
518
	 * @param bool   $single_quotes_around
519
	 *
520
	 * @return string
521
	 */
522
	abstract protected function s_internal ($string, $single_quotes_around);
523
	/**
524
	 * Get information about server
525
	 *
526
	 * @return string
527
	 */
528
	abstract function server ();
529
	/**
530
	 * Connection state
531
	 *
532
	 * @return bool
533
	 */
534
	function connected () {
535
		return $this->connected;
536
	}
537
	/**
538
	 * Database type (lowercase, for example <i>mysql</i>)
539
	 *
540
	 * @return string
541
	 */
542
	function db_type () {
543
		return $this->db_type;
544
	}
545
	/**
546
	 * Database name
547
	 *
548
	 * @return string
549
	 */
550
	function database () {
551
		return $this->database;
552
	}
553
	/**
554
	 * Queries array, has 3 properties:<ul>
555
	 * <li>num - total number of performed queries
556
	 * <li>time - array with time of each query execution
557
	 * <li>text - array with text text of each query
558
	 *
559
	 * @return array
560
	 */
561
	function queries () {
562
		return $this->queries;
563
	}
564
	/**
565
	 * Last query information, has 2 properties:<ul>
566
	 * <li>time - execution time
567
	 * <li>text - query text
568
	 *
569
	 * @return array
570
	 */
571
	function query () {
572
		return $this->query;
573
	}
574
	/**
575
	 * Total working time (including connection, queries execution and other delays)
576
	 *
577
	 * @return int
578
	 */
579
	function time () {
580
		return $this->time;
581
	}
582
	/**
583
	 * Connecting time
584
	 *
585
	 * @return float
586
	 */
587
	function connecting_time () {
588
		return $this->connecting_time;
589
	}
590
	/**
591
	 * Cloning restriction
592
	 *
593
	 * @final
594
	 */
595
	final function __clone () {
596
	}
597
	/**
598
	 * Disconnecting from DB
599
	 */
600
	abstract function __destruct ();
601
}
602