Db   F
last analyzed

Complexity

Total Complexity 106

Size/Duplication

Total Lines 540
Duplicated Lines 0 %

Test Coverage

Coverage 82.54%

Importance

Changes 43
Bugs 4 Features 0
Metric Value
eloc 210
c 43
b 4
f 0
dl 0
loc 540
ccs 156
cts 189
cp 0.8254
rs 2
wmc 106

25 Methods

Rating   Name   Duplication   Size   Complexity  
A prepare() 0 14 3
A free() 0 6 2
D connect() 0 43 18
A queryReturn() 0 14 4
A useDb() 0 3 1
A real_escape() 0 6 4
A disconnect() 0 5 3
A selectDb() 0 4 1
A qr() 0 3 1
A bind_param() 0 9 3
A transactionCommit() 0 6 3
A seek() 0 14 2
A getLastInsertId() 0 7 5
A fetchObject() 0 4 1
A unlock() 0 10 3
A lock() 0 22 6
A next_record() 0 17 5
F query() 0 88 28
A transactionAbort() 0 6 3
A execute() 0 11 2
A affectedRows() 0 3 1
A num_rows() 0 3 1
A transactionBegin() 0 9 3
A tableNames() 0 12 2
A num_fields() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like Db 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 Db, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
* MySQL Related Functionality
4
* @author Joe Huss <[email protected]>
5
* @copyright 2025
6
* @package MyAdmin
7
* @category SQL
8
*/
9
10
namespace MyDb\Mysqli;
11
12
use MyDb\Generic;
13
use MyDb\Db_Interface;
14
15
/**
16
* Db
17
*
18
* @access public
19
*/
20
class Db extends Generic implements Db_Interface
21
{
22
    /**
23
    * @var string
24
    */
25
    public $type = 'mysqli';
26
    public $statement;
27
    public $statement_query;
28
    public $statement_vars;
29
30
    /**
31
    * alias function of select_db, changes the database we are working with.
32
    *
33 1
    * @param string $database the name of the database to use
34
    * @return void
35 1
    */
36
    public function useDb($database)
37
    {
38
        $this->selectDb($database);
39
    }
40
41
    /**
42
    * changes the database we are working with.
43
    *
44 1
    * @param string $database the name of the database to use
45
    * @return void
46 1
    */
47 1
    public function selectDb($database)
48
    {
49
        $this->connect();
50
        mysqli_select_db($this->linkId, $database);
51
    }
52
53
    /* public: connection management */
54
55
    /**
56
    * Db::connect()
57
    * @param string $database
58
    * @param string $host
59
    * @param string $user
60 26
    * @param string $password
61
    * @return int|\mysqli
62
    */
63 26
    public function connect($database = '', $host = '', $user = '', $password = '', $port = '')
64 26
    {
65
        /* Handle defaults */
66 26
        if ($database == '') {
67 26
            $database = $this->database;
68
        }
69 26
        if ($host == '') {
70 26
            $host = $this->host;
71
        }
72 26
        if ($user == '') {
73 26
            $user = $this->user;
74
        }
75 26
        if ($password == '') {
76 26
            $password = $this->password;
77
        }
78
        if ($port == '') {
79 26
            $port = $this->port;
80 26
        }
81 26
        /* establish connection, select database */
82 6
        if (!is_object($this->linkId)) {
83
            $this->connectionAttempt++;
84 26
            if ($this->connectionAttempt >= $this->maxConnectErrors - 1) {
85
                error_log("MySQLi Connection Attempt #{$this->connectionAttempt}/{$this->maxConnectErrors}");
86
                exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
87
            }
88 26
            if ($this->connectionAttempt >= $this->maxConnectErrors) {
89 26
                $this->halt("connect($host, $user, \$password) failed. ".(is_object($this->linkId) && isset( $this->linkId->connect_error) ? $this->linkId->connect_error : ''));
0 ignored issues
show
introduced by
The condition is_object($this->linkId) is always false.
Loading history...
90 26
                return 0;
91
            }
92
            //error_log("real_connect($host, $user, $password, $database, $port)");
0 ignored issues
show
Unused Code Comprehensibility introduced by
80% 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...
93 26
            $this->linkId = mysqli_init();
94
            $this->linkId->options(MYSQLI_INIT_COMMAND, "SET NAMES {$this->characterSet} COLLATE {$this->collation}, COLLATION_CONNECTION = {$this->collation}, COLLATION_DATABASE = {$this->collation}");
95 26
            if (!$this->linkId->real_connect($host, $user, $password, $database, $port != '' ? $port : NULL)) {
96 26
                $this->halt("connect($host, $user, \$password) failed. ".(is_object($this->linkId) && isset( $this->linkId->connect_error) ? $this->linkId->connect_error : ''));
97
                return 0;
98
            }
99
            $this->linkId->set_charset($this->characterSet);
100
            if ($this->linkId->connect_errno) {
101 26
                $this->halt("connect($host, $user, \$password) failed. ".(is_object($this->linkId) && isset( $this->linkId->connect_error) ? $this->linkId->connect_error : ''));
102
                return 0;
103
            }
104
        }
105
        return $this->linkId;
106
    }
107
108 1
    /**
109
    * Db::disconnect()
110 1
    * @return bool
111 1
    */
112 1
    public function disconnect()
113
    {
114
        $return = !is_int($this->linkId) && method_exists($this->linkId, 'close') ? $this->linkId->close() : false;
115
        $this->linkId = 0;
116
        return $return;
117
    }
118
119 2
    /**
120
    * @param $string
121 2
    * @return string
122
    */
123
    public function real_escape($string = '')
124 2
    {
125
        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...
126
            return $this->escape($string);
127
        }
128
        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 $mysql 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

128
        return mysqli_real_escape_string(/** @scrutinizer ignore-type */ $this->linkId, $string);
Loading history...
129
    }
