Completed
Push — master ( 4ee263...3e5f87 )
by Harald
05:34 queued 02:48
created

Db::save()   F

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
25
    public static function initialize(
26
        $server = null,
27
        $username = null,
28
        $password = null,
29
        $database = null,
30
        $port = null,
31
        array $driver_options = []
32
    ) {
33
        if (!isset($server)) {
34
            $server = OSCOM::getConfig('db_server');
35
        }
36
37
        if (!isset($username)) {
38
            $username = OSCOM::getConfig('db_server_username');
39
        }
40
41
        if (!isset($password)) {
42
            $password = OSCOM::getConfig('db_server_password');
43
        }
44
45
        if (!isset($database)) {
46
            $database = OSCOM::getConfig('db_database');
47
        }
48
49
        if (!isset($driver_options[\PDO::ATTR_ERRMODE])) {
50
            $driver_options[\PDO::ATTR_ERRMODE] = \PDO::ERRMODE_EXCEPTION;
51
        }
52
53
        if (!isset($driver_options[\PDO::ATTR_DEFAULT_FETCH_MODE])) {
54
            $driver_options[\PDO::ATTR_DEFAULT_FETCH_MODE] = \PDO::FETCH_ASSOC;
55
        }
56
57
        if (!isset($driver_options[\PDO::ATTR_STATEMENT_CLASS])) {
58
            $driver_options[\PDO::ATTR_STATEMENT_CLASS] = array('OSC\OM\DbStatement');
59
        }
60
61
        $class = 'OSC\OM\Db\MySQL';
62
        $object = new $class($server, $username, $password, $database, $port, $driver_options);
63
64
        return $object;
65
    }
66
67
    public function exec($statement)
68
    {
69
        $statement = $this->autoPrefixTables($statement);
70
71
        return parent::exec($statement);
72
    }
73
74
    public function prepare($statement, $driver_options = null)
75
    {
76
        $statement = $this->autoPrefixTables($statement);
77
78
        $DbStatement = parent::prepare($statement, is_array($driver_options) ? $driver_options : []);
79
        $DbStatement->setQueryCall('prepare');
80
        $DbStatement->setPDO($this);
81
82
        return $DbStatement;
83
    }
84
85
    public function query($statement)
86
    {
87
        $statement = $this->autoPrefixTables($statement);
88
89
        $args = func_get_args();
90
91
        if (count($args) > 1) {
92
            $DbStatement = call_user_func_array(array($this, 'parent::query'), $args);
93
        } else {
94
            $DbStatement = parent::query($statement);
95
        }
96
97
        if ($DbStatement !== false) {
98
            $DbStatement->setQueryCall('query');
99
            $DbStatement->setPDO($this);
100
        }
101
102
        return $DbStatement;
103
    }
104
105
    public function get($table, $fields, array $where = null, $order = null, $limit = null, $cache = null, array $options = null)
106
    {
107
        if (!is_array($table)) {
108
            $table = [ $table ];
109
        }
110
111 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...
112
            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...
113
                if ((strlen($v) < 7) || (substr($v, 0, 7) != ':table_')) {
114
                    $v = ':table_' . $v;
115
                }
116
            });
117
        }
118
119
        if (!is_array($fields)) {
120
            $fields = [ $fields ];
121
        }
122
123
        if (isset($order) && !is_array($order)) {
124
            $order = [ $order ];
125
        }
126
127
        if (isset($limit)) {
128
            if (is_array($limit) && (count($limit) === 2) && is_numeric($limit[0]) && is_numeric($limit[1])) {
129
                $limit = implode(', ', $limit);
130
            } elseif (!is_numeric($limit)) {
131
                $limit = null;
132
            }
133
        }
134
135
        $statement = 'select ' . implode(', ', $fields) . ' from ' . implode(', ', $table);
136
137
        if (!isset($where) && !isset($cache)) {
138
            if (isset($order)) {
139
                $statement .= ' order by ' . implode(', ', $order);
140
            }
141
142
            return $this->query($statement);
143
        }
