Completed
Push — master ( a6bfe9...c42bcf )
by Joe
10:58 queued 07:09
created

Generic::limitQuery()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 4.1755

Importance

Changes 0
Metric Value
cc 4
eloc 9
nc 8
nop 5
dl 0
loc 13
ccs 7
cts 9
cp 0.7778
crap 4.1755
rs 9.9666
c 0
b 0
f 0
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
	/**
48
	 * @var int|object
49
	 */
50
	public $linkId = 0;
51
	public $queryId = 0;
52
53
	public $characterSet = 'utf8mb4';
54
	public $collation = 'utf8mb4_unicode_ci';
55
56
	/**
57
	 * Constructs the db handler, can optionally specify connection parameters
58
	 *
59
	 * @param string $database Optional The database name
60
	 * @param string $user Optional The username to connect with
61
	 * @param string $password Optional The password to use
62
	 * @param string $host Optional The hostname where the server is, or default to localhost
63
	 * @param string $query Optional query to perform immediately
64
	 */
65 1
	public function __construct($database = '', $user = '', $password = '', $host = 'localhost', $query = '') {
66 1
		$this->database = $database;
67 1
		$this->user = $user;
68 1
		$this->password = $password;
69 1
		$this->host = $host;
70 1
		if ($query != '')
71
			$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

71
			$this->/** @scrutinizer ignore-call */ 
72
          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...
72 1
		$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...
73
	}
74
75
	/**
76
	 * @param string $message
77
	 * @param string $line
78
	 * @param string $file
79
	 * @return void
80
	 */
81
	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

81
	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

81
	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

81
	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...
82
		//if (function_exists('myadmin_log'))
83
			//myadmin_log('db', $level, $message, $line, $file, isset($GLOBALS['tf']));
84
		//else
85
			error_log($message);
86
	}
87
88
	/**
89
	 * @return int|object
90
	 */
91 2
	public function linkId() {
92 2
		return $this->linkId;
93
	}
94
95
	/**
96
	 * @return int|object
97
	 */
98 1
	public function queryId() {
99 1
		return $this->queryId;
100
	}
101
102
	/**
103
	 * @param $string
104
	 * @return string
105
	 */
106 1
	public function real_escape($string = '') {
107 1
		if ((!is_resource($this->linkId) || $this->linkId == 0) && !$this->connect())
0 ignored issues
show
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

107
		if ((!is_resource($this->linkId) || $this->linkId == 0) && !$this->/** @scrutinizer ignore-call */ connect())
Loading history...
introduced by
The condition is_resource($this->linkId) is always false.
Loading history...
108 1
			return $this->escape($string);
109
		return mysqli_real_escape_string($this->linkId, $string);
0 ignored issues
show
Bug introduced by
It seems like $this->linkId can also be of type resource and integer; however, parameter $link of mysqli_real_escape_string() does only seem to accept mysqli, maybe add an additional type check? ( Ignorable by Annotation )

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

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

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

212
		return $this->/** @scrutinizer ignore-call */ queryReturn($query, $line, $file);
Loading history...
213
	}
214
215
	/**
216
	 * gets a field
217
	 *
218
	 * @param mixed  $name
219
	 * @param string $stripSlashes
220
	 * @return string
221
	 */
222 2
	public function f($name, $stripSlashes = '') {
223 2
		if ($stripSlashes || ($this->autoStripslashes && !$stripSlashes)) {
224
			return stripslashes($this->Record[$name]);
225
		} else {
226 2
			return $this->Record[$name];
227
		}
228
	}
229
230
	/**
231
	 * error handling
232
	 *
233
	 * @param mixed $msg
234
	 * @param string $line
235
	 * @param string $file
236
	 * @return void
237
	 */
238
	public function halt($msg, $line = '', $file = '') {
239
		$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

239
		$this->/** @scrutinizer ignore-call */ 
240
         unlock(false);
Loading history...
240
		/* Just in case there is a table currently locked */
241
242
		//$this->Error = @$this->linkId->error;
243
		//$this->Errno = @$this->linkId->errno;
244
		if ($this->haltOnError == 'no')
245
			return;
246
		if ($msg != '')
247
			$this->haltmsg($msg, $line, $file);
248
		if ($this->haltOnError != 'report') {
249
			echo '<p><b>Session halted.</b>';
250
			// FIXME! Add check for error levels
251
			if (isset($GLOBALS['tf']))
252
				$GLOBALS['tf']->terminate();
253
		}
254
	}
255
256
	/**
257
	 * @param mixed $msg
258
	 * @param string $line
259
	 * @param string $file
260
	 * @return mixed|void
261
	 */
262
	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

262
	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...
263
		$backtrace = (function_exists('debug_backtrace') ? debug_backtrace() : []);
