Passed
Push — master ( d58dcf...ca13dd )
by Joe
02:54
created

Generic   F

Complexity

Total Complexity 61

Size/Duplication

Total Lines 289
Duplicated Lines 0 %

Test Coverage

Coverage 22.22%

Importance

Changes 0
Metric Value
eloc 107
dl 0
loc 289
ccs 22
cts 99
cp 0.2222
rs 3.52
c 0
b 0
f 0
wmc 61

17 Methods

Rating   Name   Duplication   Size   Complexity  
A toTimestamp() 0 2 1
A haltmsg() 0 7 3
A halt() 0 15 5
A indexNames() 0 2 1
A fromTimestamp() 0 14 6
A dbAddslashes() 0 5 3
D logBackTrace() 0 22 21
A queryId() 0 2 1
A real_escape() 0 4 4
A escape() 0 2 1
A f() 0 5 4
A log() 0 5 1
A limit() 0 8 2
A linkId() 0 2 1
A __construct() 0 8 2
A qr() 0 2 1
A limitQuery() 0 13 4

How to fix   Complexity   

Complex Class

Complex classes like Generic often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Generic, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Generic SQL Driver Related Functionality
4
 * @author Joe Huss <[email protected]>
5
 * @copyright 2018
6
 * @package MyAdmin
7
 * @category SQL
8
 */
9
10
namespace MyDb;
11
12
/**
13
 * Class Generic
14
 */