130
131 1
    /**
132
    * discard the query result
133 1
    * @return void
134
    */
135
    public function free()
136 1
    {
137
        if (is_resource($this->queryId)) {
0 ignored issues
show
introduced by
The condition is_resource($this->queryId) is always false.
Loading history...
138
            @mysqli_free_result($this->queryId);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for mysqli_free_result(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

138
            /** @scrutinizer ignore-unhandled */ @mysqli_free_result($this->queryId);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
139
        }
140
        $this->queryId = 0;
141
    }
142
143
    /**
144
    * Db::queryReturn()
145
    *
146
    * Sends an SQL query to the server like the normal query() command but iterates through
147
    * any rows and returns the row or rows immediately or FALSE on error
148
    *
149
    * @param mixed $query SQL Query to be used
150 1
    * @param string $line optionally pass __LINE__ calling the query for logging
151
    * @param string $file optionally pass __FILE__ calling the query for logging
152 1
    * @return mixed FALSE if no rows, if a single row it returns that, if multiple it returns an array of rows, associative responses only
153 1
    */
154 1
    public function queryReturn($query, $line = '', $file = '')
155 1
    {
156 1
        $this->query($query, $line, $file);
0 ignored issues
show
Bug introduced by
$line of type string is incompatible with the type integer expected by parameter $line of MyDb\Mysqli\Db::query(). ( Ignorable by Annotation )

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

156
        $this->query($query, /** @scrutinizer ignore-type */ $line, $file);
Loading history...
157 1
        if ($this->num_rows() == 0) {
158
            return false;
159 1
        } elseif ($this->num_rows() == 1) {
160 1
            $this->next_record(MYSQLI_ASSOC);
161 1
            return $this->Record;
162
        } else {
163 1
            $out = [];
164
            while ($this->next_record(MYSQLI_ASSOC)) {
165
                $out[] = $this->Record;
166
            }
167
            return $out;
168
        }
169
    }
170
171
    /**
172
    * db:qr()
173
    *
174
    *  alias of queryReturn()
175
    *
176
    * @param mixed $query SQL Query to be used
177 1
    * @param string $line optionally pass __LINE__ calling the query for logging
178
    * @param string $file optionally pass __FILE__ calling the query for logging
179 1
    * @return mixed FALSE if no rows, if a single row it returns that, if multiple it returns an array of rows, associative responses only
180
    */
181
    public function qr($query, $line = '', $file = '')
182
    {
183
        return $this->queryReturn($query, $line, $file);
184
    }
185
186
    /**
187
    * creates a prepaired statement from query
188
    *
189
    * @param string $query sql query like INSERT INTO table (col) VALUES (?)  or  SELECT * from table WHERE col1 = ? and col2 = ?  or  UPDATE table SET col1 = ?, col2 = ? WHERE col3 = ?
190 1
    * @return false|mysqli_stmt
0 ignored issues
show
Bug introduced by
The type MyDb\Mysqli\mysqli_stmt was not found. Did you mean mysqli_stmt? If so, make sure to prefix the type with \.
Loading history...
191
    * @param string $line
192 1
    * @param string $file
193
    */
194
    public function prepare($query, $line = '', $file = '')
195 1
    {
196 1
        if (!$this->connect()) {
197 1
            return 0;
198 1
        }
199 1
        $haltPrev = $this->haltOnError;
0 ignored issues
show
Unused Code introduced by
The assignment to $haltPrev is dead and can be removed.
Loading history...
200 1
        $this->haltOnError = 'no';
201
        $start = microtime(true);
202
        $this->statement = mysqli_prepare($this->linkId, $query);
203
        if (!isset($GLOBALS['disable_db_queries'])) {
204
            $this->statement_query = $query;
205
            $this->addLog($query, microtime(true) - $start, $line, $file);
206
        }
207
        return $this->statement;
208
    }
209
210
    /**
211
    * Binds variables to a prepared statement as parameters
212
    * 
213 10
    * @param string $types A string that contains one or more characters which specify the types for the corresponding bind variables: (i)nt, (d)ecimal, (s)tring, (b)inary 
214
    * @param mixed $vars
215
    * @return bool indicates success
216
    */
217
    public function bind_param($types, &...$vars) {
218
        $params = [$this->statement, $types];
219
        foreach ($vars as &$var) {
220 10
            $params[] = &$var; // Ensure they stay references
221 1
        }
222
        if (!isset($GLOBALS['disable_db_queries'])) {
223 10
            $this->statement_vars &= $vars;
224
        }
225
        return call_user_func_array('mysqli_stmt_bind_param', $params);
226
    }
227 10
228 10
    /**
229
    * Executes a prepared statement
230 10
    * 
231
    * @return bool success
232
    */
233 10
    public function execute($line = '', $file = '') {
234 1
        $start = microtime(true);
235
        $return = mysqli_stmt_execute($this->statement);
236 10
        if (!isset($GLOBALS['disable_db_queries'])) {
237
            $vars = $this->statement_vars;
238
            $query = $result = preg_replace_callback('/\?/', function () use (&$vars) {
0 ignored issues
show
Unused Code introduced by
The assignment to $result is dead and can be removed.
Loading history...
239 10
                return array_shift($vars);
240 10
                }, $this->statement_query);
241 10
            $this->addLog($query, microtime(true) - $start, $line, $file);
242 10
        }
243 10
        return $return;
244 10
    }
245
246
    /**
247
    * Db::query()
248 10
    *
249 10
    *  Sends an SQL query to the database
250 10
    *
251 10
    * @param mixed $queryString
252
    * @param int $line
253
    * @param string $file
254
    * @param bool $log
255
    * @return mixed 0 if no query or query id handler, safe to ignore this return
256
    */
257
    public function query($queryString, $line = '', $file = '', $log = false)
258 10
    {
259
        /* No empty queries, please, since PHP4 chokes on them. */
260
        /* The empty query string is passed on from the constructor,
261 10
        * when calling the class without a query, e.g. in situations
262 10
        * like these: '$db = new db_Subclass;'
263 10
        */
264 10
        if ($queryString == '') {
265 10
            return 0;
266
        }
267
        if (!$this->connect()) {
268
            return 0;
269 10
            /* we already complained in connect() about that. */
270 10
        }
271
        $haltPrev = $this->haltOnError;
272
        $this->haltOnError = 'no';
273
        // New query, discard previous result.
274
        if (is_resource($this->queryId)) {
275 10
            $this->free();
276
        }
277
        if ($this->Debug) {
278
            printf("Debug: query = %s<br>\n", $queryString);
279
        }
280
        if ($log === true || (isset($GLOBALS['log_queries']) && $GLOBALS['log_queries'] !== false)) {
281 1
            $this->log($queryString, $line, $file);
282
        }
283 1
        $tries = 2;
284 1
        $try = 0;
285
        $this->queryId = false;
286
        while ((null === $this->queryId || $this->queryId === false) && $try <= $tries) {
287
            $try++;
288
            if ($try > 1) {
289
                @mysqli_close($this->linkId);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for mysqli_close(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

289
                /** @scrutinizer ignore-unhandled */ @mysqli_close($this->linkId);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
290
                $this->linkId = 0;
291
            }
292
            $start = microtime(true);
293
            $onlyRollback = true;
294
            $fails = -1;
295 6
            while ($fails < 30 && (null === $this->queryId || $this->queryId === false)) {
296
                $this->connect();
297 6
                $fails++;
298
                try {
299
                    $this->queryId = @mysqli_query($this->linkId, $queryString, MYSQLI_STORE_RESULT);
300
                    if (in_array((int)@mysqli_errno($this->linkId), [1213, 2006, 3101, 1180])) {
301
                        //error_log("got ".@mysqli_errno($this->linkId)." sql error fails {$fails} on query {$queryString} from {$line}:{$file}");
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% 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...
302 6
                        usleep(250000); // 0.25 second
303 6
                    } else {
304 6
                        $onlyRollback = false;
305 6
                        if (in_array((int)@mysqli_errno($this->linkId), [1064])) {
306
                            $tries = 0;
307 6
                        }
308 6
                        break;
309
                    }
310
                } catch (\mysqli_sql_exception $e) {
311 6
                    if (in_array((int)$e->getCode(), [1213, 2006, 3101, 1180])) {
312
                        //error_log("got ".$e->getCode()." sql error fails {$fails}");
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% 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...
313
                        usleep(250000); // 0.25 second
314
                    } else {
315
                        error_log('Got mysqli_sql_exception code '.$e->getCode().' error '.$e->getMessage().' on query '.$queryString.' from '.$line.':'.$file);
316
                        $onlyRollback = false;
317
                        if (in_array((int)@mysqli_errno($this->linkId), [1064])) {
318
                            $tries = 0;
319
                        }
320 1
                        break;
321
                    }
322 1
                }
323 1
            }
324 1
            if (!isset($GLOBALS['disable_db_queries'])) {
325
                $this->addLog($queryString, microtime(true) - $start, $line, $file);
326 1
            }
327
            $this->Row = 0;
328 1
            $this->Errno = @mysqli_errno($this->linkId);
329 1
            $this->Error = @mysqli_error($this->linkId);
330 1
            if ($try == 1 && (null === $this->queryId || $this->queryId === false)) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
331 1
                //$this->emailError($queryString, 'Error #'.$this->Errno.': '.$this->Error, $line, $file);
0 ignored issues
show
Unused Code Comprehensibility introduced by
66% 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...
332
            }
333 1
        }
334
        $this->haltOnError = $haltPrev;
335
        if ($onlyRollback === true && false === $this->queryId) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $onlyRollback does not seem to be defined for all execution paths leading up to this point.
Loading history...
336
            error_log('Got MySQLi 3101 Rollback Error '.$fails.' Times, Giving Up on '.$queryString.' from '.$line.':'.$file.' on '.__LINE__.':'.__FILE__);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $fails does not seem to be defined for all execution paths leading up to this point.
Loading history...
337
        }
338
        if (null === $this->queryId || $this->queryId === false) {
339
            $this->emailError($queryString, 'Error #'.$this->Errno.': '.$this->Error, $line, $file);
340
            $this->halt('', $line, $file);
341 26
        }
342
343 26
        // Will return nada if it fails. That's fine.
344
        return $this->queryId;
345
    }
