Passed
Push — master ( ec35e7...305365 )
by Joe
07:09
created

Generic::toTimestamp()   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 1
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
    public $port = '';
23
24
	/* public: configuration parameters */
25
	public $autoStripslashes = false;
26
	public $Debug = 0; // Set to 1 for debugging messages.
27
	public $haltOnError = 'yes'; // "yes" (halt with message), "no" (ignore errors quietly), "report" (ignore error, but spit a warning)
28
29
	public $maxConnectErrors = 30;
30
	public $connectionAttempt = 0;
31
	public $maxMatches = 10000000;
32
33
	/**
34
	 * @var int
35
	 */
36
	public $autoFree = 0; // Set to 1 for automatic mysql_free_result()
37
38
	/* public: result array and current row number */
39
	public $Record = [];
40
	public $Row;
41
42
	/* public: current error number and error text */
43
	public $Errno = 0;
44
	public $Error = '';
45
46
	/* public: this is an api revision, not a CVS revision. */
47
	public $type = 'generic';
48
49
	/**
50
	 * @var int|object
51
	 */
52
	public $linkId = 0;
53
	public $queryId = 0;
54
55
	public $characterSet = 'utf8mb4';
56
	public $collation = 'utf8mb4_unicode_ci';
57
	
58
	/**
59
	 * Logged queries.
60
	 * @var array
61
	 */
62
	protected $log = [];    
63
64
	/**
65
	 * Constructs the db handler, can optionally specify connection parameters
66
	 *
67
	 * @param string $database Optional The database name
68
	 * @param string $user Optional The username to connect with
69
	 * @param string $password Optional The password to use
70
	 * @param string $host Optional The hostname where the server is, or default to localhost
71
	 * @param string $query Optional query to perform immediately
72
     * @param string $port optional port for the connection
73
	 */
74 1
	public function __construct($database = '', $user = '', $password = '', $host = 'localhost', $query = '', $port = '')
75
	{
76 1
		$this->database = $database;
77 1
		$this->user = $user;
78 1
		$this->password = $password;
79 1
		$this->host = $host;
80 1
        $this->port = $port;
81 1
		if ($query != '') {
82
			$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

82
			$this->/** @scrutinizer ignore-call */ 
83
          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...
83
		}
84 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...
85
	}
86
87
	/**
88
	 * @param string $message
89
	 * @param string $line
90
	 * @param string $file
91
	 * @return void
92
	 */
93 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

93
	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

93
	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

93
	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...
94
	{
95 2
		error_log($message);
96
	}
97
98
	/**
99
	 * @return int|object
100
	 */
101 2
	public function linkId()
102
	{
103 2
		return $this->linkId;
104
	}
105
106
	/**
107
	 * @return int|object
108
	 */
109 1
	public function queryId()
110
	{
111 1
		return $this->queryId;
112
	}
113
114
	/**
115
	 * @param $string
116
	 * @return string
117
	 */
118 1
	public function real_escape($string = '')
119
	{
120 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

120
		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...
121 1
			return $this->escape($string);
122
		}
123
		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

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

221
		return $this->/** @scrutinizer ignore-call */ queryReturn($query, $line, $file);
Loading history...
222
	}
223
224
	/**
225
	 * gets a field
226
	 *
227
	 * @param mixed  $name
228
	 * @param string $stripSlashes
229
	 * @return string
230
	 */
231 2
	public function f($name, $stripSlashes = '')
232
	{
233 2
		if ($stripSlashes || ($this->autoStripslashes && !$stripSlashes)) {
234
			return stripslashes($this->Record[$name]);
235
		} else {
236 2
			return $this->Record[$name];
237
		}
238
	}
239
240
	/**
241
	 * error handling
242
	 *
243
	 * @param mixed $msg
244
	 * @param string $line
245
	 * @param string $file
246
	 * @return void
247
	 */
248 1
	public function halt($msg, $line = '', $file = '')
249
	{
250 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

250
		$this->/** @scrutinizer ignore-call */ 
251
         unlock(false);
Loading history...
251
		/* Just in case there is a table currently locked */
252
253
		//$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...
254
		//$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...
255 1
		if ($this->haltOnError == 'no') {
256
			return true;
257
		}
258 1
		if ($msg != '') {
259 1
			$this->haltmsg($msg, $line, $file);
260
		}
261 1
		if ($this->haltOnError != 'report') {
262 1
			echo '<p><b>Session halted.</b>';
263
			// FIXME! Add check for error levels
264 1
			if (isset($GLOBALS['tf'])) {
265
				$GLOBALS['tf']->terminate();
266
			}
267
		}
268 1
		return true;
269
	}
270
271
	/**
272
	 * @param mixed $msg
273
	 * @param string $line
274
	 * @param string $file
275
	 * @return mixed|void
276
	 */
277 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

277
	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...