144
145
        if (isset($where)) {
146
            $statement .= ' where ';
147
148
            $counter = 0;
149
150
            $it_where = new \CachingIterator(new \ArrayIterator($where), \CachingIterator::TOSTRING_USE_CURRENT);
151
152
            foreach ($it_where as $key => $value) {
153
                if (is_array($value)) {
154
                    if (isset($value['val'])) {
155
                        $statement .= $key . ' ' . (isset($value['op']) ? $value['op'] : '=') . ' :cond_' . $counter;
156
                    }
157
158
                    if (isset($value['rel'])) {
159
                        if (isset($value['val'])) {
160
                            $statement .= ' and ';
161
                        }
162
163
                        if (is_array($value['rel'])) {
164
                            $it_rel = new \CachingIterator(new \ArrayIterator($value['rel']), \CachingIterator::TOSTRING_USE_CURRENT);
165
166
                            foreach ($it_rel as $rel) {
167
                                $statement .= $key . ' = ' . $rel;
168
169
                                if ($it_rel->hasNext()) {
170
                                    $statement .= ' and ';
171
                                }
172
                            }
173
                        } else {
174
                            $statement .= $key . ' = ' . $value['rel'];
175
                        }
176
                    }
177
                } else {
178
                    $statement .= $key . ' = :cond_' . $counter;
179
                }
180
181
                if ($it_where->hasNext()) {
182
                    $statement .= ' and ';
183
                }
184
185
                $counter++;
186
            }
187
        }
188
189
        if (isset($order)) {
190
            $statement .= ' order by ' . implode(', ', $order);
191
        }
192
193
        if (isset($limit)) {
194
            $statement .= ' limit ' . $limit;
195
        }
196
197
        $Q = $this->prepare($statement);
198
199
        if (isset($where)) {
200
            $counter = 0;
201
202
            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...
203
                if (is_array($value)) {
204
                    if (isset($value['val'])) {
205
                        $Q->bindValue(':cond_' . $counter, $value['val']);
206
                    }
207
                } else {
208
                    $Q->bindValue(':cond_' . $counter, $value);
209
                }
210
211
                $counter++;
212
            }
213
        }
214
215
        if (isset($cache)) {
216
            if (!is_array($cache)) {
217
                $cache = [ $cache ];
218
            }
219
220
            call_user_func_array([$Q, 'setCache'], $cache);
221
        }
222
223
        $Q->execute();
224
225
        return $Q;
226
    }
227
228
    public function save($table, array $data, array $where_condition = null, array $options = null)
229
    {
230
        if (empty($data)) {
231
            return false;
232
        }
233
234 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...
235
            if ((strlen($table) < 7) || (substr($table, 0, 7) != ':table_')) {
236
                $table = ':table_' . $table;
237
            }
238
        }
239
240
        if (isset($where_condition)) {
241
            $statement = 'update ' . $table . ' set ';
242
243
            foreach ($data as $c => $v) {
244
                if (is_null($v)) {
245
                    $v = 'null';
246
                }
247
248
                if ($v == 'now()' || $v == 'null') {
249
                    $statement .= $c . ' = ' . $v . ', ';
250
                } else {
251
                    $statement .= $c . ' = :new_' . $c . ', ';
252
                }
253
            }
254
255
            $statement = substr($statement, 0, -2) . ' where ';
256
257
            foreach (array_keys($where_condition) as $c) {
258
                $statement .= $c . ' = :cond_' . $c . ' and ';
259
            }
260
261
            $statement = substr($statement, 0, -5);
262
263
            $Q = $this->prepare($statement);
264
265 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...
266
                if ($v != 'now()' && $v != 'null' && !is_null($v)) {
267
                    $Q->bindValue(':new_' . $c, $v);
268
                }
269
            }
270
271
            foreach ($where_condition as $c => $v) {
272
                $Q->bindValue(':cond_' . $c, $v);
273
            }
274
275
            $Q->execute();
276
277
            return $Q->rowCount();
278
        } else {
279
            $is_prepared = false;
280
281
            $statement = 'insert into ' . $table . ' (' . implode(', ', array_keys($data)) . ') values (';
282
283
            foreach ($data as $c => $v) {
284
                if (is_null($v)) {
285
                    $v = 'null';
286
                }
287
288
                if ($v == 'now()' || $v == 'null') {
289
                    $statement .= $v . ', ';
290
                } else {
291
                    if ($is_prepared === false) {
292
                        $is_prepared = true;
293
                    }
294
295
                    $statement .= ':' . $c . ', ';
296
                }
297
            }
298
299
            $statement = substr($statement, 0, -2) . ')';
300
301
            if ($is_prepared === true) {
302
                $Q = $this->prepare($statement);
303
304 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...
305
                    if ($v != 'now()' && $v != 'null' && !is_null($v)) {
306
                        $Q->bindValue(':' . $c, $v);
307
                    }
308
                }
309
310
                $Q->execute();
311
312
                return $Q->rowCount();
313
            } else {
314
                return $this->exec($statement);
315
            }
316
        }
317
318
        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...
319
    }