346 26
347
    /**
348
    * @return array|null|object
349 26
    */
350
    public function fetchObject()
351
    {
352
        $this->Record = @mysqli_fetch_object($this->queryId);
0 ignored issues
show
Bug introduced by
$this->queryId of type integer is incompatible with the type mysqli_result expected by parameter $result of mysqli_fetch_object(). ( Ignorable by Annotation )

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

352
        $this->Record = @mysqli_fetch_object(/** @scrutinizer ignore-type */ $this->queryId);
Loading history...
353
        return $this->Record;
354
    }
355
356
    /* public: walk result set */
357 1
358
    /**
359 1
    * Db::next_record()
360
    *
361
    * @param mixed $resultType
362 1
    * @return bool
363
    */
364
    public function next_record($resultType = MYSQLI_BOTH)
365
    {
366
        if ($this->queryId === false) {
0 ignored issues
show
introduced by
The condition $this->queryId === false is always false.
Loading history...
367
            $this->haltmsg('next_record called with no query pending.');
368
            return 0;
369
        }
370 26
371
        $this->Record = @mysqli_fetch_array($this->queryId, $resultType);
0 ignored issues
show
Bug introduced by
$this->queryId of type integer is incompatible with the type mysqli_result expected by parameter $result of mysqli_fetch_array(). ( Ignorable by Annotation )

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

371
        $this->Record = @mysqli_fetch_array(/** @scrutinizer ignore-type */ $this->queryId, $resultType);
Loading history...
372 26
        ++$this->Row;
373
        $this->Errno = mysqli_errno($this->linkId);
0 ignored issues
show
Bug introduced by
It seems like $this->linkId can also be of type integer; however, parameter $mysql of mysqli_errno() 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

373
        $this->Errno = mysqli_errno(/** @scrutinizer ignore-type */ $this->linkId);
Loading history...
374
        $this->Error = mysqli_error($this->linkId);
0 ignored issues
show
Bug introduced by
It seems like $this->linkId can also be of type integer; however, parameter $mysql of mysqli_error() 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

374
        $this->Error = mysqli_error(/** @scrutinizer ignore-type */ $this->linkId);
Loading history...
375 26
376
        $stat = is_array($this->Record);
377
        if (!$stat && $this->autoFree && is_resource($this->queryId)) {
0 ignored issues
show
introduced by
The condition is_resource($this->queryId) is always false.
Loading history...
378
            $this->free();
379
        }
380
        return $stat;
381
    }