278
	{
279 2
		$backtrace = (function_exists('debug_backtrace') ? debug_backtrace() : []);
280 2
		$this->log(
281 2
			('' !== getenv('REQUEST_URI') ? ' '.getenv('REQUEST_URI') : '').
282 2
			((isset($_POST) && count($_POST)) ? ' POST='.json_encode($_POST) : '').
283 2
			((isset($_GET) && count($_GET)) ? ' GET='.json_encode($_GET) : '').
284 2
			((isset($_FILES) && count($_FILES)) ? ' FILES='.json_encode($_FILES) : '').
285 2
			('' !== getenv('HTTP_USER_AGENT') ? ' AGENT="'.getenv('HTTP_USER_AGENT').'"' : '').
286 2
			(isset($_SERVER['REQUEST_METHOD']) ? ' METHOD="'.$_SERVER['REQUEST_METHOD'].'"'.
287 2
				($_SERVER['REQUEST_METHOD'] === 'POST' ? ' POST="'.json_encode($_POST).'"' : '') : ''),
288 2
			$line,
289 2
			$file,
290 2
			'error'
291
		);
292 2
		for ($level = 1, $levelMax = count($backtrace); $level < $levelMax; $level++) {
293 2
			$message = (isset($backtrace[$level]['file']) ? 'File: '.$backtrace[$level]['file'] : '').
294 2
				(isset($backtrace[$level]['line']) ? ' Line: '.$backtrace[$level]['line'] : '').
295 2
				' Function: '.(isset($backtrace[$level] ['class']) ? '(class '.$backtrace[$level] ['class'].') ' : '').
296 2
				(isset($backtrace[$level] ['type']) ? $backtrace[$level] ['type'].' ' : '').
297 2
				$backtrace[$level] ['function'].'(';
298 2
			if (isset($backtrace[$level] ['args'])) {
299 2
				for ($argument = 0, $argumentMax = count($backtrace[$level]['args']); $argument < $argumentMax; $argument++) {
300 2
					$message .= ($argument > 0 ? ', ' : '').
301 2
						(is_object($backtrace[$level]['args'][$argument]) ? 'class '.get_class($backtrace[$level]['args'][$argument]) : json_encode($backtrace[$level]['args'][$argument]));
302
				}
303
			}
304 2
			$message .= ')';
305 2
			$this->log($message, $line, $file, 'error');
306
		}
307
	}
308
309
	public function emailError($queryString, $error, $line, $file)
310
	{
311
		$subject = php_uname('n').' MySQLi Error';
312
		$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...
313
		$smarty->assign([
314
			'type' => $this->type,
315
			'queryString' => $queryString,
316
			'error' => $error,
317
			'line' => $line,
318
			'file' => $file,
319
			'request' => $_REQUEST,
320
			'server' => $_SERVER,
321
		]);
322
		if (isset($GLOBALS['tf'])) {
323
			$smarty->assign('account_id', $GLOBALS['tf']->session->account_id);
324
		}
325
		$email = $smarty->fetch('email/admin/sql_error.tpl');
326
		(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...
327
		(new \MyAdmin\Mail())->adminMail($subject, $email, '[email protected]', 'admin/sql_error.tpl');
328
		$this->haltmsg('Invalid SQL: '.$queryString, $line, $file);
329
	}
330
	
331
	/**
332
	 * @param mixed $msg
333
	 * @param string $line
334
	 * @param string $file
335
	 * @return mixed|void
336
	 */
337 2
	public function haltmsg($msg, $line = '', $file = '')
338
	{
339 2
		$this->log("Database error: $msg", $line, $file, 'error');
340 2
		if ($this->Errno != '0' || !in_array($this->Error, ['', '()'])) {
341
			$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

341
			$sqlstate = mysqli_sqlstate(/** @scrutinizer ignore-type */ $this->linkId);
Loading history...
342
			$this->log("MySQLi SQLState: {$sqlstate}. Error: ".$this->Errno.' ('.$this->Error.')', $line, $file, 'error');
343
		}
344 2
		$this->logBackTrace($msg, $line, $file);
345
	}
346
347
	/**
348
	 * @return array
349
	 */
350 1
	public function indexNames()
351
	{
352 1
		return [];
353
	}
354
	
355
356
	/**
357
	 * Add query to logged queries.
358
	 * @param string $statement
359
	 * @param float $time Elapsed seconds with microseconds
360
	 * @param string|int $line Line Number
361
	 * @param string $file File Name
362
	 */
363 11
	public function addLog($statement, $time, $line = '', $file = '')
364
	{
365
		$query = [
366 11
			'statement' => $statement,
367 11
			'time' => $time * 1000
368
		];
369 11
		if ($line != '') {
370 5
			$query['line'] = $line;
371
		}
372 11
		if ($file != '') {
373 5
			$query['file'] = $file;
374
		}
375 11
		if (!isset($GLOBALS['db_queries'])) {
376 1
			$GLOBALS['db_queries'] = array();
377
		}
378 11
		$GLOBALS['db_queries'][] = $query;
379 11
		array_push($this->log, $query);
380
	}
381
382
	/**
383
	 * Return logged queries.
384
	 * @return array Logged queries
385
	 */
386
	public function getLog()
387
	{
388
		return $this->log;
389
	}    
390
}
391