Test Failed
Push — master ( 8b6eb2...d03f69 )
by Joe
17:14 queued 10:05
created
src/Mysqli/Db.php 1 patch
Indentation   +536 added lines, -536 removed lines patch added patch discarded remove patch
@@ -19,545 +19,545 @@
 block discarded – undo
19 19
 */
20 20
 class Db extends Generic implements Db_Interface
21 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
-    * @param string $database the name of the database to use
34
-    * @return void
35
-    */
36
-    public function useDb($database)
37
-    {
38
-        $this->selectDb($database);
39
-    }
40
-
41
-    /**
42
-    * changes the database we are working with.
43
-    *
44
-    * @param string $database the name of the database to use
45
-    * @return void
46
-    */
47
-    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
-    * @param string $password
61
-    * @return int|\mysqli
62
-    */
63
-    public function connect($database = '', $host = '', $user = '', $password = '', $port = '')
64
-    {
65
-        /* Handle defaults */
66
-        if ($database == '') {
67
-            $database = $this->database;
68
-        }
69
-        if ($host == '') {
70
-            $host = $this->host;
71
-        }
72
-        if ($user == '') {
73
-            $user = $this->user;
74
-        }
75
-        if ($password == '') {
76
-            $password = $this->password;
77
-        }
78
-        if ($port == '') {
79
-            $port = $this->port;
80
-        }
81
-        /* establish connection, select database */
82
-        if (!is_object($this->linkId)) {
83
-            $this->connectionAttempt++;
84
-            if ($this->connectionAttempt >= $this->maxConnectErrors - 1) {
85
-                error_log("MySQLi Connection Attempt #{$this->connectionAttempt}/{$this->maxConnectErrors}");
86
-                exit;
87
-            }
88
-            if ($this->connectionAttempt >= $this->maxConnectErrors) {
89
-                $this->halt("connect($host, $user, \$password) failed. ".(is_object($this->linkId) && isset( $this->linkId->connect_error) ? $this->linkId->connect_error : ''));
90
-                return 0;
91
-            }
92
-            //error_log("real_connect($host, $user, $password, $database, $port)");
93
-            $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
-            if (!$this->linkId->real_connect($host, $user, $password, $database, $port != '' ? $port : NULL)) {
96
-                $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
-                $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
-    /**
109
-    * Db::disconnect()
110
-    * @return bool
111
-    */
112
-    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
-    /**
120
-    * @param $string
121
-    * @return string
122
-    */
123
-    public function real_escape($string = '')
124
-    {
125
-        if ((!is_resource($this->linkId) || $this->linkId == 0) && !$this->connect()) {
126
-            return $this->escape($string);
127
-        }
128
-        return mysqli_real_escape_string($this->linkId, $string);
129
-    }
130
-
131
-    /**
132
-    * discard the query result
133
-    * @return void
134
-    */
135
-    public function free()
136
-    {
137
-        if (is_resource($this->queryId)) {
138
-            @mysqli_free_result($this->queryId);
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
-    * @param string $line optionally pass __LINE__ calling the query for logging
151
-    * @param string $file optionally pass __FILE__ calling the query for logging
152
-    * @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
-    */
154
-    public function queryReturn($query, $line = '', $file = '')
155
-    {
156
-        $this->query($query, $line, $file);
157
-        if ($this->num_rows() == 0) {
158
-            return false;
159
-        } elseif ($this->num_rows() == 1) {
160
-            $this->next_record(MYSQLI_ASSOC);
161
-            return $this->Record;
162
-        } else {
163
-            $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
-    * @param string $line optionally pass __LINE__ calling the query for logging
178
-    * @param string $file optionally pass __FILE__ calling the query for logging
179
-    * @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
-    * @return false|mysqli_stmt
191
-    * @param string $line
192
-    * @param string $file
193
-    */
194
-    public function prepare($query, $line = '', $file = '')
195
-    {
196
-        if (!$this->connect()) {
197
-            return 0;
198
-        }
199
-        $haltPrev = $this->haltOnError;
200
-        $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
-    * @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
-            $params[] = &$var; // Ensure they stay references
221
-        }
222
-        if (!isset($GLOBALS['disable_db_queries'])) {
223
-            $this->statement_vars &= $vars;
224
-        }
225
-        return call_user_func_array('mysqli_stmt_bind_param', $params);
226
-    }
227
-
228
-    /**
229
-    * Executes a prepared statement
230
-    * 
231
-    * @return bool success
232
-    */
233
-    public function execute($line = '', $file = '') {
234
-        $start = microtime(true);
235
-        $return = mysqli_stmt_execute($this->statement);
236
-        if (!isset($GLOBALS['disable_db_queries'])) {
237
-            $vars = $this->statement_vars;
238
-            $query = $result = preg_replace_callback('/\?/', function () use (&$vars) {
239
-                return array_shift($vars);
240
-                }, $this->statement_query);
241
-            $this->addLog($query, microtime(true) - $start, $line, $file);
242
-        }
243
-        return $return;
244
-    }
245
-
246
-    /**
247
-    * Db::query()
248
-    *
249
-    *  Sends an SQL query to the database
250
-    *
251
-    * @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
-    {
259
-        /* No empty queries, please, since PHP4 chokes on them. */
260
-        /* The empty query string is passed on from the constructor,
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
+	 * @param string $database the name of the database to use
34
+	 * @return void
35
+	 */
36
+	public function useDb($database)
37
+	{
38
+		$this->selectDb($database);
39
+	}
40
+
41
+	/**
42
+	 * changes the database we are working with.
43
+	 *
44
+	 * @param string $database the name of the database to use
45
+	 * @return void
46
+	 */
47
+	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
+	 * @param string $password
61
+	 * @return int|\mysqli
62
+	 */
63
+	public function connect($database = '', $host = '', $user = '', $password = '', $port = '')
64
+	{
65
+		/* Handle defaults */
66
+		if ($database == '') {
67
+			$database = $this->database;
68
+		}
69
+		if ($host == '') {
70
+			$host = $this->host;
71
+		}
72
+		if ($user == '') {
73
+			$user = $this->user;
74
+		}
75
+		if ($password == '') {
76
+			$password = $this->password;
77
+		}
78
+		if ($port == '') {
79
+			$port = $this->port;
80
+		}
81
+		/* establish connection, select database */
82
+		if (!is_object($this->linkId)) {
83
+			$this->connectionAttempt++;
84
+			if ($this->connectionAttempt >= $this->maxConnectErrors - 1) {
85
+				error_log("MySQLi Connection Attempt #{$this->connectionAttempt}/{$this->maxConnectErrors}");
86
+				exit;
87
+			}
88
+			if ($this->connectionAttempt >= $this->maxConnectErrors) {
89
+				$this->halt("connect($host, $user, \$password) failed. ".(is_object($this->linkId) && isset( $this->linkId->connect_error) ? $this->linkId->connect_error : ''));
90
+				return 0;
91
+			}
92
+			//error_log("real_connect($host, $user, $password, $database, $port)");
93
+			$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
+			if (!$this->linkId->real_connect($host, $user, $password, $database, $port != '' ? $port : NULL)) {
96
+				$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
+				$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
+	/**
109
+	 * Db::disconnect()
110
+	 * @return bool
111
+	 */
112
+	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
+	/**
120
+	 * @param $string
121
+	 * @return string
122
+	 */
123
+	public function real_escape($string = '')
124
+	{
125
+		if ((!is_resource($this->linkId) || $this->linkId == 0) && !$this->connect()) {
126
+			return $this->escape($string);
127
+		}
128
+		return mysqli_real_escape_string($this->linkId, $string);
129
+	}
130
+
131
+	/**
132
+	 * discard the query result
133
+	 * @return void
134
+	 */
135
+	public function free()
136
+	{
137
+		if (is_resource($this->queryId)) {
138
+			@mysqli_free_result($this->queryId);
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
+	 * @param string $line optionally pass __LINE__ calling the query for logging
151
+	 * @param string $file optionally pass __FILE__ calling the query for logging
152
+	 * @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
+	 */
154
+	public function queryReturn($query, $line = '', $file = '')
155
+	{
156
+		$this->query($query, $line, $file);
157
+		if ($this->num_rows() == 0) {
158
+			return false;
159
+		} elseif ($this->num_rows() == 1) {
160
+			$this->next_record(MYSQLI_ASSOC);
161
+			return $this->Record;
162
+		} else {
163
+			$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
+	 * @param string $line optionally pass __LINE__ calling the query for logging
178
+	 * @param string $file optionally pass __FILE__ calling the query for logging
179
+	 * @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
+	 * @return false|mysqli_stmt
191
+	 * @param string $line
192
+	 * @param string $file
193
+	 */
194
+	public function prepare($query, $line = '', $file = '')
195
+	{
196
+		if (!$this->connect()) {
197
+			return 0;
198
+		}
199
+		$haltPrev = $this->haltOnError;
200
+		$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
+	 * @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
+			$params[] = &$var; // Ensure they stay references
221
+		}
222
+		if (!isset($GLOBALS['disable_db_queries'])) {
223
+			$this->statement_vars &= $vars;
224
+		}
225
+		return call_user_func_array('mysqli_stmt_bind_param', $params);
226
+	}
227
+
228
+	/**
229
+	 * Executes a prepared statement
230
+	 * 
231
+	 * @return bool success
232
+	 */
233
+	public function execute($line = '', $file = '') {
234
+		$start = microtime(true);
235
+		$return = mysqli_stmt_execute($this->statement);
236
+		if (!isset($GLOBALS['disable_db_queries'])) {
237
+			$vars = $this->statement_vars;
238
+			$query = $result = preg_replace_callback('/\?/', function () use (&$vars) {
239
+				return array_shift($vars);
240
+				}, $this->statement_query);
241
+			$this->addLog($query, microtime(true) - $start, $line, $file);
242
+		}
243
+		return $return;
244
+	}
245
+
246
+	/**
247
+	 * Db::query()
248
+	 *
249
+	 *  Sends an SQL query to the database
250
+	 *
251
+	 * @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
+	{
259
+		/* No empty queries, please, since PHP4 chokes on them. */
260
+		/* The empty query string is passed on from the constructor,
261 261
         * when calling the class without a query, e.g. in situations
262 262
         * like these: '$db = new db_Subclass;'
263 263
         */
264
-        if ($queryString == '') {
265
-            return 0;
266
-        }
267
-        if (!$this->connect()) {
268
-            return 0;
269
-            /* we already complained in connect() about that. */
270
-        }
271
-        $haltPrev = $this->haltOnError;
272
-        $this->haltOnError = 'no';
273
-        // New query, discard previous result.
274
-        if (is_resource($this->queryId)) {
275
-            $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
-            $this->log($queryString, $line, $file);
282
-        }
283
-        $tries = 2;
284
-        $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);
290
-                $this->linkId = 0;
291
-            }
292
-            $start = microtime(true);
293
-            $onlyRollback = true;
294
-            $fails = -1;
295
-            while ($fails < 30 && (null === $this->queryId || $this->queryId === false)) {
296
-                $this->connect();
297
-                $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}");
302
-                        usleep(250000); // 0.25 second
303
-                    } else {
304
-                        $onlyRollback = false;
305
-                        if (in_array((int)@mysqli_errno($this->linkId), [1064])) {
306
-                            $tries = 0;
307
-                        }
308
-                        break;
309
-                    }
310
-                } catch (\mysqli_sql_exception $e) {
311
-                    if (in_array((int)$e->getCode(), [1213, 2006, 3101, 1180])) {
312
-                        //error_log("got ".$e->getCode()." sql error fails {$fails}");
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
-                        break;
321
-                    }
322
-                }
323
-            }
324
-            if (!isset($GLOBALS['disable_db_queries'])) {
325
-                $this->addLog($queryString, microtime(true) - $start, $line, $file);
326
-            }
327
-            $this->Row = 0;
328
-            $this->Errno = @mysqli_errno($this->linkId);
329
-            $this->Error = @mysqli_error($this->linkId);
330
-            if ($try == 1 && (null === $this->queryId || $this->queryId === false)) {
331
-                //$this->emailError($queryString, 'Error #'.$this->Errno.': '.$this->Error, $line, $file);
332
-            }
333
-        }
334
-        $this->haltOnError = $haltPrev;
335
-        if ($onlyRollback === true && false === $this->queryId) {
336
-            error_log('Got MySQLi 3101 Rollback Error '.$fails.' Times, Giving Up on '.$queryString.' from '.$line.':'.$file.' on '.__LINE__.':'.__FILE__);
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
-        }
342
-
343
-        // Will return nada if it fails. That's fine.
344
-        return $this->queryId;
345
-    }
346
-
347
-    /**
348
-    * @return array|null|object
349
-    */
350
-    public function fetchObject()
351
-    {
352
-        $this->Record = @mysqli_fetch_object($this->queryId);
353
-        return $this->Record;
354
-    }
355
-
356
-    /* public: walk result set */
357
-
358
-    /**
359
-    * Db::next_record()
360
-    *
361
-    * @param mixed $resultType
362
-    * @return bool
363
-    */
364
-    public function next_record($resultType = MYSQLI_BOTH)
365
-    {
366
-        if ($this->queryId === false) {
367
-            $this->haltmsg('next_record called with no query pending.');
368
-            return 0;
369
-        }
370
-
371
-        $this->Record = @mysqli_fetch_array($this->queryId, $resultType);
372
-        ++$this->Row;
373
-        $this->Errno = mysqli_errno($this->linkId);
374
-        $this->Error = mysqli_error($this->linkId);
375
-
376
-        $stat = is_array($this->Record);
377
-        if (!$stat && $this->autoFree && is_resource($this->queryId)) {
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
-    * @return bool whetherit was successfu or not.
388
-    */
389
-    public function seek($pos = 0)
390
-    {
391
-        $status = @mysqli_data_seek($this->queryId, $pos);
392
-        if ($status) {
393
-            $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);
399
-            $this->Row = $rows;
400
-            return false;
401
-        }
402
-        return true;
403
-    }
404
-
405
-    /**
406
-    * Initiates a transaction
407
-    *
408
-    * @return bool
409
-    */
410
-    public function transactionBegin()
411
-    {
412
-        if (version_compare(PHP_VERSION, '5.5.0') < 0) {
413
-            return true;
414
-        }
415
-        if (!$this->connect()) {
416
-            return 0;
417
-        }
418
-        return mysqli_begin_transaction($this->linkId);
419
-    }
420
-
421
-    /**
422
-    * Commits a transaction
423
-    *
424
-    * @return bool
425
-    */
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);
432
-    }
433
-
434
-    /**
435
-    * Rolls back a transaction
436
-    *
437
-    * @return bool
438
-    */
439
-    public function transactionAbort()
440
-    {
441
-        if (version_compare(PHP_VERSION, '5.5.0') < 0 || $this->linkId === 0) {
442
-            return true;
443
-        }
444
-        return mysqli_rollback($this->linkId);
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
-    *
452
-    * @param string $table
453
-    * @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
-        }
461
-
462
-        return @mysqli_insert_id($this->linkId);
463
-    }
464
-
465
-    /* public: table locking */
466
-
467
-    /**
468
-    * Db::lock()
469
-    * @param mixed  $table
470
-    * @param string $mode
471
-    * @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
-                if ($key == 'read' && $key != 0) {
480
-                    $query .= "$value read, ";
481
-                } else {
482
-                    $query .= "$value $mode, ";
483
-                }
484
-            }
485
-            $query = mb_substr($query, 0, -2);
486
-        } else {
487
-            $query .= "$table $mode";
488
-        }
489
-        $res = @mysqli_query($this->linkId, $query);
490
-        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);
523
-    }
524
-
525
-    /**
526
-    * Db::num_rows()
527
-    * @return int
528
-    */
529
-    public function num_rows()
530
-    {
531
-        return @mysqli_num_rows($this->queryId);
532
-    }
533
-
534
-    /**
535
-    * Db::num_fields()
536
-    * @return int
537
-    */
538
-    public function num_fields()
539
-    {
540
-        return @mysqli_num_fields($this->queryId);
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()) {
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
-    }
264
+		if ($queryString == '') {
265
+			return 0;
266
+		}
267
+		if (!$this->connect()) {
268
+			return 0;
269
+			/* we already complained in connect() about that. */
270
+		}
271
+		$haltPrev = $this->haltOnError;
272
+		$this->haltOnError = 'no';
273
+		// New query, discard previous result.
274
+		if (is_resource($this->queryId)) {
275
+			$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
+			$this->log($queryString, $line, $file);
282
+		}
283
+		$tries = 2;
284
+		$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);
290
+				$this->linkId = 0;
291
+			}
292
+			$start = microtime(true);
293
+			$onlyRollback = true;
294
+			$fails = -1;
295
+			while ($fails < 30 && (null === $this->queryId || $this->queryId === false)) {
296
+				$this->connect();
297
+				$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}");
302
+						usleep(250000); // 0.25 second
303
+					} else {
304
+						$onlyRollback = false;
305
+						if (in_array((int)@mysqli_errno($this->linkId), [1064])) {
306
+							$tries = 0;
307
+						}
308
+						break;
309
+					}
310
+				} catch (\mysqli_sql_exception $e) {
311
+					if (in_array((int)$e->getCode(), [1213, 2006, 3101, 1180])) {
312
+						//error_log("got ".$e->getCode()." sql error fails {$fails}");
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
+						break;
321
+					}
322
+				}
323
+			}
324
+			if (!isset($GLOBALS['disable_db_queries'])) {
325
+				$this->addLog($queryString, microtime(true) - $start, $line, $file);
326
+			}
327
+			$this->Row = 0;
328
+			$this->Errno = @mysqli_errno($this->linkId);
329
+			$this->Error = @mysqli_error($this->linkId);
330
+			if ($try == 1 && (null === $this->queryId || $this->queryId === false)) {
331
+				//$this->emailError($queryString, 'Error #'.$this->Errno.': '.$this->Error, $line, $file);
332
+			}
333
+		}
334
+		$this->haltOnError = $haltPrev;
335
+		if ($onlyRollback === true && false === $this->queryId) {
336
+			error_log('Got MySQLi 3101 Rollback Error '.$fails.' Times, Giving Up on '.$queryString.' from '.$line.':'.$file.' on '.__LINE__.':'.__FILE__);
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
+		}
342
+
343
+		// Will return nada if it fails. That's fine.
344
+		return $this->queryId;
345
+	}
346
+
347
+	/**
348
+	 * @return array|null|object
349
+	 */
350
+	public function fetchObject()
351
+	{
352
+		$this->Record = @mysqli_fetch_object($this->queryId);
353
+		return $this->Record;
354
+	}
355
+
356
+	/* public: walk result set */
357
+
358
+	/**
359
+	 * Db::next_record()
360
+	 *
361
+	 * @param mixed $resultType
362
+	 * @return bool
363
+	 */
364
+	public function next_record($resultType = MYSQLI_BOTH)
365
+	{
366
+		if ($this->queryId === false) {
367
+			$this->haltmsg('next_record called with no query pending.');
368
+			return 0;
369
+		}
370
+
371
+		$this->Record = @mysqli_fetch_array($this->queryId, $resultType);
372
+		++$this->Row;
373
+		$this->Errno = mysqli_errno($this->linkId);
374
+		$this->Error = mysqli_error($this->linkId);
375
+
376
+		$stat = is_array($this->Record);
377
+		if (!$stat && $this->autoFree && is_resource($this->queryId)) {
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
+	 * @return bool whetherit was successfu or not.
388
+	 */
389
+	public function seek($pos = 0)
390
+	{
391
+		$status = @mysqli_data_seek($this->queryId, $pos);
392
+		if ($status) {
393
+			$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);
399
+			$this->Row = $rows;
400
+			return false;
401
+		}
402
+		return true;
403
+	}
404
+
405
+	/**
406
+	 * Initiates a transaction
407
+	 *
408
+	 * @return bool
409
+	 */
410
+	public function transactionBegin()
411
+	{
412
+		if (version_compare(PHP_VERSION, '5.5.0') < 0) {
413
+			return true;
414
+		}
415
+		if (!$this->connect()) {
416
+			return 0;
417
+		}
418
+		return mysqli_begin_transaction($this->linkId);
419
+	}
420
+
421
+	/**
422
+	 * Commits a transaction
423
+	 *
424
+	 * @return bool
425
+	 */
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);
432
+	}
433
+
434
+	/**
435
+	 * Rolls back a transaction
436
+	 *
437
+	 * @return bool
438
+	 */
439
+	public function transactionAbort()
440
+	{
441
+		if (version_compare(PHP_VERSION, '5.5.0') < 0 || $this->linkId === 0) {
442
+			return true;
443
+		}
444
+		return mysqli_rollback($this->linkId);
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
+	 *
452
+	 * @param string $table
453
+	 * @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
+		}
461
+
462
+		return @mysqli_insert_id($this->linkId);
463
+	}
464
+
465
+	/* public: table locking */
466
+
467
+	/**
468
+	 * Db::lock()
469
+	 * @param mixed  $table
470
+	 * @param string $mode
471
+	 * @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
+				if ($key == 'read' && $key != 0) {
480
+					$query .= "$value read, ";
481
+				} else {
482
+					$query .= "$value $mode, ";
483
+				}
484
+			}
485
+			$query = mb_substr($query, 0, -2);
486
+		} else {
487
+			$query .= "$table $mode";
488
+		}
489
+		$res = @mysqli_query($this->linkId, $query);
490
+		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);
523
+	}
524
+
525
+	/**
526
+	 * Db::num_rows()
527
+	 * @return int
528
+	 */
529
+	public function num_rows()
530
+	{
531
+		return @mysqli_num_rows($this->queryId);
532
+	}
533
+
534
+	/**
535
+	 * Db::num_fields()
536
+	 * @return int
537
+	 */
538
+	public function num_fields()
539
+	{
540
+		return @mysqli_num_fields($this->queryId);
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()) {
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 561
 }
562 562
 
563 563
 /**
Please login to merge, or discard this patch.