Passed
Push — master ( 09ebe9...f973a6 )
by Ryan
07:29
created

Database::checkResults()   C

Complexity

Conditions 15
Paths 30

Size

Total Lines 64
Code Lines 43

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 30
CRAP Score 19.3455

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 15
eloc 43
c 1
b 1
f 0
nc 30
nop 1
dl 0
loc 64
ccs 30
cts 41
cp 0.7317
crap 19.3455
rs 5.9166

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
namespace Godsgood33\Php_Db;
3
4
use Monolog\Logger;
5
use Monolog\Formatter\LineFormatter;
6
use Monolog\Handler\StreamHandler;
7
use Exception;
8
use mysqli;
9
10
/**
11
 * Constant to define that we want to return an object
12
 *
13
 * @var int
14
 */
15
define('MYSQLI_OBJECT', 4);
16
17
/**
18
 * Constant to return consistent date format
19
 *
20
 * @var string
21
 */
22
define('MYSQL_DATE', 'Y-m-d');
23
24
/**
25
 * Constant to return consistent datetime format
26
 *
27
 * @var string
28
 */
29
define('MYSQL_DATETIME', 'Y-m-d H:i:s');
30
31
/**
32
 * A generic database class
33
 *
34
 * @author Ryan Prather <[email protected]>
35
 */
