Passed
Push — master ( 035583...5ce7cd )
by Joe
06:11 queued 03:16
created

Generic::qr()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 3
dl 0
loc 2
ccs 0
cts 2
cp 0
crap 2
rs 10
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 2
	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 2
			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
	 * perform a query with limited result set
164
	 *
165
	 * @param string $queryString
166
	 * @param string|int $numRows
167
	 * @param int $offset
168
	 * @param string|int $line
169
	 * @param string $file
170
	 * @return mixed
171
	 */
172 1
	public function limitQuery($queryString, $numRows = '', $offset = 0, $line = '', $file = '') {
173 1
		if (!$numRows)
174
			$numRows = $this->maxMatches;
175 1
		if ($offset == 0) {
176 1
			$queryString .= ' LIMIT '.(int) $numRows;
177
		} else {
178 1
			$queryString .= ' LIMIT '.(int) $offset.','.(int) $numRows;
179
		}
180
181 1
		if ($this->Debug)
182
			printf("Debug: limitQuery = %s<br>offset=%d, num_rows=%d<br>\n", $queryString, $offset, $numRows);
183
184 1
		return $this->query($queryString, $line, $file);
185
	}
186
187
	/**
188
	 * db:qr()
189
	 *
190
	 *  alias of queryReturn()
191
	 *
192
	 * @param mixed $query SQL Query to be used
193
	 * @param string $line optionally pass __LINE__ calling the query for logging
194
	 * @param string $file optionally pass __FILE__ calling the query for logging
195
	 * @return mixed FALSE if no rows, if a single row it returns that, if multiple it returns an array of rows, associative responses only
196
	 */
197
	public function qr($query, $line = '', $file = '') {
198
		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

198
		return $this->/** @scrutinizer ignore-call */ queryReturn($query, $line, $file);
Loading history...
199
	}
200
201
	/**
202
	 * gets a field
203
	 *
204
	 * @param mixed  $name
205
	 * @param string $stripSlashes
206
	 * @return string
207
	 */
208 2
	public function f($name, $stripSlashes = '') {
209 2
		if ($stripSlashes || ($this->autoStripslashes && !$stripSlashes)) {
210
			return stripslashes($this->Record[$name]);
211
		} else {
212 2
			return $this->Record[$name];
213
		}
214
	}
215
216
	/**
217
	 * error handling
218
	 *
219
	 * @param mixed $msg
220
	 * @param string $line
221
	 * @param string $file
222
	 * @return void
223
	 */
224 1
	public function halt($msg, $line = '', $file = '') {
225 1
		$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

225
		$this->/** @scrutinizer ignore-call */ 
226
         unlock(false);
Loading history...
226
		/* Just in case there is a table currently locked */
227
228
		//$this->Error = @$this->linkId->error;
229
		//$this->Errno = @$this->linkId->errno;
230 1
		if ($this->haltOnError == 'no')
231
			return true;
232 1
		if ($msg != '')
233 1
			$this->haltmsg($msg, $line, $file);
234 1
		if ($this->haltOnError != 'report') {
235 1
			echo '<p><b>Session halted.</b>';
236
			// FIXME! Add check for error levels
237 1
			if (isset($GLOBALS['tf']))
238
				$GLOBALS['tf']->terminate();
239
		}
240 1
		return true;
241
	}
242
243
	/**
244
	 * @param mixed $msg
245
	 * @param string $line
246
	 * @param string $file
247
	 * @return mixed|void
248
	 */
249 2
	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

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

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