320
321
    public function delete($table, array $where_condition = [], array $options = null)
322
    {
323 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...
324
            if ((strlen($table) < 7) || (substr($table, 0, 7) != ':table_')) {
325
                $table = ':table_' . $table;
326
            }
327
        }
328
329
        $statement = 'delete from ' . $table;
330
331
        if (empty($where_condition)) {
332
            return $this->exec($statement);
333
        }
334
335
        $statement .= ' where ';
336
337
        foreach (array_keys($where_condition) as $c) {
338
            $statement .= $c . ' = :cond_' . $c . ' and ';
339
        }
340
341
        $statement = substr($statement, 0, -5);
342
343
        $Q = $this->prepare($statement);
344
345
        foreach ($where_condition as $c => $v) {
346
            $Q->bindValue(':cond_' . $c, $v);
347
        }
348
349
        $Q->execute();
350
351
        return $Q->rowCount();
352
    }
353
354
    public function importSQL($sql_file, $table_prefix = null)
355
    {
356
        if (is_file($sql_file)) {
357
            $import_queries = file_get_contents($sql_file);
358
        } else {
359
            trigger_error('OSC\OM\Db::importSQL(): SQL file does not exist: ' . $sql_file);
360
361
            return false;
362
        }
363
364
        set_time_limit(0);
365
366
        $sql_queries = array();
367
        $sql_length = strlen($import_queries);
368
        $pos = strpos($import_queries, ';');
369
370
        for ($i = $pos; $i < $sql_length; $i++) {
371
// remove comments
372
            if ((substr($import_queries, 0, 1) == '#') || (substr($import_queries, 0, 2) == '--')) {
373
                $import_queries = ltrim(substr($import_queries, strpos($import_queries, "\n")));
374
                $sql_length = strlen($import_queries);
375
                $i = strpos($import_queries, ';') - 1;
376
                continue;
377
            }
378
379
            if (substr($import_queries, $i + 1, 1) == "\n") {
380
                $next = '';
381
382
                for ($j = ($i+2); $j < $sql_length; $j++) {
383
                    if (!empty(substr($import_queries, $j, 1))) {
384
                        $next = substr($import_queries, $j, 6);
385
386
                        if ((substr($next, 0, 1) == '#') || (substr($next, 0, 2) == '--')) {
387
// find out where the break position is so we can remove this line (#comment line)
388
                            for ($k = $j; $k < $sql_length; $k++) {
389
                                if (substr($import_queries, $k, 1) == "\n") {
390
                                    break;
391
                                }
392
                            }
393
394
                            $query = substr($import_queries, 0, $i + 1);
395
396
                            $import_queries = substr($import_queries, $k);
397
398
// join the query before the comment appeared, with the rest of the dump
399
                            $import_queries = $query . $import_queries;
400
                            $sql_length = strlen($import_queries);
401
                            $i = strpos($import_queries, ';') - 1;
402
                            continue 2;
403
                        }
404
405
                        break;
406
                    }
407
                }
408
409
                if (empty($next)) { // get the last insert query
410
                    $next = 'insert';
411
                }
412
413
                if ((strtoupper($next) == 'DROP T') ||
414
                (strtoupper($next) == 'CREATE') ||
415
                (strtoupper($next) == 'INSERT') ||
416
                (strtoupper($next) == 'ALTER ') ||
417
                (strtoupper($next) == 'SET FO')) {
418
                    $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...
419
420
                    $sql_query = substr($import_queries, 0, $i);
421
422
                    if (isset($table_prefix) && !empty($table_prefix)) {
423
                        if (strtoupper(substr($sql_query, 0, 20)) == 'DROP TABLE IF EXISTS') {
424
                            $sql_query = 'DROP TABLE IF EXISTS ' . $table_prefix . substr($sql_query, 21);
425
                        } elseif (strtoupper(substr($sql_query, 0, 12)) == 'CREATE TABLE') {
426
                            $sql_query = 'CREATE TABLE ' . $table_prefix . substr($sql_query, 13);
427
                        } elseif (strtoupper(substr($sql_query, 0, 11)) == 'INSERT INTO') {
428
                            $sql_query = 'INSERT INTO ' . $table_prefix . substr($sql_query, 12);
429
                        } elseif (strtoupper(substr($sql_query, 0, 12)) == 'CREATE INDEX') {
430
                            $sql_query = substr($sql_query, 0, stripos($sql_query, ' on ')) .
431
                                         ' on ' .
432
                                         $table_prefix .
433
                                         substr($sql_query, stripos($sql_query, ' on ') + 4);
434
                        }
435
                    }
436
437
                    $sql_queries[] = trim($sql_query);
438
439
                    $import_queries = ltrim(substr($import_queries, $i+1));
440
                    $sql_length = strlen($import_queries);
441
                    $i = strpos($import_queries, ';')-1;
442
                }
443
            }
444
        }
445
446
        $error = false;
447
448
        foreach ($sql_queries as $q) {
449
            if ($this->exec($q) === false) {
450
                $error = true;
451
452
                break;
453
            }
454
        }
455
456
        return !$error;
457
    }
