Upgrade_230   F
last analyzed

Complexity

Total Complexity 85

Size/Duplication

Total Lines 430
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 190
dl 0
loc 430
rs 2
c 1
b 0
f 0
wmc 85

16 Methods

Rating   Name   Duplication   Size   Complexity  
A check_cache() 0 10 2
A __construct() 0 5 1
A check_bmlink() 0 16 4
A check_config() 0 10 2
B apply_config() 0 33 7
A apply_path() 0 3 1
A update_configs() 0 13 5
A set_configs() 0 16 6
A apply_db() 0 3 1
C write_mainfile() 0 33 12
A convert_db() 0 21 4
A check_db() 0 15 2
A apply_cache() 0 8 1
A apply_bmlink() 0 40 4
A check_path() 0 14 6
F convert_table() 0 86 27

How to fix   Complexity   

Complex Class

Complex classes like Upgrade_230 often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Upgrade_230, and based on these observations, apply Extract Interface, too.

1
<?php
2
/*
3
 You may not change or alter any portion of this comment or credits
4
 of supporting developers from this source code or any supporting source code
5
 which is considered copyrighted (c) material of the original comment or credit authors.
6
7
 This program is distributed in the hope that it will be useful,
8
 but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
*/
11
12
use Xmf\Database\Tables;
13
14
/**
15
 * Upgrader from 2.0.18 to 2.3.0
16
 *
17
 * See the enclosed file license.txt for licensing information.
18
 * If you did not receive this file, get it at https://www.gnu.org/licenses/gpl-2.0.html
19
 *
20
 * @copyright    (c) 2000-2025 XOOPS Project (https://xoops.org)
21
 * @license          GNU GPL 2.0 or later (https://www.gnu.org/licenses/gpl-2.0.html)
22
 * @package          upgrader
23
 * @since            2.3.0
24
 * @author           Taiwen Jiang <[email protected]>
25
 */
26
27
include_once __DIR__ . '/pathcontroller.php';
28
29
/**
30
 * Class upgrade_230
31
 */
