Misc::getHREF()   F
last analyzed

Complexity

Conditions 13
Paths 512

Size

Total Lines 23
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 12
c 0
b 0
f 0
nc 512
nop 1
dl 0
loc 23
rs 3.1277

How to fix   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
/**
4
 * PHPPgAdmin 6.1.3
5
 */
6
7
namespace PHPPgAdmin;
8
9
use PHPPgAdmin\Database\Postgres;
10
11
/**
12
 * @file
13
 * Class to hold various commonly used functions
14
 *
15
 * Id: Misc.php,v 1.171 2008/03/17 21:35:48 ioguix Exp $
16
 */
17
18
/**
19
 * Class to hold various commonly used functions.
20
 *
21
 * Release: Misc.php,v 1.171 2008/03/17 21:35:48 ioguix Exp $
22
 */
23
class Misc
24
{
25
    use \PHPPgAdmin\Traits\HelperTrait;
26
    use \PHPPgAdmin\Traits\MiscTrait;
27
28
    /**
29
     * @var array
30
     */
31
    public $appLangFiles = [];
32
33
    /**
34
     * @var string
35
     */
36
    public $appName = '';
37
38
    /**
39
     * @var string
40
     */
41
    public $appVersion = '';
42
43
    public $form = '';
44
45
    /**
46
     * @var string
47
     */
48
    public $href = '';
49
50
    /**
51
     * @var array
52
     */
53
    public $lang = [];
54
55
    /**
56
     * @var array
57
     */
58
    public $conf;
59
60
    /**
61
     * @var string
62
     */
63
    public $phpMinVer;
64
65
    /**
66
     * @var string
67
     */
68
    public $postgresqlMinVer;
69
70
    /**
71
     * @var \PHPPgAdmin\ViewManager
72
     */
73
    public $view;
74
75
    /**
76
     * @var \PHPPgAdmin\ContainerUtils
77
     */
78
    protected $container;
79
80
    /**
81
     * @var null|\PHPPgAdmin\Connection
82
     */
83
    private $_connection;
84
85
    /**
86
     * @var bool
87
     */
88
    private $_no_db_connection = false;
89
90
    /**
91
     * @var null|Postgres
92
     */
93
    private $_data;
94
95
    /**
96
     * @var null|string
97
     */
98
    private $_database;
99
100
    /**
101
     * @var null|string
102
     */
103
    private $_server_id;
104
105
    /**
106
     * @var null|array
107
     */
108
    private $_server_info;
109
110
    /**
111
     * @var string
112
     */
113
    private $_error_msg = '';
114
115
    /**
116
     * @param \PHPPgAdmin\ContainerUtils $container The container
117
     */
118
    public function __construct(\PHPPgAdmin\ContainerUtils $container)
119
    {
120
        $this->container = $container;
121
122
        $this->lang = $container->get('lang');
123
        $this->conf = $container->get('conf');
124
125
        //$this->view           = $container->get('view');
126
127
        $this->appLangFiles = $container->get('appLangFiles');
128
129
        $this->appName = $container->get('settings')['appName'];
130
        $this->appVersion = $container->get('settings')['appVersion'];
131
        $this->postgresqlMinVer = $container->get('settings')['postgresqlMinVer'];
132
        $this->phpMinVer = $container->get('settings')['phpMinVer'];
133
134
        $base_version = $container->get('settings')['base_version'];
135
136
        // Check for config file version mismatch
137
        if (!isset($this->conf['version']) || $base_version > $this->conf['version']) {
138
            $container->addError($this->lang['strbadconfig']);
139
        }
140
141
        // Check database support is properly compiled in
142
        if (!\function_exists('pg_connect')) {
143
            $container->addError($this->lang['strnotloaded']);
144
        }
145
146
        // Check the version of PHP
147
        if (\version_compare(\PHP_VERSION, $this->phpMinVer, '<')) {
148
            $container->addError(\sprintf('Version of PHP not supported. Please upgrade to version %s or later.', $this->phpMinVer));
149
        }
150
        //$this->dumpAndDie($this);
151
152
        $this->getServerId();
153
    }
154
155
    /**
156
     * Gets the value of a config property, or the array of all config properties.
157
     *
158
     * @param null|string $key value of the key to be retrieved. If null, the full array is returnes
159
     *
160
     * @return null|array|string the whole $conf array, the value of $conf[key] or null if said key does not exist
161
     */
162
    public function getConf($key = null)
163
    {
164
        if (null === $key) {
165
            return $this->conf;
166
        }
167
168
        if (\array_key_exists($key, $this->conf)) {
169
            return $this->conf[$key];
170
        }
171
172
        return null;
173
    }
174
175
    /**
176
     * Adds or modifies a key in the $conf instance property of this class.
177
     *
178
     * @param string $key   name of the key to set
179
     * @param mixed  $value value of the key to set
180
     *
181
     * @return \PHPPgAdmin\Misc this class instance
182
     */
183
    public function setConf($key, $value)
184
    {
185
        $this->conf[$key] = $value;
186
187
        return $this;
188
    }
189
190
    /**
191
     * @return null|string
192
     */
193
    public function serverToSha()
194
    {
195
        $request_server = $this->container->request->getParam('server');
196
197
        if (null === $request_server) {
198
            return null;
199
        }
200
        $srv_array = \explode(':', $request_server);
201
202
        if (3 === \count($srv_array)) {
203
            return \sha1($request_server);
204
        }
205
206
        return $request_server;
207
    }
208
209
    /**
210
     * @return string
211
     */
212
    public function getServerId()
213
    {
214
        if ($this->_server_id) {
215
            return $this->_server_id;
216
        }
217
218
        $request_server = $this->serverToSha();
219
220
        if (1 === \count($this->conf['servers'])) {
221
            $info = $this->conf['servers'][0];
222
            $this->_server_id = \sha1($info['host'] . ':' . $info['port'] . ':' . $info['sslmode']);
223
        } elseif (null !== $request_server) {
224
            $this->_server_id = $request_server;
225
        } elseif (isset($_SESSION['webdbLogin']) && 0 < \count($_SESSION['webdbLogin'])) {
226
            $this->_server_id = \array_keys($_SESSION['webdbLogin'])[0];
227
        }
228
229
        return $this->_server_id;
230
    }
231
232
    /**
233
     * Sets the view instance property of this class.
234
     *
235
     * @param \PHPPgAdmin\ViewManager $view view instance
236
     *
237
     * @return \PHPPgAdmin\Misc this class instance
238
     */
239
    public function setView(\PHPPgAdmin\ViewManager $view)
240
    {
241
        $this->view = $view;
242
243
        return $this;
244
    }
245
246
    public function getContainer()
247
    {
248
        return $this->container;
249
    }
250
251
    /**
252
     * Sets $_no_db_connection boolean value, allows to render scripts that do not need an active session.
253
     *
254
     * @param bool $flag true or false to allow unconnected clients to access the view
255
     *
256
     * @return \PHPPgAdmin\Misc this class instance
257
     */
258
    public function setNoDBConnection($flag)
259
    {
260
        $this->_no_db_connection = (bool) $flag;
261
262
        return $this;
263
    }
264
265
    /**
266
     * Gets member variable $_no_db_connection.
267
     *
268
     * @return bool value of member variable $_no_db_connection
269
     */
270
    public function getNoDBConnection()
271
    {
272
        return $this->_no_db_connection;
273
    }
274
275
    /**
276
     * Sets the last error message to display afterwards instead of just dying with the error msg.
277
     *
278
     * @param string $msg error message string
279
     *
280
     * @return \PHPPgAdmin\Misc this class instance
281
     */
282
    public function setErrorMsg($msg)
283
    {
284
        $this->_error_msg = $msg;
285
286
        return $this;
287
    }
288
289
    /**
290
     * Returns the error messages stored in member variable $_error_msg.
291
     *
292
     * @return string the error message
293
     */
294
    public function getErrorMsg()
295
    {
296
        return $this->_error_msg;
297
    }
298
299
    /**
300
     * Creates a database accessor.
301
     *
302
     * @param string $database  the name of the database
303
     * @param mixed  $server_id the id of the server
304
     *
305
     * @internal mixed $plaform placeholder that will receive the value of the platform
306
     *
307
     * @return null|\PHPPgAdmin\Database\Postgres|void the database accessor instance
308
     */
309
    public function getDatabaseAccessor($database = '', $server_id = null)
310
    {
311
        $lang = $this->lang;
312
313
        if (null !== $server_id) {
314
            $this->_server_id = $server_id;
315
        }
316
317
        $server_info = $this->getServerInfo($this->_server_id);
318
319
        if ($this->getNoDBConnection() || !isset($server_info['username'])) {
320
            return null;
321
        }
322
323
        if (null === $this->_data) {
324
            try {
325
                $_connection = $this->getConnection($database, $this->_server_id);
326
            } catch (\Exception $e) {
327
                $this->setServerInfo(null, null, $this->_server_id);
328
                $this->setNoDBConnection(true);
329
                $this->setErrorMsg($e->getMessage());
330
331
                return null;
332
            }
333
334
            if (!$_connection) {
0 ignored issues
show
introduced by
$_connection is of type PHPPgAdmin\Connection, thus it always evaluated to true.
Loading history...
335
                $this->container->addError($lang['strloginfailed']);
336
                $this->setErrorMsg($lang['strloginfailed']);
337
338
                return null;
339
            }
340
            $platform = '';
341
            // Get the name of the database driver we need to use.
342
            // The description of the server is returned in $platform.
343
            $_type = $_connection->getDriver($platform);
344
345
            if (null === $_type ?? null) {
346
                $errormsg = \sprintf($lang['strpostgresqlversionnotsupported'], $this->postgresqlMinVer);
347
                $this->container->addError($errormsg);
348
                $this->setErrorMsg($errormsg);
349
350
                return null;
351
            }
352
            /**
353
             * @var \class-string<\PHPPgAdmin\Database\Postgres>
354
             */
355
            $_type = '\\PHPPgAdmin\\Database\\' . $_type;
356
357
            $this->setServerInfo('platform', $platform, $this->_server_id);
358
            $this->setServerInfo('pgVersion', $_connection->getVersion(), $this->_server_id);
359
360
            // Create a database wrapper class for easy manipulation of the
361
            // connection.
362
363
            $this->_data = new $_type($_connection->conn, $this->container, $server_info);
364
            $this->_data->platform = $_connection->platform;
365
366
            //$this->_data->getHelpPages();
367
368
            /* we work on UTF-8 only encoding */
369
            $this->_data->execute("SET client_encoding TO 'UTF-8'");
370
371
            if ($this->_data->hasByteaHexDefault()) {
372
                $this->_data->execute('SET bytea_output TO escape');
373
            }
374
        }
375
376
        if (false !== $this->getNoDBConnection() ||
377
        null === $this->getDatabase() ||
378
            !isset($_REQUEST['schema'])
379
        ) {
380
            return $this->_data;
381
        }
382
383
        $status = $this->_data->setSchema($_REQUEST['schema']);
384
385
        if (0 !== $status) {
386
            $this->container->addError($this->lang['strbadschema']);
387
            $this->setErrorMsg($this->lang['strbadschema']);
388
        }
389
390
        return $this->_data;
391
    }
392
393
    /**
394
     * Undocumented function.
395
     *
396
     * @param string $database
397
     * @param string $server_id
398
     *
399
     * @return null|\PHPPgAdmin\Connection
400
     */
401
    public function getConnection(string $database = '', $server_id = null): ?\PHPPgAdmin\Connection
402
    {
403
        $lang = $this->lang;
404
405
        if (null === $this->_connection) {
406
            if (null !== $server_id) {
407
                $this->_server_id = $server_id;
408
            }
409
            $server_info = $this->getServerInfo($this->_server_id);
410
            $database_to_use = $this->getDatabase($database);
411
412
            // Perform extra security checks if this config option is set
413
            if ($this->conf['extra_login_security']) {
414
                // Disallowed logins if extra_login_security is enabled.
415
                // These must be lowercase.
416
                $bad_usernames = [
417
                    'pgsql' => 'pgsql',
418
                    'postgres' => 'postgres',
419
                    'root' => 'root',
420
                    'administrator' => 'administrator',
421
                ];
422
423
                if (isset($server_info['username']) &&
424
                    \array_key_exists(\mb_strtolower($server_info['username']), $bad_usernames)
425
                ) {
426
                    $msg = $lang['strlogindisallowed'];
427
428
                    throw new \Exception($msg);
429
                }
430
431
                if (!isset($server_info['password']) ||
432
                    '' === $server_info['password']
433
                ) {
434
                    $msg = $lang['strlogindisallowed'];
435
436
                    throw new \Exception($msg);
437
                }
438
            }
439
440
            try {
441
                // Create the connection object and make the connection
442
                $this->_connection = new \PHPPgAdmin\Connection(
443
                    $server_info,
444
                    $database_to_use,
445
                    $this->container
446
                );
447
            } catch (\PHPPgAdmin\ADOdbException $e) {
448
                throw new \Exception($lang['strloginfailed']);
449
            }
450
        }
451
452
        return $this->_connection;
453
    }
454
455
    /**
456
     * Validate and retrieve information on a server. If the parameter isn't supplied then the currently connected
457
     * server is returned.
458
     *
459
     * @param string $server_id A server identifier (host:port)
460
     *
461
     * @return null|array An associative array of server properties
462
     */
463
    public function getServerInfo($server_id = null)
464
    {
465
        if (null !== $server_id) {
466
            $this->_server_id = $server_id;
467
        } elseif (null !== $this->_server_info) {
468
            return $this->_server_info;
469
        }
470
471
        // Check for the server in the logged-in list
472
        if (isset($_SESSION['webdbLogin'][$this->_server_id])) {
473
            $this->_server_info = $_SESSION['webdbLogin'][$this->_server_id];
474
475
            return $this->_server_info;
476
        }
477
478
        // Otherwise, look for it in the conf file
479
        foreach ($this->conf['servers'] as $idx => $info) {
480
            $server_string = $info['host'] . ':' . $info['port'] . ':' . $info['sslmode'];
481
            $server_sha = \sha1($server_string);
482
483
            if ($this->_server_id === $server_string ||
484
                $this->_server_id === $server_sha
485
            ) {
486
                if (isset($info['username'])) {
487
                    $this->setServerInfo(null, $info, $this->_server_id);
488
                } elseif (isset($_SESSION['sharedUsername'])) {
489
                    $info['username'] = $_SESSION['sharedUsername'];
490
                    $info['password'] = $_SESSION['sharedPassword'];
491
                    $this->container->get('view')->setReloadBrowser(true);
492
                    $this->setServerInfo(null, $info, $this->_server_id);
493
                }
494
                $this->_server_info = $info;
495
496
                return $this->_server_info;
497
            }
498
        }
499
500
        if (null === $server_id) {
501
            $this->_server_info = null;
502
503
            return $this->_server_info;
504
        }
505
506
        //      //$this->prtrace('Invalid server param');
507
        $this->_server_info = null;
508
        // Unable to find a matching server, are we being hacked?
509
        $this->halt($this->lang['strinvalidserverparam']);
510
511
        return $this->_server_info;
512
    }
513
514
    /**
515
     * Set server information.
516
     *
517
     * @param null|string $key       parameter name to set, or null to replace all
518
     *                               params with the assoc-array in $value
519
     * @param mixed       $value     the new value, or null to unset the parameter
520
     * @param null|string $server_id the server identifier, or null for current server
521
     */
522
    public function setServerInfo($key, $value, $server_id = null): void
523
    {
524
        if (null === $server_id) {
525
            $server_id = $this->container->request->getParam('server');
526
        }
527
528
        if (null === $key) {
529
            if (null === $value) {
530
                unset($_SESSION['webdbLogin'][$server_id]);
531
            } else {
532
                $_SESSION['webdbLogin'][$server_id] = $value;
533
            }
534
        } else {
535
            if (null === $value) {
536
                unset($_SESSION['webdbLogin'][$server_id][$key]);
537
            } else {
538
                $_SESSION['webdbLogin'][$server_id][$key] = $value;
539
            }
540
        }
541
    }
542
543
    public function getDatabase(string $database = '')
544
    {
545
        if (null === $this->_server_id && !isset($_REQUEST['database'])) {
546
            return null;
547
        }
548
549
        $server_info = $this->getServerInfo($this->_server_id);
550
551
        if (null !== $this->_server_id &&
552
            isset($server_info['useonlydefaultdb']) &&
553
            true === $server_info['useonlydefaultdb'] &&
554
            isset($server_info['defaultdb'])
555
        ) {
556
            $this->_database = $server_info['defaultdb'];
557
        } elseif ('' !== $database) {
558
            $this->_database = $database;
559
        } elseif (isset($_REQUEST['database'])) {
560
            // Connect to the current database
561
            $this->_database = $_REQUEST['database'];
562
        } elseif (isset($server_info['defaultdb'])) {
563
            // or if one is not specified then connect to the default database.
564
            $this->_database = $server_info['defaultdb'];
565
        } else {
566
            return null;
567
        }
568
569
        return $this->_database;
570
    }
571
572
    /**
573
     * Set the current schema.
574
     *
575
     * @param string $schema The schema name
576
     *
577
     * @return int 0 on success
578
     */
579
    public function setCurrentSchema($schema)
580
    {
581
        $data = $this->getDatabaseAccessor();
582
583
        $status = $data->setSchema($schema);
584
585
        if (0 !== $status) {
586
            return $status;
587
        }
588
589
        $_REQUEST['schema'] = $schema;
590
        $this->container->offsetSet('schema', $schema);
591
        $this->setHREF();
592
593
        return 0;
594
    }
595
596
    /**
597
     * Checks if dumps are properly set up.
598
     *
599
     * @param bool $all (optional) True to check pg_dumpall, false to just check pg_dump
600
     *
601
     * @return bool True, dumps are set up, false otherwise
602
     */
603
    public function isDumpEnabled($all = false)
604
    {
605
        $info = $this->getServerInfo();
606
607
        return !empty($info[$all ? 'pg_dumpall_path' : 'pg_dump_path']);
608
    }
609
610
    /**
611
     * Sets the href tracking variable.
612
     *
613
     * @return \PHPPgAdmin\Misc this class instance
614
     */
615
    public function setHREF()
616
    {
617
        $this->href = $this->getHREF();
618
619
        return $this;
620
    }
621
622
    /**
623
     * Get a href query string, excluding objects below the given object type (inclusive).
624
     *
625
     * @param null|string $exclude_from
626
     *
627
     * @return string
628
     */
629
    public function getHREF($exclude_from = null)
630
    {
631
        $href = [];
632
633
        $server = $this->container->server || isset($_REQUEST['server']) ? $_REQUEST['server'] : null;
634
        $database = $this->container->database || isset($_REQUEST['database']) ? $_REQUEST['database'] : null;
635
        $schema = $this->container->schema || isset($_REQUEST['schema']) ? $_REQUEST['schema'] : null;
636
637
        if ($server && 'server' !== $exclude_from) {
638
            $href[] = 'server=' . \urlencode($server);
639
        }
640
641
        if ($database && 'database' !== $exclude_from) {
642
            $href[] = 'database=' . \urlencode($database);
643
        }
644
645
        if ($schema && 'schema' !== $exclude_from) {
646
            $href[] = 'schema=' . \urlencode($schema);
647
        }
648
649
        $this->href = \htmlentities(\implode('&', $href));
650
651
        return $this->href;
652
    }
653
654
    /**
655
     * A function to recursively strip slashes.  Used to
656
     * enforce magic_quotes_gpc being off.
657
     *
658
     * @param mixed $var The variable to strip (passed by reference)
659
     */
660
    public function stripVar(&$var): void
661
    {
662
        if (\is_array($var)) {
663
            foreach ($var as $k => $v) {
664
                $this->stripVar($var[$k]);
665
666
                /* magic_quotes_gpc escape keys as well ...*/
667
                if (\is_string($k)) {
668
                    $ek = \stripslashes($k);
669
670
                    if ($ek !== $k) {
671
                        $var[$ek] = $var[$k];
672
                        unset($var[$k]);
673
                    }
674
                }
675
            }
676
        } else {
677
            $var = \stripslashes($var);
678
        }
679
    }
680
681
    /**
682
     * Converts a PHP.INI size variable to bytes.  Taken from publically available
683
     * function by Chris DeRose, here: http://www.php.net/manual/en/configuration.directives.php#ini.file-uploads.
684
     *
685
     * @param mixed $strIniSize The PHP.INI variable
686
     *
687
     * @return bool|float|int size in bytes, false on failure
688
     */
689
    public function inisizeToBytes($strIniSize)
690
    {
691
        // This function will take the string value of an ini 'size' parameter,
692
        // and return a double (64-bit float) representing the number of bytes
693
        // that the parameter represents. Or false if $strIniSize is unparseable.
694
        $a_IniParts = [];
695
696
        if (!\is_string($strIniSize)) {
697
            return false;
698
        }
699
700
        if (!\preg_match('/^(\d+)([bkm]*)$/i', $strIniSize, $a_IniParts)) {
701
            return false;
702
        }
703
704
        $nSize = (float) $a_IniParts[1];
705
        $strUnit = \mb_strtolower($a_IniParts[2]);
706
707
        switch ($strUnit) {
708
            case 'm':
709
                return $nSize * (float) 1048576;
710
            case 'k':
711
                return $nSize * (float) 1024;
712
            case 'b':
713
            default:
714
                return $nSize;
715
        }
716
    }
717
718
    public function getRequestVars($subject = '')
719
    {
720
        $v = [];
721
722
        if (!empty($subject)) {
723
            $v['subject'] = $subject;
724
        }
725
726
        if (null !== $this->_server_id && 'root' !== $subject) {
727
            $v['server'] = $this->_server_id;
728
729
            if (null !== $this->_database && 'server' !== $subject) {
730
                $v['database'] = $this->_database;
731
732
                if (isset($_REQUEST['schema']) && 'database' !== $subject) {
733
                    $v['schema'] = $_REQUEST['schema'];
734
                }
735
            }
736
        }
737
738
        return $v;
739
    }
740
741
    /**
742
     * Function to escape command line parameters.
743
     *
744
     * @param string $str The string to escape
745
     *
746
     * @return null|string The escaped string
747
     */
748
    public function escapeShellArg($str): ?string
749
    {
750
        //$data = $this->getDatabaseAccessor();
751
        $lang = $this->lang;
752
753
        if ('WIN' === \mb_strtoupper(\mb_substr(\PHP_OS, 0, 3))) {
754
            // Due to annoying PHP bugs, shell arguments cannot be escaped
755
            // (command simply fails), so we cannot allow complex objects
756
            // to be dumped.
757
            if (\preg_match('/^[_.[:alnum:]]+$/', $str)) {
758
                return $str;
759
            }
760
761
            return $this->halt($lang['strcannotdumponwindows']);
762
        }
763
764
        return \escapeshellarg($str);
765
    }
766
767
    /**
768
     * Function to escape command line programs.
769
     *
770
     * @param string $str The string to escape
771
     *
772
     * @return string The escaped string
773
     */
774
    public function escapeShellCmd($str)
775
    {
776
        $data = $this->getDatabaseAccessor();
777
778
        if ('WIN' === \mb_strtoupper(\mb_substr(\PHP_OS, 0, 3))) {
779
            $data->fieldClean($str);
780
781
            return '"' . $str . '"';
782
        }
783
784
        return \escapeshellcmd($str);
785
    }
786
787
    /**
788
     * Save the given SQL script in the history
789
     * of the database and server.
790
     *
791
     * @param string $script the SQL script to save
792
     */
793
    public function saveScriptHistory($script): void
794
    {
795
        [$usec, $sec] = \explode(' ', \microtime());
796
        $time = ((float) $usec + (float) $sec);
797
798
        $server = $this->container->server ? $this->container->server : $_REQUEST['server'];
799
        $database = $this->container->database ? $this->container->database : $_REQUEST['database'];
800
801
        $_SESSION['history'][$server][$database]["{$time}"] = [
802
            'query' => $script,
803
            'paginate' => !isset($_REQUEST['paginate']) ? 'f' : 't',
804
            'queryid' => $time,
805
        ];
806
    }
807
}
808