Passed
Push — develop ( 16b665...d246a9 )
by Felipe
05:54
created

Misc::icon()   B

Complexity

Conditions 8
Paths 8

Size

Total Lines 35
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

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