GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Issues (3647)

symphony/lib/toolkit/class.mysql.php (74 issues)

1
<?php
2
3
/**
4
 * @package toolkit
5
 */
6
7
/**
8
 * The DatabaseException class extends a normal Exception to add in
9
 * debugging information when a SQL query fails such as the internal
10
 * database error code and message in additional to the usual
11
 * Exception information. It allows a DatabaseException to contain a human
12
 * readable error, as well more technical information for debugging.
13
 */
14
class DatabaseException extends Exception
15
{
16
    /**
17
     * An associative array with three keys, 'query', 'msg' and 'num'
18
     * @var array
19
     */
20
    private $_error = array();
21
22
    /**
23
     * Constructor takes a message and an associative array to set to
24
     * `$_error`. The message is passed to the default Exception constructor
25
     */
26
    public function __construct($message, array $error = null)
0 ignored issues
show
Incorrect spacing between argument "$error" and equals sign; expected 0 but found 1
Loading history...
Incorrect spacing between default value and equals sign for argument "$error"; expected 0 but found 1
Loading history...
27
    {
28
        parent::__construct($message);
29
        $this->_error = $error;
30
    }
31
32
    /**
33
     * Accessor function for the original query that caused this Exception
34
     *
35
     * @return string
36
     */
37
    public function getQuery()
38
    {
39
        return $this->_error['query'];
40
    }
41
42
    /**
43
     * Accessor function for the Database error code for this type of error
44
     *
45
     * @return integer
46
     */
47
    public function getDatabaseErrorCode()
48
    {
49
        return $this->_error['num'];
50
    }
51
52
    /**
53
     * Accessor function for the Database message from this Exception
54
     *
55
     * @return string
56
     */
57
    public function getDatabaseErrorMessage()
58
    {
59
        return $this->_error['msg'];
60
    }
61
}
62
63
/**
64
 * The MySQL class acts as a wrapper for connecting to the Database
65
 * in Symphony. It utilises mysqli_* functions in PHP to complete the usual
66
 * querying. As well as the normal set of insert, update, delete and query
67
 * functions, some convenience functions are provided to return results
68
 * in different ways. Symphony uses a prefix to namespace it's tables in a
69
 * database, allowing it play nice with other applications installed on the
70
 * database. An errors that occur during a query throw a `DatabaseException`.
71
 * By default, Symphony logs all queries to be used for Profiling and Debug
72
 * devkit extensions when a Developer is logged in. When a developer is not
73
 * logged in, all queries and errors are made available with delegates.
74
 */
