Passed
Push — master ( 217341...391851 )
by Ryan
01:37
created

Database::extendedInsert()   D

Complexity

Conditions 18
Paths 21

Size

Total Lines 53
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 31
CRAP Score 18.0721

Importance

Changes 5
Bugs 4 Features 0
Metric Value
cc 18
eloc 35
c 5
b 4
f 0
nc 21
nop 4
dl 0
loc 53
ccs 31
cts 33
cp 0.9394
crap 18.0721
rs 4.8666

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