Db::save()   F
last analyzed

Complexity

Conditions 27
Paths 265

Size

Total Lines 92
Code Lines 50

Duplication

Lines 15
Ratio 16.3 %

Importance

Changes 0
Metric Value
cc 27
eloc 50
nc 265
nop 4
dl 15
loc 92
rs 3.5143
c 0
b 0
f 0

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
/**
3
  * osCommerce Online Merchant
4
  *
5
  * @copyright (c) 2016 osCommerce; https://www.oscommerce.com
6
  * @license MIT; https://www.oscommerce.com/license/mit.txt
7
  */
8
9
namespace OSC\OM;
10
11
use OSC\OM\HTML;
12
use OSC\OM\OSCOM;
13
14
class Db extends \PDO
15
{
16
    protected $connected = false;
17
    protected $server;
18
    protected $username;
19
    protected $password;
20
    protected $database;
21
    protected $table_prefix;
22
    protected $port;
23
    protected $driver_options = [];
24
    protected $options = [];
25
26
    public static function initialize(
27
        $server = null,
28
        $username = null,
29
        $password = null,
30
        $database = null,
31
        $port = null,
32
        array $driver_options = null,
33
        array $options = null
34
    ) {
35
        if (!isset($server)) {
36
            $server = OSCOM::getConfig('db_server');
37
        }
38
39
        if (!isset($username)) {
40
            $username = OSCOM::getConfig('db_server_username');
41
        }
42
43
        if (!isset($password)) {
44
            $password = OSCOM::getConfig('db_server_password');
45
        }
46
47
        if (!isset($database)) {
48
            $database = OSCOM::getConfig('db_database');
49
        }
50
51
        if (!is_array($driver_options)) {
52
            $driver_options = [];
53
        }
54
55
        if (!isset($driver_options[\PDO::ATTR_ERRMODE])) {
56
            $driver_options[\PDO::ATTR_ERRMODE] = \PDO::ERRMODE_EXCEPTION;
57
        }
58
59
        if (!isset($driver_options[\PDO::ATTR_DEFAULT_FETCH_MODE])) {
60
            $driver_options[\PDO::ATTR_DEFAULT_FETCH_MODE] = \PDO::FETCH_ASSOC;
61
        }
62
63
        if (!isset($driver_options[\PDO::ATTR_STATEMENT_CLASS])) {
64
            $driver_options[\PDO::ATTR_STATEMENT_CLASS] = array('OSC\OM\DbStatement');
65
        }
66
67
        if (!is_array($options)) {
68
            $options = [];
69
        }
70
71
        $object = false;
72
73
        try {
74
            $class = 'OSC\OM\Db\MySQL';
75
            $object = new $class($server, $username, $password, $database, $port, $driver_options, $options);
76
        } catch (\Exception $e) {
77
            $message = $e->getMessage();
78
            // $message .= "\n" . $e->getTraceAsString(); // the trace will contain the password in plain text
79
80
            if (!isset($options['log_errors']) || ($options['log_errors'] === true)) {
81
                error_log('OSC\OM\Db::initialize(): ' . $message);
82
            }
83
84
            throw new \Exception($message, $e->getCode());
85
        }
86
87
        return $object;
88
    }
89
90
    public function exec($statement)
91
    {
92
        $statement = $this->autoPrefixTables($statement);
93
94
        return parent::exec($statement);
95
    }
96
97
    public function prepare($statement, $driver_options = null)
98
    {
99
        $statement = $this->autoPrefixTables($statement);
100
101
        $DbStatement = parent::prepare($statement, is_array($driver_options) ? $driver_options : []);
102
        $DbStatement->setQueryCall('prepare');
103
        $DbStatement->setPDO($this);
104
105
        return $DbStatement;
106
    }
107
108
    public function query($statement)
109
    {
110
        $statement = $this->autoPrefixTables($statement);
111
112
        $args = func_get_args();
113
114
        if (count($args) > 1) {
115
            $DbStatement = call_user_func_array(array($this, 'parent::query'), $args);
116
        } else {
117
            $DbStatement = parent::query($statement);
118
        }
119
120
        if ($DbStatement !== false) {
121
            $DbStatement->setQueryCall('query');
122
            $DbStatement->setPDO($this);
123
        }
124
125
        return $DbStatement;
126
    }
127
128
    public function get($table, $fields, array $where = null, $order = null, $limit = null, $cache = null, array $options = null)
129
    {
130
        if (!is_array($table)) {
131
            $table = [ $table ];
132
        }
133
134 View Code Duplication
        if (!isset($options['prefix_tables']) || ($options['prefix_tables'] === true)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
135
            array_walk($table, function(&$v, &$k) {
0 ignored issues
show
Unused Code introduced by
The parameter $k is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
136
                if ((strlen($v) < 7) || (substr($v, 0, 7) != ':table_')) {
137
                    $v = ':table_' . $v;
138
                }
139
            });
140
        }
141
142
        if (!is_array($fields)) {
143
            $fields = [ $fields ];
144
        }
145
146
        if (isset($order) && !is_array($order)) {
147
            $order = [ $order ];
148
        }
149
150
        if (isset($limit)) {
151
            if (is_array($limit) && (count($limit) === 2) && is_numeric($limit[0]) && is_numeric($limit[1])) {
152
                $limit = implode(', ', $limit);
153
            } elseif (!is_numeric($limit)) {
154
                $limit = null;
155
            }
156
        }
157
158
        $statement = 'select ' . implode(', ', $fields) . ' from ' . implode(', ', $table);
159
160
        if (!isset($where) && !isset($cache)) {
161
            if (isset($order)) {
162
                $statement .= ' order by ' . implode(', ', $order);
163
            }
164
165
            return $this->query($statement);
166
        }
167
168
        if (isset($where)) {
169
            $statement .= ' where ';
170
171
            $counter = 0;
172
173
            $it_where = new \CachingIterator(new \ArrayIterator($where), \CachingIterator::TOSTRING_USE_CURRENT);
174
175
            foreach ($it_where as $key => $value) {
176
                if (is_array($value)) {
177
                    if (isset($value['val'])) {
178
                        $statement .= $key . ' ' . (isset($value['op']) ? $value['op'] : '=') . ' :cond_' . $counter;
179
                    }
180
181
                    if (isset($value['rel'])) {
182
                        if (isset($value['val'])) {
183
                            $statement .= ' and ';
184
                        }
185
186
                        if (is_array($value['rel'])) {
187
                            $it_rel = new \CachingIterator(new \ArrayIterator($value['rel']), \CachingIterator::TOSTRING_USE_CURRENT);
188
189
                            foreach ($it_rel as $rel) {
190
                                $statement .= $key . ' = ' . $rel;
191
192
                                if ($it_rel->hasNext()) {
193
                                    $statement .= ' and ';
194
                                }
195
                            }
196
                        } else {
197
                            $statement .= $key . ' = ' . $value['rel'];
198
                        }
199
                    }
200
                } else {
201
                    $statement .= $key . ' = :cond_' . $counter;
202
                }
203
204
                if ($it_where->hasNext()) {
205
                    $statement .= ' and ';
206
                }
207
208
                $counter++;
209
            }
210
        }
211
212
        if (isset($order)) {
213
            $statement .= ' order by ' . implode(', ', $order);
214
        }
215
216
        if (isset($limit)) {
217
            $statement .= ' limit ' . $limit;
218
        }
219
220
        $Q = $this->prepare($statement);
221
222
        if (isset($where)) {
223
            $counter = 0;
224
225
            foreach ($it_where as $value) {
0 ignored issues
show
Bug introduced by
The variable $it_where does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
226
                if (is_array($value)) {
227
                    if (isset($value['val'])) {
228
                        $Q->bindValue(':cond_' . $counter, $value['val']);
229
                    }
230
                } else {
231
                    $Q->bindValue(':cond_' . $counter, $value);
232
                }
233
234
                $counter++;
235
            }
236
        }
237
238
        if (isset($cache)) {
239
            if (!is_array($cache)) {
240
                $cache = [ $cache ];
241
            }
242
243
            call_user_func_array([$Q, 'setCache'], $cache);
244
        }
245
246
        $Q->execute();
247
248
        return $Q;
249
    }
250
251
    public function save($table, array $data, array $where_condition = null, array $options = null)
252
    {
253
        if (empty($data)) {
254
            return false;
255
        }
256
257 View Code Duplication
        if (!isset($options['prefix_tables']) || ($options['prefix_tables'] === true)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
258
            if ((strlen($table) < 7) || (substr($table, 0, 7) != ':table_')) {
259
                $table = ':table_' . $table;
260
            }
261
        }
262
263
        if (isset($where_condition)) {
264
            $statement = 'update ' . $table . ' set ';
265
266
            foreach ($data as $c => $v) {
267
                if (is_null($v)) {
268
                    $v = 'null';
269
                }
270
271
                if ($v == 'now()' || $v == 'null') {
272
                    $statement .= $c . ' = ' . $v . ', ';
273
                } else {
274
                    $statement .= $c . ' = :new_' . $c . ', ';
275
                }
276
            }
277
278
            $statement = substr($statement, 0, -2) . ' where ';
279
280
            foreach (array_keys($where_condition) as $c) {
281
                $statement .= $c . ' = :cond_' . $c . ' and ';
282
            }
283
284
            $statement = substr($statement, 0, -5);
285
286
            $Q = $this->prepare($statement);
287
288 View Code Duplication
            foreach ($data as $c => $v) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
289
                if ($v != 'now()' && $v != 'null' && !is_null($v)) {
290
                    $Q->bindValue(':new_' . $c, $v);
291
                }
292
            }
293
294
            foreach ($where_condition as $c => $v) {
295
                $Q->bindValue(':cond_' . $c, $v);
296
            }
297
298
            $Q->execute();
299
300
            return $Q->rowCount();
301
        } else {
302
            $is_prepared = false;
303
304
            $statement = 'insert into ' . $table . ' (' . implode(', ', array_keys($data)) . ') values (';
305
306
            foreach ($data as $c => $v) {
307
                if (is_null($v)) {
308
                    $v = 'null';
309
                }
310
311
                if ($v == 'now()' || $v == 'null') {
312
                    $statement .= $v . ', ';
313
                } else {
314
                    if ($is_prepared === false) {
315
                        $is_prepared = true;
316
                    }
317
318
                    $statement .= ':' . $c . ', ';
319
                }
320
            }
321
322
            $statement = substr($statement, 0, -2) . ')';
323
324
            if ($is_prepared === true) {
325
                $Q = $this->prepare($statement);
326
327 View Code Duplication
                foreach ($data as $c => $v) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
328
                    if ($v != 'now()' && $v != 'null' && !is_null($v)) {
329
                        $Q->bindValue(':' . $c, $v);
330
                    }
331
                }
332
333
                $Q->execute();
334
335
                return $Q->rowCount();
336
            } else {
337
                return $this->exec($statement);
338
            }
339
        }
