Passed
Push — master ( a5e222...57c8f1 )
by Maurício
06:57
created

ReplicationGui::getHtmlForReplicationStatusTable()   B

Complexity

Conditions 8
Paths 14

Size

Total Lines 61
Code Lines 42

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 42
dl 0
loc 61
rs 8.0035
c 0
b 0
f 0
cc 8
nc 14
nop 3

How to fix   Long Method   

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
/* vim: set expandtab sw=4 ts=4 sts=4: */
3
/**
4
 * Functions for the replication GUI
5
 *
6
 * @package PhpMyAdmin
7
 */
8
declare(strict_types=1);
9
10
namespace PhpMyAdmin;
11
12
/**
13
 * Functions for the replication GUI
14
 *
15
 * @package PhpMyAdmin
16
 */
17
class ReplicationGui
18
{
19
    /**
20
     * @var Replication
21
     */
22
    private $replication;
23
24
    /**
25
     * @var Template
26
     */
27
    private $template;
28
29
    /**
30
     * ReplicationGui constructor.
31
     */
32
    public function __construct()
33
    {
34
        $this->replication = new Replication();
35
        $this->template = new Template();
36
    }
37
38
    /**
39
     * returns HTML for error message
40
     *
41
     * @return string HTML code
42
     */
43
    public function getHtmlForErrorMessage()
44
    {
45
        $html = '';
46
        if (isset($_SESSION['replication']['sr_action_status'])
47
            && isset($_SESSION['replication']['sr_action_info'])
48
        ) {
49
            if ($_SESSION['replication']['sr_action_status'] == 'error') {
50
                $error_message = $_SESSION['replication']['sr_action_info'];
51
                $html .= Message::error($error_message)->getDisplay();
52
                $_SESSION['replication']['sr_action_status'] = 'unknown';
53
            } elseif ($_SESSION['replication']['sr_action_status'] == 'success') {
54
                $success_message = $_SESSION['replication']['sr_action_info'];
55
                $html .= Message::success($success_message)->getDisplay();
56
                $_SESSION['replication']['sr_action_status'] = 'unknown';
57
            }
58
        }
59
        return $html;
60
    }
61
62
    /**
63
     * returns HTML for master replication
64
     *
65
     * @return string HTML code
66
     */
67
    public function getHtmlForMasterReplication()
68
    {
69
        if (! isset($_POST['repl_clear_scr'])) {
70
            $masterStatusTable = $this->getHtmlForReplicationStatusTable('master', true, false);
71
            $slaves = $GLOBALS['dbi']->fetchResult('SHOW SLAVE HOSTS', null, null);
72
73
            $urlParams = $GLOBALS['url_params'];
74
            $urlParams['mr_adduser'] = true;
75
            $urlParams['repl_clear_scr'] = true;
76
        }
77
78
        if (isset($_POST['mr_adduser'])) {
79
            $masterAddSlaveUser = $this->getHtmlForReplicationMasterAddSlaveUser();
80
        }
81
82
        return $this->template->render('server/replication/master_replication', [
83
            'clear_screen' => isset($_POST['repl_clear_scr']),
84
            'master_status_table' => $masterStatusTable ?? '',
85
            'slaves' => $slaves ?? [],
86
            'url_params' => $urlParams ?? [],
87
            'master_add_user' => isset($_POST['mr_adduser']),
88
            'master_add_slave_user' => $masterAddSlaveUser ?? '',
89
        ]);
90
    }
91
92
    /**
93
     * returns HTML for master replication configuration
94
     *
95
     * @return string HTML code
96
     */
97
    public function getHtmlForMasterConfiguration()
98
    {
99
        $databaseMultibox = $this->getHtmlForReplicationDbMultibox();
100
101
        return $this->template->render('server/replication/master_configuration', [
102
            'database_multibox' => $databaseMultibox,
103
        ]);
104
    }
105
106
    /**
107
     * returns HTML for slave replication configuration
108
     *
109
     * @param bool  $serverSlaveStatus      Whether it is Master or Slave
110
     * @param array $serverSlaveReplication Slave replication
111
     *
112
     * @return string HTML code
113
     */
114
    public function getHtmlForSlaveConfiguration(
115
        $serverSlaveStatus,
116
        array $serverSlaveReplication
117
    ) {
118
        $serverSlaveMultiReplication = $GLOBALS['dbi']->fetchResult(
119
            'SHOW ALL SLAVES STATUS'
120
        );
121
        if ($serverSlaveStatus) {
122
            $urlParams = $GLOBALS['url_params'];
123
            $urlParams['sr_take_action'] = true;
124
            $urlParams['sr_slave_server_control'] = true;
125
126
            if ($serverSlaveReplication[0]['Slave_IO_Running'] == 'No') {
127
                $urlParams['sr_slave_action'] = 'start';
128
            } else {
129
                $urlParams['sr_slave_action'] = 'stop';
130
            }
131
132
            $urlParams['sr_slave_control_parm'] = 'IO_THREAD';
133
            $slaveControlIoLink = Url::getCommon($urlParams, '');
134
135
            if ($serverSlaveReplication[0]['Slave_SQL_Running'] == 'No') {
136
                $urlParams['sr_slave_action'] = 'start';
137
            } else {
138
                $urlParams['sr_slave_action'] = 'stop';
139
            }
140
141
            $urlParams['sr_slave_control_parm'] = 'SQL_THREAD';
142
            $slaveControlSqlLink = Url::getCommon($urlParams, '');
143
144
            if ($serverSlaveReplication[0]['Slave_IO_Running'] == 'No'
145
                || $serverSlaveReplication[0]['Slave_SQL_Running'] == 'No'
146
            ) {
147
                $urlParams['sr_slave_action'] = 'start';
148
            } else {
149
                $urlParams['sr_slave_action'] = 'stop';
150
            }
151
152
            $urlParams['sr_slave_control_parm'] = null;
153
            $slaveControlFullLink = Url::getCommon($urlParams, '');
154
155
            $urlParams['sr_slave_action'] = 'reset';
156
            $slaveControlResetLink = Url::getCommon($urlParams, '');
157
158
            $urlParams = $GLOBALS['url_params'];
159
            $urlParams['sr_take_action'] = true;
160
            $urlParams['sr_slave_skip_error'] = true;
161
            $slaveSkipErrorLink = Url::getCommon($urlParams, '');
162
163
            $urlParams = $GLOBALS['url_params'];
164
            $urlParams['sl_configure'] = true;
165
            $urlParams['repl_clear_scr'] = true;
166
167
            $reconfigureMasterLink =  Url::getCommon($urlParams, '');
168
169
            $slaveStatusTable = $this->getHtmlForReplicationStatusTable('slave', true, false);
170
171
            $slaveIoRunning = $serverSlaveReplication[0]['Slave_IO_Running'] !== 'No';
172
            $slaveSqlRunning = $serverSlaveReplication[0]['Slave_SQL_Running'] !== 'No';
173
        }
174
175
        return $this->template->render('server/replication/slave_configuration', [
176
            'server_slave_multi_replication' => $serverSlaveMultiReplication,
177
            'url_params' => $GLOBALS['url_params'],
178
            'master_connection' => $_POST['master_connection'] ?? '',
179
            'server_slave_status' => $serverSlaveStatus,
180
            'slave_status_table' => $slaveStatusTable ?? '',
181
            'slave_sql_running' => $slaveSqlRunning ?? false,
182
            'slave_io_running' => $slaveIoRunning ?? false,
183
            'slave_control_full_link' => $slaveControlFullLink ?? '',
184
            'slave_control_reset_link' => $slaveControlResetLink ?? '',
185
            'slave_control_sql_link' => $slaveControlSqlLink ?? '',
186
            'slave_control_io_link' => $slaveControlIoLink ?? '',
187
            'slave_skip_error_link' => $slaveSkipErrorLink ?? '',
188
            'reconfigure_master_link' => $reconfigureMasterLink ?? '',
189
            'has_slave_configure' => isset($_POST['sl_configure']),
190
        ]);
191
    }
192
193
    /**
194
     * returns HTML code for selecting databases
195
     *
196
     * @return string HTML code
197
     */
198
    public function getHtmlForReplicationDbMultibox()
199
    {
200
        $databases = [];
201
        foreach ($GLOBALS['dblist']->databases as $database) {
202
            if (! $GLOBALS['dbi']->isSystemSchema($database)) {
203
                $databases[] = $database;
204
            }
205
        }
206
207
        return $this->template->render('server/replication/database_multibox', [
208
            'databases' => $databases,
209
        ]);
210
    }
211
212
    /**
213
     * returns HTML for changing master
214
     *
215
     * @param string $submitName submit button name
216
     *
217
     * @return string HTML code
218
     */
219
    public function getHtmlForReplicationChangeMaster($submitName)
220
    {
221
        list(
222
            $usernameLength,
223
            $hostnameLength
224
        ) = $this->getUsernameHostnameLength();
225
226
        return $this->template->render('server/replication/change_master', [
227
            'server_id' => time(),
228
            'username_length' => $usernameLength,
229
            'hostname_length' => $hostnameLength,
230
            'submit_name' => $submitName,
231
        ]);
232
    }
233
234
    /**
235
     * This function returns html code for table with replication status.
236
     *
237
     * @param string  $type     either master or slave
238
     * @param boolean $isHidden if true, then default style is set to hidden,
239
     *                          default value false
240
     * @param boolean $hasTitle if true, then title is displayed, default true
241
     *
242
     * @return string HTML code
243
     */
244
    public function getHtmlForReplicationStatusTable(
245
        $type,
246
        $isHidden = false,
247
        $hasTitle = true
248
    ): string {
249
        global $master_variables, $slave_variables;
250
        global $master_variables_alerts, $slave_variables_alerts;
251
        global $master_variables_oks, $slave_variables_oks;
252
        global $server_master_replication, $server_slave_replication;
253
254
        $replicationVariables = $master_variables;
255
        $variablesAlerts = $master_variables_alerts;
256
        $variablesOks = $master_variables_oks;
257
        $serverReplication = $server_master_replication;
258
        if ($type === 'slave') {
259
            $replicationVariables = $slave_variables;
260
            $variablesAlerts = $slave_variables_alerts;
261
            $variablesOks = $slave_variables_oks;
262
            $serverReplication = $server_slave_replication;
263
        }
264
265
        $variables = [];
266
        foreach ($replicationVariables as $variable) {
267
            $variables[$variable] = [
268
                'name' => $variable,
269
                'status' => '',
270
                'value' => $serverReplication[0][$variable],
271
            ];
272
273
            if (isset($variablesAlerts[$variable])
274
                && $variablesAlerts[$variable] === $serverReplication[0][$variable]
275
            ) {
276
                $variables[$variable]['status'] = 'attention';
277
            } elseif (isset($variablesOks[$variable])
278
                && $variablesOks[$variable] === $serverReplication[0][$variable]
279
            ) {
280
                $variables[$variable]['status'] = 'allfine';
281
            }
282
283
            $variablesWrap = [
284
                'Replicate_Do_DB',
285
                'Replicate_Ignore_DB',
286
                'Replicate_Do_Table',
287
                'Replicate_Ignore_Table',
288
                'Replicate_Wild_Do_Table',
289
                'Replicate_Wild_Ignore_Table',
290
            ];
291
            if (in_array($variable, $variablesWrap)) {
292
                $variables[$variable]['value'] = str_replace(
293
                    ',',
294
                    ', ',
295
                    $serverReplication[0][$variable]
296
                );
297
            }
298
        }
299
300
        return $this->template->render('server/replication/status_table', [
301
            'type' => $type,
302
            'is_hidden' => $isHidden,
303
            'has_title' => $hasTitle,
304
            'variables' => $variables,
305
        ]);
306
    }
307
308
    /**
309
     * get the correct username and hostname lengths for this MySQL server
310
     *
311
     * @return array   username length, hostname length
312
     */
313
    public function getUsernameHostnameLength()
314
    {
315
        $fields_info = $GLOBALS['dbi']->getColumns('mysql', 'user');
316
        $username_length = 16;
317
        $hostname_length = 41;
318
        foreach ($fields_info as $val) {
319
            if ($val['Field'] == 'User') {
320
                strtok($val['Type'], '()');
321
                $v = strtok('()');
322
                if (is_int($v)) {
323
                    $username_length = $v;
324
                }
325
            } elseif ($val['Field'] == 'Host') {
326
                strtok($val['Type'], '()');
327
                $v = strtok('()');
328
                if (is_int($v)) {
329
                    $hostname_length = $v;
330
                }
331
            }
332
        }
333
        return [
334
            $username_length,
335
            $hostname_length,
336
        ];
337
    }
338
339
    /**
340
     * returns html code to add a replication slave user to the master
341
     *
342
     * @return string HTML code
343
     */
344
    public function getHtmlForReplicationMasterAddSlaveUser()
345
    {
346
        list(
347
            $usernameLength,
348
            $hostnameLength
349
        ) = $this->getUsernameHostnameLength();
350
351
        if (isset($_POST['username']) && strlen($_POST['username']) === 0) {
352
            $GLOBALS['pred_username'] = 'any';
353
        }
354
355
        $username = '';
356
        if (! empty($_POST['username'])) {
357
            $username = $GLOBALS['new_username'] ?? $_POST['username'];
358
        }
359
360
        $currentUser = $GLOBALS['dbi']->fetchValue('SELECT USER();');
361
        if (! empty($currentUser)) {
362
            $userHost = str_replace(
363
                "'",
364
                '',
365
                mb_substr(
366
                    $currentUser,
367
                    mb_strrpos($currentUser, '@') + 1
368
                )
369
            );
370
            if ($userHost !== 'localhost' && $userHost !== '127.0.0.1') {
371
                $thisHost = $userHost;
372
            }
373
        }
374
375
        // when we start editing a user, $GLOBALS['pred_hostname'] is not defined
376
        if (! isset($GLOBALS['pred_hostname']) && isset($_POST['hostname'])) {
377
            switch (mb_strtolower($_POST['hostname'])) {
378
                case 'localhost':
379
                case '127.0.0.1':
380
                    $GLOBALS['pred_hostname'] = 'localhost';
381
                    break;
382
                case '%':
383
                    $GLOBALS['pred_hostname'] = 'any';
384
                    break;
385
                default:
386
                    $GLOBALS['pred_hostname'] = 'userdefined';
387
                    break;
388
            }
389
        }
390
391
        return $this->template->render('server/replication/master_add_slave_user', [
392
            'username_length' => $usernameLength,
393
            'hostname_length' => $hostnameLength,
394
            'has_username' => isset($_POST['username']),
395
            'username' => $username,
396
            'hostname' => $_POST['hostname'] ?? '',
397
            'predefined_username' => $GLOBALS['pred_username'] ?? '',
398
            'predefined_hostname' => $GLOBALS['pred_hostname'] ?? '',
399
            'this_host' => $thisHost ?? null,
400
        ]);
401
    }
402
403
    /**
404
     * handle control requests
405
     *
406
     * @return void
407
     */
408
    public function handleControlRequest()
409
    {
410
        if (isset($_POST['sr_take_action'])) {
411
            $refresh = false;
412
            $result = false;
413
            $messageSuccess = null;
414
            $messageError = null;
415
416
            if (isset($_POST['slave_changemaster']) && ! $GLOBALS['cfg']['AllowArbitraryServer']) {
417
                $_SESSION['replication']['sr_action_status'] = 'error';
418
                $_SESSION['replication']['sr_action_info'] = __('Connection to server is disabled, please enable $cfg[\'AllowArbitraryServer\'] in phpMyAdmin configuration.');
419
            } elseif (isset($_POST['slave_changemaster'])) {
420
                $result = $this->handleRequestForSlaveChangeMaster();
421
            } elseif (isset($_POST['sr_slave_server_control'])) {
422
                $result = $this->handleRequestForSlaveServerControl();
423
                $refresh = true;
424
425
                switch ($_POST['sr_slave_action']) {
426
                    case 'start':
427
                        $messageSuccess = __('Replication started successfully.');
428
                        $messageError = __('Error starting replication.');
429
                        break;
430
                    case 'stop':
431
                        $messageSuccess = __('Replication stopped successfully.');
432
                        $messageError = __('Error stopping replication.');
433
                        break;
434
                    case 'reset':
435
                        $messageSuccess = __('Replication resetting successfully.');
436
                        $messageError = __('Error resetting replication.');
437
                        break;
438
                    default:
439
                        $messageSuccess = __('Success.');
440
                        $messageError = __('Error.');
441
                        break;
442
                }
443
            } elseif (isset($_POST['sr_slave_skip_error'])) {
444
                $result = $this->handleRequestForSlaveSkipError();
445
            }
446
447
            if ($refresh) {
448
                $response = Response::getInstance();
449
                if ($response->isAjax()) {
450
                    $response->setRequestStatus($result);
451
                    $response->addJSON(
452
                        'message',
453
                        $result
454
                        ? Message::success($messageSuccess)
0 ignored issues
show
Bug introduced by
It seems like $messageSuccess can also be of type null; however, parameter $string of PhpMyAdmin\Message::success() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

454
                        ? Message::success(/** @scrutinizer ignore-type */ $messageSuccess)
Loading history...
455
                        : Message::error($messageError)
0 ignored issues
show
Bug introduced by
It seems like $messageError can also be of type null; however, parameter $string of PhpMyAdmin\Message::error() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

455
                        : Message::error(/** @scrutinizer ignore-type */ $messageError)
Loading history...
456
                    );
457
                } else {
458
                    Core::sendHeaderLocation(
459
                        './server_replication.php'
460
                        . Url::getCommonRaw($GLOBALS['url_params'])
461
                    );
462
                }
463
            }
464
            unset($refresh);
465
        }
466
    }
467
468
    /**
469
     * handle control requests for Slave Change Master
470
     *
471
     * @return boolean
472
     */
473
    public function handleRequestForSlaveChangeMaster()
474
    {
475
        $sr = [];
476
        $_SESSION['replication']['m_username'] = $sr['username']
477
            = $GLOBALS['dbi']->escapeString($_POST['username']);
478
        $_SESSION['replication']['m_password'] = $sr['pma_pw']
479
            = $GLOBALS['dbi']->escapeString($_POST['pma_pw']);
480
        $_SESSION['replication']['m_hostname'] = $sr['hostname']
481
            = $GLOBALS['dbi']->escapeString($_POST['hostname']);
482
        $_SESSION['replication']['m_port']     = $sr['port']
483
            = $GLOBALS['dbi']->escapeString($_POST['text_port']);
484
        $_SESSION['replication']['m_correct']  = '';
485
        $_SESSION['replication']['sr_action_status'] = 'error';
486
        $_SESSION['replication']['sr_action_info'] = __('Unknown error');
487
488
        // Attempt to connect to the new master server
489
        $link_to_master = $this->replication->connectToMaster(
490
            $sr['username'],
491
            $sr['pma_pw'],
492
            $sr['hostname'],
493
            $sr['port']
494
        );
495
496
        if (! $link_to_master) {
497
            $_SESSION['replication']['sr_action_status'] = 'error';
498
            $_SESSION['replication']['sr_action_info'] = sprintf(
499
                __('Unable to connect to master %s.'),
500
                htmlspecialchars($sr['hostname'])
501
            );
502
        } else {
503
            // Read the current master position
504
            $position = $this->replication->slaveBinLogMaster($link_to_master);
505
506
            if (empty($position)) {
507
                $_SESSION['replication']['sr_action_status'] = 'error';
508
                $_SESSION['replication']['sr_action_info']
509
                    = __(
510
                        'Unable to read master log position. '
511
                        . 'Possible privilege problem on master.'
512
                    );
513
            } else {
514
                $_SESSION['replication']['m_correct']  = true;
515
516
                if (! $this->replication->slaveChangeMaster(
517
                    $sr['username'],
518
                    $sr['pma_pw'],
519
                    $sr['hostname'],
520
                    $sr['port'],
521
                    $position,
522
                    true,
523
                    false
524
                )
525
                ) {
526
                    $_SESSION['replication']['sr_action_status'] = 'error';
527
                    $_SESSION['replication']['sr_action_info']
528
                        = __('Unable to change master!');
529
                } else {
530
                    $_SESSION['replication']['sr_action_status'] = 'success';
531
                    $_SESSION['replication']['sr_action_info'] = sprintf(
532
                        __('Master server changed successfully to %s.'),
533
                        htmlspecialchars($sr['hostname'])
534
                    );
535
                }
536
            }
537
        }
538
539
        return $_SESSION['replication']['sr_action_status'] === 'success';
540
    }
541
542
    /**
543
     * handle control requests for Slave Server Control
544
     *
545
     * @return boolean
546
     */
547
    public function handleRequestForSlaveServerControl()
548
    {
549
        if (empty($_POST['sr_slave_control_parm'])) {
550
            $_POST['sr_slave_control_parm'] = null;
551
        }
552
        if ($_POST['sr_slave_action'] == 'reset') {
553
            $qStop = $this->replication->slaveControl("STOP");
554
            $qReset = $GLOBALS['dbi']->tryQuery("RESET SLAVE;");
555
            $qStart = $this->replication->slaveControl("START");
556
557
            $result = ($qStop !== false && $qStop !== -1 &&
558
                $qReset !== false && $qReset !== -1 &&
559
                $qStart !== false && $qStart !== -1);
560
        } else {
561
            $qControl = $this->replication->slaveControl(
562
                $_POST['sr_slave_action'],
563
                $_POST['sr_slave_control_parm']
564
            );
565
566
            $result = ($qControl !== false && $qControl !== -1);
567
        }
568
569
        return $result;
570
    }
571
572
    /**
573
     * handle control requests for Slave Skip Error
574
     *
575
     * @return boolean
576
     */
577
    public function handleRequestForSlaveSkipError()
578
    {
579
        $count = 1;
580
        if (isset($_POST['sr_skip_errors_count'])) {
581
            $count = $_POST['sr_skip_errors_count'] * 1;
582
        }
583
584
        $qStop = $this->replication->slaveControl("STOP");
585
        $qSkip = $GLOBALS['dbi']->tryQuery(
586
            "SET GLOBAL SQL_SLAVE_SKIP_COUNTER = " . $count . ";"
587
        );
588
        $qStart = $this->replication->slaveControl("START");
589
590
        $result = ($qStop !== false && $qStop !== -1 &&
591
            $qSkip !== false && $qSkip !== -1 &&
592
            $qStart !== false && $qStart !== -1);
593
594
        return $result;
595
    }
596
}
597