382
383
    /**
384
    * switch to position in result set
385
    *
386
    * @param integer $pos the row numbe starting at 0 to switch to
387 2
    * @return bool whetherit was successfu or not.
388
    */
389 2
    public function seek($pos = 0)
390
    {
391
        $status = @mysqli_data_seek($this->queryId, $pos);
0 ignored issues
show
Bug introduced by
$this->queryId of type integer is incompatible with the type mysqli_result expected by parameter $result of mysqli_data_seek(). ( Ignorable by Annotation )

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

391
        $status = @mysqli_data_seek(/** @scrutinizer ignore-type */ $this->queryId, $pos);
Loading history...
392
        if ($status) {
393 2
            $this->Row = $pos;
394
        } else {
395
            $this->haltmsg("seek({$pos}) failed: result has ".$this->num_rows().' rows', __LINE__, __FILE__);
396
            /* half assed attempt to save the day, but do not consider this documented or even desirable behaviour. */
397
            $rows = $this->num_rows();
398
            @mysqli_data_seek($this->queryId, $rows);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for mysqli_data_seek(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

398
            /** @scrutinizer ignore-unhandled */ @mysqli_data_seek($this->queryId, $rows);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
399
            $this->Row = $rows;
400
            return false;
401
        }
402
        return true;
403
    }
404 1
405
    /**
406 1
    * Initiates a transaction
407 1
    *
408 1
    * @return bool
409 1
    */
410 1
    public function transactionBegin()
411
    {
412
        if (version_compare(PHP_VERSION, '5.5.0') < 0) {
413 1
            return true;
414
        }
415
        if (!$this->connect()) {
416 1
            return 0;
417
        }
418 1
        return mysqli_begin_transaction($this->linkId);
419
    }
420 1
421 1
    /**
422
    * Commits a transaction
423
    *
424
    * @return bool
425 1
    */
426
    public function transactionCommit()
427
    {
428
        if (version_compare(PHP_VERSION, '5.5.0') < 0 || $this->linkId === 0) {
429
            return true;
430
        }
431
        return mysqli_commit($this->linkId);
0 ignored issues
show
Bug introduced by
It seems like $this->linkId can also be of type integer; however, parameter $mysql of mysqli_commit() 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

431
        return mysqli_commit(/** @scrutinizer ignore-type */ $this->linkId);
Loading history...
432
    }
433 2
434
    /**
435 2
    * Rolls back a transaction
436
    *
437 2
    * @return bool
438 2
    */
439
    public function transactionAbort()
440
    {
441
        if (version_compare(PHP_VERSION, '5.5.0') < 0 || $this->linkId === 0) {
442 2
            return true;
443
        }
444
        return mysqli_rollback($this->linkId);
0 ignored issues
show
Bug introduced by
It seems like $this->linkId can also be of type integer; however, parameter $mysql of mysqli_rollback() 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

444
        return mysqli_rollback(/** @scrutinizer ignore-type */ $this->linkId);
Loading history...
445
    }
446
447
    /**
448
    * This will get the last insert ID created on the current connection.  Should only be called after an insert query is
449
    * run on a table that has an auto incrementing field.  $table and $field are required, but unused here since it's
450
    * unnecessary for mysql.  For compatibility with pgsql, the params must be supplied.
451 2
    *
452
    * @param string $table
453 2
    * @param string $field
454
    * @return int|string
455
    */
456
    public function getLastInsertId($table, $field)
457
    {
458
        if (!isset($table) || $table == '' || !isset($field) || $field == '') {
459
            return -1;
460 6
        }
461
462 6
        return @mysqli_insert_id($this->linkId);
0 ignored issues
show
Bug introduced by
It seems like $this->linkId can also be of type integer; however, parameter $mysql of mysqli_insert_id() 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

462
        return @mysqli_insert_id(/** @scrutinizer ignore-type */ $this->linkId);
Loading history...
463
    }
464
465
    /* public: table locking */
466
467
    /**
468
    * Db::lock()
469 1
    * @param mixed  $table
470
    * @param string $mode
471 1
    * @return bool|int|\mysqli_result
472
    */
473
    public function lock($table, $mode = 'write')
474
    {
475
        $this->connect();
476
        $query = 'lock tables ';
477
        if (is_array($table)) {
478
            foreach ($table as $key => $value) {
479 1
                if ($key == 'read' && $key != 0) {
480
                    $query .= "$value read, ";
481 1
                } else {
482 1
                    $query .= "$value $mode, ";
483 1
                }
484 1
            }
485 1
            $query = mb_substr($query, 0, -2);
486 1
        } else {
487 1
            $query .= "$table $mode";
488 1
        }
489
        $res = @mysqli_query($this->linkId, $query);
490 1
        if (!$res) {
491
            $this->halt("lock($table, $mode) failed.");
492
            return 0;
493
        }
494
        return $res;
495
    }
496
497
    /**
498
    * Db::unlock()
499
    * @param bool $haltOnError optional, defaults to TRUE, whether or not to halt on error
500
    * @return bool|int|\mysqli_result
501
    */
502
    public function unlock($haltOnError = true)
503
    {
504
        $this->connect();
505
506
        $res = @mysqli_query($this->linkId, 'unlock tables');
507
        if ($haltOnError === true && !$res) {
508
            $this->halt('unlock() failed.');
509
            return 0;
510
        }
511
        return $res;
512
    }
513
514
    /* public: evaluate the result (size, width) */
515
516
    /**
517
    * Db::affectedRows()
518
    * @return int
519
    */
520
    public function affectedRows()
521
    {
522
        return @mysqli_affected_rows($this->linkId);
0 ignored issues
show
Bug introduced by
It seems like $this->linkId can also be of type integer; however, parameter $mysql of mysqli_affected_rows() 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

522
        return @mysqli_affected_rows(/** @scrutinizer ignore-type */ $this->linkId);
Loading history...
523
    }
524
525
    /**
526
    * Db::num_rows()
527
    * @return int
528
    */
529
    public function num_rows()
530
    {
531
        return @mysqli_num_rows($this->queryId);
0 ignored issues
show
Bug introduced by
$this->queryId of type integer is incompatible with the type mysqli_result expected by parameter $result of mysqli_num_rows(). ( Ignorable by Annotation )

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

531
        return @mysqli_num_rows(/** @scrutinizer ignore-type */ $this->queryId);
Loading history...
532
    }
533
534
    /**
535
    * Db::num_fields()
536
    * @return int
537
    */
538
    public function num_fields()
539
    {
540
        return @mysqli_num_fields($this->queryId);
0 ignored issues
show
Bug introduced by
$this->queryId of type integer is incompatible with the type mysqli_result expected by parameter $result of mysqli_num_fields(). ( Ignorable by Annotation )

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

540
        return @mysqli_num_fields(/** @scrutinizer ignore-type */ $this->queryId);
Loading history...
541
    }
542
543
    /**
544
    * gets an array of the table names in teh current datase
545
    *
546
    * @return array
547
    */
548
    public function tableNames()
549
    {
550
        $return = [];
551
        $this->query('SHOW TABLES');
552
        $i = 0;
553
        while ($info = $this->queryId->fetch_row()) {
0 ignored issues
show
Bug introduced by
The method fetch_row() does not exist on integer. ( Ignorable by Annotation )

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

553
        while ($info = $this->queryId->/** @scrutinizer ignore-call */ fetch_row()) {

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...
554
            $return[$i]['table_name'] = $info[0];
555
            $return[$i]['tablespace_name'] = $this->database;
556
            $return[$i]['database'] = $this->database;
557
            ++$i;
558
        }
559
        return $return;
560
    }
561
}
562
563
/**
564
* @param $result
565
* @param $row
566
* @param int|string $field
567
* @return bool
568
*/
569
/*
0 ignored issues
show
Unused Code Comprehensibility introduced by
56% 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...
570
function mysqli_result($result, $row, $field = 0) {
571
if ($result === false) return false;
572
if ($row >= mysqli_num_rows($result)) return false;
573
if (is_string($field) && !(mb_strpos($field, '.') === false)) {
574
$tField = explode('.', $field);
575
$field = -1;
576
$tFields = mysqli_fetch_fields($result);
577
for ($id = 0, $idMax = mysqli_num_fields($result); $id < $idMax; $id++) {
578
if ($tFields[$id]->table == $tField[0] && $tFields[$id]->name == $tField[1]) {
579
$field = $id;
580
break;
581
}
582
}
583
if ($field == -1) return false;
584
}
585
mysqli_data_seek($result, $row);
586
$line = mysqli_fetch_array($result);
587
return isset($line[$field]) ? $line[$field] : false;
588
}
589
*/
590