Completed
Push — master ( 234725...26c785 )
by Joe
06:12
created

Generic::log()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 4
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
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 2019
6
 * @package MyAdmin
7
 * @category SQL
8
 */
9
10
namespace MyDb;
11
12
/**
13
 * Class Generic
14
 */
15
abstract class Generic
16
{
17
	/* public: connection parameters */
18
	public $host = 'localhost';
19
	public $database = '';
20
	public $user = '';
21
	public $password = '';
22
23
	/* public: configuration parameters */
24
	public $autoStripslashes = false;
25
	public $Debug = 0; // Set to 1 for debugging messages.
26
	public $haltOnError = 'yes'; // "yes" (halt with message), "no" (ignore errors quietly), "report" (ignore error, but spit a warning)
27
28
	public $maxConnectErrors = 30;
29
	public $connectionAttempt = 0;
30
	public $maxMatches = 10000000;
31
32
	/**
33
	 * @var int
34
	 */
35
	public $autoFree = 0; // Set to 1 for automatic mysql_free_result()
36
37
	/* public: result array and current row number */
38
	public $Record = [];
39
	public $Row;
40
41
	/* public: current error number and error text */
42
	public $Errno = 0;
43
	public $Error = '';
44
45
	/* public: this is an api revision, not a CVS revision. */
46
	public $type = 'generic';
47
48
	/**
49
	 * @var int|object
50
	 */
51
	public $linkId = 0;
52
	public $queryId = 0;
53
54
	public $characterSet = 'utf8mb4';
55
	public $collation = 'utf8mb4_unicode_ci';
56
57
	/**
58
	 * Constructs the db handler, can optionally specify connection parameters
59
	 *
60
	 * @param string $database Optional The database name
61
	 * @param string $user Optional The username to connect with
62
	 * @param string $password Optional The password to use
63
	 * @param string $host Optional The hostname where the server is, or default to localhost
64
	 * @param string $query Optional query to perform immediately
65
	 */
66 1
	public function __construct($database = '', $user = '', $password = '', $host = 'localhost', $query = '')
67
	{
68 1
		$this->database = $database;
69 1
		$this->user = $user;
70 1
		$this->password = $password;
71 1
		$this->host = $host;
72 1
		if ($query != '') {
73
			$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

73
			$this->/** @scrutinizer ignore-call */ 
74
          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...
74
		}
75 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...
76
	}
77
78
	/**
79
	 * @param string $message
80
	 * @param string $line
81
	 * @param string $file
82
	 * @return void
83
	 */
84 2
	public function log($message, $line = '', $file = '', $level = 'info')
0 ignored issues
show
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

84
	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

84
	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...
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

84
	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...
85
	{
86 2
		error_log($message);
87
	}
88
89
	/**
90
	 * @return int|object
91
	 */
92 2
	public function linkId()
93
	{
94 2
		return $this->linkId;
95
	}
96
97
	/**
98
	 * @return int|object
99
	 */
100 1
	public function queryId()
101
	{
102 1
		return $this->queryId;
103
	}
104
105
	/**
106
	 * @param $string
107
	 * @return string
108
	 */
109 1
	public function real_escape($string = '')
110
	{
111 1
		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

111
		if ((!is_resource($this->linkId) || $this->linkId == 0) && !$this->/** @scrutinizer ignore-call */ connect()) {
Loading history...
112 1
			return $this->escape($string);
113
		}
114
		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 integer and resource; 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

114
		return mysqli_real_escape_string(/** @scrutinizer ignore-type */ $this->linkId, $string);
Loading history...
115
	}
116
117
	/**
118
	 * @param $string
119
	 * @return string
120
	 */
121 4
	public function escape($string = '')
122
	{
123
		//if (function_exists('mysql_escape_string'))
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

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.

Loading history...
124
		//return mysql_escape_string($string);
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

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.

Loading history...
125 4
		return str_replace(array('\\', "\0", "\n", "\r", "'", '"', "\x1a"), array('\\\\', '\\0', '\\n', '\\r', "\\'", '\\"', '\\Z'), $string);
126
	}
127
128
	/**
129
	 * @param mixed $str
130
	 * @return string
131
	 */
132 3
	public function dbAddslashes($str = '')
133
	{
134 3
		if (!isset($str) || $str == '') {
135 3
			return '';
136
		}
137 3
		return addslashes($str);
138
	}
139
140
	/**
141
	 * Db::toTimestamp()
142
	 * @param mixed $epoch
143
	 * @return bool|string
144
	 */
145 2
	public function toTimestamp($epoch)
146
	{
147 2
		return date('Y-m-d H:i:s', $epoch);
148
	}
149
150
	/**
151
	 * Db::fromTimestamp()
152
	 * @param mixed $timestamp
153
	 * @return bool|int|mixed
154
	 */
155 2
	public function fromTimestamp($timestamp)
156
	{
157 2
		if (preg_match('/([0-9]{4})-([0-9]{2})-([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2})/', $timestamp, $parts)) {
158 2
			$time = mktime($parts[4], $parts[5], $parts[6], $parts[2], $parts[3], $parts[1]);
159
		} elseif (preg_match('/([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})/', $timestamp, $parts)) {
160
			$time = mktime($parts[4], $parts[5], $parts[6], $parts[2], $parts[3], $parts[1]);
161
		} elseif (preg_match('/([0-9]{4})([0-9]{2})([0-9]{2})/', $timestamp, $parts)) {
162
			$time = mktime(1, 1, 1, $parts[2], $parts[3], $parts[1]);
163
		} elseif (is_numeric($timestamp) && $timestamp >= 943938000) {
164
			$time = $timestamp;
165
		} else {
166
			$this->log('Cannot Match Timestamp from '.$timestamp, __LINE__, __FILE__);
167
			$time = false;
168
		}
169 2
		return $time;
170
	}
171
172
	/**
173
	 * perform a query with limited result set
174
	 *
175
	 * @param string $queryString
176
	 * @param string|int $numRows
177
	 * @param int $offset
178
	 * @param string|int $line
179
	 * @param string $file
180
	 * @return mixed
181
	 */
182 1
	public function limitQuery($queryString, $numRows = '', $offset = 0, $line = '', $file = '')
183
	{
184 1
		if (!$numRows) {
185
			$numRows = $this->maxMatches;
186
		}
187 1
		if ($offset == 0) {
188 1
			$queryString .= ' LIMIT '.(int) $numRows;
189
		} else {
190 1
			$queryString .= ' LIMIT '.(int) $offset.','.(int) $numRows;
191
		}
192
193 1
		if ($this->Debug) {
194
			printf("Debug: limitQuery = %s<br>offset=%d, num_rows=%d<br>\n", $queryString, $offset, $numRows);
195
		}
196
197 1
		return $this->query($queryString, $line, $file);
198
	}
199
200
	/**
201
	 * db:qr()
202
	 *
203
	 *  alias of queryReturn()
204
	 *
205
	 * @param mixed $query SQL Query to be used
206
	 * @param string $line optionally pass __LINE__ calling the query for logging
207
	 * @param string $file optionally pass __FILE__ calling the query for logging
208
	 * @return mixed FALSE if no rows, if a single row it returns that, if multiple it returns an array of rows, associative responses only
209
	 */
210
	public function qr($query, $line = '', $file = '')
211
	{
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
	{
224 2
		if ($stripSlashes || ($this->autoStripslashes && !$stripSlashes)) {
225
			return stripslashes($this->Record[$name]);
226
		} else {
227 2
			return $this->Record[$name];
228
		}
229
	}
230
231
	/**
232
	 * error handling
233
	 *
234
	 * @param mixed $msg
235
	 * @param string $line
236
	 * @param string $file
237
	 * @return void
238
	 */
239 1
	public function halt($msg, $line = '', $file = '')
240
	{
241 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

241
		$this->/** @scrutinizer ignore-call */ 
242
         unlock(false);
Loading history...
242
		/* Just in case there is a table currently locked */
243
244
		//$this->Error = @$this->linkId->error;
0 ignored issues
show
Unused Code Comprehensibility introduced by
54% of this comment could be valid code. Did you maybe forget this after debugging?

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.

Loading history...
245
		//$this->Errno = @$this->linkId->errno;
0 ignored issues
show
Unused Code Comprehensibility introduced by
54% of this comment could be valid code. Did you maybe forget this after debugging?

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.

Loading history...
246 1
		if ($this->haltOnError == 'no') {
247
			return true;
248
		}
249 1
		if ($msg != '') {
250 1
			$this->haltmsg($msg, $line, $file);
251
		}
252 1
		if ($this->haltOnError != 'report') {
253 1
			echo '<p><b>Session halted.</b>';
254
			// FIXME! Add check for error levels
255 1
			if (isset($GLOBALS['tf'])) {
256
				$GLOBALS['tf']->terminate();
257
			}
258
		}
259 1
		return true;
260
	}
261
262
	/**
263
	 * @param mixed $msg
264
	 * @param string $line
265
	 * @param string $file
266
	 * @return mixed|void
267
	 */
268 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

268
	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...
269
	{
270 2
		$backtrace = (function_exists('debug_backtrace') ? debug_backtrace() : []);
271 2
		$this->log(
272 2
			('' !== getenv('REQUEST_URI') ? ' '.getenv('REQUEST_URI') : '').
273 2
			((isset($_POST) && count($_POST)) ? ' POST='.json_encode($_POST) : '').
274 2
			((isset($_GET) && count($_GET)) ? ' GET='.json_encode($_GET) : '').
275 2
			((isset($_FILES) && count($_FILES)) ? ' FILES='.json_encode($_FILES) : '').
276 2
			('' !== getenv('HTTP_USER_AGENT') ? ' AGENT="'.getenv('HTTP_USER_AGENT').'"' : '').
277 2
			(isset($_SERVER['REQUEST_METHOD']) ? ' METHOD="'.$_SERVER['REQUEST_METHOD'].'"'.
278 2
				($_SERVER['REQUEST_METHOD'] === 'POST' ? ' POST="'.json_encode($_POST).'"' : '') : ''),
279 2
			$line,
280 2
			$file,
281 2
			'error'
282
		);
283 2
		for ($level = 1, $levelMax = count($backtrace); $level < $levelMax; $level++) {
284 2
			$message = (isset($backtrace[$level]['file']) ? 'File: '.$backtrace[$level]['file'] : '').
285 2
				(isset($backtrace[$level]['line']) ? ' Line: '.$backtrace[$level]['line'] : '').
286 2
				' Function: '.(isset($backtrace[$level] ['class']) ? '(class '.$backtrace[$level] ['class'].') ' : '').
287 2
				(isset($backtrace[$level] ['type']) ? $backtrace[$level] ['type'].' ' : '').
288 2
				$backtrace[$level] ['function'].'(';
289 2
			if (isset($backtrace[$level] ['args'])) {
290 2
				for ($argument = 0, $argumentMax = count($backtrace[$level]['args']); $argument < $argumentMax; $argument++) {
291 2
					$message .= ($argument > 0 ? ', ' : '').
292 2
						(is_object($backtrace[$level]['args'][$argument]) ? 'class '.get_class($backtrace[$level]['args'][$argument]) : json_encode($backtrace[$level]['args'][$argument]));
293
				}
294
			}
295 2
			$message .= ')';
296 2
			$this->log($message, $line, $file, 'error');
297
		}
298
	}
299
300
	public function emailError($queryString, $error, $line, $file)
301
	{
302
		$subject = php_uname('n').' MySQLi Error';
303
		$smarty = new \TFSmarty();
0 ignored issues
show
Bug introduced by
The type TFSmarty was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
304
		$smarty->assign([
305
			'type' => $this->type,
306
			'queryString' => $queryString,
307
			'error' => $error,
308
			'line' => $line,
309
			'file' => $file,
310
			'request' => $_REQUEST,
311
			'server' => $_SERVER,
312
		]);
313
		if (isset($GLOBALS['tf'])) {
314
			$smarty->assign('account_id', $GLOBALS['tf']->session->account_id);
315
		}
316
		$email = $smarty->fetch('email/admin/sql_error.tpl');
317
		(new \MyAdmin\Mail())->adminMail($subject, $email, '[email protected]', 'admin/sql_error.tpl');
0 ignored issues
show
Bug introduced by
The type MyAdmin\Mail was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
318
		(new \MyAdmin\Mail())->adminMail($subject, $email, '[email protected]', 'admin/sql_error.tpl');
319
		$this->haltmsg('Invalid SQL: '.$queryString, $line, $file);
320
	}
321
	
322
	/**
323
	 * @param mixed $msg
324
	 * @param string $line
325
	 * @param string $file
326
	 * @return mixed|void
327
	 */
328 2
	public function haltmsg($msg, $line = '', $file = '')
329
	{
330 2
		$this->log("Database error: $msg", $line, $file, 'error');
331 2
		if ($this->Errno != '0' || !in_array($this->Error, ['', '()'])) {
332
			$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

332
			$sqlstate = mysqli_sqlstate(/** @scrutinizer ignore-type */ $this->linkId);
Loading history...
333
			$this->log("MySQLi SQLState: {$sqlstate}. Error: ".$this->Errno.' ('.$this->Error.')', $line, $file, 'error');
334
		}
335 2
		$this->logBackTrace($msg, $line, $file);
336
	}
337
338
	/**
339
	 * @return array
340
	 */
341 1
	public function indexNames()
342
	{
343 1
		return [];
344
	}
345
}
346