340
341
        return false;
0 ignored issues
show
Unused Code introduced by
return false; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
342
    }
343
344
    public function delete($table, array $where_condition = [], array $options = null)
345
    {
346 View Code Duplication
        if (!isset($options['prefix_tables']) || ($options['prefix_tables'] === true)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
347
            if ((strlen($table) < 7) || (substr($table, 0, 7) != ':table_')) {
348
                $table = ':table_' . $table;
349
            }
350
        }
351
352
        $statement = 'delete from ' . $table;
353
354
        if (empty($where_condition)) {
355
            return $this->exec($statement);
356
        }
357
358
        $statement .= ' where ';
359
360
        foreach (array_keys($where_condition) as $c) {
361
            $statement .= $c . ' = :cond_' . $c . ' and ';
362
        }
363
364
        $statement = substr($statement, 0, -5);
365
366
        $Q = $this->prepare($statement);
367
368
        foreach ($where_condition as $c => $v) {
369
            $Q->bindValue(':cond_' . $c, $v);
370
        }
371
372
        $Q->execute();
373
374
        return $Q->rowCount();
375
    }
376
377
    public function importSQL($sql_file, $table_prefix = null)
378
    {
379
        if (is_file($sql_file)) {
380
            $import_queries = file_get_contents($sql_file);
381
        } else {
382
            trigger_error('OSC\OM\Db::importSQL(): SQL file does not exist: ' . $sql_file);
383
384
            return false;
385
        }
386
387
        set_time_limit(0);
388
389
        $sql_queries = array();
390
        $sql_length = strlen($import_queries);
391
        $pos = strpos($import_queries, ';');
392
393
        for ($i = $pos; $i < $sql_length; $i++) {
394
// remove comments
395
            if ((substr($import_queries, 0, 1) == '#') || (substr($import_queries, 0, 2) == '--')) {
396
                $import_queries = ltrim(substr($import_queries, strpos($import_queries, "\n")));
397
                $sql_length = strlen($import_queries);
398
                $i = strpos($import_queries, ';') - 1;
399
                continue;
400
            }
401
402
            if (substr($import_queries, $i + 1, 1) == "\n") {
403
                $next = '';
404
405
                for ($j = ($i+2); $j < $sql_length; $j++) {
406
                    if (!empty(substr($import_queries, $j, 1))) {
407
                        $next = substr($import_queries, $j, 6);
408
409
                        if ((substr($next, 0, 1) == '#') || (substr($next, 0, 2) == '--')) {
410
// find out where the break position is so we can remove this line (#comment line)
411
                            for ($k = $j; $k < $sql_length; $k++) {
412
                                if (substr($import_queries, $k, 1) == "\n") {
413
                                    break;
414
                                }
415
                            }
416
417
                            $query = substr($import_queries, 0, $i + 1);
418
419
                            $import_queries = substr($import_queries, $k);
420
421
// join the query before the comment appeared, with the rest of the dump
422
                            $import_queries = $query . $import_queries;
423
                            $sql_length = strlen($import_queries);
424
                            $i = strpos($import_queries, ';') - 1;
425
                            continue 2;
426
                        }
427
428
                        break;
429
                    }
430
                }
431
432
                if (empty($next)) { // get the last insert query
433
                    $next = 'insert';
434
                }
435
436
                if ((strtoupper($next) == 'DROP T') ||
437
                (strtoupper($next) == 'CREATE') ||
438
                (strtoupper($next) == 'INSERT') ||
439
                (strtoupper($next) == 'ALTER ') ||
440
                (strtoupper($next) == 'SET FO')) {
441
                    $next = '';
0 ignored issues
show
Unused Code introduced by
$next is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
442
443
                    $sql_query = substr($import_queries, 0, $i);
444
445
                    if (isset($table_prefix) && !empty($table_prefix)) {
446
                        if (strtoupper(substr($sql_query, 0, 20)) == 'DROP TABLE IF EXISTS') {
447
                            $sql_query = 'DROP TABLE IF EXISTS ' . $table_prefix . substr($sql_query, 21);
448
                        } elseif (strtoupper(substr($sql_query, 0, 12)) == 'CREATE TABLE') {
449
                            $sql_query = 'CREATE TABLE ' . $table_prefix . substr($sql_query, 13);
450
                        } elseif (strtoupper(substr($sql_query, 0, 11)) == 'INSERT INTO') {
451
                            $sql_query = 'INSERT INTO ' . $table_prefix . substr($sql_query, 12);
452
                        } elseif (strtoupper(substr($sql_query, 0, 12)) == 'CREATE INDEX') {
453
                            $sql_query = substr($sql_query, 0, stripos($sql_query, ' on ')) .
454
                                         ' on ' .
455
                                         $table_prefix .
456
                                         substr($sql_query, stripos($sql_query, ' on ') + 4);
457
                        }
458
                    }
459
460
                    $sql_queries[] = trim($sql_query);
461
462
                    $import_queries = ltrim(substr($import_queries, $i+1));
463
                    $sql_length = strlen($import_queries);
464
                    $i = strpos($import_queries, ';')-1;
465
                }
466
            }
467
        }
468
469
        $error = false;
470
471
        foreach ($sql_queries as $q) {
472
            if ($this->exec($q) === false) {
473
                $error = true;
474
475
                break;
476
            }
477
        }
478
479
        return !$error;
480
    }