36
class Database
37
{
38
39
    /**
40
     * Constant defining a SELECT query
41
     *
42
     * @var integer
43
     */
44
    const SELECT = 1;
45
46
    /**
47
     * Constant defining a SELECT COUNT query
48
     *
49
     * @var integer
50
     */
51
    const SELECT_COUNT = 2;
52
53
    /**
54
     * Constant defining a CREATE TABLE query
55
     *
56
     * @var integer
57
     */
58
    const CREATE_TABLE = 3;
59
60
    /**
61
     * Constant defining DROP query
62
     *
63
     * @var integer
64
     */
65
    const DROP = 4;
66
67
    /**
68
     * Constant defining DELETE query
69
     *
70
     * @var integer
71
     */
72
    const DELETE = 5;
73
74
    /**
75
     * Constant defining INSERT query
76
     *
77
     * @var integer
78
     */
79
    const INSERT = 6;
80
81
    /**
82
     * Constant defining REPLACE query
83
     *
84
     * @var integer
85
     */
86
    const REPLACE = 7;
87
88
    /**
89
     * Constant defining UPDATE query
90
     *
91
     * @var integer
92
     */
93
    const UPDATE = 8;
94
95
    /**
96
     * Constant defining EXTENDED INSERT query
97
     *
98
     * @var integer
99
     */
100
    const EXTENDED_INSERT = 9;
101
102
    /**
103
     * Constant defining EXTENDED REPLACE query
104
     *
105
     * @var integer
106
     */
107
    const EXTENDED_REPLACE = 10;
108
109
    /**
110
     * Constant defining EXTENDED UPDATE query
111
     *
112
     * @var integer
113
     */
114
    const EXTENDED_UPDATE = 11;
115
116
    /**
117
     * Constant defining ALTER TABLE query
118
     *
119
     * @var integer
120
     */
121
    const ALTER_TABLE = 12;
122
123
    /**
124
     * Constant defining action for alter table statement
125
     *
126
     * @var integer
127
     */
128
    const ADD_COLUMN = 1;
129
130
    /**
131
     * Constant defining action for alter table statement
132
     *
133
     * @var integer
134
     */
135
    const DROP_COLUMN = 2;
136
137
    /**
138
     * Constant defining action for alter table statement
139
     *
140
     * @var integer
141
     */
142
    const MODIFY_COLUMN = 3;
143
144
    /**
145
     * Constant defining action to add a constraint
146
     *
147
     * @var integer
148
     */
149
    const ADD_CONSTRAINT = 4;
150
151
    /**
152
     * Constant defining a TRUNCATE TABLE query
153
     *
154
     * @var integer
155
     */
156
    const TRUNCATE = 13;
157
158
    /**
159
     * The mysqli connection
160
     *
161
     * @access protected
162
     * @var \mysqli
163
     */
164
    protected $_c;
165
166
    /**
167
     * To store the SQL statement
168
     *
169
     * @access private
170
     * @var string
171
     */
172
    private $_sql = null;
173
174
    /**
175
     * A variable to store the type of query that is being run
176
     *
177
     * @access private
178
     * @var int
179
     */
180
    private $_queryType = null;
181
182
    /**
183
     * The result of the query
184
     *
185
     * @access protected
186
     * @var mixed
187
     */
188
    protected $_result = null;
189
190
    /**
191
     * Log level
192
     *
193
     * @access private
194
     * @var string
195
     */
196
    private $_logLevel = Logger::ERROR;
197
198
    /**
199
     * Variable to store the logger
200
     *
201
     * @access private
202
     * @var \Monolog\Logger
203
     */
204
    private $_logger = null;
205
206
    /**
207
     * Path for the logger to log the file
208
     *
209
     * @access private
210
     * @var string
211
     */
212
    private $_logPath = null;
213
214
    /**
215
     * Variable to store the most recent insert ID from an insert query
216
     *
217
     * @access protected
218
     * @var mixed
219
     */
220
    protected $_insertId = null;
221
222
    /**
223
     * Constructor
224
     *
225
     * @param string $strLogPath
226
     *            [optional]
227
     * @param \mysqli $dbh
228
     *            [optional]
229
     *            [by ref]
230
     *            mysqli object to perform queries.
231
     * @param int $intLogLevel
232
     */
233 129
    public function __construct($strLogPath = __DIR__, mysqli &$dbh = null, $intLogLevel = null)
234
    {
235 129
        if (! is_null($dbh) && is_a($dbh, 'mysqli')) {
236 1
            $this->_c = $dbh;
237 129
        } elseif (!defined('PHP_DB_SERVER') || !defined('PHP_DB_USER') || !defined('PHP_DB_PWD') || !defined('PHP_DB_SCHEMA')) {
238
            throw new Exception("Please create and include a constant file with the following constants defining your DB connection (PHP_DB_SERVER, PHP_DB_USER, PHP_DB_PWD, PHP_DB_SCHEMA)", E_USER_ERROR);
239 129
        } elseif (defined('PHP_DB_ENCRYPT') && (!defined('PHP_DB_ENCRYPT_ALGORITHM') || !defined('PHP_DB_ENCRYPT_SALT'))) {
240
            throw new Exception("Missing required PHP_DB_ENCRYPT_ALGORITHM or PHP_DB_ENCRYPT_SALT constants");
241
        }
242
243 129
        if (defined('PHP_DB_ENCRYPT') && PHP_DB_ENCRYPT) {
244 129
            $pwd = $this->decrypt(PHP_DB_PWD);
0 ignored issues
show
Bug introduced by
The constant Godsgood33\Php_Db\PHP_DB_PWD was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
245
        } else {
246
            $pwd = PHP_DB_PWD;
247
        }
248
249 129
        $this->_c = new mysqli(PHP_DB_SERVER, PHP_DB_USER, $pwd, PHP_DB_SCHEMA);
0 ignored issues
show
Bug introduced by
The constant Godsgood33\Php_Db\PHP_DB_SERVER was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant Godsgood33\Php_Db\PHP_DB_SCHEMA was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant Godsgood33\Php_Db\PHP_DB_USER was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
250
251 129
        if ($this->_c->connect_errno) {
252
            throw new Exception("Could not create database class due to error {$this->_c->connect_error}", E_ERROR);
253
        }
254
255 129
        $this->_logPath = $strLogPath;
256 129
        touch($this->_logPath . "/db.log");
257
258 129
        if (!defined("PHP_DB_LOG_LEVEL") && is_null($intLogLevel)) {
259
            $this->_logLevel = Logger::ERROR;
260 129
        } elseif (!is_null($intLogLevel)) {
261
            $this->_logLevel = $intLogLevel;
262 129
        } elseif (defined('PHP_DB_LOG_LEVEL')) {
263 129
            $this->_logLevel = PHP_DB_LOG_LEVEL;
0 ignored issues
show
Bug introduced by
The constant Godsgood33\Php_Db\PHP_DB_LOG_LEVEL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
264
        }
265
266 129
        $this->_logger = new Logger('db', [
267 129
            new StreamHandler(realpath($this->_logPath . "/db.log"), $this->_logLevel)
268
        ]);
269
270 129
        if (PHP_SAPI == 'cli' && defined('PHP_DB_CLI_LOG') && PHP_DB_CLI_LOG) {
0 ignored issues
show
Bug introduced by
The constant Godsgood33\Php_Db\PHP_DB_CLI_LOG was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
271
            $stream = new StreamHandler(STDOUT, $this->_logLevel);
272
            $stream->setFormatter(new LineFormatter("%datetime% %level_name% %message%" . PHP_EOL, "H:i:s.u"));
273
            $this->_logger->pushHandler($stream);
274
        }
275
276 129
        $this->_logger->info("Database connected");
277 129
        $this->_logger->debug("Connection details:", [
278 129
            'Server' => PHP_DB_SERVER,
279 129
            'User'   => PHP_DB_USER,
280 129
            'Schema' => PHP_DB_SCHEMA
281
        ]);
282
283 129
        $this->setVar("time_zone", "+00:00");
284 129
        $this->setVar("sql_mode", "");
285 129
    }
286
287
    /**
288
     * Function to make sure that the database is connected
289
     *
290
     * @return boolean
291
     */
292 1
    public function isConnected()
293
    {
294 1
        $this->_logger->debug("Pinging server");
295 1
        return $this->_c->ping();
296
    }
297
298
    /**
299
     * Setter function for _logger
300
     *
301
     * @param Logger $log
302
     */
303 1
    public function setLogger(Logger $log)
304
    {
305 1
        $this->_logger->debug("Setting logger");
306 1
        $this->_logger = $log;
307 1
        return true;
308
    }
309
310
    /**
311
     * Getter function for _logLevel
312
     *
313
     * @return string
314
     */
315
    public function getLogLevel()
316
    {
317
        $level = $this->_logLevel;
318
319
        $this->_logger->debug("Getting log level ({$level})");
320
        return $level;
321
    }
322
323
    /**
324
     * Getter function for _queryType
325
     *
326
     * @return int
327
     */
328 2
    public function getQueryType()
329
    {
330 2
        return $this->_queryType;
331
    }
332
333
    /**
334
     * Setter function for _queryType
335
     *
336
     * @param int $qt
337
     */
338 1
    public function setQueryType($qt)
339
    {
340 1
        $this->_queryType = $qt;
341 1
    }
342
343
    /**
344
     * Getter function for _sql
345
     *
346
     * @return string
347
     */
348 63
    public function getSql()
349
    {
350 63
        return $this->_sql;
351
    }
352
353
    /**
354
     * Function to return the currently selected database schema
355
     *
356
     * @return string|boolean
357
     */
358 1
    public function getSchema()
359
    {
360 1
        if ($res = $this->_c->query("SELECT DATABASE()")) {
361 1
            $row = $res->fetch_row();
362
363 1
            $this->_logger->debug("Getting schema {$row[0]}");
364 1
            return $row[0];
365
        }
366
    }
367
368
    /**
369
     * Function to set schema
370
     *
371
     * @param string $strSchema
372
     */
373 2
    public function setSchema($strSchema)
374
    {
375 2
        $this->_logger->debug("Setting schema to {$strSchema}");
376 2
        if (! $this->_c->select_db($strSchema)) {
377 1
            $this->_logger->emergency("Unknown schema {$strSchema}", [debug_backtrace()]);
378 1
            return false;
379
        }
380 1
        return true;
381
    }
382
383
    /**
384
     * Method to set a MYSQL variable
385
     *
386
     * @param string $strName
387
     * @param string $strVal
388
     *
389
     * @return boolean
390
     */
391 129
    public function setVar($strName, $strVal)
392
    {
393 129
        if (! $strName) {
394 1
            $this->_logger->debug("name is blank", [
395 1
                'name'  => $strName
396
            ]);
397 1
            return false;
398
        }
399
400 129
        $this->_logger->debug("Setting {$strName} = '{$strVal}'");
401
402 129
        if ($this->_c->real_query("SET $strName = {$this->_escape($strVal)}")) {
403 129
            return true;
404
        } else {
405 1
            $this->_logger->error("Failed to set variable {$this->_c->error}");
406 1
            return false;
407
        }
408
    }
409
410
    /**
411
     * Function to execute the statement
412
     *
413
     * @param mixed $return
414
     *            [optional]
415
     *            MYSQLI constant to control what is returned from the mysqli_result object
416
     * @param string $class
417
     *            [optional]
418
     *            Class to use when returning object
419
     * @param string $strSql
420
     *            [optional]
421
     *            Optional SQL query
422
     *
423
     * @throws \Exception
424
     * @throws \InvalidArgumentException
425
     *
426
     * @return mixed
427
     */
428 13
    public function execute($return = MYSQLI_OBJECT, $strSql = null)
429
    {
430 13
        if (! is_null($strSql)) {
431
            $this->_sql = $strSql;
432
        }
433
434 13
        $this->_result = false;
435 13
        $this->_insertId = null;
436
437 13
        if (is_a($this->_c, 'mysqli')) {
438 13
            if (! $this->_c->ping()) {
439
                throw new Exception("Database lost connection", E_ERROR);
440
            }
441
        } else {
442
            throw new Exception('Database was not connected', E_ERROR);
443
        }
444
445 13
        $this->_logger->info("Executing {$this->_queryType} query");
446 13
        $this->_logger->debug($this->_sql);
447
448
        try {
449 13
            if (in_array($this->_queryType, [
450 13
                self::SELECT,
451 13
                self::SELECT_COUNT
452
            ])) {
453 6
                $this->_result = $this->_c->query($this->_sql);
454 6
                if ($this->_c->error) {
455
                    $this->_logger->error("There is an error {$this->_c->error}");
456
                    $this->_logger->debug("Errored on query", [$this->_sql]);
457
                    throw new Exception("There was an error {$this->_c->error}", E_ERROR);
458
                }
459
            } else {
460 7
                $this->_result = $this->_c->real_query($this->_sql);
461 7
                if ($this->_c->errno) {
462
                    $this->_logger->error("There was an error {$this->_c->error}");
463
                    $this->_logger->debug("Errored on query", [$this->_sql]);
464
                    throw new Exception("There was an error {$this->_c->error}", E_ERROR);
465
                }
466
            }
467
468 13
            $this->_logger->debug("Checking for query results");
469 13
            $this->_result = $this->checkResults($return);
470
        } catch (Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
471
        }
472
473 13
        return $this->_result;
474
    }
475
476
    /**
477
     * Function to check the results and return what is expected
478
     *
479
     * @param mixed $returnType
480
     *            [optional]
481
     *            Optional return mysqli_result return type
482
     *
483
     * @return mixed
484
     */
485 13
    protected function checkResults($returnType)
486
    {
487 13
        $res = null;
488
489 13
        if (in_array($this->_queryType, [Database::CREATE_TABLE, Database::ALTER_TABLE, Database::TRUNCATE, Database::DROP])) {
490 5
            $res = $this->_result;
491 8
        } elseif (in_array($this->_queryType, [Database::INSERT, Database::EXTENDED_INSERT, Database::DELETE, Database::UPDATE, Database::EXTENDED_UPDATE, Database::REPLACE, Database::EXTENDED_REPLACE, Database::DELETE])) {
492 2
            $res = $this->_c->affected_rows;
493
494 2
            if (in_array($this->_queryType, [Database::INSERT, Database::REPLACE, Database::EXTENDED_INSERT])) {
495 2
                $this->_insertId = $this->_c->insert_id;
496
            }
497 6
        } elseif ($this->_queryType == Database::SELECT_COUNT) {
498 1
            if (! is_a($this->_result, 'mysqli_result')) {
499
                $this->_logger->error("Error with return on query");
500
                return null;
501
            }
502
503 1
            if ($this->_result->num_rows == 1) {
504 1
                $row = $this->_result->fetch_assoc();
505 1
                if (isset($row['count'])) {
506 1
                    $this->_logger->debug("Returning SELECT_COUNT query", [
507 1
                        'count' => $row['count']
508
                    ]);
509 1
                    $res = $row['count'];
510
                }
511
            } elseif ($this->_result->num_rows > 1) {
512
                $this->_logger->debug("Returning SELECT_COUNT query", [
513
                    'count' => $this->_result->num_rows
514
                ]);
515
                $res = $this->_result->num_rows;
516
            }
517
518 1
            mysqli_free_result($this->_result);
519
        } else {
520 5
            $method = "mysqli_fetch_object";
521 5
            if ($returnType == MYSQLI_ASSOC) {
522 1
                $method = "mysqli_fetch_assoc";
523 4
            } elseif ($returnType == MYSQLI_NUM) {
524 1
                $method = "mysqli_fetch_array";
525
            }
526
527 5
            if (is_a($this->_result, 'mysqli_result')) {
528 5
                if ($this->_result->num_rows > 1) {
529 3
                    $res = [];
530 3
                    while ($row = call_user_func($method, $this->_result)) {
531 3
                        $res[] = $row;
532
                    }
533
                } else {
534 2
                    $res = call_user_func($method, $this->_result);
535
                }
536
            } else {
537
                $this->_logger->error("Error with return on query");
538
                return null;
539
            }
540
        }
541
542 13
        if ($this->_c->error) {
543
            $this->_logger->error("Encountered a SQL error", ['error' => $this->_c->error, 'list' => $this->_c->error_list]);
544
            $this->_logger->debug("Debug", ['debug' => debug_backtrace()]);
545
            return null;
546
        }
547
548 13
        return $res;
549
    }
550
551
    /**
552
     * Function to pass through calling the query function (used for backwards compatibility and for more complex queries that aren't currently supported)
553
     * Nothing is escaped
554
     *
555
     * @param string $strSql
556
     *            [optional]
557
     *            Optional query to pass in and execute
558
     *
559
     * @return \mysqli_result|boolean
560
     */
561 2
    public function query($strSql = null)
562
    {
563 2
        if (is_null($strSql)) {
564 1
            return $this->_c->query($this->_sql);
565
        } else {
566 1
            return $this->_c->query($strSql);
567
        }
568
    }
569
570
    /**
571
     * A function to build a select query
572
     *
573
     * @param string $strTableName
574
     *            The table to query
575
     * @param array|string $fields
576
     *            [optional]
577
     *            Optional array of fields to return (defaults to '*')
578
     * @param array $arrWhere
579
     *            [optional]
580
     *            Optional 2-dimensional array to build where clause from
581
     * @param array $arrFlags
582
     *            [optional]
583
     *            Optional 2-dimensional array to allow other flags
584
     *
585
     * @see Database::flags()
586
     *
587
     * @throws Exception
588
     *
589
     * @return mixed
590
     */
591 35
    public function select($strTableName, $fields = null, $arrWhere = [], $arrFlags = [])
592
    {
593 35
        $this->_sql = null;
594 35
        $this->_queryType = self::SELECT;
595
596 35
        if (! is_null($strTableName) && is_string($strTableName)) {
0 ignored issues
show
introduced by
The condition is_string($strTableName) is always true.
Loading history...
introduced by
The condition is_null($strTableName) is always false.
Loading history...
597 34
            $this->_logger->debug("Starting SELECT query of {$strTableName}", [
598 34
                'fields' => $this->fields($fields)
599
            ]);
600 33
            $this->_sql = "SELECT " . $this->fields($fields) . " FROM $strTableName";
601
        } else {
602 1
            $this->_logger->emergency("Table name is invalid or wrong type", [debug_backtrace()]);
603 1
            throw new Exception("Table name is invalid");
604
        }
605
606 33
        if (isset($arrFlags['joins']) && is_array($arrFlags['joins']) && count($arrFlags['joins'])) {
607 1
            $this->_logger->debug("Adding joins", [
608 1
                'joins' => implode(' ', $arrFlags['joins'])
609
            ]);
610 1
            $this->_sql .= " " . implode(" ", $arrFlags['joins']);
611
        } else {
612 32
            $this->_logger->debug("No joins");
613
        }
614
615 33
        $where = $this->parseClause($arrWhere);
616
617 31
        if (! is_null($where) && is_array($where) && count($where)) {
0 ignored issues
show
introduced by
The condition is_null($where) is always false.
Loading history...
introduced by
The condition is_array($where) is always true.
Loading history...
618 8
            $where_str = " WHERE";
619 8
            $this->_logger->debug("Parsing where clause and adding to query");
620 8
            foreach ($where as $x => $w) {
621 8
                if ($x > 0) {
622 1
                    $where_str .= " {$w->sqlOperator}";
623
                }
624 8
                $where_str .= $w;
625
            }
626 8
            if (strlen($where_str) > strlen(" WHERE")) {
627 8
                $this->_sql .= $where_str;
628
            }
629
        }
630
631 31
        if (is_array($arrFlags) && count($arrFlags)) {
632 8
            $this->_logger->debug("Parsing flags and adding to query", $arrFlags);
633 8
            $this->_sql .= $this->flags($arrFlags);
634
        }
635
636 30
        if (defined("PHP_DB_AUTORUN") && PHP_DB_AUTORUN) {
0 ignored issues
show
Bug introduced by
The constant Godsgood33\Php_Db\PHP_DB_AUTORUN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
637
            return $this->execute();
638
        }
639
640 30
        return $this->_sql;
641
    }
642
643
    /**
644
     * Function to build a query to check the number of rows in a table
645
     *
646
     * @param string $strTableName
647
     *            The table to query
648
     * @param array $arrWhere
649
     *            [optional]
650
     *            Optional 2-dimensional array to build where clause
651
     * @param array $arrFlags
652
     *            [optional]
653
     *            Optional 2-dimensional array to add flags
654
     *
655
     * @see Database::flags()
656
     *
657
     * @return string|NULL
658
     */
659 5
    public function selectCount($strTableName, $arrWhere = [], $arrFlags = [])
660
    {
661 5
        $this->_sql = null;
662 5
        $this->_queryType = self::SELECT_COUNT;
663
664 5
        if (! is_null($strTableName) && is_string($strTableName)) {
0 ignored issues
show
introduced by
The condition is_null($strTableName) is always false.
Loading history...
introduced by
The condition is_string($strTableName) is always true.
Loading history...
665 4
            $this->_sql = "SELECT COUNT(1) AS 'count' FROM $strTableName";
666
        } else {
667 1
            $this->_logger->emergency("Table name is invalid or wrong type", [debug_backtrace()]);
668 1
            throw new Exception("Table name is invalid");
669
        }
670
671 4
        if (isset($arrFlags['joins']) && is_array($arrFlags['joins'])) {
672 1
            $this->_sql .= " " . implode(" ", $arrFlags['joins']);
673
        }
674
675 4
        $where = $this->parseClause($arrWhere);
676
677 4
        if (! is_null($where) && is_array($where) && count($where)) {
0 ignored issues
show
introduced by
The condition is_array($where) is always true.
Loading history...
introduced by
The condition is_null($where) is always false.
Loading history...
678 2
            $where_str = " WHERE";
679 2
            $this->_logger->debug("Parsing where clause and adding to query");
680 2
            foreach ($where as $x => $w) {
681 2
                if ($x > 0) {
682 1
                    $where_str .= " {$w->sqlOperator}";
683
                }
684 2
                $where_str .= $w;
685
            }
686 2
            if (strlen($where_str) > strlen(" WHERE")) {
687 2
                $this->_sql .= $where_str;
688
            }
689
        }
690
691 4
        if (is_array($arrFlags) && count($arrFlags)) {
692 1
            $this->_sql .= $this->flags($arrFlags);
693
        }
694
695 4
        if (defined("PHP_DB_AUTORUN") && PHP_DB_AUTORUN) {
0 ignored issues
show
Bug introduced by
The constant Godsgood33\Php_Db\PHP_DB_AUTORUN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
696
            return $this->execute();
697
        }
698
699 4
        return $this->_sql;
700
    }
701
702
    /**
703
     * Function to build an insert query statement
704
     *
705
     * @param string $strTableName
706
     * @param array|string $arrParams
707
     * @param boolean $blnToIgnore
708
     *
709
     * @return string|NULL
710
     */
711 10
    public function insert($strTableName, $arrParams = null, $blnToIgnore = false)
712
    {
713 10
        $this->_sql = null;
714 10
        $this->_queryType = self::INSERT;
715
716 10
        if (! is_null($strTableName) && is_string($strTableName)) {
0 ignored issues
show
introduced by
The condition is_string($strTableName) is always true.
Loading history...
introduced by
The condition is_null($strTableName) is always false.
Loading history...
717 9
            $this->_sql = "INSERT" . ($blnToIgnore ? " IGNORE" : "") . " INTO {$strTableName}";
718
        } else {
719 1
            throw new Exception("Table name is invalid");
720
        }
721
722 9
        if (is_array($arrParams) && count($arrParams)) {
723 5
            if (is_array($arrParams) && count($arrParams)) {
724 5
                $this->_sql .= " (`" . implode("`,`", array_keys($arrParams)) . "`)";
725
            }
726 5
            $this->_sql .= " VALUES (" . implode(",", array_map([
727 5
                $this,
728 5
                '_escape'
729 5
            ], array_values($arrParams))) . ")";
730 4
        } elseif (is_string($arrParams) && strpos(strtolower($arrParams), 'select') !== false) {
731 1
            $this->_sql .= " {$arrParams}";
732 3
        } elseif (is_object($arrParams)) {
733 2
            $interfaces = \class_implements($arrParams);
734 2
            if (in_array("Godsgood33\Php_Db\DBInterface", $interfaces) && is_callable(get_class($arrParams) . "::insert")) {
735 1
                $params = \call_user_func([$arrParams, "insert"]);
736 1
                $this->_sql .= " (`" . implode("`,`", array_keys($params)) . "`) VALUES ";
737 1
                $this->_sql .= "(" . implode(",", array_map([$this, '_escape'], array_values($params))) . ")";
738
            } else {
739 1
                throw new Exception("Object does not implement the DBInterface interface and methods");
740
            }
741
        } else {
742 1
            throw new Exception("Invalid type passed to insert " . gettype($arrParams));
743
        }
744
745 7
        if (defined("PHP_DB_AUTORUN") && PHP_DB_AUTORUN) {
0 ignored issues
show
Bug introduced by
The constant Godsgood33\Php_Db\PHP_DB_AUTORUN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
746
            return $this->execute();
747
        }
748
749 7
        return $this->_sql;
750
    }
751
752
    /**
753
     * Function to create an extended insert query statement
754
     *
755
     * @param string $strTableName
756
     *            The table name that the data is going to be inserted on
757
     * @param array $arrFields
758
     *            An array of field names that each value represents
759
     * @param array|string $params
760
     *            An array of array of values or a string with a SELECT statement to populate the insert with
761
     * @param boolean $blnToIgnore
762
     *            [optional]
763
     *            Boolean to decide if we need to use the INSERT IGNORE INTO syntax
764
     *
765
     * @return NULL|string Returns the SQL if self::$autorun is set to false, else it returns the output from running.
766
     */
767 8
    public function extendedInsert($strTableName, $arrFields, $params, $blnToIgnore = false)
768
    {
769 8
        $this->_sql = null;
770 8
        $this->_queryType = self::EXTENDED_INSERT;
771
772 8
        if (! is_null($strTableName) && is_string($strTableName)) {
0 ignored issues
show
introduced by
The condition is_null($strTableName) is always false.
Loading history...
introduced by
The condition is_string($strTableName) is always true.
Loading history...
773 7
            $this->_sql = "INSERT " . ($blnToIgnore ? "IGNORE " : "") . "INTO $strTableName " . "(`" . implode("`,`", $arrFields) . "`)";
774
        } else {
775 1
            throw new Exception("Table name is invalid");
776
        }
777
778 7
        if (is_array($params) && count($params)) {
779 6
            $this->_sql .= " VALUES ";
780 6
            if (isset($params[0]) && is_array($params[0])) {
781 4
                foreach ($params as $p) {
782 4
                    if (count($p) != count($arrFields)) {
783 2
                        $this->_logger->emergency("Inconsistent number of fields to values in extendedInsert", [
784 2
                            $p,
785 2
                            debug_backtrace()
786
                        ]);
787 2
                        throw new Exception("Inconsistent number of fields in fields and values in extendedInsert " . print_r($p, true));
788
                    }
789 3
                    $this->_sql .= "(" . implode(",", array_map([$this, '_escape'], array_values($p))) . ")";
790
791 3
                    if ($p != end($params)) {
792 3
                        $this->_sql .= ",";
793
                    }
794
                }
795 2
            } elseif (isset($params[0]) && is_object($params[0])) {
796 2
                $interfaces = \class_implements($params[0]);
797 2
                if (!in_array("Godsgood33\Php_Db\DBInterface", $interfaces)) {
798 1
                    throw new Exception("Object does not implement DBInterface interface and methods");
799
                }
800 1
                foreach ($params as $param) {
801 1
                    if (!is_callable(get_class($param) . "::insert")) {
802
                        throw new Exception("Cannot call insert method");
803
                    }
804 1
                    $key_value = \call_user_func([$param, "insert"]);
805 1
                    $this->_sql .= "(" . implode(",", array_map([$this, '_escape'], array_values($key_value))) . "),";
806
                }
807 1
                $this->_sql = substr($this->_sql, 0, -1);
808
            } else {
809
                $this->_sql .= "(" . implode("),(", array_map([$this, '_escape'], array_values($params))) . ")";
810
            }
811
        } else {
812 1
            throw new Exception("Invalid param type");
813
        }
814
815 3
        if (defined("PHP_DB_AUTORUN") && PHP_DB_AUTORUN) {
0 ignored issues
show
Bug introduced by
The constant Godsgood33\Php_Db\PHP_DB_AUTORUN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
816
            return $this->execute();
817
        }
818
819 3
        return $this->_sql;
820
    }
821
822
    /**
823
     * Build a statement to update a table
824
     *
825
     * @param string $strTableName
826
     *            The table name to update
827
     * @param array $arrParams
828
     *            Name/value pairs of the field name and value
829
     * @param array $arrWhere
830
     *            [optional]
831
     *            Two-dimensional array to create where clause
832
     * @param array $arrFlags
833
     *            [optional]
834
     *            Two-dimensional array to create other flag options (joins, order, and group)
835
     *
836
     * @see Database::flags()
837
     *
838
     * @return NULL|string
839
     */
840 10
    public function update($strTableName, $arrParams, $arrWhere = [], $arrFlags = [])
841
    {
842 10
        $this->_sql = "UPDATE ";
843 10
        $this->_queryType = self::UPDATE;
844
845 10
        if (! is_null($strTableName) && is_string($strTableName)) {
0 ignored issues
show
introduced by
The condition is_string($strTableName) is always true.
Loading history...
introduced by
The condition is_null($strTableName) is always false.
Loading history...
846 9
            $this->_sql .= $strTableName;
847
848 9
            if (isset($arrFlags['joins']) && is_array($arrFlags['joins'])) {
849 1
                $this->_sql .= " " . implode(" ", $arrFlags['joins']);
850 1
                unset($arrFlags['joins']);
851
            }
852
853 9
            $this->_sql .= " SET ";
854
        } else {
855 1
            throw new Exception("Table name is invalid");
856
        }
857
858 9
        if (is_array($arrParams) && count($arrParams)) {
859 6
            $keys = array_keys($arrParams);
860 6
            foreach ($arrParams as $f => $p) {
861 6
                $field = $f;
862 6
                if ((strpos($f, "`") === false) && (strpos($f, ".") === false) && (strpos($f, "*") === false) && (stripos($f, " as ") === false)) {
863 5
                    $field = "`{$f}`";
864
                }
865
866 6
                if (! is_null($p)) {
867 5
                    $this->_sql .= "$field={$this->_escape($p)}";
868
                } else {
869 1
                    $this->_sql .= "$field=NULL";
870
                }
871
872 6
                if ($f != end($keys)) {
873 1
                    $this->_sql .= ",";
874
                }
875
            }
876 3
        } elseif (is_object($arrParams)) {
877 2
            $interfaces = \class_implements($arrParams);
878 2
            if (in_array("Godsgood33\Php_Db\DBInterface", $interfaces) && is_callable(get_class($arrParams) . "::update")) {
879 1
                $params = \call_user_func([$arrParams, "update"]);
880 1
                $fields = array_keys($params);
881 1
                $values = array_map([$this, '_escape'], array_values($params));
882 1
                foreach ($fields as $x => $f) {
883 1
                    if ($x > 0) {
884 1
                        $this->_sql .= ",";
885
                    }
886 1
                    $this->_sql .= "`{$f}`={$values[$x]}";
887
                }
888
            } else {
889 1
                throw new Exception("Params is an object that doesn't implement DBInterface");
890
            }
891
        } else {
892 1
            throw new Exception("No fields to update");
893
        }
894
895 7
        $where = $this->parseClause($arrWhere);
896
897 7
        if (! is_null($where) && is_array($where) && count($where)) {
0 ignored issues
show
introduced by
The condition is_array($where) is always true.
Loading history...
introduced by
The condition is_null($where) is always false.
Loading history...
898 3
            $where_str = " WHERE";
899 3
            $this->_logger->debug("Parsing where clause and adding to query");
900 3
            foreach ($where as $x => $w) {
901 3
                if ($x > 0) {
902 1
                    $where_str .= " {$w->sqlOperator}";
903
                }
904 3
                $where_str .= $w;
905
            }
906 3
            if (strlen($where_str) > strlen(" WHERE")) {
907 3
                $this->_sql .= $where_str;
908
            }
909
        }
910
911 7
        if (! is_null($arrFlags) && is_array($arrFlags) && count($arrFlags)) {
912
            $this->_sql .= $this->flags($arrFlags);
913
        }
914
915 7
        if (defined("PHP_DB_AUTORUN") && PHP_DB_AUTORUN) {
0 ignored issues
show
Bug introduced by
The constant Godsgood33\Php_Db\PHP_DB_AUTORUN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
916
            return $this->execute();
917
        }
918
919 7
        return $this->_sql;
920
    }
921
922
    /**
923
     * Function to offer an extended updated functionality by using two different tables.
924
     *
925
     * @param string $strTableToUpdate
926
     *            The table that you want to update (alias 'tbu' is automatically added)
927
     * @param string $strOriginalTable
928
     *            The table with the data you want to overwrite to_be_updated table (alias 'o' is automatically added)
929
     * @param string $strLinkField
930
     *            The common index value between them that will join the fields
931
     * @param array|string $arrParams
932
     *            If string only a single field is updated (tbu.$params = o.$params)
933
     *            If array each element in the array is a field to be updated (tbu.$param = o.$param)
934
     *
935
     * @return mixed
936
     */
937 4
    public function extendedUpdate($strTableToUpdate, $strOriginalTable, $strLinkField, $arrParams)
938
    {
939 4
        $this->_sql = "UPDATE ";
940 4
        $this->_queryType = self::EXTENDED_UPDATE;
941
942 4
        if (! is_null($strTableToUpdate) && ! is_null($strOriginalTable) && ! is_null($strLinkField)) {
0 ignored issues
show
introduced by
The condition is_null($strLinkField) is always false.
Loading history...
introduced by
The condition is_null($strTableToUpdate) is always false.
Loading history...
introduced by
The condition is_null($strOriginalTable) is always false.
Loading history...
943 3
            $this->_sql .= "$strTableToUpdate tbu INNER JOIN $strOriginalTable o USING ($strLinkField) SET ";
944
        } else {
945 1
            throw new Exception("Missing necessary fields");
946
        }
947
948 3
        if (is_array($arrParams) && count($arrParams)) {
949 1
            foreach ($arrParams as $param) {
950 1
                if ($param != $strLinkField) {
951 1
                    $this->_sql .= "tbu.`$param` = o.`$param`,";
952
                }
953
            }
954 1
            $this->_sql = substr($this->_sql, 0, - 1);
955 2
        } elseif (is_string($arrParams)) {
956 1
            $this->_sql .= "tbu.`$arrParams` = o.`$arrParams`";
957
        } else {
958 1
            throw new Exception("Do not understand datatype " . gettype($arrParams), E_ERROR);
959
        }
960
961 2
        if (defined("PHP_DB_AUTORUN") && PHP_DB_AUTORUN) {
0 ignored issues
show
Bug introduced by
The constant Godsgood33\Php_Db\PHP_DB_AUTORUN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
962
            return $this->execute();
963
        }
964
965 2
        return $this->_sql;
966
    }
967
968
    /**
969
     * Function to build a replace query
970
     *
971
     * @param string $strTableName
972
     *            The table to update
973
     * @param array $arrParams
974
     *            Name/value pair to insert
975
     *
976
     * @return NULL|string
977
     */
978 3
    public function replace($strTableName, $arrParams)
979
    {
980 3
        $this->_sql = null;
981 3
        $this->_queryType = self::REPLACE;
982
983 3
        if (! is_null($strTableName) && is_string($strTableName)) {
0 ignored issues
show
introduced by
The condition is_string($strTableName) is always true.
Loading history...
introduced by
The condition is_null($strTableName) is always false.
Loading history...
984 2
            $this->_sql = "REPLACE INTO $strTableName ";
985
        } else {
986 1
            throw new Exception("Table name is invalid");
987
        }
988
989 2
        if (is_array($arrParams) && count($arrParams)) {
990 1
            $keys = array_keys($arrParams);
991 1
            $vals = array_values($arrParams);
992
993 1
            $this->_sql .= "(`" . implode("`,`", $keys) . "`)";
994 1
            $this->_sql .= " VALUES (" . implode(",", array_map([
995 1
                $this,
996 1
                '_escape'
997 1
            ], array_values($vals))) . ")";
998 1
        } elseif (is_object($arrParams)) {
999 1
            $interfaces = class_implements($arrParams);
1000 1
            if (in_array("Godsgood33\Php_Db\DBInterface", $interfaces) && is_callable(get_class($arrParams) . "::replace")) {
1001 1
                $params = \call_user_func([$arrParams, "replace"]);
1002 1
                $this->_sql .= "(`" . implode("`,`", array_keys($params)) . "`) VALUES ";
1003 1
                $this->_sql .= "(" . implode(",", array_map([$this, '_escape'], array_values($params))) . ")";
1004
            }
1005
        }
1006
1007 2
        if (defined("PHP_DB_AUTORUN") && PHP_DB_AUTORUN) {
0 ignored issues
show
Bug introduced by
The constant Godsgood33\Php_Db\PHP_DB_AUTORUN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1008
            return $this->execute();
1009
        }
1010
1011 2
        return $this->_sql;
1012
    }
1013
1014
    /**
1015
     * Function to build an extended replace statement
1016
     *
1017
     * @param string $strTableName
1018
     *            Table name to update
1019
     * @param array $arrFields
1020
     *            Array of fields
1021
     * @param array $arrParams
1022
     *            Two-dimensional array of values
1023
     *
1024
     * @return NULL|string
1025
     */
1026 2
    public function extendedReplace($strTableName, $arrFields, $arrParams)
1027
    {
1028 2
        $this->_sql = null;
1029 2
        $this->_queryType = self::EXTENDED_REPLACE;
1030
1031 2
        if (! is_array($arrFields) || ! count($arrFields)) {
0 ignored issues
show
introduced by
The condition is_array($arrFields) is always true.
Loading history...
1032 1
            throw new Exception("Error with the field type");
1033
        }
1034
1035 1
        if (! is_null($strTableName) && is_string($strTableName)) {
0 ignored issues
show
introduced by
The condition is_null($strTableName) is always false.
Loading history...
introduced by
The condition is_string($strTableName) is always true.
Loading history...
1036 1
            $this->_sql = "REPLACE INTO $strTableName " . "(`" . implode("`,`", $arrFields) . "`)";
1037
        } else {
1038
            throw new Exception("Table name is invalid");
1039
        }
1040
1041 1
        if (is_array($arrParams) && count($arrParams)) {
1042 1
            $this->_sql .= " VALUES ";
1043 1
            foreach ($arrParams as $p) {
1044 1
                $this->_sql .= "(" . implode(",", array_map([
1045 1
                    $this,
1046 1
                    '_escape'
1047 1
                ], array_values($p))) . ")";
1048
1049 1
                if ($p != end($arrParams)) {
1050 1
                    $this->_sql .= ",";
1051
                }
1052
            }
1053
        }
1054
1055 1
        if (defined("PHP_DB_AUTORUN") && PHP_DB_AUTORUN) {
0 ignored issues
show
Bug introduced by
The constant Godsgood33\Php_Db\PHP_DB_AUTORUN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1056
            return $this->execute();
1057
        }
1058
1059 1
        return $this->_sql;
1060
    }
1061
1062
    /**
1063
     * Function to build a delete statement
1064
     *
1065
     * @param string $strTableName
1066
     *            Table name to act on
1067
     * @param array $arrFields
1068
     *            [optional]
1069
     *            Optional list of fields to delete (used when including multiple tables)
1070
     * @param array $arrWhere
1071
     *            [optional]
1072
     *            Optional 2-dimensional array to build where clause from
1073
     * @param array $arrJoins
1074
     *            [optional]
1075
     *            Optional 2-dimensional array to add other flags
1076
     *
1077
     * @see Database::flags()
1078
     *
1079
     * @return string|NULL
1080
     */
1081 5
    public function delete($strTableName, $arrFields = [], $arrWhere = [], $arrJoins = [])
1082
    {
1083 5
        $this->_sql = "DELETE";
1084 5
        $this->_queryType = self::DELETE;
1085
1086 5
        $this->_logger->debug("Deleting table data");
1087
1088 5
        if (! is_null($arrFields) && is_array($arrFields) && count($arrFields)) {
0 ignored issues
show
introduced by
The condition is_array($arrFields) is always true.
Loading history...
introduced by
The condition is_null($arrFields) is always false.
Loading history...
1089 1
            $this->_sql .= " " . implode(",", $arrFields);
1090
        }
1091
1092 5
        if (! is_null($strTableName) && is_string($strTableName)) {
0 ignored issues
show
introduced by
The condition is_null($strTableName) is always false.
Loading history...
introduced by
The condition is_string($strTableName) is always true.
Loading history...
1093 4
            $this->_sql .= " FROM $strTableName";
1094
        } else {
1095 1
            throw new Exception("Table name is invalid");
1096
        }
1097
1098 4
        if (! is_null($arrJoins) && is_array($arrJoins) && count($arrJoins)) {
0 ignored issues
show
introduced by
The condition is_array($arrJoins) is always true.
Loading history...
introduced by
The condition is_null($arrJoins) is always false.
Loading history...
1099 1
            $this->_sql .= " " . implode(" ", $arrJoins);
1100
        }
1101
1102 4
        $where = $this->parseClause($arrWhere);
1103
1104 4
        if (! is_null($where) && is_array($where) && count($where)) {
0 ignored issues
show
introduced by
The condition is_null($where) is always false.
Loading history...
introduced by
The condition is_array($where) is always true.
Loading history...
1105 2
            $where_str = " WHERE";
1106 2
            $this->_logger->debug("Parsing where clause and adding to query");
1107 2
            foreach ($where as $x => $w) {
1108 2
                if ($x > 0) {
1109 1
                    $where_str .= " {$w->sqlOperator}";
1110
                }
1111 2
                $where_str .= $w;
1112
            }
1113 2
            if (strlen($where_str) > strlen(" WHERE")) {
1114 2
                $this->_sql .= $where_str;
1115
            }
1116
        }
1117
1118 4
        if (defined("PHP_DB_AUTORUN") && PHP_DB_AUTORUN) {
0 ignored issues
show
Bug introduced by
The constant Godsgood33\Php_Db\PHP_DB_AUTORUN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1119
            return $this->execute();
1120
        }
1121
1122 4
        return $this->_sql;
1123
    }
1124
1125
    /**
1126
     * Function to build a drop table statement (automatically executes)
1127
     *
1128
     * @param string $strTableName
1129
     *            Table to drop
1130
     * @param string $strType
1131
     *            [optional]
1132
     *            Type of item to drop ('table', 'view') (defaulted to 'table')
1133
     * @param boolean $blnIsTemp
1134
     *            [optional]
1135
     *            Optional boolean if this is a temporary table
1136
     *
1137
     * @return string|NULL
1138
     */
1139 7
    public function drop($strTableName, $strType = 'table', $blnIsTemp = false)
1140
    {
1141 7
        $this->_sql = null;
1142 7
        $this->_queryType = self::DROP;
1143
1144 7
        switch ($strType) {
1145 7
            case 'table':
1146 5
                $strType = 'TABLE';
1147 5
                break;
1148 2
            case 'view':
1149 1
                $strType = 'VIEW';
1150 1
                break;
1151
            default:
1152 1
                throw new Exception("Invalid type " . gettype($strType), E_ERROR);
1153
        }
1154
1155 6
        if (! is_null($strTableName) && is_string($strTableName)) {
0 ignored issues
show
introduced by
The condition is_string($strTableName) is always true.
Loading history...
introduced by
The condition is_null($strTableName) is always false.
Loading history...
1156 5
            $this->_sql = "DROP" . ($blnIsTemp ? " TEMPORARY" : "") . " $strType IF EXISTS `{$strTableName}`";
1157
        } else {
1158 1
            throw new Exception("Table name is invalid");
1159
        }
1160
1161 5
        if (defined("PHP_DB_AUTORUN") && PHP_DB_AUTORUN) {
0 ignored issues
show
Bug introduced by
The constant Godsgood33\Php_Db\PHP_DB_AUTORUN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1162
            return $this->execute();
1163
        }
1164
1165 5
        return $this->_sql;
1166
    }
1167
1168
    /**
1169
     * Function to build a truncate table statement (automatically executes)
1170
     *
1171
     * @param string $strTableName
1172
     *            Table to truncate
1173
     *
1174
     * @throws Exception
1175
     *
1176
     * @return string|NULL
1177
     */
1178 2
    public function truncate($strTableName)
1179
    {
1180 2
        $this->_sql = null;
1181 2
        $this->_queryType = self::TRUNCATE;
1182
1183 2
        if (! is_null($strTableName) && is_string($strTableName)) {
0 ignored issues
show
introduced by
The condition is_null($strTableName) is always false.
Loading history...
introduced by
The condition is_string($strTableName) is always true.
Loading history...
1184 1
            $this->_sql = "TRUNCATE TABLE $strTableName";
1185
        } else {
1186 1
            throw new Exception("Table name is invalid");
1187
        }
1188
1189 1
        if (defined("PHP_DB_AUTORUN") && PHP_DB_AUTORUN) {
0 ignored issues
show
Bug introduced by
The constant Godsgood33\Php_Db\PHP_DB_AUTORUN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1190
            return $this->execute();
1191
        }
1192
1193 1
        return $this->_sql;
1194
    }
1195
1196
    /**
1197
     * Function to build a create temporary table statement
1198
     *
1199
     * @param string $strTableName
1200
     *            Name to give the table when creating
1201
     * @param boolean $blnIsTemp
1202
     *            [optional]
1203
     *            Optional boolean to make the table a temporary table
1204
     * @param mixed $strSelect
1205
     *            [optional]
1206
     *            Optional parameter if null uses last built statement
1207
     *            If string, will be made the SQL statement executed to create the table
1208
     *            If array, 2-dimensional array with "field", "datatype" values to build table fields
1209
     *
1210
     * @return NULL|string
1211
     */
1212 4
    public function createTable($strTableName, $blnIsTemp = false, $strSelect = null)
1213
    {
1214 4
        $this->_queryType = self::CREATE_TABLE;
1215
1216 4
        if (is_null($strSelect) && ! is_null($this->_sql) && substr($this->_sql, 0, 6) == 'SELECT') {
1217 1
            $this->_sql = "CREATE" . ($blnIsTemp ? " TEMPORARY" : "") . " TABLE IF NOT EXISTS $strTableName AS ($this->_sql)";
1218 3
        } elseif (! is_null($strTableName) && is_string($strTableName) && is_string($strSelect)) {
0 ignored issues
show
introduced by
The condition is_null($strTableName) is always false.
Loading history...
introduced by
The condition is_string($strTableName) is always true.
Loading history...
1219 1
            $this->_sql = "CREATE" . ($blnIsTemp ? " TEMPORARY" : "") . " TABLE IF NOT EXISTS $strTableName AS ($strSelect)";
1220 2
        } elseif (! is_null($strTableName) && is_string($strTableName) && is_array($strSelect)) {
1221 2
            $this->_sql = "CREATE" . ($blnIsTemp ? " TEMPORARY" : "") . " TABLE IF NOT EXISTS $strTableName (";
1222
1223 2
            foreach ($strSelect as $field) {
1224 2
                $default = null;
1225 2
                if (is_a($field, 'Godsgood33\Php_Db\DBCreateTable')) {
1226 1
                    $this->_sql .= (string) $field . ",";
1227 1
                } elseif (is_array($field)) {
1228 1
                    if (isset($field['default'])) {
1229 1
                        $default = (is_null($field['default']) ? "" : " DEFAULT '{$field['default']}'");
1230
                    }
1231 1
                    $this->_sql .= "`{$field['field']}` {$field['datatype']}" . $default . (isset($field['option']) ? " {$field['option']}" : '') . ",";
1232
                }
1233
            }
1234 2
            $this->_sql = substr($this->_sql, 0, - 1) . ")";
1235
        }
1236
1237 4
        if (defined("PHP_DB_AUTORUN") && PHP_DB_AUTORUN) {
0 ignored issues
show
Bug introduced by
The constant Godsgood33\Php_Db\PHP_DB_AUTORUN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1238
            return $this->execute();
1239
        }
1240
1241 4
        return $this->_sql;
1242
    }
1243
1244
    /**
1245
     * Function to create a table using a stdClass object derived from JSON
1246
     *
1247
     * @param \stdClass $json
1248
     *
1249
     * @example /examples/create_table_json.json
1250
     *
1251
     */
1252 3
    public function createTableJson($json)
1253
    {
1254 3
        $this->_queryType = self::CREATE_TABLE;
1255 3
        $this->_c->select_db($json->schema);
1256
1257 3
        $this->_sql = "CREATE TABLE IF NOT EXISTS `{$json->name}` (";
1258 3
        foreach ($json->fields as $field) {
1259 3
            $this->_sql .= "`{$field->name}` {$field->dataType}";
1260
1261 3
            if ($field->dataType == 'enum' && isset($field->values)) {
1262 1
                $this->_sql .= "('" . implode("','", $field->values) . "')";
1263
            }
1264
1265 3
            if (isset($field->ai) && $field->ai) {
1266 3
                $this->_sql .= " AUTO_INCREMENT";
1267
            }
1268
1269 3
            if (isset($field->nn) && $field->nn) {
1270 3
                $this->_sql .= " NOT NULL";
1271 2
            } elseif (isset($field->default)) {
1272 2
                if (strtolower($field->default) == 'null') {
1273 1
                    $this->_sql .= " DEFAULT NULL";
1274 1
                } elseif (strlen($field->default)) {
1275 1
                    $this->_sql .= " DEFAULT '{$field->default}'";
1276
                }
1277
            }
1278
1279 3
            if ($field != end($json->fields)) {
1280 2
                $this->_sql .= ",";
1281
            }
1282
        }
1283
1284 3
        if (isset($json->index) && count($json->index)) {
1285 1
            foreach ($json->index as $ind) {
1286 1
                $ref = null;
1287 1
                if (is_array($ind->ref)) {
1288
                    $ref = "";
1289
                    foreach ($ind->ref as $r) {
1290
                        $ref .= "`{$r}` ASC,";
1291
                    }
1292
                    $ref = substr($ref, 0, -1);
1293 1
                } elseif (is_string($ind->ref)) {
1294 1
                    $ref = $ind->ref;
1295
                }
1296 1
                if (!is_null($ref)) {
1297 1
                    $this->_sql .= ", " . strtoupper($ind->type) . " `{$ind->id}` (`{$ref}`)";
1298
                }
1299
            }
1300
        }
1301
1302 3
        if (isset($json->constraints) && count($json->constraints)) {
1303
            foreach ($json->constraints as $con) {
1304
                $this->_sql .= ", CONSTRAINT `{$con->id}` " . "FOREIGN KEY (`{$con->local}`) " . "REFERENCES `{$con->schema}`.`{$con->table}` (`{$con->field}`) " . "ON DELETE " . (is_null($con->delete) ? "NO ACTION" : strtoupper($con->delete)) . " " . "ON UPDATE " . (is_null($con->update) ? "NO ACTION" : strtoupper($con->update));
1305
            }
1306
        }
1307
1308 3
        if (isset($json->unique) && count($json->unique)) {
1309 1
            $this->_sql .= ", UNIQUE(`" . implode("`,`", $json->unique) . "`)";
1310
        }
1311
1312 3
        if (isset($json->primary_key) && count($json->primary_key)) {
1313 3
            $this->_sql .= ", PRIMARY KEY(`" . implode("`,`", $json->primary_key) . "`))";
1314
        } else {
1315
            if (substr($this->_sql, - 1) == ',') {
1316
                $this->_sql = substr($this->_sql, 0, - 1);
1317
            }
1318
1319
            $this->_sql .= ")";
1320
        }
1321
1322 3
        if (defined("PHP_DB_AUTORUN") && PHP_DB_AUTORUN) {
0 ignored issues
show
Bug introduced by
The constant Godsgood33\Php_Db\PHP_DB_AUTORUN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1323
            return $this->execute();
1324
        }
1325
1326 3
        return $this->_sql;
1327
    }
1328
1329
    /**
1330
     * Method to add a column to the database (only one at a time!)
1331
     *
1332
     * @param string $strTableName
1333
     * @param stdClass $params
0 ignored issues
show
Bug introduced by
The type Godsgood33\Php_Db\stdClass was not found. Did you mean stdClass? If so, make sure to prefix the type with \.
Loading history...
1334
     *
1335
     * @return string|mixed
1336
     */
1337 3
    public function addColumn($strTableName, $params)
1338
    {
1339 3
        $this->_queryType = self::ALTER_TABLE;
1340 3
        $this->_sql = "ALTER TABLE {$strTableName} ADD COLUMN";
1341
1342 3
        if (!self::checkObject($params, ['name', 'dataType'])) {
1343 1
            $this->_logger->error("Missing elements for the addColumn method (need 'name', 'dataType')", [$params]);
1344 1
            throw new \Exception("Missing elements for the addColumn method");
1345
        }
1346
1347 2
        $nn = (isset($params->nn) && $params->nn ? " NOT NULL" : "");
1348 2
        $default = null;
1349 2
        if ($params->default === null) {
1350 1
            $default = " DEFAULT NULL";
1351 1
        } elseif (strlen($params->default)) {
1352 1
            $default = " DEFAULT {$this->_escape($params->default)}";
1353
        }
1354 2
        $this->_sql .= " `{$params->name}` {$params->dataType}" . $nn . $default;
1355
1356 2
        if (defined("PHP_DB_AUTORUN") && PHP_DB_AUTORUN) {
0 ignored issues
show
Bug introduced by
The constant Godsgood33\Php_Db\PHP_DB_AUTORUN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1357
            return $this->execute();
1358
        }
1359
1360 2
        return $this->_sql;
1361
    }
1362
1363
    /**
1364
     * Method to drop a fields from a table
1365
     *
1366
     * @param string $strTableName
1367
     * @param string|array:string $params
1368
     *
1369
     * @return string|mixed
1370
     */
1371 3
    public function dropColumn($strTableName, $params)
1372
    {
1373 3
        $this->_queryType = self::ALTER_TABLE;
1374 3
        $this->_sql = "ALTER TABLE {$strTableName} DROP COLUMN";
1375
1376 3
        if (is_array($params) && count($params)) {
1377 2
            foreach ($params as $col) {
1378 2
                $this->_sql .= " `{$col->name}`";
1379
1380 2
                if ($col != end($params)) {
1381 1
                    $this->_sql .= ",";
1382
                }
1383
            }
1384 1
        } elseif (is_string($params)) {
1385 1
            $this->_sql .= " `{$params}`";
1386
        }
1387
1388 3
        if (defined("PHP_DB_AUTORUN") && PHP_DB_AUTORUN) {
0 ignored issues
show
Bug introduced by
The constant Godsgood33\Php_Db\PHP_DB_AUTORUN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1389
            return $this->execute();
1390
        }
1391
1392 3
        return $this->_sql;
1393
    }
1394
1395
    /**
1396
     * Method to modify a field to change it's datatype, name, or other parameter
1397
     *
1398
     * @param string $strTableName
1399
     * @param stdClass $params
1400
     *
1401
     * @return string|mixed
1402
     */
1403 3
    public function modifyColumn($strTableName, $params)
1404
    {
1405 3
        $this->_queryType = self::ALTER_TABLE;
1406 3
        $this->_sql = "ALTER TABLE {$strTableName} MODIFY COLUMN";
1407
1408 3
        if (!self::checkObject($params, ['name', 'dataType'])) {
1409 1
            $this->_logger->error("Missing elements to the modifyColumn method (need 'name' and 'dataType')", [$params]);
1410 1
            throw new \Exception("Missing elements to the modifyColumn method");
1411
        }
1412
1413 2
        if (!isset($params->new_name)) {
1414 1
            $params->new_name = $params->name;
1415
        }
1416
1417 2
        $nn = (isset($params->nn) && $params->nn ? " NOT NULL" : "");
1418 2
        $default = null;
1419 2
        if ($params->default === null) {
1420 1
            $default = " DEFAULT NULL";
1421 1
        } elseif (strlen($params->default)) {
1422 1
            $default = " DEFAULT {$this->_escape($params->default)}";
1423
        }
1424 2
        $this->_sql .= " `{$params->name}` `{$params->new_name}` {$params->dataType}" . $nn . $default;
1425
1426 2
        if (defined("PHP_DB_AUTORUN") && PHP_DB_AUTORUN) {
0 ignored issues
show
Bug introduced by
The constant Godsgood33\Php_Db\PHP_DB_AUTORUN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1427
            return $this->execute();
1428
        }
1429
1430 2
        return $this->_sql;
1431
    }
1432
1433
    /**
1434
     * Method to add a constraint to a table
1435
     *
1436
     * @param string $strTableName
1437
     * @param stdClass $params
1438
     *
1439
     * @return string|mixed
1440
     */
1441 7
    public function addConstraint($strTableName, $params)
1442
    {
1443 7
        $this->_queryType = self::ALTER_TABLE;
1444 7
        $this->_sql = "ALTER TABLE {$strTableName} ADD CONSTRAINT";
1445
1446 7
        if (!is_a($params, 'stdClass')) {
1447 1
            $this->_logger->critical("Error in reading constraint field");
1448 1
            throw new \Exception("Error in reading constraint field");
1449
        }
1450
1451 6
        if (!self::checkObject($params, ['id', 'local', 'schema', 'table', 'field', 'delete', 'update'])) {
1452 1
            $this->_logger->error("Missing elements in the addConstraint method (need 'id', 'local', 'schema', 'table', 'field', 'delete', 'update')", [$params]);
1453 1
            throw new \Exception("There are some missing elements for the addConstraint action");
1454
        }
1455
1456 5
        if (!in_array(strtoupper($params->delete), ['CASCADE', 'SET NULL', 'RESTRICT', 'NO ACTION'])) {
1457 1
            $this->_logger->error("Invalid action for deletion on addConstraint");
1458 1
            throw new \Exception("Invalid action for deletion on addConstraint");
1459
        }
1460
1461 4
        if (!in_array(strtoupper($params->update), ['CASCADE', 'SET NULL', 'RESTRICT', 'NO ACTION'])) {
1462 1
            $this->_logger->error("Invalid action for update on addConstraint");
1463 1
            throw new Exception("Invalid action for update on addConstraint");
1464
        }
1465
1466 3
        if (is_array($params->field) && is_array($params->local)) {
1467 1
            $field = "`" . implode("`,`", $params->field) . "`";
1468 1
            $local = "`" . implode("`,`", $params->local) . "`";
1469 2
        } elseif (is_string($params->field) && is_string($params->local)) {
1470 1
            $field = "`{$params->field}`";
1471 1
            $local = "`{$params->local}`";
1472
        } else {
1473 1
            throw new Exception("Invalid type for the field and local values both must be an array or string");
1474
        }
1475 2
        $this->_sql .= " `{$params->id}` FOREIGN KEY ({$local}) REFERENCES `{$params->schema}`.`{$params->table}` ({$field}) ON DELETE {$params->delete} ON UPDATE {$params->update}";
1476
1477 2
        if (defined("PHP_DB_AUTORUN") && PHP_DB_AUTORUN) {
0 ignored issues
show
Bug introduced by
The constant Godsgood33\Php_Db\PHP_DB_AUTORUN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1478
            return $this->execute();
1479
        }
1480
1481 2
        return $this->_sql;
1482
    }
1483
1484
    /**
1485
     * Check to see if a field in a table exists
1486
     *
1487
     * @param string $strTableName
1488
     *            Table to check
1489
     * @param string $strFieldName
1490
     *            Field name to find
1491
     *
1492
     * @return boolean Returns TRUE if field is found in that schema and table, otherwise FALSE
1493
     */
1494 2
    public function fieldExists($strTableName, $strFieldName)
1495
    {
1496 2
        $fdata = $this->fieldData($strTableName);
1497
1498 2
        if (is_array($fdata) && count($fdata)) {
1499 2
            foreach ($fdata as $field) {
1500 2
                if ($field->name == $strFieldName) {
1501 1
                    return true;
1502
                }
1503
            }
1504
        }
1505
1506 1
        return false;
1507
    }
1508
1509
    /**
1510
     * Function to get the column data (datatype, flags, defaults, etc)
1511
     *
1512
     * @param string $strTableName
1513
     *            Table to query
1514
     * @param mixed $field
1515
     *            [optional]
1516
     *            Optional field to retrieve data (if null, returns data from all fields)
1517
     *
1518
     * @return array
1519
     */
1520 4
    public function fieldData($strTableName, $field = null)
1521
    {
1522 4
        if (is_null($field)) {
1523 3
            $res = $this->_c->query("SELECT * FROM $strTableName LIMIT 1");
1524 2
        } elseif (is_array($field)) {
1525 2
            $res = $this->_c->query("SELECT `" . implode("`,`", $field) . "` FROM $strTableName LIMIT 1");
1526 1
        } elseif (is_string($field)) {
1527 1
            $res = $this->_c->query("SELECT $field FROM $strTableName LIMIT 1");
1528
        } else {
1529 1
            return null;
1530
        }
1531
1532 4
        $fields = null;
1533 4
        if (is_a($res, 'mysqli_result')) {
1534 4
            $fields = $res->fetch_fields();
1535 4
            foreach ($fields as $i => $f) {
1536 4
                $fields["{$f->name}"] = $f;
1537 4
                unset($fields[$i]);
1538
            }
1539
        }
1540
1541 4
        return $fields;
1542
    }
1543
1544
    /**
1545
     * Function to check that all field parameters are set correctly
1546
     *
1547
     * @param object $field_data
1548
     * @param object $check
1549
     * @param array $pks
1550
     * @param object $index
1551
     *
1552
     * @return array|string
1553
     */
1554 1
    public function fieldCheck($field_data, $check, $pks, $index)
1555
    {
1556 1
        $default = null;
1557 1
        $ret = null;
1558
1559 1
        $nn = (isset($check->nn) && $check->nn ? " NOT NULL" : null);
1560 1
        if ($check->default === null) {
1561
            $default = " DEFAULT NULL";
1562 1
        } elseif (strlen($check->default)) {
1563
            $default = " DEFAULT '{$check->default}'";
1564
        }
1565
1566 1
        if ($field_data->type != $check->type && $check->type != MYSQLI_TYPE_ENUM) {
1567
            $this->_logger->notice("Wrong datatype", [
1568
                'name' => $field_data->name,
1569
                'datatype' => $check->dataType
1570
            ]);
1571
            $ret = " CHANGE COLUMN `{$field_data->name}` `{$check->name}` {$check->dataType}" . "{$nn}{$default}";
1572 1
        } elseif (! is_null($check->length) && $field_data->length != $check->length) {
1573 1
            $this->_logger->notice("Incorrect size", [
1574 1
                'name' => $field_data->name,
1575 1
                'current' => $field_data->length,
1576 1
                'new_size' => $check->length
1577
            ]);
1578 1
            $ret = " CHANGE COLUMN `{$field_data->name}` `{$check->name}` {$check->dataType}" . "{$nn}{$default}";
1579
        } elseif ($check->type == MYSQLI_TYPE_ENUM && ! ($field_data->flags & MYSQLI_ENUM_FLAG)) {
1580
            $this->_logger->notice("Setting ENUM type", [
1581
                'name' => $field_data->name,
1582
                'values' => implode(",", $check->values)
1583
            ]);
1584
            $ret = " CHANGE COLUMN `{$field_data->name}` `{$check->name}` {$check->dataType}('" . implode("','", $check->values) . "')" . "{$nn}{$default}";
1585
        }
1586
1587 1
        if (! is_null($index) && count($index)) {
1588
            foreach ($index as $ind) {
1589
                if ($check->name == $ind->ref && ! ($field_data->flags & MYSQLI_MULTIPLE_KEY_FLAG)) {
1590
                    $this->_logger->debug("Missing index", [
1591
                        'name' => $field_data->name
1592
                    ]);
1593
                    $ret .= ($ret ? "," : "") . " ADD INDEX `{$ind->id}` (`{$ind->ref}` ASC)";
1594
                }
1595
            }
1596
        }
1597
1598 1
        if (in_array($check->name, $pks) && ! ($field_data->flags & MYSQLI_PRI_KEY_FLAG)) {
1599
            $this->_logger->debug("Setting PKs", [
1600
                'keys' => implode(',', $pks)
1601
            ]);
1602
            $ret .= ($ret ? "," : "") . " DROP PRIMARY KEY, ADD PRIMARY KEY(`" . implode("`,`", $pks) . "`)";
1603
        }
1604
1605 1
        return $ret;
1606
    }
1607
1608
    /**
1609
     * Function to check for the existence of a table within a schema
1610
     *
1611
     * @param string $strSchema
1612
     *            The schema to search in
1613
     * @param string $strTableName
1614
     *            Table to search for
1615
     *
1616
     * @return integer|boolean Returns number of tables that match if table is found in that schema, otherwise FALSE
1617
     */
1618 3
    public function tableExists($strSchema, $strTableName)
1619
    {
1620 3
        if (! $this->_c->select_db($strSchema)) {
1621
            $this->_logger->error("Schema {$strSchema} not found", [$this->_c->error]);
1622
            throw new Exception("Error connecting to schema {$strSchema}");
1623
        }
1624
1625 3
        if (preg_match("/[^A-Za-z0-9_%\-]/i", $strTableName)) {
1626
            $this->_logger->warning("Invalid table name {$strTableName}");
1627
            return false;
1628
        }
1629
1630 3
        $sql = "SHOW TABLES LIKE '{$strTableName}'";
1631
1632 3
        if ($res = $this->_c->query($sql)) {
1633 3
            if (gettype($res) == 'object' && is_a($res, 'mysqli_result') && $res->num_rows) {
1634 2
                return $res->num_rows;
1635
            }
1636
        } else {
1637
            if ($this->_c->errno) {
1638
                $this->_logger->error($this->_c->error);
1639
            }
1640
        }
1641
1642 1
        return false;
1643
    }
1644
1645
    /**
1646
     * Function to detect if string is a JSON object or not
1647
     *
1648
     * @param string $strVal
1649
     *
1650
     * @return boolean
1651
     */
1652 1
    public function isJson($strVal)
1653
    {
1654 1
        json_decode($strVal);
1655 1
        return (json_last_error() == JSON_ERROR_NONE);
1656
    }
1657
1658
    /**
1659
     * Function to escape SQL characters to prevent SQL injection
1660
     *
1661
     * @param mixed $val
1662
     *            Value to escape
1663
     * @param boolean $blnEscape
1664
     *            Decide if we should escape or not
1665
     *
1666
     * @return string Escaped value
1667
     */
1668 129
    public function _escape($val, $blnEscape = true)
1669
    {
1670 129
        if (is_null($val) || (is_string($val) && strtolower($val) == 'null')) {
1671 1
            return 'NULL';
1672 129
        } elseif (is_numeric($val) || is_string($val)) {
1673 129
            if (stripos($val, "IF(") !== false) {
1674
                return $val;
1675 129
            } elseif ($blnEscape) {
1676 129
                return "'{$this->_c->real_escape_string($val)}'";
1677
            }
1678
            return $val;
1679 6
        } elseif (is_a($val, 'DateTime')) {
1680 1
            return "'{$val->format(MYSQL_DATETIME)}'";
1681 5
        } elseif (is_bool($val)) {
1682 1
            return $val ? "'1'" : "'0'";
1683 4
        } elseif (is_array($val)) {
1684 1
            $ret = [];
1685 1
            foreach ($val as $v) {
1686 1
                $ret[] = $this->_escape($v);
1687
            }
1688 1
            return "(" . implode(",", $ret) . ")";
1689 3
        } elseif (is_object($val) && method_exists($val, '_escape')) {
1690 2
            $ret = call_user_func([
1691 2
                $val,
1692 2
                '_escape'
1693
            ]);
1694 2
            if ($ret !== false) {
1695 1
                return $ret;
1696
            } else {
1697 1
                throw new Exception("Error in return from _escape method in " . get_class($val), E_ERROR);
1698
            }
1699
        }
1700
1701 1
        throw new Exception("Unknown datatype to escape in SQL string {$this->_sql} " . gettype($val), E_ERROR);
1702
    }
1703
1704
    /**
1705
     * Function to populate the fields for the SQL
1706
     *
1707
     * @param array|string $fields
1708
     *            [optional]
1709
     *            Optional array of fields to string together to create a field list
1710
     *
1711
     * @return string
1712
     */
1713 34
    protected function fields($fields = null)
1714
    {
1715 34
        $ret = null;
1716
1717 34
        if (is_array($fields) && count($fields) && isset($fields[0]) && is_string($fields[0])) {
1718 2
            foreach ($fields as $field) {
1719 2
                if ((strpos($field, '`') === false) && (strpos($field, '.') === false) && (strpos($field, '*') === false) && (strpos($field, 'JSON_') === false) && (stripos($field, ' as ') === false)) {
1720 2
                    $ret .= "`$field`,";
1721
                } else {
1722
                    $ret .= "$field,";
1723
                }
1724
            }
1725 2
            $ret = substr($ret, - 1) == ',' ? substr($ret, 0, - 1) : $ret;
1726 32
        } elseif (is_string($fields)) {
1727 4
            $ret = $fields;
1728 28
        } elseif (is_null($fields)) {
1729 27
            $ret = "*";
1730
        } else {
1731 1
            throw new \InvalidArgumentException("Invalid field type");
1732
        }
1733
1734 33
        return $ret;
1735
    }
1736
1737
    /**
1738
     * Function to parse the flags
1739
     *
1740
     * @param array $flags
1741
     *            Two-dimensional array to added flags
1742
     *
1743
     *            <code>
1744
     *            [
1745
     *            &nbsp;&nbsp;'joins' => [
1746
     *            &nbsp;&nbsp;&nbsp;&nbsp;"JOIN table2 t2 ON t2.id=t1.id"
1747
     *            &nbsp;&nbsp;],
1748
     *            &nbsp;&nbsp;'group' => 'field',
1749
     *            &nbsp;&nbsp;'having' => 'field',
1750
     *            &nbsp;&nbsp;'order' => 'field',
1751
     *            &nbsp;&nbsp;'start' => 0,
1752
     *            &nbsp;&nbsp;'limit' => 0
1753
     *            ]
1754
     *            </code>
1755
     *
1756
     * @see Database::groups()
1757
     * @see Database::having()
1758
     * @see Database::order()
1759
     *
1760
     * @return string
1761
     */
1762 9
    protected function flags($arrFlags)
1763
    {
1764 9
        $ret = '';
1765
1766 9
        if (isset($arrFlags['group'])) {
1767 3
            $ret .= $this->groups($arrFlags['group']);
1768
        }
1769
1770 8
        if (isset($arrFlags['having']) && is_array($arrFlags['having'])) {
1771 1
            $having = " HAVING";
1772 1
            $this->_logger->debug("Parsing where clause and adding to query");
1773 1
            foreach ($arrFlags['having'] as $x => $h) {
1774 1
                if ($x > 0) {
1775 1
                    $having .= " {$h->sqlOperator}";
1776
                }
1777 1
                $having .= $h;
1778
            }
1779 1
            if (strlen($having) > strlen(" HAVING")) {
1780 1
                $ret .= $having;
1781
            }
1782
        }
1783
1784 8
        if (isset($arrFlags['order'])) {
1785 2
            $ret .= $this->order($arrFlags['order']);
1786
        }
1787
1788 8
        if (isset($arrFlags['limit']) && (is_string($arrFlags['limit']) || is_numeric($arrFlags['limit']))) {
1789 1
            $ret .= " LIMIT ";
1790 1
            if (isset($arrFlags['start']) && (is_string($arrFlags['start']) || is_numeric($arrFlags['start']))) {
1791 1
                $ret .= "{$arrFlags['start']},";
1792
            }
1793 1
            $ret .= "{$arrFlags['limit']}";
1794
        }
1795
1796 8
        return $ret;
1797
    }
1798
1799
    /**
1800
     * Function to parse SQL GROUP BY statements
1801
     *
1802
     * @param mixed $groups
1803
     *
1804
     * @return string
1805
     */
1806 3
    protected function groups($groups)
1807
    {
1808 3
        $ret = '';
1809 3
        if (is_array($groups) && count($groups)) {
1810 1
            $ret .= " GROUP BY";
1811
1812 1
            foreach ($groups as $grp) {
1813 1
                $ret .= " $grp";
1814
1815 1
                if ($grp != end($groups)) {
1816 1
                    $ret .= ",";
1817
                }
1818
            }
1819 2
        } elseif (is_string($groups)) {
1820 1
            $ret .= " GROUP BY {$groups}";
1821
        } else {
1822 1
            throw (new Exception("Error in datatype for groups " . gettype($groups), E_ERROR));
1823
        }
1824
1825 2
        return $ret;
1826
    }
1827
1828
    /**
1829
     * Function to parse SQL ORDER BY statements
1830
     *
1831
     * @param mixed $order
1832
     *
1833
     * @return string
1834
     */
1835 2
    protected function order($order)
1836
    {
1837 2
        $ret = '';
1838 2
        if (is_array($order)) {
1839 1
            $ret .= " ORDER BY";
1840
1841 1
            foreach ($order as $ord) {
1842 1
                $ret .= " {$ord['field']} {$ord['sort']}";
1843
1844 1
                if ($ord != end($order)) {
1845 1
                    $ret .= ",";
1846
                }
1847
            }
1848 1
        } elseif (is_string($order)) {
1849 1
            $ret .= " ORDER BY {$order}";
1850
        }
1851
1852 2
        return $ret;
1853
    }
1854
1855
    /**
1856
     * Function to see if a constraint exists
1857
     *
1858
     * @param string $strConstraintId
1859
     *
1860
     * @return boolean
1861
     */
1862
    public function isConstraint($strConstraintId)
1863
    {
1864
        $res = $this->_c->query("SELECT * FROM information_schema.TABLE_CONSTRAINTS WHERE CONSTRAINT_NAME = '{$strConstraintId}'");
1865
1866
        if ($res->num_rows) {
1867
            return true;
1868
        }
1869
1870
        return false;
1871
    }
1872
1873
    /**
1874
     * Method to add a where clause
1875
     *
1876
     * @param DBWhere|array:DBWhere $where
1877
     *
1878
     * @return boolean|array:DBWhere
1879
     */
1880 48
    public function parseClause($where)
1881
    {
1882 48
        $ret = [];
1883 48
        $interfaces = [];
1884 48
        if (is_object($where)) {
1885 9
            $interfaces = \class_implements($where);
1886
        }
1887 48
        if (is_array($where)) {
1888 38
            foreach ($where as $k => $w) {
1889 9
                if (!is_a($w, 'Godsgood33\Php_Db\DBWhere')) {
1890 1
                    return false;
1891
                }
1892 8
                $v = $this->_escape($w->value, $w->escape);
0 ignored issues
show
Bug Best Practice introduced by
The property escape does not exist on Godsgood33\Php_Db\DBWhere. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug Best Practice introduced by
The property value does not exist on Godsgood33\Php_Db\DBWhere. Since you implemented __get, consider adding a @property annotation.
Loading history...
1893 8
                $where[$k]->value = $v;
1894
1895 8
                $ret[] = $where[$k];
1896
            }
1897 10
        } elseif (is_a($where, 'Godsgood33\Php_Db\DBWhere')) {
1898 9
            $v = $this->_escape($where->value, $where->escape);
1899 7
            $where->value = $v;
0 ignored issues
show
Bug Best Practice introduced by
The property value does not exist on Godsgood33\Php_Db\DBWhere. Since you implemented __set, consider adding a @property annotation.
Loading history...
1900 7
            $ret[] = $where;
1901 2
        } elseif (in_array("Godsgood33\Php_Db\DBInterface", $interfaces) && is_callable(get_class($where) . "::where")) {
1902 1
            $params = \call_user_func([$where, "where"]);
1903 1
            $ret = $this->parseClause($params);
1904
        } else {
1905 1
            $this->_logger->warning("Failed to get where from", [$where]);
1906
        }
1907
1908 45
        return $ret;
1909
    }
1910
1911
    /**
1912
     * Encryption algorithm
1913
     *
1914
     * @param string $data
1915
     * @param string $key
1916
     *
1917
     * @throws Exception
1918
     *
1919
     * @return string
1920
     */
1921
    public static function encrypt($data, $salt = null)
1922
    {
1923
        if (!defined('PHP_DB_ENCRYPT_SALT') || !defined('PHP_DB_ENCRYPT_ALGORITHM')) {
1924
            throw new Exception("Need to declare and populate PHP_DB_ENCRYPT_SALT and PHP_DB_ENCRYPT_ALGORITHM");
1925
        }
1926
1927
        // Remove the base64 encoding from our key
1928
        if (is_null($salt)) {
1929
            $encryption_key = base64_decode(PHP_DB_ENCRYPT_SALT);
1930
        } else {
1931
            $encryption_key = base64_decode($salt);
1932
        }
1933
        // Generate an initialization vector
1934
        $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length(PHP_DB_ENCRYPT_ALGORITHM));
1935
        // Encrypt the data using AES 256 encryption in CBC mode using our encryption key and initialization vector.
1936
        $encrypted = openssl_encrypt($data, PHP_DB_ENCRYPT_ALGORITHM, $encryption_key, 0, $iv);
1937
        // The $iv is just as important as the key for decrypting, so save it with our encrypted data using a unique separator (::)
1938
        return base64_encode($encrypted . '::' . $iv);
1939
    }