458
459
    public static function getSchemaFromFile($file)
460
    {
461
        $table = substr(basename($file), 0, strrpos(basename($file), '.'));
462
463
        $schema = [
464
            'name' => $table
465
        ];
466
467
        $is_index = $is_foreign = $is_property = false;
468
469
        foreach (file($file) as $row) {
470
            $row = trim($row);
471
472
            if (!empty($row)) {
473
                if ($row == '--') {
474
                    $is_index = true;
475
                    $is_foreign = $is_property = false;
476
477
                    continue;
478
                } elseif ($row == '==') {
479
                    $is_foreign = true;
480
                    $is_index = $is_property = false;
481
482
                    continue;
483
                } elseif ($row == '##') {
484
                    $is_property = true;
485
                    $is_index = $is_foreign = false;
486
487
                    continue;
488
                }
489
490
                $details = str_getcsv($row, ' ');
491
492
                $field_name = array_shift($details);
493
494
                if ($is_index === true) {
495
                    $schema['index'][$field_name] = $details;
496
497
                    continue;
498
                } elseif ($is_foreign === true) {
499
                    foreach ($details as $d) {
500
                        if (strpos($d, '(') === false) {
501
                            $schema['foreign'][$field_name]['col'][] = $d;
502
503
                            continue;
504
                        }
505
506
                        if (preg_match('/(.*)\((.*)\)/', $d, $info)) {
507
                            switch ($info[1]) {
508
                                case 'ref_table':
509
                                case 'on_delete':
510
                                case 'on_update':
511
                                case 'prefix':
512
                                    $schema['foreign'][$field_name][$info[1]] = $info[2];
513
514
                                    break;
515
516
                                case 'ref_col':
517
                                    $schema['foreign'][$field_name]['ref_col'] = explode(' ', $info[2]);
518
                                    break;
519
                            }
520
                        }
521
                    }
522
523
                    continue;
524
                } elseif ($is_property === true) {
525
                    switch ($field_name) {
526
                        case 'engine':
527
                            $schema['property']['engine'] = implode(' ', $details);
528
                            break;
529
530
                        case 'character_set':
531
                            $schema['property']['character_set'] = implode(' ', $details);
532
                            break;
533
534
                        case 'collate':
535
                            $schema['property']['collate'] = implode(' ', $details);
536
                            break;
537
                    }
538
539
                    continue;
540
                }
541
542
                $field_type = array_shift($details);
543
544
                if (preg_match('/(.*)\((.*)\)/', $field_type, $type_details)) {
545
                    $schema['col'][$field_name]['type'] = $type_details[1];
546
                    $schema['col'][$field_name]['length'] = $type_details[2];
547
                } else {
548
                    $schema['col'][$field_name]['type'] = $field_type;
549
                }
550
551
                if (preg_match('/default\((.*)\)/', implode(' ', $details), $type_default)) {
552
                    $schema['col'][$field_name]['default'] = $type_default[1];
553
554
                    $default_pos = array_search('default(' . $type_default[1] . ')', $details);
555
                    array_splice($details, $default_pos, 1);
556
                }
557
558
                $is_binary = array_search('binary', $details);
559
560
                if (is_integer($is_binary)) {
561
                    array_splice($details, $is_binary, 1);
562
                    $schema['col'][$field_name]['binary'] = true;
563
                }
564
565
                $is_unsigned = array_search('unsigned', $details);
566
567
                if (is_integer($is_unsigned)) {
568
                    array_splice($details, $is_unsigned, 1);
569
                    $schema['col'][$field_name]['unsigned'] = true;
570
                }
571
572
                $is_not_null = array_search('not_null', $details);
573
574
                if (is_integer($is_not_null)) {
575
                    array_splice($details, $is_not_null, 1);
576
                    $schema['col'][$field_name]['not_null'] = true;
577
                }
578
579
                $is_auto_increment = array_search('auto_increment', $details);
580
581
                if (is_integer($is_auto_increment)) {
582
                    array_splice($details, $is_auto_increment, 1);
583
                    $schema['col'][$field_name]['auto_increment'] = true;
584
                }
585
586
                if (!empty($details)) {
587
                    $schema['col'][$field_name]['other'] = implode(' ', $details);
588
                }
589
            }
590
        }
591
592
        return $schema;
593
    }