481
482
    public static function getSchemaFromFile($file)
483
    {
484
        $table = substr(basename($file), 0, strrpos(basename($file), '.'));
485
486
        $schema = [
487
            'name' => $table
488
        ];
489
490
        $is_index = $is_foreign = $is_property = false;
491
492
        foreach (file($file) as $row) {
493
            $row = trim($row);
494
495
            if (!empty($row)) {
496
                if ($row == '--') {
497
                    $is_index = true;
498
                    $is_foreign = $is_property = false;
499
500
                    continue;
501
                } elseif ($row == '==') {
502
                    $is_foreign = true;
503
                    $is_index = $is_property = false;
504
505
                    continue;
506
                } elseif ($row == '##') {
507
                    $is_property = true;
508
                    $is_index = $is_foreign = false;
509
510
                    continue;
511
                }
512
513
                $details = str_getcsv($row, ' ');
514
515
                $field_name = array_shift($details);
516
517
                if ($is_index === true) {
518
                    $schema['index'][$field_name] = $details;
519
520
                    continue;
521
                } elseif ($is_foreign === true) {
522
                    foreach ($details as $d) {
523
                        if (strpos($d, '(') === false) {
524
                            $schema['foreign'][$field_name]['col'][] = $d;
525
526
                            continue;
527
                        }
528
529
                        if (preg_match('/(.*)\((.*)\)/', $d, $info)) {
530
                            switch ($info[1]) {
531
                                case 'ref_table':
532
                                case 'on_delete':
533
                                case 'on_update':
534
                                case 'prefix':
535
                                    $schema['foreign'][$field_name][$info[1]] = $info[2];
536
537
                                    break;
538
539
                                case 'ref_col':
540
                                    $schema['foreign'][$field_name]['ref_col'] = explode(' ', $info[2]);
541
                                    break;
542
                            }
543
                        }
544
                    }
545
546
                    continue;
547
                } elseif ($is_property === true) {
548
                    switch ($field_name) {
549
                        case 'engine':
550
                            $schema['property']['engine'] = implode(' ', $details);
551
                            break;
552
553
                        case 'character_set':
554
                            $schema['property']['character_set'] = implode(' ', $details);
555
                            break;
556
557
                        case 'collate':
558
                            $schema['property']['collate'] = implode(' ', $details);
559
                            break;
560
                    }
561
562
                    continue;
563
                }
564
565
                $field_type = array_shift($details);
566
567
                if (preg_match('/(.*)\((.*)\)/', $field_type, $type_details)) {
568
                    $schema['col'][$field_name]['type'] = $type_details[1];
569
                    $schema['col'][$field_name]['length'] = $type_details[2];
570
                } else {
571
                    $schema['col'][$field_name]['type'] = $field_type;
572
                }
573
574
                if (preg_match('/default\((.*)\)/', implode(' ', $details), $type_default)) {
575
                    $schema['col'][$field_name]['default'] = $type_default[1];
576
577
                    $default_pos = array_search('default(' . $type_default[1] . ')', $details);
578
                    array_splice($details, $default_pos, 1);
579
                }
580
581
                $is_binary = array_search('binary', $details);
582
583
                if (is_integer($is_binary)) {
584
                    array_splice($details, $is_binary, 1);
585
                    $schema['col'][$field_name]['binary'] = true;
586
                }
587
588
                $is_unsigned = array_search('unsigned', $details);
589
590
                if (is_integer($is_unsigned)) {
591
                    array_splice($details, $is_unsigned, 1);
592
                    $schema['col'][$field_name]['unsigned'] = true;
593
                }
594
595
                $is_not_null = array_search('not_null', $details);
596
597
                if (is_integer($is_not_null)) {
598
                    array_splice($details, $is_not_null, 1);
599
                    $schema['col'][$field_name]['not_null'] = true;
600
                }
601
602
                $is_auto_increment = array_search('auto_increment', $details);
603
604
                if (is_integer($is_auto_increment)) {
605
                    array_splice($details, $is_auto_increment, 1);
606
                    $schema['col'][$field_name]['auto_increment'] = true;
607
                }
608
609
                if (!empty($details)) {
610
                    $schema['col'][$field_name]['other'] = implode(' ', $details);
611
                }
612
            }
613
        }
614
615
        return $schema;
616
    }