1940
1941
    /**
1942
     * Decryption algorithm
1943
     *
1944
     * @param string $data
1945
     *
1946
     * @throws Exception
1947
     *
1948
     * @return string
1949
     */
1950 129
    public static function decrypt($data)
1951
    {
1952 129
        if (!defined('PHP_DB_ENCRYPT_SALT') || !defined('PHP_DB_ENCRYPT_ALGORITHM')) {
1953
            throw new Exception("Need to declare and populate PHP_DB_ENCRYPT_SALT and PHP_DB_ENCRYPT_ALGORITHM");
1954
        }
1955
1956
        // Remove the base64 encoding from our key
1957 129
        $encryption_key = base64_decode(PHP_DB_ENCRYPT_SALT);
1958
1959
        // To decrypt, split the encrypted data from our IV - our unique separator used was "::"
1960 129
        list($encrypted_data, $iv) = explode('::', base64_decode($data), 2);
1961 129
        $plaintext = openssl_decrypt($encrypted_data, PHP_DB_ENCRYPT_ALGORITHM, $encryption_key, 0, $iv);
1962 129
        return $plaintext;
1963
    }
1964
1965
    /**
1966
     * Method to check if all required fields are available in the object
1967
     *
1968
     * @param object $object
1969
     * @param array:string $requiredFields
1970
     *
1971
     * @return boolean
1972
     */
1973 12
    public static function checkObject($object, $requiredFields)
1974
    {
1975 12
        $haystack = array_keys(json_decode(json_encode($object), true));
1976 12
        foreach ($requiredFields as $r) {
1977 12
            if (!in_array($r, $haystack)) {
1978 3
                return false;
1979
            }
1980
        }
1981
1982 9
        return true;
1983
    }
1984
1985
    /**
1986
     * Method to retrieve the error data
1987
     *
1988
     * @return string
1989
     */
1990
    public function error()
1991
    {
1992
        return $this->_c->error;
1993
    }
1994
}
1995