32
class Upgrade_230 extends XoopsUpgrade
33
{
34
    /*
35
     *  __construct()
36
     */
37
    public function __construct()
38
    {
39
        parent::__construct(basename(__DIR__));
40
        $this->usedFiles = ['mainfile.php'];
41
        $this->tasks     = ['config', 'cache', 'path', 'db', 'bmlink'];
42
    }
43
44
    /**
45
     * Check if cpanel config already exists
46
     *
47
     */
48
    public function check_config()
49
    {
50
        $sql = 'SELECT COUNT(*) FROM `' . $GLOBALS['xoopsDB']->prefix('config') . "` WHERE `conf_name` IN ('welcome_type', 'cpanel')";
51
        $result = $GLOBALS['xoopsDB']->queryF($sql);
52
        if (!$GLOBALS['xoopsDB']->isResultSet($result)) {
53
            return false;
54
        }
55
        [$count] = $GLOBALS['xoopsDB']->fetchRow($result);
56
57
        return ($count == 2);
58
    }
59
60
    /**
61
     * Check if cache_model table already exists
62
     *
63
     */
64
    public function check_cache()
65
    {
66
        $sql    = "SHOW TABLES LIKE '" . $GLOBALS['xoopsDB']->prefix('cache_model') . "'";
67
        $result = $GLOBALS['xoopsDB']->queryF($sql);
68
        if (!$GLOBALS['xoopsDB']->isResultSet($result)) {
69
            return false;
70
        }
71
72
        $temp = $GLOBALS['xoopsDB']->getRowsNum($result) > 0;
73
        return $temp;
74
75
        /*
76
        $sql = "SELECT COUNT(*) FROM `" . $GLOBALS['xoopsDB']->prefix('cache_model') . "`";
77
        if ( !$result = $GLOBALS['xoopsDB']->queryF( $sql ) ) {
78
            return false;
79
        }
80
81
        return true;
82
        */
83
    }
84
85
    /**
86
     * Check if primary key for `block_module_link` is already set
87
     *
88
     */
89
    public function check_bmlink()
90
    {
91
        // MySQL 5.0+
92
        //$sql = "SHOW KEYS FROM `" . $GLOBALS['xoopsDB']->prefix('block_module_link') . "` WHERE `KEY_NAME` LIKE 'PRIMARY'";
93
        $sql = 'SHOW KEYS FROM `' . $GLOBALS['xoopsDB']->prefix('block_module_link') . '`';
94
        $result = $GLOBALS['xoopsDB']->queryF($sql);
95
        if (!$GLOBALS['xoopsDB']->isResultSet($result)) {
96
            return false;
97
        }
98
        while (false !== ($row = $GLOBALS['xoopsDB']->fetchArray($result))) {
99
            if ($row['Key_name'] === 'PRIMARY') {
100
                return true;
101
            }
102
        }
103
104
        return false;
105
    }
106
107
    /**
108
     * @return bool
109
     */
110
    public function apply_bmlink()
111
    {
112
        $tableName = 'block_module_link';
113
        $tableNameOld = $tableName . '_old';
114
115
        $tables = new Tables();
116
117
        $tables->useTable($tableName);
118
        $tables->renameTable($tableName, $tableNameOld);
119
        $result = $tables->executeQueue(true);
120
        if (true !== $result) {
121
            throw new \RuntimeException(
122
                __METHOD__ . ' failed.',
123
                E_USER_ERROR,
124
            );
125
        }
126
        $tables->resetQueue();
127
        $tables->addTable($tableName);
128
        $tables->addColumn($tableName, 'block_id', 'int');
129
        $tables->addColumn($tableName, 'module_id', 'int');
130
        $tables->addPrimaryKey($tableName, 'block_id, module_id');
131
        $result = $tables->executeQueue(true);
132
        if (true !== $result) {
133
            throw new \RuntimeException(
134
                __METHOD__ . ' failed.',
135
                E_USER_ERROR,
136
            );
137
        }
138
        $prefixedName = $GLOBALS['xoopsDB']->prefix('block_module_link');
139
        $sql = 'INSERT INTO `' . $prefixedName . '` (`block_id`, `module_id`) ' .
140
            'SELECT DISTINCT `block_id`, `module_id` FROM `' . $prefixedName . '_old`';
141
        $result = $GLOBALS['xoopsDB']->queryF($sql);
142
        if (true !== $result) {
143
            throw new \RuntimeException(
144
                __METHOD__ . ' failed.',
145
                E_USER_ERROR,
146
            );
147
        }
148
149
        return true;
150
    }
151
152
    /**
153
     * @return bool
154
     */
155
    public function apply_config()
156
    {
157
        $result = true;
158
        if (!isset($GLOBALS['xoopsConfig']['cpanel'])) {
159
            $sql = 'INSERT INTO ' . $GLOBALS['xoopsDB']->prefix('config') . ' (conf_id, conf_modid, conf_catid, conf_name, conf_title, conf_value, conf_desc, conf_formtype, conf_valuetype, conf_order) ' . ' VALUES ' . " (NULL, 0, 1, 'cpanel', '_MD_AM_CPANEL', 'default', '_MD_AM_CPANELDSC', 'cpanel', 'other', 11)";
160
161
            $result *= $GLOBALS['xoopsDB']->queryF($sql);
162
        }
163
164
        $welcometype_installed = false;
165
        $sql                   = 'SELECT COUNT(*) FROM `' . $GLOBALS['xoopsDB']->prefix('config') . "` WHERE `conf_name` = 'welcome_type'";
166
        $result = $GLOBALS['xoopsDB']->queryF($sql);
167
        if ($GLOBALS['xoopsDB']->isResultSet($result)) {
168
            [$count] = $GLOBALS['xoopsDB']->fetchRow($result);
169
            if ($count == 1) {
170
                $welcometype_installed = true;
171
            }
172
        }
173
        if (!$welcometype_installed) {
174
            $sql = 'INSERT INTO ' . $GLOBALS['xoopsDB']->prefix('config') . ' (conf_id, conf_modid, conf_catid, conf_name, conf_title, conf_value, conf_desc, conf_formtype, conf_valuetype, conf_order) ' . ' VALUES ' . " (NULL, 0, 2, 'welcome_type', '_MD_AM_WELCOMETYPE', '1', '_MD_AM_WELCOMETYPE_DESC', 'select', 'int', 3)";
175
176
            if (!$GLOBALS['xoopsDB']->queryF($sql)) {
177
                return false;
178
            }
179
            $config_id = $GLOBALS['xoopsDB']->getInsertId();
180
181
            $sql = 'INSERT INTO ' . $GLOBALS['xoopsDB']->prefix('configoption') . ' (confop_id, confop_name, confop_value, conf_id)' . ' VALUES' . " (NULL, '_NO', '0', {$config_id})," . " (NULL, '_MD_AM_WELCOMETYPE_EMAIL', '1', {$config_id})," . " (NULL, '_MD_AM_WELCOMETYPE_PM', '2', {$config_id})," . " (NULL, '_MD_AM_WELCOMETYPE_BOTH', '3', {$config_id})";
182
            if (!$result = $GLOBALS['xoopsDB']->queryF($sql)) {
183
                return false;
184
            }
185
        }
186
187
        return $result;
188
    }
189
190
    public function apply_cache()
191
    {
192
        $allowWebChanges                     = $GLOBALS['xoopsDB']->allowWebChanges;
193
        $GLOBALS['xoopsDB']->allowWebChanges = true;
194
        $result                              = $GLOBALS['xoopsDB']->queryFromFile(__DIR__ . '/mysql.structure.sql');
195
        $GLOBALS['xoopsDB']->allowWebChanges = $allowWebChanges;
196
197
        return $result;
198
    }
199
200
    /**
201
     * @return bool
202
     */
203
    public function check_path()
204
    {
205
        if (!(defined('XOOPS_PATH') && defined('XOOPS_VAR_PATH') && defined('XOOPS_TRUST_PATH'))) {
206
            return false;
207
        }
208
        $ctrl = new PathController();
0 ignored issues
show
Bug introduced by
The call to PathController::__construct() has too few arguments starting with xoopsPathDefault. ( Ignorable by Annotation )

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

208
        $ctrl = /** @scrutinizer ignore-call */ new PathController();

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
209
        if (!$ctrl->checkPath()) {
210
            return false;
211
        }
212
        if (!$ctrl->checkPermissions()) {
0 ignored issues
show
Bug introduced by
The call to PathController::checkPermissions() has too few arguments starting with path. ( Ignorable by Annotation )

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

212
        if (!$ctrl->/** @scrutinizer ignore-call */ checkPermissions()) {

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
213
            return false;
214
        }
215
216
        return true;
217
    }
218
219
    /**
220
     * @return bool
221
     */
222
    public function apply_path()
223
    {
224
        return $this->update_configs('path');
225
    }
226
227
    /**
228
     * @return bool
229
     */
230
    public function check_db()
231
    {
232
        // mainfile was included to get here, just check for definition
233
        if (defined('XOOPS_DB_CHARSET')) {
234
            return true;
235
        }
236
        /*
237
        $lines = file(XOOPS_ROOT_PATH . '/mainfile.php');
238
        foreach ($lines as $line) {
239
            if (preg_match("/(define\(\s*)([\"'])(XOOPS_DB_CHARSET)\\2,\s*([\"'])([^\"']*?)\\4\s*\);/", $line)) {
240
                return true;
241
            }
242
        }
243
        */
244
        return false;
245
    }
246
247
    /**
248
     * @return bool
249
     */
250
    public function apply_db()
251
    {
252
        return $this->update_configs('db');
253
    }
254
255
    /**
256
     * @param $task
257
     *
258
     * @return bool
259
     */
260
    public function update_configs($task)
261
    {
262
        if (!$vars = $this->set_configs($task)) {
263
            return false;
264
        }
265
        if ($task === 'db' && !empty($vars['XOOPS_DB_COLLATION'])) {
266
            if ($pos = strpos($vars['XOOPS_DB_COLLATION'], '_')) {
267
                $vars['XOOPS_DB_CHARSET'] = substr($vars['XOOPS_DB_COLLATION'], 0, $pos);
268
                $this->convert_db($vars['XOOPS_DB_CHARSET'], $vars['XOOPS_DB_COLLATION']);
269
            }
270
        }
271
272
        return $this->write_mainfile($vars);
273
    }
274
275
    /**
276
     * @param $charset
277
     * @param $collation
278
     *
279
     * @return bool
280
     */
281
    public function convert_db($charset, $collation)
282
    {
283
        $sql = 'ALTER DATABASE `' . XOOPS_DB_NAME . '` DEFAULT CHARACTER SET ' . $GLOBALS['xoopsDB']->quote($charset) . ' COLLATE ' . $GLOBALS['xoopsDB']->quote($collation);
284
        $result = $GLOBALS['xoopsDB']->queryF($sql);
285
        if (!$GLOBALS['xoopsDB']->isResultSet($result)) {
286
            return false;
287
        }
288
289
        $sql = "SHOW TABLES LIKE '" . XOOPS_DB_PREFIX . "\_%'";
290
        $result = $GLOBALS['xoopsDB']->queryF($sql);
291
        if (!$GLOBALS['xoopsDB']->isResultSet($result)) {
292
            return false;
293
        }
294
        $tables = [];
295
        while (false !== (list($table) = $GLOBALS['xoopsDB']->fetchRow($result))) {
296
            $tables[] = $table;
297
            //$GLOBALS["xoopsDB"]->queryF( "ALTER TABLE `{$table}` DEFAULT CHARACTER SET " . $GLOBALS["xoopsDB"]->quote($charset) . " COLLATE " . $GLOBALS["xoopsDB"]->quote($collation) );
298
            //$GLOBALS["xoopsDB"]->queryF( "ALTER TABLE `{$table}` CONVERT TO CHARACTER SET " . $GLOBALS["xoopsDB"]->quote($charset) . " COLLATE " . $GLOBALS["xoopsDB"]->quote($collation) );
299
        }
300
        $this->convert_table($tables, $charset, $collation);
301
        return null;
302
    }
303
304
    // Some code not ready to use
305
    /**
306
     * @param $tables
307
     * @param $charset
308
     * @param $collation
309
     *
310
     * @return array
311
     */
312
    public function convert_table($tables, $charset, $collation)
313
    {
314
        // Initialize vars.
315
        $string_querys     = [];
316
        $binary_querys     = [];
317
        $gen_index_querys  = [];
318
        $drop_index_querys = [];
319
        $tables_querys     = [];
320
        $optimize_querys   = [];
321
        $final_querys      = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $final_querys is dead and can be removed.
Loading history...
322
323
        // Begin Converter Core
324
        if (!empty($tables)) {
325
            foreach ((array) $tables as $table) {
326
                // Analyze tables for string types columns and generate his binary and string correctness sql sentences.
327
                $sql = "DESCRIBE $table";
328
                $result = $GLOBALS['xoopsDB']->queryF($sql);
329
                if (!$GLOBALS['xoopsDB']->isResultSet($result)) {
330
                    throw new \RuntimeException(
331
                        \sprintf(_DB_QUERY_ERROR, $sql) . $GLOBALS['xoopsDB']->error(),
332
                        E_USER_ERROR,
333
                    );
334
                }
335
                while (false !== ($myrow = $GLOBALS['xoopsDB']->fetchArray($result))) {
336
                    if (preg_match('/(char)|(text)|(enum)|(set)/', $myrow['Type'])) {
337
                        // String Type SQL Sentence.
338
                        $string_querys[] = "ALTER TABLE `$table` MODIFY `" . $myrow['Field'] . '` ' . $myrow['Type'] . " CHARACTER SET $charset COLLATE $collation " . (((!empty($myrow['Default'])) || ($myrow['Default'] === '0') || ($myrow['Default'] === 0)) ? "DEFAULT '" . $myrow['Default'] . "' " : '') . ('YES' === $myrow['Null'] ? '' : 'NOT ') . 'NULL';
339
340
                        // Binary String Type SQL Sentence.
341
                        if (preg_match('/(enum)|(set)/', $myrow['Type'])) {
342
                            $binary_querys[] = "ALTER TABLE `$table` MODIFY `" . $myrow['Field'] . '` ' . $myrow['Type'] . ' CHARACTER SET binary ' . (((!empty($myrow['Default'])) || ($myrow['Default'] === '0') || ($myrow['Default'] === 0)) ? "DEFAULT '" . $myrow['Default'] . "' " : '') . ('YES' === $myrow['Null'] ? '' : 'NOT ') . 'NULL';
343
                        } else {
344
                            $myrow['Type']  = str_replace('char', 'binary', $myrow['Type']);
345
                            $myrow['Type']  = str_replace('text', 'blob', $myrow['Type']);
346
                            $binary_querys[] = "ALTER TABLE `$table` MODIFY `" . $myrow['Field'] . '` ' . $myrow['Type'] . ' ' . (((!empty($myrow['Default'])) || ($myrow['Default'] === '0') || ($myrow['Default'] === 0)) ? "DEFAULT '" . $myrow['Default'] . "' " : '') . ('YES' === $myrow['Null'] ? '' : 'NOT ') . 'NULL';
347
                        }
348
                    }
349
                }
350
351
                // Analyze table indexes for any FULLTEXT-Type of index in the table.
352
                $fulltext_indexes = [];
353
                $sql         = "SHOW INDEX FROM `$table`";
354
                $result = $GLOBALS['xoopsDB']->queryF($sql);
355
                if (!$GLOBALS['xoopsDB']->isResultSet($result)) {
356
                    throw new \RuntimeException(
357
                        \sprintf(_DB_QUERY_ERROR, $sql) . $GLOBALS['xoopsDB']->error(),
358
                        E_USER_ERROR,
359
                    );
360
                }
361
                while (false !== ($myrow = $GLOBALS['xoopsDB']->fetchArray($result))) {
362
                    if (preg_match('/FULLTEXT/', $myrow['Index_type'])) {
363
                        $fulltext_indexes[$myrow['Key_name']][$myrow['Column_name']] = 1;
364
                    }
365
                }
366
367
                // Generate the SQL Sentence for drop and add every FULLTEXT index we found previously.
368
                if (!empty($fulltext_indexes)) {
369
                    foreach ((array) $fulltext_indexes as $key_name => $column) {
370
                        $drop_index_querys[] = "ALTER TABLE `$table` DROP INDEX `$key_name`";
371
                        $tmp_gen_index_query = "ALTER TABLE `$table` ADD FULLTEXT `$key_name`(";
372
                        $fields_names        = array_keys($column);
373
                        for ($i = 1; $i <= count($column); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
374
                            $tmp_gen_index_query .= $fields_names[$i - 1] . (($i == count($column)) ? '' : ', ');
375
                        }
376
                        $gen_index_querys[] = $tmp_gen_index_query . ')';
377
                    }
378
                }
379
380
                // Generate the SQL Sentence for change default table character set.
381
                $tables_querys[] = "ALTER TABLE `$table` DEFAULT CHARACTER SET $charset COLLATE $collation";
382
383
                // Generate the SQL Sentence for Optimize Table.
384
                $optimize_querys[] = "OPTIMIZE TABLE `$table`";
385
            }
386
        }
387
        // End Converter Core
388
389
        // Merge all SQL Sentences that we temporary store in arrays.
390
        $final_querys = array_merge((array) $drop_index_querys, (array) $binary_querys, (array) $tables_querys, (array) $string_querys, (array) $gen_index_querys, (array) $optimize_querys);
391
392
        foreach ($final_querys as $sql) {
393
            $GLOBALS['xoopsDB']->queryF($sql);
394
        }
395
396
        // Time to return.
397
        return $final_querys;
398
    }
399
400
    /**
401
     * @param $vars
402
     *
403
     * @return bool
404
     */
405
    public function write_mainfile($vars)
406
    {
407
        if (empty($vars)) {
408
            return false;
409
        }
410
411
        $file = __DIR__ . '/mainfile.dist.php';
412
413
        $lines = file($file);
414
        foreach (array_keys($lines) as $ln) {
415
            if (preg_match("/(define\()([\"'])(XOOPS_[^\"']+)\\2,\s*([0-9]+)\s*\)/", $lines[$ln], $matches)) {
416
                $val        = isset($vars[$matches[3]]) ? (string) constant($matches[3]) : (defined($matches[3]) ? (string) constant($matches[3]) : '0');
417
                $lines[$ln] = preg_replace("/(define\()([\"'])(XOOPS_[^\"']+)\\2,\s*([0-9]+)\s*\)/", "define('" . $matches[3] . "', " . $val . ' )', $lines[$ln]);
418
            } elseif (preg_match("/(define\()([\"'])(XOOPS_[^\"']+)\\2,\s*([\"'])([^\"']*?)\\4\s*\)/", $lines[$ln], $matches)) {
419
                $val        = isset($vars[$matches[3]]) ? (string) $vars[$matches[3]] : (defined($matches[3]) ? (string) constant($matches[3]) : '');
420
                $lines[$ln] = preg_replace("/(define\()([\"'])(XOOPS_[^\"']+)\\2,\s*([\"'])(.*?)\\4\s*\)/", "define('" . $matches[3] . "', '" . $val . "' )", $lines[$ln]);
421
            }
422
        }
423
424
        $fp = fopen(XOOPS_ROOT_PATH . '/mainfile.php', 'wt');
425
        if (!$fp) {
0 ignored issues
show
introduced by
$fp is of type resource, thus it always evaluated to false.
Loading history...
426
            echo ERR_COULD_NOT_WRITE_MAINFILE;
427
            echo "<pre style='border: 1px solid black; width: 80%; overflow: auto;'><div style='color: #ff0000; font-weight: bold;'><div>" . implode('</div><div>', array_map('htmlspecialchars', $lines)) . '</div></div></pre>';
428
429
            return false;
430
        } else {
431
            $newline = defined(PHP_EOL) ? PHP_EOL : (strpos(php_uname(), 'Windows') ? "\r\n" : "\n");
432
            $content = str_replace(["\r\n", "\n"], $newline, implode('', $lines));
433
434
            fwrite($fp, $content);
435
            fclose($fp);
436
437
            return true;
438
        }
439
    }
440
441
    /**
442
     * @param $task
443
     *
444
     * @return array|bool
445
     */
446
    public function set_configs($task)
447
    {
448
        $ret     = [];
449
        $configs = include __DIR__ . "/settings_{$task}.php";
450
        if (!$configs || !is_array($configs)) {
451
            return $ret;
452
        }
453
        if (empty($_POST['task']) || $_POST['task'] != $task) {
454
            return false;
455
        }
456
457
        foreach ($configs as $key => $val) {
458
            $ret['XOOPS_' . $key] = $val;
459
        }
460
461
        return $ret;
462
    }
463
}
464
465
$upg = new Upgrade_230();
466
return $upg;
467