15
abstract class Generic {
16
	/* public: connection parameters */
17
	public $host = 'localhost';
18
	public $database = '';
19
	public $user = '';
20
	public $password = '';
21
22
	/* public: configuration parameters */
23
	public $autoStripslashes = false;
24
	public $Debug = 0; // Set to 1 for debugging messages.
25
	public $haltOnError = 'yes'; // "yes" (halt with message), "no" (ignore errors quietly), "report" (ignore error, but spit a warning)
26
27
	public $maxConnectErrors = 30;
28
	public $connectionAttempt = 0;
29
	public $maxMatches = 10000000;
30
31
	/**
32
	 * @var int
33
	 */
34
	public $autoFree = 0; // Set to 1 for automatic mysql_free_result()
35
36
	/* public: result array and current row number */
37
	public $Record = [];
38
	public $Row;
39
40
	/* public: current error number and error text */
41
	public $Errno = 0;
42
	public $Error = '';
43
44
	/* public: this is an api revision, not a CVS revision. */
45
	public $type = 'generic';
46
47
	/* private: link and query handles */
48
	public $linkId = 0;
49
	public $queryId = 0;
50
51
	public $characterSet = 'utf8mb4';
52
	public $collation = 'utf8mb4_unicode_ci';
53
54
	/**
55
	 * Constructs the db handler, can optionally specify connection parameters
56
	 *
57
	 * @param string $database Optional The database name
58
	 * @param string $user Optional The username to connect with
59
	 * @param string $password Optional The password to use
60
	 * @param string $host Optional The hostname where the server is, or default to localhost
61
	 * @param string $query Optional query to perform immediately
62
	 */
63
	public function __construct($database = '', $user = '', $password = '', $host = 'localhost', $query = '') {
64
		$this->database = $database;
65
		$this->user = $user;
66
		$this->password = $password;
67
		$this->host = $host;
68
		if ($query != '')
69
			$this->query($query);
0 ignored issues
show
Bug introduced by
The method query() does not exist on MyDb\Generic. Did you maybe mean queryId()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

69
			$this->/** @scrutinizer ignore-call */ 
70
          query($query);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
70
		$this->connection_atttempt = 0;
0 ignored issues
show
Bug Best Practice introduced by
The property connection_atttempt does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
71
	}
72
73
	/**
74
	 * @param string $message
75
	 * @param string $line
76
	 * @param string $file
77
	 * @return void
78
	 */
79
	public function log($message, $line = '', $file = '', $level = 'info') {
0 ignored issues
show
Unused Code introduced by
The parameter $file is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

79
	public function log($message, $line = '', /** @scrutinizer ignore-unused */ $file = '', $level = 'info') {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $line is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

79
	public function log($message, /** @scrutinizer ignore-unused */ $line = '', $file = '', $level = 'info') {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $level is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

79
	public function log($message, $line = '', $file = '', /** @scrutinizer ignore-unused */ $level = 'info') {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
80
		//if (function_exists('myadmin_log'))
81
			//myadmin_log('db', $level, $message, $line, $file, isset($GLOBALS['tf']));
82
		//else
83
			error_log($message);
84
	}
85
86
	/**
87
	 * @return int
88
	 */
89 1
	public function linkId() {
90 1
		return $this->linkId;
91
	}
92
93
	/**
94
	 * @return int
95
	 */
96 1
	public function queryId() {
97 1
		return $this->queryId;
98
	}
99
100
	/**
101
	 * @param $string
102
	 * @return string
103
	 */
104
	public function real_escape($string) {
105
		if ((!is_resource($this->linkId) || $this->linkId == 0) && !$this->connect())
0 ignored issues
show
introduced by
The condition is_resource($this->linkId) is always false.
Loading history...
Bug introduced by
The method connect() does not exist on MyDb\Generic. Since it exists in all sub-types, consider adding an abstract or default implementation to MyDb\Generic. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

105
		if ((!is_resource($this->linkId) || $this->linkId == 0) && !$this->/** @scrutinizer ignore-call */ connect())
Loading history...
106
			return mysqli_escape_string($string);
0 ignored issues
show
Bug introduced by
The call to mysqli_escape_string() has too few arguments starting with query. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

106
			return /** @scrutinizer ignore-call */ mysqli_escape_string($string);

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
107
		return mysqli_real_escape_string($this->linkId, $string);
0 ignored issues
show
Bug introduced by
$this->linkId of type resource|integer is incompatible with the type mysqli expected by parameter $link of mysqli_real_escape_string(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

107
		return mysqli_real_escape_string(/** @scrutinizer ignore-type */ $this->linkId, $string);
Loading history...
108
	}
109
110
	/**
111
	 * @param $string
112
	 * @return string
113
	 */
114
	public function escape($string) {
115
		return mysql_escape_string($string);
0 ignored issues
show
Deprecated Code introduced by
The function mysql_escape_string() has been deprecated: 5.3.0 Use mysql_real_escape_string() instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

115
		return /** @scrutinizer ignore-deprecated */ mysql_escape_string($string);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
116
	}
117
118
	/**
119
	 * @param mixed $str
120
	 * @return string
121
	 */
122
	public function dbAddslashes($str) {
123
		if (!isset($str) || $str == '')
124
			return '';
125
126
		return addslashes($str);
127
	}
128
129
	/**
130
	 * Db::toTimestamp()
131
	 * @param mixed $epoch
132
	 * @return bool|string
133
	 */
134 1
	public function toTimestamp($epoch) {
135 1
		return date('Y-m-d H:i:s', $epoch);
136
	}
137
138
	/**
139
	 * Db::fromTimestamp()
140
	 * @param mixed $timestamp
141
	 * @return bool|int|mixed
142
	 */
143 1
	public function fromTimestamp($timestamp) {
144 1
		if (preg_match('/([0-9]{4})-([0-9]{2})-([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2})/', $timestamp, $parts))
145 1
			$time = mktime($parts[4], $parts[5], $parts[6], $parts[2], $parts[3], $parts[1]);
146
		elseif (preg_match('/([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})/', $timestamp, $parts))
147
			$time = mktime($parts[4], $parts[5], $parts[6], $parts[2], $parts[3], $parts[1]);
148
		elseif (preg_match('/([0-9]{4})([0-9]{2})([0-9]{2})/', $timestamp, $parts))
149
			$time = mktime(1, 1, 1, $parts[2], $parts[3], $parts[1]);
150
		elseif (is_numeric($timestamp) && $timestamp >= 943938000)
151
			$time = $timestamp;
152
		else {
153
			$this->log('Cannot Match Timestamp from '.$timestamp, __LINE__, __FILE__);
154
			$time = false;
155
		}
156 1
		return $time;
157
	}
158
159
	/**
160
	 * @param int $start
161
	 * @return string
162
	 */
163
	public function limit($start = 0) {
164
		echo '<b>Warning: limit() is no longer used, use limitQuery()</b>';
165
		if ($start == 0) {
166
			$s = 'limit '.(int) $this->maxMatches;
167
		} else {
168
			$s = 'limit '.(int) $start.','.(int) $this->maxMatches;
169
		}
170
		return $s;
171
	}
172
173
	/**
174
	 * perform a query with limited result set
175
	 *
176
	 * @param string $queryString
177
	 * @param int $offset
178
	 * @param string|int $numRows
179
	 * @param string|int $line
180
	 * @param string $file
181
	 * @return mixed
182
	 */
183 1
	public function limitQuery($queryString, $numRows = '', $offset = 0, $line = '', $file = '') {
184 1
		if (!$numRows)
185
			$numRows = $this->maxMatches;
186 1
		if ($offset == 0) {
187 1
			$queryString .= ' LIMIT '.(int) $numRows;
188
		} else {
189 1
			$queryString .= ' LIMIT '.(int) $offset.','.(int) $numRows;
190
		}
191
192 1
		if ($this->Debug)
193
			printf("Debug: limitQuery = %s<br>offset=%d, num_rows=%d<br>\n", $queryString, $offset, $numRows);
194
195 1
		return $this->query($queryString, $line, $file);
196
	}
197
198
	/**
199
	 * db:qr()
200
	 *
201
	 *  alias of queryReturn()
202
	 *
203
	 * @param mixed $query SQL Query to be used
204
	 * @param string $line optionally pass __LINE__ calling the query for logging
205
	 * @param string $file optionally pass __FILE__ calling the query for logging
206
	 * @return mixed FALSE if no rows, if a single row it returns that, if multiple it returns an array of rows, associative responses only
207
	 */
208
	public function qr($query, $line = '', $file = '') {
209
		return $this->queryReturn($query, $line, $file);
0 ignored issues
show
Bug introduced by
The method queryReturn() does not exist on MyDb\Generic. Since it exists in all sub-types, consider adding an abstract or default implementation to MyDb\Generic. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

209
		return $this->/** @scrutinizer ignore-call */ queryReturn($query, $line, $file);
Loading history...
210
	}
211
212
	/**
213
	 * gets a field
214
	 *
215
	 * @param mixed  $name
216
	 * @param string $stripSlashes
217
	 * @return string
218
	 */
219 1
	public function f($name, $stripSlashes = '') {
220 1
		if ($stripSlashes || ($this->autoStripslashes && !$stripSlashes)) {
221
			return stripslashes($this->Record[$name]);
222
		} else {
223 1
			return $this->Record[$name];
224
		}
225
	}
226
227
	/**
228
	 * error handling
229
	 *
230
	 * @param mixed $msg
231
	 * @param string $line
232
	 * @param string $file
233
	 * @return void
234
	 */
235
	public function halt($msg, $line = '', $file = '') {
236
		$this->unlock(false);
0 ignored issues
show
Bug introduced by
The method unlock() does not exist on MyDb\Generic. Since it exists in all sub-types, consider adding an abstract or default implementation to MyDb\Generic. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

236
		$this->/** @scrutinizer ignore-call */ 
237
         unlock(false);
Loading history...
237
		/* Just in case there is a table currently locked */
238
239
		//$this->Error = @$this->linkId->error;
240
		//$this->Errno = @$this->linkId->errno;
241
		if ($this->haltOnError == 'no')
242
			return;
243
		if ($msg != '')
244
			$this->haltmsg($msg, $line, $file);
245
		if ($this->haltOnError != 'report') {
246
			echo '<p><b>Session halted.</b>';
247
			// FIXME! Add check for error levels
248
			if (isset($GLOBALS['tf']))
249
				$GLOBALS['tf']->terminate();
250
		}
251
	}
252
253
	/**
254
	 * @param mixed $msg
255
	 * @param string $line
256
	 * @param string $file
257
	 * @return mixed|void
258
	 */
259
	public function logBackTrace($msg, $line = '', $file = '') {
0 ignored issues
show
Unused Code introduced by
The parameter $msg is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

259
	public function logBackTrace(/** @scrutinizer ignore-unused */ $msg, $line = '', $file = '') {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
260
		$backtrace = (function_exists('debug_backtrace') ? debug_backtrace() : []);
261
		$this->log(
262
			('' !== getenv('REQUEST_URI') ? ' '.getenv('REQUEST_URI') : '').
263
			((isset($_POST) && count($_POST)) ? ' POST='.json_encode($_POST) : '').
264
			((isset($_GET) && count($_GET)) ? ' GET='.json_encode($_GET) : '').
265
			((isset($_FILES) && count($_FILES)) ? ' FILES='.json_encode($_FILES) : '').
266
			('' !== getenv('HTTP_USER_AGENT') ? ' AGENT="'.getenv('HTTP_USER_AGENT').'"' : '').
267
			(isset($_SERVER['REQUEST_METHOD']) ? ' METHOD="'.$_SERVER['REQUEST_METHOD'].'"'.
268
				($_SERVER['REQUEST_METHOD'] === 'POST' ? ' POST="'.json_encode($_POST).'"' : '') : ''), $line, $file, 'error');
269
		for ($level = 1, $levelMax = count($backtrace); $level < $levelMax; $level++) {
270
			$message = (isset($backtrace[$level]['file']) ? 'File: '.$backtrace[$level]['file'] : '').
271
				(isset($backtrace[$level]['line']) ? ' Line: '.$backtrace[$level]['line'] : '').
272
				' Function: '.(isset($backtrace[$level] ['class']) ? '(class '.$backtrace[$level] ['class'].') ' : '').
273
				(isset($backtrace[$level] ['type']) ? $backtrace[$level] ['type'].' ' : '').
274
				$backtrace[$level] ['function'].'(';
275
			if (isset($backtrace[$level] ['args']))
276
				for ($argument = 0, $argumentMax = count($backtrace[$level]['args']); $argument < $argumentMax; $argument++)
277
					$message .= ($argument > 0 ? ', ' : '').
278
						(is_object($backtrace[$level]['args'][$argument]) ? 'class '.get_class($backtrace[$level]['args'][$argument]) : json_encode($backtrace[$level]['args'][$argument]));
279
			$message .= ')';
280
			$this->log($message, $line, $file, 'error');
281
		}
282
	}
283
284
	/**
285
	 * @param mixed $msg
286
	 * @param string $line
287
	 * @param string $file
288
	 * @return mixed|void
289
	 */
290
	public function haltmsg($msg, $line = '', $file = '') {
291
		$this->log("Database error: $msg", $line, $file, 'error');
292
		if ($this->Errno != '0' || !in_array($this->Error, '', '()')) {
0 ignored issues
show
Bug introduced by
'' of type string is incompatible with the type array expected by parameter $haystack of in_array(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

292
		if ($this->Errno != '0' || !in_array($this->Error, /** @scrutinizer ignore-type */ '', '()')) {
Loading history...
Bug introduced by
'()' of type string is incompatible with the type boolean expected by parameter $strict of in_array(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

292
		if ($this->Errno != '0' || !in_array($this->Error, '', /** @scrutinizer ignore-type */ '()')) {
Loading history...
293
			$sqlstate = mysqli_sqlstate($this->linkId);
0 ignored issues
show
Bug introduced by
$this->linkId of type integer is incompatible with the type mysqli expected by parameter $link of mysqli_sqlstate(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

293
			$sqlstate = mysqli_sqlstate(/** @scrutinizer ignore-type */ $this->linkId);
Loading history...
294
			$this->log("MySQLi SQLState: {$sqlstate}. Error: ".$this->Errno.' ('.$this->Error.')', $line, $file, 'error');
295
		}
296
		$this->logBackTrace($msg, $line, $file);
297
	}
298
299
	/**
300
	 * @return array
301
	 */
302 1
	public function indexNames() {
303 1
		return [];
304
	}
305
306
}
307