264
		$this->log(
265
			('' !== getenv('REQUEST_URI') ? ' '.getenv('REQUEST_URI') : '').
266
			((isset($_POST) && count($_POST)) ? ' POST='.json_encode($_POST) : '').
267
			((isset($_GET) && count($_GET)) ? ' GET='.json_encode($_GET) : '').
268
			((isset($_FILES) && count($_FILES)) ? ' FILES='.json_encode($_FILES) : '').
269
			('' !== getenv('HTTP_USER_AGENT') ? ' AGENT="'.getenv('HTTP_USER_AGENT').'"' : '').
270
			(isset($_SERVER['REQUEST_METHOD']) ? ' METHOD="'.$_SERVER['REQUEST_METHOD'].'"'.
271
				($_SERVER['REQUEST_METHOD'] === 'POST' ? ' POST="'.json_encode($_POST).'"' : '') : ''), $line, $file, 'error');
272
		for ($level = 1, $levelMax = count($backtrace); $level < $levelMax; $level++) {
273
			$message = (isset($backtrace[$level]['file']) ? 'File: '.$backtrace[$level]['file'] : '').
274
				(isset($backtrace[$level]['line']) ? ' Line: '.$backtrace[$level]['line'] : '').
275
				' Function: '.(isset($backtrace[$level] ['class']) ? '(class '.$backtrace[$level] ['class'].') ' : '').
276
				(isset($backtrace[$level] ['type']) ? $backtrace[$level] ['type'].' ' : '').
277
				$backtrace[$level] ['function'].'(';
278
			if (isset($backtrace[$level] ['args']))
279
				for ($argument = 0, $argumentMax = count($backtrace[$level]['args']); $argument < $argumentMax; $argument++)
280
					$message .= ($argument > 0 ? ', ' : '').
281
						(is_object($backtrace[$level]['args'][$argument]) ? 'class '.get_class($backtrace[$level]['args'][$argument]) : json_encode($backtrace[$level]['args'][$argument]));
282
			$message .= ')';
283
			$this->log($message, $line, $file, 'error');
284
		}
285
	}
286
287
	public function emailError($queryString, $error, $line, $file) {
288
		$email = $this->type." Error<br>\n".'Query: '.$queryString."<br>\n".$error."<br>\n".'Line: '.$line."<br>\n".'File: '.$file."<br>\n".(isset($GLOBALS['tf']) ? 'User: '.$GLOBALS['tf']->session->account_id."<br>\n" : '');
289
		$email .= '<br><br>Request Variables:<br>'.print_r($_REQUEST, true);
290
		$email .= '<br><br>Server Variables:<br>'.print_r($_SERVER, true);
291
		$subject = php_uname('n').' MySQLi Error';
292
		$headers = '';
293
		$headers .= 'MIME-Version: 1.0'.PHP_EOL;
294
		$headers .= 'Content-type: text/html; charset=UTF-8'.PHP_EOL;
295
		$headers .= 'From: No-Reply <[email protected]>'.PHP_EOL;
296
		$headers .= 'X-Mailer: Trouble-Free.Net Admin Center'.PHP_EOL;
297
		mail('[email protected]', $subject, $email, $headers);
298
		mail('[email protected]', $subject, $email, $headers);
299
		$this->haltmsg('Invalid SQL: '.$queryString, $line, $file);
300
		
301
	}
302
	
303
	/**
304
	 * @param mixed $msg
305
	 * @param string $line
306
	 * @param string $file
307
	 * @return mixed|void
308
	 */
309
	public function haltmsg($msg, $line = '', $file = '') {
310
		$this->log("Database error: $msg", $line, $file, 'error');
311
		if ($this->Errno != '0' || !in_array($this->Error, '', '()')) {
0 ignored issues
show
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

311
		if ($this->Errno != '0' || !in_array($this->Error, '', /** @scrutinizer ignore-type */ '()')) {
Loading history...
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

311
		if ($this->Errno != '0' || !in_array($this->Error, /** @scrutinizer ignore-type */ '', '()')) {
Loading history...
312
			$sqlstate = mysqli_sqlstate($this->linkId);
0 ignored issues
show
Bug introduced by
It seems like $this->linkId can also be of type integer; however, parameter $link of mysqli_sqlstate() does only seem to accept mysqli, maybe add an additional type check? ( Ignorable by Annotation )

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

312
			$sqlstate = mysqli_sqlstate(/** @scrutinizer ignore-type */ $this->linkId);
Loading history...
313
			$this->log("MySQLi SQLState: {$sqlstate}. Error: ".$this->Errno.' ('.$this->Error.')', $line, $file, 'error');
314
		}
315
		$this->logBackTrace($msg, $line, $file);
316
	}
317
318
	/**
319
	 * @return array
320
	 */
321 1
	public function indexNames() {
322 1
		return [];
323
	}
324
325
}
326