594
595
    public static function getSqlFromSchema($schema, $prefix = null)
596
    {
597
        $sql = 'CREATE TABLE ' . (isset($prefix) ? $prefix : '') . $schema['name'] . ' (' . "\n";
598
599
        $rows = [];
600
601
        foreach ($schema['col'] as $name => $fields) {
602
            $row = '  ' . $name . ' ' . $fields['type'];
603
604
            if (isset($fields['length'])) {
605
                $row .= '(' . $fields['length'] . ')';
606
            }
607
608
            if (isset($fields['binary']) && ($fields['binary'] === true)) {
609
                $row .= ' binary';
610
            }
611
612
            if (isset($fields['unsigned']) && ($fields['unsigned'] === true)) {
613
                $row .= ' unsigned';
614
            }
615
616
            if (isset($fields['default'])) {
617
                $row .= ' DEFAULT ' . $fields['default'];
618
            }
619
620
            if (isset($fields['not_null']) && ($fields['not_null'] === true)) {
621
                $row .= ' NOT NULL';
622
            }
623
624
            if (isset($fields['auto_increment']) && ($fields['auto_increment'] === true)) {
625
                $row .= ' auto_increment';
626
            }
627
628
            $rows[] = $row;
629
        }
630
631
        if (isset($schema['index'])) {
632
            foreach ($schema['index'] as $name => $fields) {
633
                if ($name == 'primary') {
634
                    $name = 'PRIMARY KEY';
635
                } else {
636
                    $name = 'KEY ' . $name;
637
                }
638
639
                $row = '  ' . $name . ' (' . implode(', ', $fields) . ')';
640
641
                $rows[] = $row;
642
            }
643
        }
644
645
        if (isset($schema['foreign'])) {
646
            foreach ($schema['foreign'] as $name => $fields) {
647
                $row = '  FOREIGN KEY ' . $name . ' (' . implode(', ', $fields['col']) . ') REFERENCES ' . (isset($prefix) && (!isset($fields['prefix']) || ($fields['prefix'] != 'false')) ? $prefix : '') . $fields['ref_table'] . '(' . implode(', ', $fields['ref_col']) . ')';
648
649
                if (isset($fields['on_update'])) {
650
                    $row .= ' ON UPDATE ' . strtoupper($fields['on_update']);
651
                }
652
653
                if (isset($fields['on_delete'])) {
654
                    $row .= ' ON DELETE ' . strtoupper($fields['on_delete']);
655
                }
656
657
                $rows[] = $row;
658
            }
659
        }
660
661
        $sql .= implode(',' . "\n", $rows) . "\n" . ')';
662
663
        if (isset($schema['property'])) {
664
            if (isset($schema['property']['engine'])) {
665
                $sql .= ' ENGINE ' . $schema['property']['engine'];
666
            }
667
668
            if (isset($schema['property']['character_set'])) {
669
                $sql .= ' CHARACTER SET ' . $schema['property']['character_set'];
670
            }
671
672
            if (isset($schema['property']['collate'])) {
673
                $sql .= ' COLLATE ' . $schema['property']['collate'];
674
            }
675
        }
676
677
        $sql .= ';';
678
679
        return $sql;
680
    }
681
682
    public static function prepareInput($string)
683
    {
684
        if (is_string($string)) {
685
            return HTML::sanitize($string);
686
        } elseif (is_array($string)) {
687
            foreach ($string as $k => $v) {
688
                $string[$k] = static::prepareInput($v);
689
            }
690
691
            return $string;
692
        } else {
693
            return $string;
694
        }
695
    }
696
697
    public static function prepareIdentifier($string)
698
    {
699
        return '`' . str_replace('`', '``', $string) . '`';
700
    }
701
702
    public function setTablePrefix($prefix)
703
    {
704
        $this->table_prefix = $prefix;
705
    }
706
707
    protected function autoPrefixTables($statement)
708
    {
709
        $prefix = '';
710
711
        if (isset($this->table_prefix)) {
712
            $prefix = $this->table_prefix;
713
        } elseif (OSCOM::configExists('db_table_prefix')) {
714
            $prefix = OSCOM::getConfig('db_table_prefix');
715
        }
716
717
        $statement = str_replace(':table_', $prefix, $statement);
718
719
        return $statement;
720
    }
721
}
722