Failed Conditions
Push — master ( 481c82...217341 )
by Ryan
02:09
created

Database::addConstraint()   B

Complexity

Conditions 11
Paths 9

Size

Total Lines 41
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 25
CRAP Score 11.0069

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 11
eloc 26
c 1
b 0
f 0
nc 9
nop 2
dl 0
loc 41
ccs 25
cts 26
cp 0.9615
crap 11.0069
rs 7.3166

How to fix   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 128
    public function __construct($strLogPath = __DIR__, mysqli &$dbh = null, $intLogLevel = null)
234
    {
235 128
        if(! is_null($dbh) && is_a($dbh, 'mysqli')) {
236 1
            $this->_c = $dbh;
237 128
        } 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 128
        } 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 128
        if(defined('PHP_DB_ENCRYPT') && PHP_DB_ENCRYPT) {
244 128
            $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 128
        $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 128
        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 128
        $this->_logPath = $strLogPath;
256 128
        touch($this->_logPath . "/db.log");
257
258 128
        if(!defined("PHP_DB_LOG_LEVEL") && is_null($intLogLevel)) {
259
            $this->_logLevel = Logger::ERROR;
260 128
        } elseif(!is_null($intLogLevel)) {
261
            $this->_logLevel = $intLogLevel;
262 128
        } elseif(defined('PHP_DB_LOG_LEVEL')) {
263 128
            $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 128
        $this->_logger = new Logger('db', [
267 128
            new StreamHandler(realpath($this->_logPath . "/db.log"), $this->_logLevel)
0 ignored issues
show
Bug introduced by
$this->_logLevel of type string is incompatible with the type integer expected by parameter $level of Monolog\Handler\StreamHandler::__construct(). ( Ignorable by Annotation )

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

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