617
618
    public static function getSqlFromSchema($schema, $prefix = null)
619
    {
620
        $sql = 'CREATE TABLE ' . (isset($prefix) ? $prefix : '') . $schema['name'] . ' (' . "\n";
621
622
        $rows = [];
623
624
        foreach ($schema['col'] as $name => $fields) {
625
            $row = '  ' . $name . ' ' . $fields['type'];
626
627
            if (isset($fields['length'])) {
628
                $row .= '(' . $fields['length'] . ')';
629
            }
630
631
            if (isset($fields['binary']) && ($fields['binary'] === true)) {
632
                $row .= ' binary';
633
            }
634
635
            if (isset($fields['unsigned']) && ($fields['unsigned'] === true)) {
636
                $row .= ' unsigned';
637
            }
638
639
            if (isset($fields['default'])) {
640
                $row .= ' DEFAULT ' . $fields['default'];
641
            }
642
643
            if (isset($fields['not_null']) && ($fields['not_null'] === true)) {
644
                $row .= ' NOT NULL';
645
            }
646
647
            if (isset($fields['auto_increment']) && ($fields['auto_increment'] === true)) {
648
                $row .= ' auto_increment';
649
            }
650
651
            $rows[] = $row;
652
        }
653
654
        if (isset($schema['index'])) {
655
            foreach ($schema['index'] as $name => $fields) {
656
                if ($name == 'primary') {
657
                    $name = 'PRIMARY KEY';
658
                } else {
659
                    $name = 'KEY ' . $name;
660
                }
661
662
                $row = '  ' . $name . ' (' . implode(', ', $fields) . ')';
663
664
                $rows[] = $row;
665
            }
666
        }
667
668
        if (isset($schema['foreign'])) {
669
            foreach ($schema['foreign'] as $name => $fields) {
670
                $row = '  FOREIGN KEY ' . $name . ' (' . implode(', ', $fields['col']) . ') REFERENCES ' . (isset($prefix) && (!isset($fields['prefix']) || ($fields['prefix'] != 'false')) ? $prefix : '') . $fields['ref_table'] . '(' . implode(', ', $fields['ref_col']) . ')';
671
672
                if (isset($fields['on_update'])) {
673
                    $row .= ' ON UPDATE ' . strtoupper($fields['on_update']);
674
                }
675
676
                if (isset($fields['on_delete'])) {
677
                    $row .= ' ON DELETE ' . strtoupper($fields['on_delete']);
678
                }
679
680
                $rows[] = $row;
681
            }
682
        }
683
684
        $sql .= implode(',' . "\n", $rows) . "\n" . ')';
685
686
        if (isset($schema['property'])) {
687
            if (isset($schema['property']['engine'])) {
688
                $sql .= ' ENGINE ' . $schema['property']['engine'];
689
            }
690
691
            if (isset($schema['property']['character_set'])) {
692
                $sql .= ' CHARACTER SET ' . $schema['property']['character_set'];
693
            }
694
695
            if (isset($schema['property']['collate'])) {
696
                $sql .= ' COLLATE ' . $schema['property']['collate'];
697
            }
698
        }
699
700
        $sql .= ';';
701
702
        return $sql;
703
    }
704
705
    public static function prepareInput($string)
706
    {
707
        if (is_string($string)) {
708
            return HTML::sanitize($string);
709
        } elseif (is_array($string)) {
710
            foreach ($string as $k => $v) {
711
                $string[$k] = static::prepareInput($v);
712
            }
713
714
            return $string;
715
        } else {
716
            return $string;
717
        }
718
    }
719
720
    public static function prepareIdentifier($string)
721
    {
722
        return '`' . str_replace('`', '``', $string) . '`';
723
    }
724
725
    public function setTablePrefix($prefix)
726
    {
727
        $this->table_prefix = $prefix;
728
    }
729
730
    protected function autoPrefixTables($statement)
731
    {
732
        $prefix = '';
733
734
        if (isset($this->table_prefix)) {
735
            $prefix = $this->table_prefix;
736
        } elseif (OSCOM::configExists('db_table_prefix')) {
737
            $prefix = OSCOM::getConfig('db_table_prefix');
738
        }
739
740
        $statement = str_replace(':table_', $prefix, $statement);
741
742
        return $statement;
743
    }
744
}
745