75
class MySQL
76
{
77
    /**
78
     * Constant to indicate whether the query is a write operation.
79
     *
80
     * @var integer
81
     */
82
    const __WRITE_OPERATION__ = 0;
83
84
    /**
85
     * Constant to indicate whether the query is a write operation
86
     *
87
     * @var integer
88
     */
89
    const __READ_OPERATION__ = 1;
90
91
    /**
92
     * Sets the current `$_log` to be an empty array
93
     *
94
     * @var array
95
     */
96
    private static $_log = array();
97
98
    /**
99
     * The number of queries this class has executed, defaults to 0.
100
     *
101
     * @var integer
102
     */
103
    private static $_query_count = 0;
104
105
    /**
106
     * Whether query caching is enabled or not. By default this is set
107
     * to true which will use SQL_CACHE to cache the results of queries
108
     *
109
     * @var boolean
110
     */
111
    private static $_cache = true;
112
113
    /**
114
     * Whether query logging is enabled or not. By default this is set
115
     * to true, which allows profiling of queries
116
     *
117
     * @var boolean
118
     */
119
    private static $_logging = true;
120
121
    /**
122
     * An associative array of connection properties for this MySQL
123
     * database including the host, port, username, password and
124
     * selected database.
125
     *
126
     * @var array
127
     */
128
    private static $_connection = array();
129
130
    /**
131
     * The resource of the last result returned from mysqli_query
132
     *
133
     * @var resource
134
     */
135
    private $_result = null;
136
137
    /**
138
     * The last query that was executed by the class
139
     */
140
    private $_lastQuery = null;
141
142
    /**
143
     * The hash value of the last query that was executed by the class
144
     */
145
    private $_lastQueryHash = null;
146
147
    /**
148
     * The auto increment value returned by the last query that was executed
149
     * by the class
150
     */
151
    private $_lastInsertID = null;
152
153
    /**
154
     * By default, an array of arrays or objects representing the result set
155
     * from the `$this->_lastQuery`
156
     */
157
    private $_lastResult = array();
158
159
    /**
160
     * Magic function that will flush the MySQL log and close the MySQL
161
     * connection when the MySQL class is removed or destroyed.
162
     *
163
     * @link http://php.net/manual/en/language.oop5.decon.php
164
     */
165
    public function __destruct()
166
    {
167
        $this->flush();
168
        $this->close();
169
    }
170
171
    /**
172
     * Resets the result, `$this->_lastResult` and `$this->_lastQuery` to their empty
173
     * values. Called on each query and when the class is destroyed.
174
     */
175
    public function flush()
176
    {
177
        $this->_result = null;
178
        $this->_lastResult = array();
179
        $this->_lastQuery = null;
180
        $this->_lastQueryHash = null;
181
    }
182
183
    /**
184
     * Sets the current `$_log` to be an empty array
185
     */
186
    public static function flushLog()
187
    {
188
        self::$_log = array();
189
    }
190
191
    /**
192
     * Returns the number of queries that has been executed
193
     *
194
     * @return integer
195
     */
196
    public static function queryCount()
197
    {
198
        return self::$_query_count;
199
    }
200
201
    /**
202
     * Sets query caching to true, this will prepend all READ_OPERATION
203
     * queries with SQL_CACHE. Symphony by default enables caching. It
204
     * can be turned off by setting the `query_cache` parameter to `off` in the
205
     * Symphony config file.
206
     *
207
     * @link http://dev.mysql.com/doc/refman/5.1/en/query-cache.html
208
     */
209
    public static function enableCaching()
210
    {
211
        self::$_cache = true;
212
    }
213
214
    /**
215
     * Sets query caching to false, this will prepend all READ_OPERATION
216
     * queries will SQL_NO_CACHE.
217
     */
218
    public static function disableCaching()
219
    {
220
        self::$_cache = false;
221
    }
222
223
    /**
224
     * Returns boolean if query caching is enabled or not
225
     *
226
     * @return boolean
227
     */
228
    public static function isCachingEnabled()
229
    {
230
        return self::$_cache;
231
    }
232
233
    /**
234
     * Enables query logging and profiling.
235
     *
236
     * @since Symphony 2.6.2
237
     */
238
    public static function enableLogging()
239
    {
240
        self::$_logging = true;
241
    }
242
243
    /**
244
     * Disables query logging and profiling. Use this in low memory environments
245
     * to reduce memory usage.
246
     *
247
     * @since Symphony 2.6.2
248
     * @link https://github.com/symphonycms/symphony-2/issues/2398
249
     */
250
    public static function disableLogging()
251
    {
252
        self::$_logging = false;
253
    }
254
255
    /**
256
     * Returns boolean if logging is enabled or not
257
     *
258
     * @since Symphony 2.6.2
259
     * @return boolean
260
     */
261
    public static function isLoggingEnabled()
262
    {
263
        return self::$_logging;
264
    }
265
266
    /**
267
     * Symphony uses a prefix for all it's database tables so it can live peacefully
268
     * on the same database as other applications. By default this is `sym_`, but it
269
     * can be changed when Symphony is installed.
270
     *
271
     * @param string $prefix
272
     *  The table prefix for Symphony, by default this is `sym_`
273
     */
274
    public function setPrefix($prefix)
275
    {
276
        self::$_connection['tbl_prefix'] = $prefix;
277
    }
278
279
    /**
280
     * Returns the prefix used by Symphony for this Database instance.
281
     *
282
     * @since Symphony 2.4
283
     * @return string
284
     */
285
    public function getPrefix()
286
    {
287
        return self::$_connection['tbl_prefix'];
288
    }
289
290
    /**
291
     * Determines if a connection has been made to the MySQL server
292
     *
293
     * @return boolean
294
     */
295
    public static function isConnected()
296
    {
297
        try {
298
            $connected = (
299
                isset(self::$_connection['id'])
300
                && !is_null(self::$_connection['id'])
301
            );
302
        } catch (Exception $ex) {
303
            return false;
304
        }
305
306
        return $connected;
307
    }
308
309
    /**
310
     * Called when the script has finished executing, this closes the MySQL
311
     * connection
312
     *
313
     * @return boolean
314
     */
315
    public function close()
316
    {
317
        if ($this->isConnected()) {
318
            return mysqli_close(self::$_connection['id']);
319
        }
320
    }
321
322
    /**
323
     * Creates a connect to the database server given the credentials. If an
324
     * error occurs, a `DatabaseException` is thrown, otherwise true is returned
325
     *
326
     * @param string $host
327
     *  Defaults to null, which MySQL assumes as localhost.
328
     * @param string $user
329
     *  Defaults to null
330
     * @param string $password
331
     *  Defaults to null
332
     * @param string $port
333
     *  Defaults to 3306.
334
     * @param null $database
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $database is correct as it would always require null to be passed?
Loading history...
335
     * @throws DatabaseException
336
     * @return boolean
337
     */
338
    public function connect($host = null, $user = null, $password = null, $port = '3306', $database = null)
0 ignored issues
show
Incorrect spacing between argument "$host" and equals sign; expected 0 but found 1
Loading history...
Incorrect spacing between default value and equals sign for argument "$host"; expected 0 but found 1
Loading history...
Incorrect spacing between argument "$user" and equals sign; expected 0 but found 1
Loading history...
Incorrect spacing between default value and equals sign for argument "$user"; expected 0 but found 1
Loading history...
Incorrect spacing between argument "$password" and equals sign; expected 0 but found 1
Loading history...
Incorrect spacing between default value and equals sign for argument "$password"; expected 0 but found 1
Loading history...
Incorrect spacing between argument "$port" and equals sign; expected 0 but found 1
Loading history...
Incorrect spacing between default value and equals sign for argument "$port"; expected 0 but found 1
Loading history...
Incorrect spacing between argument "$database" and equals sign; expected 0 but found 1
Loading history...
Incorrect spacing between default value and equals sign for argument "$database"; expected 0 but found 1
Loading history...
339
    {
340
        self::$_connection = array(
341
            'host' => $host,
342
            'user' => $user,
343
            'pass' => $password,
344
            'port' => $port,
345
            'database' => $database
346
        );
347
348
        try {
349
            self::$_connection['id'] = mysqli_connect(
350
                self::$_connection['host'],
351
                self::$_connection['user'],
352
                self::$_connection['pass'],
353
                self::$_connection['database'],
354
                self::$_connection['port']
355
            );
356
357
            if (!$this->isConnected()) {
358
                $this->__error('connect');
359
            }
360
        } catch (Exception $ex) {
361
            $this->__error('connect');
362
        }
363
364
        return true;
365
    }
366
367
    /**
368
     * Accessor for the current MySQL resource from PHP. May be
369
     * useful for developers who want complete control over their
370
     * database queries and don't want anything abstract by the MySQL
371
     * class.
372
     *
373
     * @return resource
374
     */
375
    public static function getConnectionResource()
376
    {
377
        return self::$_connection['id'];
378
    }
379
380
    /**
381
     * This will set the character encoding of the connection for sending and
382
     * receiving data. This function will run every time the database class
383
     * is being initialized. If no character encoding is provided, UTF-8
384
     * is assumed.
385
     *
386
     * @link http://au2.php.net/manual/en/function.mysql-set-charset.php
387
     * @param string $set
388
     *  The character encoding to use, by default this 'utf8'
389
     */
390
    public function setCharacterEncoding($set = 'utf8')
0 ignored issues
show
Incorrect spacing between argument "$set" and equals sign; expected 0 but found 1
Loading history...
Incorrect spacing between default value and equals sign for argument "$set"; expected 0 but found 1
Loading history...
391
    {
392
        mysqli_set_charset(self::$_connection['id'], $set);
393
    }
394
395
    /**
396
     * This function will set the character encoding of the database so that any
397
     * new tables that are created by Symphony use this character encoding
398
     *
399
     * @link http://dev.mysql.com/doc/refman/5.0/en/charset-connection.html
400
     * @param string $set
401
     *  The character encoding to use, by default this 'utf8'
402
     * @throws DatabaseException
403
     */
404
    public function setCharacterSet($set = 'utf8')
0 ignored issues
show
Incorrect spacing between argument "$set" and equals sign; expected 0 but found 1
Loading history...
Incorrect spacing between default value and equals sign for argument "$set"; expected 0 but found 1
Loading history...
405
    {
406
        $this->query("SET character_set_connection = '$set', character_set_database = '$set', character_set_server = '$set'");
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $set instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
407
        $this->query("SET CHARACTER SET '$set'");
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $set instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
408
    }
409
410
    /**
411
     * Sets the MySQL connection to use this timezone instead of the default
412
     * MySQL server timezone.
413
     *
414
     * @throws DatabaseException
415
     * @link https://dev.mysql.com/doc/refman/5.6/en/time-zone-support.html
416
     * @link https://github.com/symphonycms/symphony-2/issues/1726
417
     * @since Symphony 2.3.3
418
     * @param string $timezone
419
     *  Timezone will human readable, such as Australia/Brisbane.
420
     */
421
    public function setTimeZone($timezone = null)
0 ignored issues
show
Incorrect spacing between argument "$timezone" and equals sign; expected 0 but found 1
Loading history...
Incorrect spacing between default value and equals sign for argument "$timezone"; expected 0 but found 1
Loading history...
422
    {
423
        if (is_null($timezone)) {
424
            return;
425
        }
426
427
        // What is the time now in the install timezone
428
        $symphony_date = new DateTime('now', new DateTimeZone($timezone));
429
430
        // MySQL wants the offset to be in the format +/-H:I, getOffset returns offset in seconds
431
        $utc = new DateTime('now ' . $symphony_date->getOffset() . ' seconds', new DateTimeZone("UTC"));
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal UTC does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
432
433
        // Get the difference between the symphony install timezone and UTC
434
        $offset = $symphony_date->diff($utc)->format('%R%H:%I');
435
436
        $this->query("SET time_zone = '$offset'");
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $offset instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
437
    }
438
439
    /**
440
     * This function will clean a string using the `mysqli_real_escape_string` function
441
     * taking into account the current database character encoding. Note that this
442
     * function does not encode _ or %. If `mysqli_real_escape_string` doesn't exist,
443
     * `addslashes` will be used as a backup option
444
     *
445
     * @param string $value
446
     *  The string to be encoded into an escaped SQL string
447
     * @return string
448
     *  The escaped SQL string
449
     */
450
    public static function cleanValue($value)
451
    {
452
        if (function_exists('mysqli_real_escape_string') && self::isConnected()) {
453
            return mysqli_real_escape_string(self::$_connection['id'], $value);
454
        } else {
455
            return addslashes($value);
456
        }
457
    }
458
459
    /**
460
     * This function will apply the `cleanValue` function to an associative
461
     * array of data, encoding only the value, not the key. This function
462
     * can handle recursive arrays. This function manipulates the given
463
     * parameter by reference.
464
     *
465
     * @see cleanValue
466
     * @param array $array
467
     *  The associative array of data to encode, this parameter is manipulated
468
     *  by reference.
469
     */
470
    public static function cleanFields(array &$array)
471
    {
472
        foreach ($array as $key => $val) {
0 ignored issues
show
Blank line found at start of control structure
Loading history...
473
474
            // Handle arrays with more than 1 level
475
            if (is_array($val)) {
476
                self::cleanFields($val);
477
                continue;
478
            } elseif (strlen($val) == 0) {
479
                $array[$key] = 'null';
480
            } else {
481
                $array[$key] = "'" . self::cleanValue($val) . "'";
482
            }
483
        }
484
    }
485
486
    /**
487
     * Determines whether this query is a read operation, or if it is a write operation.
488
     * A write operation is determined as any query that starts with CREATE, INSERT,
489
     * REPLACE, ALTER, DELETE, UPDATE, OPTIMIZE, TRUNCATE or DROP. Anything else is
490
     * considered to be a read operation which are subject to query caching.
491
     *
492
     * @param string $query
493
     * @return integer
494
     *  `self::__WRITE_OPERATION__` or `self::__READ_OPERATION__`
495
     */
496
    public function determineQueryType($query)
497
    {
498
        return (preg_match('/^(create|insert|replace|alter|delete|update|optimize|truncate|drop)/i', $query) ? self::__WRITE_OPERATION__ : self::__READ_OPERATION__);
499
    }
500
501
    /**
502
     * Takes an SQL string and executes it. This function will apply query
503
     * caching if it is a read operation and if query caching is set. Symphony
504
     * will convert the `tbl_` prefix of tables to be the one set during installation.
505
     * A type parameter is provided to specify whether `$this->_lastResult` will be an array
506
     * of objects or an array of associative arrays. The default is objects. This
507
     * function will return boolean, but set `$this->_lastResult` to the result.
508
     *
509
     * @uses PostQueryExecution
510
     * @param string $query
511
     *  The full SQL query to execute.
512
     * @param string $type
513
     *  Whether to return the result as objects or associative array. Defaults
514
     *  to OBJECT which will return objects. The other option is ASSOC. If $type
515
     *  is not either of these, it will return objects.
516
     * @throws DatabaseException
517
     * @return boolean
518
     *  true if the query executed without errors, false otherwise
519
     */
520
    public function query($query, $type = "OBJECT")
0 ignored issues
show
Incorrect spacing between argument "$type" and equals sign; expected 0 but found 1
Loading history...
Incorrect spacing between default value and equals sign for argument "$type"; expected 0 but found 1
Loading history...
Coding Style Comprehensibility introduced by
The string literal OBJECT does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
521
    {
522
        if (empty($query) || self::isConnected() === false) {
523
            return false;
524
        }
525
526
        $start = precision_timer();
527
        $query = trim($query);
528
        $query_type = $this->determineQueryType($query);
529
        $query_hash = md5($query.$start);
530
531
        if (self::$_connection['tbl_prefix'] !== 'tbl_') {
532
            $query = preg_replace('/tbl_(\S+?)([\s\.,]|$)/', self::$_connection['tbl_prefix'].'\\1\\2', $query);
533
        }
534
535
        // TYPE is deprecated since MySQL 4.0.18, ENGINE is preferred
536
        if ($query_type == self::__WRITE_OPERATION__) {
537
            $query = preg_replace('/TYPE=(MyISAM|InnoDB)/i', 'ENGINE=$1', $query);
538
        } elseif ($query_type == self::__READ_OPERATION__ && !preg_match('/^SELECT\s+SQL(_NO)?_CACHE/i', $query)) {
539
            if ($this->isCachingEnabled()) {
540
                $query = preg_replace('/^SELECT\s+/i', 'SELECT SQL_CACHE ', $query);
541
            } else {
542
                $query = preg_replace('/^SELECT\s+/i', 'SELECT SQL_NO_CACHE ', $query);
543
            }
544
        }
545
546
        $this->flush();
547
        $this->_lastQuery = $query;
548
        $this->_lastQueryHash = $query_hash;
549
        $this->_result = mysqli_query(self::$_connection['id'], $query);
0 ignored issues
show
Documentation Bug introduced by
It seems like mysqli_query(self::_connection['id'], $query) of type boolean or mysqli_result is incompatible with the declared type resource of property $_result.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
550
        $this->_lastInsertID = mysqli_insert_id(self::$_connection['id']);
551
        self::$_query_count++;
552
553
        if (mysqli_error(self::$_connection['id'])) {
554
            $this->__error();
555
        } elseif (($this->_result instanceof mysqli_result)) {
556
            if ($type == "ASSOC") {
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal ASSOC does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
557
                while ($row = mysqli_fetch_assoc($this->_result)) {
558
                    $this->_lastResult[] = $row;
559
                }
560
            } else {
561
                while ($row = mysqli_fetch_object($this->_result)) {
562
                    $this->_lastResult[] = $row;
563
                }
564
            }
565
566
            mysqli_free_result($this->_result);
567
        }
568
569
        $stop = precision_timer('stop', $start);
570
571
        /**
572
         * After a query has successfully executed, that is it was considered
573
         * valid SQL, this delegate will provide the query, the query_hash and
574
         * the execution time of the query.
575
         *
576
         * Note that this function only starts logging once the ExtensionManager
577
         * is available, which means it will not fire for the first couple of
578
         * queries that set the character set.
579
         *
580
         * @since Symphony 2.3
581
         * @delegate PostQueryExecution
582
         * @param string $context
583
         * '/frontend/' or '/backend/'
584
         * @param string $query
585
         *  The query that has just been executed
586
         * @param string $query_hash
587
         *  The hash used by Symphony to uniquely identify this query
588
         * @param float $execution_time
589
         *  The time that it took to run `$query`
590
         */
591
        if (self::$_logging === true) {
592
            if (Symphony::ExtensionManager() instanceof ExtensionManager) {
0 ignored issues
show
Symphony::ExtensionManager() is always a sub-type of ExtensionManager.
Loading history...
593
                Symphony::ExtensionManager()->notifyMembers('PostQueryExecution', class_exists('Administration', false) ? '/backend/' : '/frontend/', array(
594
                    'query' => $query,
595
                    'query_hash' => $query_hash,
596
                    'execution_time' => $stop
597
                ));
598
599
                // If the ExceptionHandler is enabled, then the user is authenticated
600
                // or we have a serious issue, so log the query.
601
                if (GenericExceptionHandler::$enabled) {
602
                    self::$_log[$query_hash] = array(
603
                        'query' => $query,
604
                        'query_hash' => $query_hash,
605
                        'execution_time' => $stop
606
                    );
607
                }
608
609
                // Symphony isn't ready yet. Log internally
610
            } else {
611
                self::$_log[$query_hash] = array(
612
                    'query' => $query,
613
                    'query_hash' => $query_hash,
614
                    'execution_time' => $stop
615
                );
616
            }
617
        }
618
619
        return true;
620
    }
621
622
    /**
623
     * Returns the last insert ID from the previous query. This is
624
     * the value from an auto_increment field.
625
     *
626
     * @return integer
627
     *  The last interested row's ID
628
     */
629
    public function getInsertID()
630
    {
631
        return $this->_lastInsertID;
632
    }
633
634
    /**
635
     * A convenience method to insert data into the Database. This function
636
     * takes an associative array of data to input, with the keys being the column
637
     * names and the table. An optional parameter exposes MySQL's ON DUPLICATE
638
     * KEY UPDATE functionality, which will update the values if a duplicate key
639
     * is found.
640
     *
641
     * @param array $fields
642
     *  An associative array of data to input, with the key's mapping to the
643
     *  column names. Alternatively, an array of associative array's can be
644
     *  provided, which will perform multiple inserts
645
     * @param string $table
646
     *  The table name, including the tbl prefix which will be changed
647
     *  to this Symphony's table prefix in the query function
648
     * @param boolean $updateOnDuplicate
649
     *  If set to true, data will updated if any key constraints are found that cause
650
     *  conflicts. By default this is set to false, which will not update the data and
651
     *  would return an SQL error
652
     * @throws DatabaseException
653
     * @return boolean
654
     */
655
    public function insert(array $fields, $table, $updateOnDuplicate = false)
0 ignored issues
show
Incorrect spacing between argument "$updateOnDuplicate" and equals sign; expected 0 but found 1
Loading history...
Incorrect spacing between default value and equals sign for argument "$updateOnDuplicate"; expected 0 but found 1
Loading history...
656
    {
657
        // Multiple Insert
658
        if (is_array(current($fields))) {
659
            $sql  = "INSERT INTO `$table` (`".implode('`, `', array_keys(current($fields))).'`) VALUES ';
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $table instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
660
            $rows = array();
661
662
            foreach ($fields as $key => $array) {
663
                // Sanity check: Make sure we dont end up with ',()' in the SQL.
664
                if (!is_array($array)) {
665
                    continue;
666
                }
667
668
                self::cleanFields($array);
669
                $rows[] = '('.implode(', ', $array).')';
670
            }
671
672
            $sql .= implode(", ", $rows);
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal , does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
673
674
            // Single Insert
675
        } else {
676
            self::cleanFields($fields);
677
            $sql  = "INSERT INTO `$table` (`".implode('`, `', array_keys($fields)).'`) VALUES ('.implode(', ', $fields).')';
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $table instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
678
679
            if ($updateOnDuplicate) {
680
                $sql .= ' ON DUPLICATE KEY UPDATE ';
681
682
                foreach ($fields as $key => $value) {
683
                    $sql .= " `$key` = $value,";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $key instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $value instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
684
                }
685
686
                $sql = trim($sql, ',');
687
            }
688
        }
689
690
        return $this->query($sql);
691
    }
692
693
    /**
694
     * A convenience method to update data that exists in the Database. This function
695
     * takes an associative array of data to input, with the keys being the column
696
     * names and the table. A WHERE statement can be provided to select the rows
697
     * to update
698
     *
699
     * @param array $fields
700
     *  An associative array of data to input, with the key's mapping to the
701
     *  column names.
702
     * @param string $table
703
     *  The table name, including the tbl prefix which will be changed
704
     *  to this Symphony's table prefix in the query function
705
     * @param string $where
706
     *  A WHERE statement for this UPDATE statement, defaults to null
707
     *  which will update all rows in the $table
708
     * @throws DatabaseException
709
     * @return boolean
710
     */
711
    public function update($fields, $table, $where = null)
0 ignored issues
show
Incorrect spacing between argument "$where" and equals sign; expected 0 but found 1
Loading history...
Incorrect spacing between default value and equals sign for argument "$where"; expected 0 but found 1
Loading history...
712
    {
713
        self::cleanFields($fields);
714
        $sql = "UPDATE $table SET ";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $table instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
715
        $rows = array();
716
717
        foreach ($fields as $key => $val) {
718
            $rows[] = " `$key` = $val";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $key instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $val instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
719
        }
720
721
        $sql .= implode(', ', $rows) . (!is_null($where) ? ' WHERE ' . $where : null);
722
723
        return $this->query($sql);
724
    }
725
726
    /**
727
     * Given a table name and a WHERE statement, delete rows from the
728
     * Database.
729
     *
730
     * @param string $table
731
     *  The table name, including the tbl prefix which will be changed
732
     *  to this Symphony's table prefix in the query function
733
     * @param string $where
734
     *  A WHERE statement for this DELETE statement, defaults to null,
735
     *  which will delete all rows in the $table
736
     * @throws DatabaseException
737
     * @return boolean
738
     */
739
    public function delete($table, $where = null)
0 ignored issues
show
Incorrect spacing between argument "$where" and equals sign; expected 0 but found 1
Loading history...
Incorrect spacing between default value and equals sign for argument "$where"; expected 0 but found 1
Loading history...
740
    {
741
        $sql = "DELETE FROM `$table`";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $table instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
742
743
        if (!is_null($where)) {
744
            $sql .= " WHERE $where";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $where instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
745
        }
746
747
        return $this->query($sql);
748
    }
749
750
    /**
751
     * Returns an associative array that contains the results of the
752
     * given `$query`. Optionally, the resulting array can be indexed
753
     * by a particular column.
754
     *
755
     * @param string $query
756
     *  The full SQL query to execute. Defaults to null, which will
757
     *  use the _lastResult
758
     * @param string $index_by_column
759
     *  The name of a column in the table to use it's value to index
760
     *  the result by. If this is omitted (and it is by default), an
761
     *  array of associative arrays is returned, with the key being the
762
     *  column names
763
     * @throws DatabaseException
764
     * @return array
765
     *  An associative array with the column names as the keys
766
     */
767
    public function fetch($query = null, $index_by_column = null)
0 ignored issues
show
Incorrect spacing between argument "$query" and equals sign; expected 0 but found 1
Loading history...
Incorrect spacing between default value and equals sign for argument "$query"; expected 0 but found 1
Loading history...
Incorrect spacing between argument "$index_by_column" and equals sign; expected 0 but found 1
Loading history...
Incorrect spacing between default value and equals sign for argument "$index_by_column"; expected 0 but found 1
Loading history...
768
    {
769
        if (!is_null($query)) {
770
            $this->query($query, "ASSOC");
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal ASSOC does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
771
        } elseif (is_null($this->_lastResult)) {
0 ignored issues
show
The condition is_null($this->_lastResult) is always false.
Loading history...
772
            return array();
773
        }
774
775
        $result = $this->_lastResult;
776
777
        if (!is_null($index_by_column) && isset($result[0][$index_by_column])) {
778
            $n = array();
779
780
            foreach ($result as $ii) {
781
                $n[$ii[$index_by_column]] = $ii;
782
            }
783
784
            $result = $n;
785
        }
786
787
        return $result;
788
    }
789
790
    /**
791
     * Returns the row at the specified index from the given query. If no
792
     * query is given, it will use the `$this->_lastResult`. If no offset is provided,
793
     * the function will return the first row. This function does not imply any
794
     * LIMIT to the given `$query`, so for the more efficient use, it is recommended
795
     * that the `$query` have a LIMIT set.
796
     *
797
     * @param integer $offset
798
     *  The row to return from the SQL query. For instance, if the second
799
     *  row from the result was required, the offset would be 1, because it
800
     *  is zero based.
801
     * @param string $query
802
     *  The full SQL query to execute. Defaults to null, which will
803
     *  use the `$this->_lastResult`
804
     * @throws DatabaseException
805
     * @return array
806
     *  If there is no row at the specified `$offset`, an empty array will be returned
807
     *  otherwise an associative array of that row will be returned.
808
     */
809
    public function fetchRow($offset = 0, $query = null)
0 ignored issues
show
Incorrect spacing between argument "$offset" and equals sign; expected 0 but found 1
Loading history...
Incorrect spacing between default value and equals sign for argument "$offset"; expected 0 but found 1
Loading history...
Incorrect spacing between argument "$query" and equals sign; expected 0 but found 1
Loading history...
Incorrect spacing between default value and equals sign for argument "$query"; expected 0 but found 1
Loading history...
810
    {
811
        $result = $this->fetch($query);
812
        return (empty($result) ? array() : $result[$offset]);
813
    }
814
815
    /**
816
     * Returns an array of values for a specified column in a given query.
817
     * If no query is given, it will use the `$this->_lastResult`.
818
     *
819
     * @param string $column
820
     *  The column name in the query to return the values for
821
     * @param string $query
822
     *  The full SQL query to execute. Defaults to null, which will
823
     *  use the `$this->_lastResult`
824
     * @throws DatabaseException
825
     * @return array
826
     *  If there is no results for the `$query`, an empty array will be returned
827
     *  otherwise an array of values for that given `$column` will be returned
828
     */
829
    public function fetchCol($column, $query = null)
0 ignored issues
show
Incorrect spacing between argument "$query" and equals sign; expected 0 but found 1
Loading history...
Incorrect spacing between default value and equals sign for argument "$query"; expected 0 but found 1
Loading history...
830
    {
831
        $result = $this->fetch($query);
832
833
        if (empty($result)) {
834
            return array();
835
        }
836
837
        $rows = array();
838
        foreach ($result as $row) {
839
            $rows[] = $row[$column];
840
        }
841
842
        return $rows;
843
    }
844
845
    /**
846
     * Returns the value for a specified column at a specified offset. If no
847
     * offset is provided, it will return the value for column of the first row.
848
     * If no query is given, it will use the `$this->_lastResult`.
849
     *
850
     * @param string $column
851
     *  The column name in the query to return the values for
852
     * @param integer $offset
853
     *  The row to use to return the value for the given `$column` from the SQL
854
     *  query. For instance, if `$column` form the second row was required, the
855
     *  offset would be 1, because it is zero based.
856
     * @param string $query
857
     *  The full SQL query to execute. Defaults to null, which will
858
     *  use the `$this->_lastResult`
859
     * @throws DatabaseException
860
     * @return string|null
861
     *  Returns the value of the given column, if it doesn't exist, null will be
862
     *  returned
863
     */
864
    public function fetchVar($column, $offset = 0, $query = null)
0 ignored issues
show
Incorrect spacing between argument "$offset" and equals sign; expected 0 but found 1
Loading history...
Incorrect spacing between default value and equals sign for argument "$offset"; expected 0 but found 1
Loading history...
Incorrect spacing between argument "$query" and equals sign; expected 0 but found 1
Loading history...
Incorrect spacing between default value and equals sign for argument "$query"; expected 0 but found 1
Loading history...
865
    {
866
        $result = $this->fetch($query);
867
        return (empty($result) ? null : $result[$offset][$column]);
868
    }
869
870
    /**
871
     * This function takes `$table` and `$field` names and returns boolean
872
     * if the `$table` contains the `$field`.
873
     *
874
     * @since Symphony 2.3
875
     * @link  https://dev.mysql.com/doc/refman/en/describe.html
876
     * @param string $table
877
     *  The table name
878
     * @param string $field
879
     *  The field name
880
     * @throws DatabaseException
881
     * @return boolean
882
     *  true if `$table` contains `$field`, false otherwise
883
     */
884
    public function tableContainsField($table, $field)
885
    {
886
        $table = MySQL::cleanValue($table);
887
        $field = MySQL::cleanValue($field);
888
        $results = $this->fetch("DESC `{$table}` `{$field}`");
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $table instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $field instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
889
        return (is_array($results) && !empty($results));
890
    }
891
892
    /**
893
     * This function takes `$table` and returns boolean
894
     * if it exists or not.
895
     *
896
     * @since Symphony 2.3.4
897
     * @link  https://dev.mysql.com/doc/refman/en/show-tables.html
898
     * @param string $table
899
     *  The table name
900
     * @throws DatabaseException
901
     * @return boolean
902
     *  true if `$table` exists, false otherwise
903
     */
904
    public function tableExists($table)
905
    {
906
        $table = MySQL::cleanValue($table);
907
        $results = $this->fetch(sprintf("SHOW TABLES LIKE '%s'", $table));
908
        return (is_array($results) && !empty($results));
909
    }
910
911
    /**
912
     * If an error occurs in a query, this function is called which logs
913
     * the last query and the error number and error message from MySQL
914
     * before throwing a `DatabaseException`
915
     *
916
     * @uses QueryExecutionError
917
     * @throws DatabaseException
918
     * @param string $type
919
     *  Accepts one parameter, 'connect', which will return the correct
920
     *  error codes when the connection sequence fails
921
     */
922
    private function __error($type = null)
0 ignored issues
show
Incorrect spacing between argument "$type" and equals sign; expected 0 but found 1
Loading history...
Incorrect spacing between default value and equals sign for argument "$type"; expected 0 but found 1
Loading history...
923
    {
924
        if ($type == 'connect') {
925
            $msg = mysqli_connect_error();
926
            $errornum = mysqli_connect_errno();
927
        } else {
928
            $msg = mysqli_error(self::$_connection['id']);
929
            $errornum = mysqli_errno(self::$_connection['id']);
930
        }
931
932
        /**
933
         * After a query execution has failed this delegate will provide the query,
934
         * query hash, error message and the error number.
935
         *
936
         * Note that this function only starts logging once the `ExtensionManager`
937
         * is available, which means it will not fire for the first couple of
938
         * queries that set the character set.
939
         *
940
         * @since Symphony 2.3
941
         * @delegate QueryExecutionError
942
         * @param string $context
943
         * '/frontend/' or '/backend/'
944
         * @param string $query
945
         *  The query that has just been executed
946
         * @param string $query_hash
947
         *  The hash used by Symphony to uniquely identify this query
948
         * @param string $msg
949
         *  The error message provided by MySQL which includes information on why the execution failed
950
         * @param integer $num
951
         *  The error number that corresponds with the MySQL error message
952
         */
953
        if (self::$_logging === true) {
954
            if (Symphony::ExtensionManager() instanceof ExtensionManager) {
0 ignored issues
show
Symphony::ExtensionManager() is always a sub-type of ExtensionManager.
Loading history...
955
                Symphony::ExtensionManager()->notifyMembers('QueryExecutionError', class_exists('Administration', false) ? '/backend/' : '/frontend/', array(
956
                    'query' => $this->_lastQuery,
957
                    'query_hash' => $this->_lastQueryHash,
958
                    'msg' => $msg,
959
                    'num' => $errornum
960
                ));
961
            }
962
        }
963
964
        throw new DatabaseException(__('MySQL Error (%1$s): %2$s in query: %3$s', array($errornum, $msg, $this->_lastQuery)), array(
965
            'msg' => $msg,
966
            'num' => $errornum,
967
            'query' => $this->_lastQuery
968
        ));
969
    }
970
971
    /**
972
     * Returns all the log entries by type. There are two valid types,
973
     * error and debug. If no type is given, the entire log is returned,
974
     * otherwise only log messages for that type are returned
975
     *
976
     * @param null|string $type
977
     * @return array
978
     *  An array of associative array's. Log entries of the error type
979
     *  return the query the error occurred on and the error number and
980
     *  message from MySQL. Log entries of the debug type return the
981
     *  the query and the start/stop time to indicate how long it took
982
     *  to run
983
     */
984
    public function debug($type = null)
0 ignored issues
show
Incorrect spacing between argument "$type" and equals sign; expected 0 but found 1
Loading history...
Incorrect spacing between default value and equals sign for argument "$type"; expected 0 but found 1
Loading history...
985
    {
986
        if (!$type) {
987
            return self::$_log;
988
        }
989
990
        return ($type == 'error' ? self::$_log['error'] : self::$_log['query']);
0 ignored issues
show
Inline shorthand IF statement requires brackets around comparison
Loading history...
991
    }
992
993
    /**
994
     * Returns some basic statistics from the MySQL class about the
995
     * number of queries, the time it took to query and any slow queries.
996
     * A slow query is defined as one that took longer than 0.0999 seconds
997
     * This function is used by the Profile devkit
998
     *
999
     * @return array
1000
     *  An associative array with the number of queries, an array of slow
1001
     *  queries and the total query time.
1002
     */
1003
    public function getStatistics()
1004
    {
1005
        $query_timer = 0.0;
1006
        $slow_queries = array();
1007
1008
        foreach (self::$_log as $key => $val) {
1009
            $query_timer += $val['execution_time'];
1010
            if ($val['execution_time'] > 0.0999) {
1011
                $slow_queries[] = $val;
1012
            }
1013
        }
1014
1015
        return array(
1016
            'queries' => self::queryCount(),
1017
            'slow-queries' => $slow_queries,
1018
            'total-query-time' => number_format($query_timer, 4, '.', '')
1019
        );
1020
    }
1021
1022
    /**
1023
     * Convenience function to allow you to execute multiple SQL queries at once
1024
     * by providing a string with the queries delimited with a `;`
1025
     *
1026
     * @throws DatabaseException
1027
     * @throws Exception
1028
     * @param string $sql
1029
     *  A string containing SQL queries delimited by `;`
1030
     * @param boolean $force_engine
1031
     *  If set to true, this will set MySQL's default storage engine to MyISAM.
1032
     *  Defaults to false, which will use MySQL's default storage engine when
1033
     *  tables don't explicitly define which engine they should be created with
1034
     * @return boolean
1035
     *  If one of the queries fails, false will be returned and no further queries
1036
     *  will be executed, otherwise true will be returned.
1037
     */
1038
    public function import($sql, $force_engine = false)
0 ignored issues
show
Incorrect spacing between argument "$force_engine" and equals sign; expected 0 but found 1
Loading history...
Incorrect spacing between default value and equals sign for argument "$force_engine"; expected 0 but found 1
Loading history...
1039
    {
1040
        if ($force_engine) {
1041
            // Silently attempt to change the storage engine. This prevents INNOdb errors.
1042
            $this->query('SET default_storage_engine = MYISAM');
1043
        }
1044
1045
        $queries = preg_split('/;[\\r\\n]+/', $sql, -1, PREG_SPLIT_NO_EMPTY);
1046
1047
        if (!is_array($queries) || empty($queries) || count($queries) <= 0) {
1048
            throw new Exception('The SQL string contains no queries.');
1049
        }
1050
1051
        foreach ($queries as $sql) {
0 ignored issues
show
$sql is overwriting one of the parameters of this function.
Loading history...
1052
            if (trim($sql) !== '') {
1053
                $result = $this->query($sql);
1054
            }
1055
1056
            if (!$result) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $result does not seem to be defined for all execution paths leading up to this point.
Loading history...
1057
                return false;
1058
            }
1059
        }
1060
1061
        return true;
1062
    }
1063
}
1064