Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/HuasoFoundries/phpPgAdmin6.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/Core/Misc.php')
-rw-r--r--src/Core/Misc.php821
1 files changed, 821 insertions, 0 deletions
diff --git a/src/Core/Misc.php b/src/Core/Misc.php
new file mode 100644
index 00000000..a8f0b151
--- /dev/null
+++ b/src/Core/Misc.php
@@ -0,0 +1,821 @@
+<?php
+
+/**
+ * PHPPgAdmin6
+ */
+
+namespace PHPPgAdmin\Core;
+
+use Exception;
+use PHPPgAdmin\Database\Postgres;
+use PHPPgAdmin\Traits\HelperTrait;
+use PHPPgAdmin\Traits\MiscTrait;
+
+/**
+ * @file
+ * Class to hold various commonly used functions
+ *
+ * Id: Misc.php,v 1.171 2008/03/17 21:35:48 ioguix Exp $
+ */
+
+/**
+ * Class to hold various commonly used functions.
+ *
+ * Release: Misc.php,v 1.171 2008/03/17 21:35:48 ioguix Exp $
+ */
+class Misc
+{
+ use HelperTrait;
+ use MiscTrait;
+
+ /**
+ * @var array<array-key, mixed>
+ */
+ public $appLangFiles = [];
+
+ /**
+ * @var string
+ */
+ public $appName = '';
+
+ /**
+ * @var string
+ */
+ public $appVersion = '';
+
+ public $form = '';
+
+ /**
+ * @var string
+ */
+ public $href = '';
+
+ /**
+ * @var array<array-key, mixed>
+ */
+ public $lang = [];
+
+ /**
+ * @var array<array-key, mixed>
+ */
+ public $conf;
+
+ /**
+ * @var string
+ */
+ public $phpMinVer;
+
+ /**
+ * @var string
+ */
+ public $postgresqlMinVer;
+
+ /**
+ * @var ViewManager
+ */
+ public $view;
+
+ /**
+ * @var ContainerUtils
+ */
+ protected $container;
+
+ /**
+ * @var null|Connection
+ */
+ private $_connection;
+
+ /**
+ * @var bool
+ */
+ private $_no_db_connection = false;
+
+ /**
+ * @var null|Postgres
+ */
+ private $_data;
+
+ /**
+ * @var null|string
+ */
+ private $_database;
+
+ /**
+ * @var null|string
+ */
+ private $_server_id;
+
+ /**
+ * @var array<array-key, mixed>|null
+ */
+ private $_server_info;
+
+ /**
+ * @var string
+ */
+ private $_error_msg = '';
+
+ /**
+ * @param ContainerUtils $container The container
+ */
+ public function __construct(ContainerUtils $container)
+ {
+ $this->container = $container;
+
+ $this->lang = $container->get('lang');
+ $this->conf = $container->get('conf');
+
+ //$this->view = $container->get('view');
+
+ $this->appLangFiles = $container->get('appLangFiles');
+
+ $this->appName = $container->get('settings')['appName'];
+ $this->appVersion = $container->get('settings')['appVersion'];
+ $this->postgresqlMinVer = $container->get('settings')['postgresqlMinVer'];
+ $this->phpMinVer = $container->get('settings')['phpMinVer'];
+
+ $base_version = $container->get('settings')['base_version'];
+
+ // Check for config file version mismatch
+ if (!isset($this->conf['version']) || $base_version > $this->conf['version']) {
+ $container->addError($this->lang['strbadconfig']);
+ }
+
+ // Check database support is properly compiled in
+ if (!\function_exists('pg_connect')) {
+ $container->addError($this->lang['strnotloaded']);
+ }
+
+ // Check the version of PHP
+ if (\version_compare(\PHP_VERSION, $this->phpMinVer, '<')) {
+ $container->addError(\sprintf(
+ 'Version of PHP not supported. Please upgrade to version %s or later.',
+ $this->phpMinVer
+ ));
+ }
+ //$this->dumpAndDie($this->);
+
+ $this->getServerId();
+ }
+
+ /**
+ * Gets the value of a config property, or the array of all config properties.
+ *
+ * @param null|string $key value of the key to be retrieved. If null, the full array is returnes
+ *
+ * @return array<array-key, mixed>|null|string the whole $conf array, the value of $conf[key] or null if said key does not exist
+ */
+ public function getConf($key = null)
+ {
+ if (null === $key) {
+ return $this->conf;
+ }
+
+ if (\array_key_exists($key, $this->conf)) {
+ return $this->conf[$key];
+ }
+
+ return null;
+ }
+
+ /**
+ * Adds or modifies a key in the $conf instance property of this class.
+ *
+ * @param string $key name of the key to set
+ * @param mixed $value value of the key to set
+ *
+ * @return static this class instance
+ */
+ public function setConf($key, $value)
+ {
+ $this->conf[$key] = $value;
+
+ return $this;
+ }
+
+ /**
+ * @return null|string
+ */
+ public function serverToSha()
+ {
+ $request_server = $this->container->request->getParam('server');
+
+ if (null === $request_server) {
+ return null;
+ }
+ $srv_array = \explode(':', $request_server);
+
+ if (3 === \count($srv_array)) {
+ return \sha1($request_server);
+ }
+
+ return $request_server;
+ }
+
+ /**
+ * @return null|string
+ */
+ public function getServerId()
+ {
+ if ($this->_server_id) {
+ return $this->_server_id;
+ }
+
+ $request_server = $this->serverToSha();
+
+ if (1 === \count($this->conf['servers'])) {
+ $info = $this->conf['servers'][0];
+ $this->_server_id = \sha1($info['host'] . ':' . $info['port'] . ':' . $info['sslmode']);
+ } elseif (null !== $request_server) {
+ $this->_server_id = $request_server;
+ } elseif (isset($_SESSION['webdbLogin']) && 0 < \count($_SESSION['webdbLogin'])) {
+ $this->_server_id = \array_keys($_SESSION['webdbLogin'])[0];
+ }
+
+ return $this->_server_id;
+ }
+
+ /**
+ * Sets the view instance property of this class.
+ *
+ * @param ViewManager $view view instance
+ *
+ * @return static this class instance
+ */
+ public function setView(ViewManager $view)
+ {
+ $this->view = $view;
+
+ return $this;
+ }
+
+ public function getContainer(): ContainerUtils
+ {
+ return $this->container;
+ }
+
+ /**
+ * Sets $_no_db_connection boolean value, allows to render scripts that do not need an active session.
+ *
+ * @param bool $flag true or false to allow unconnected clients to access the view
+ *
+ * @return static this class instance
+ */
+ public function setNoDBConnection($flag)
+ {
+ $this->_no_db_connection = (bool) $flag;
+
+ return $this;
+ }
+
+ /**
+ * Gets member variable $_no_db_connection.
+ *
+ * @return bool value of member variable $_no_db_connection
+ */
+ public function getNoDBConnection()
+ {
+ return $this->_no_db_connection;
+ }
+
+ /**
+ * Sets the last error message to display afterwards instead of just dying with the error msg.
+ *
+ * @param string $msg error message string
+ *
+ * @return static this class instance
+ */
+ public function setErrorMsg($msg)
+ {
+ $this->_error_msg = $msg;
+
+ return $this;
+ }
+
+ /**
+ * Returns the error messages stored in member variable $_error_msg.
+ *
+ * @return string the error message
+ */
+ public function getErrorMsg()
+ {
+ return $this->_error_msg;
+ }
+
+ /**
+ * Creates a database accessor.
+ *
+ * @param string $database the name of the database
+ * @param null|mixed $server_id the id of the server
+ *
+ * @internal mixed $plaform placeholder that will receive the value of the platform
+ *
+ * @return null|Postgres the database accessor instance
+ */
+ public function getDatabaseAccessor($database = '', $server_id = null)
+ {
+ $lang = $this->lang;
+
+ if (null !== $server_id) {
+ $this->_server_id = $server_id;
+ }
+
+ $server_info = $this->getServerInfo($this->_server_id);
+
+ if ($this->getNoDBConnection() || !isset($server_info['username'])) {
+ return null;
+ }
+
+ if (null === $this->_data) {
+ try {
+ $_connection = $this->getConnection($database, $this->_server_id);
+ } catch (Exception $e) {
+ $this->setServerInfo(null, null, $this->_server_id);
+ $this->setNoDBConnection(true);
+ $this->setErrorMsg($e->getMessage());
+
+ return null;
+ }
+
+ if (null === $_connection) {
+ $this->container->addError($lang['strloginfailed']);
+ $this->setErrorMsg($lang['strloginfailed']);
+
+ return null;
+ }
+ $platform = '';
+ // Get the name of the database driver we need to use.
+ // The description of the server is returned in $platform.
+ $_type = $_connection->getDriver($platform);
+
+ if (null === $_type ?? null) {
+ $errormsg = \sprintf(
+ $lang['strpostgresqlversionnotsupported'],
+ $this->postgresqlMinVer
+ );
+ $this->container->addError($errormsg);
+ $this->setErrorMsg($errormsg);
+
+ return null;
+ }
+ /**
+ * @var class-string<Postgres>
+ */
+ $_type = '\\PHPPgAdmin\\Database\\' . $_type;
+
+ $this->setServerInfo('platform', $platform, $this->_server_id);
+ $this->setServerInfo('pgVersion', $_connection->getVersion(), $this->_server_id);
+
+ // Create a database wrapper class for easy manipulation of the
+ // connection.
+
+ $this->_data = new $_type($_connection, $this->container, $server_info);
+ $this->_data->platform = $_connection->platform;
+
+ //$this->_data->getHelpPages();
+
+ /* we work on UTF-8 only encoding */
+ $this->_data->execute("SET client_encoding TO 'UTF-8'");
+
+ if ($this->_data->hasByteaHexDefault()) {
+ $this->_data->execute('SET bytea_output TO escape');
+ }
+ }
+
+ if ($this->getNoDBConnection()
+ || null === $this->getDatabase()
+ || !isset($_REQUEST['schema'])
+ ) {
+ return $this->_data;
+ }
+
+ $status = $this->_data->setSchema($_REQUEST['schema']);
+
+ if (0 !== $status) {
+ $this->container->addError($this->lang['strbadschema']);
+ $this->setErrorMsg($this->lang['strbadschema']);
+ }
+
+ return $this->_data;
+ }
+
+ /**
+ * Undocumented function.
+ *
+ * @param null|string $server_id
+ */
+ public function getConnection(string $database = '', $server_id = null): ?Connection
+ {
+ $lang = $this->lang;
+
+ if (null === $this->_connection) {
+ if (null !== $server_id) {
+ $this->_server_id = $server_id;
+ }
+ $server_info = $this->getServerInfo($this->_server_id);
+ $database_to_use = $this->getDatabase($database);
+
+ // Perform extra security checks if this config option is set
+ if ($this->conf['extra_login_security']) {
+ // Disallowed logins if extra_login_security is enabled.
+ // These must be lowercase.
+ $bad_usernames = [
+ 'pgsql' => 'pgsql',
+ 'postgres' => 'postgres',
+ 'root' => 'root',
+ 'administrator' => 'administrator',
+ ];
+
+ if (isset($server_info['username'])
+ && \array_key_exists(\mb_strtolower($server_info['username']), $bad_usernames)
+ ) {
+ $msg = $lang['strlogindisallowed'];
+
+ throw new Exception($msg);
+ }
+
+ if (!isset($server_info['password'])
+ || '' === $server_info['password']
+ ) {
+ $msg = $lang['strlogindisallowed'];
+
+ throw new Exception($msg);
+ }
+ }
+
+ try {
+ // Create the connection object and make the connection
+ $this->_connection = new Connection(
+ $server_info,
+ $database_to_use,
+ $this->container
+ );
+ } catch (ADOdbException $e) {
+ throw new Exception($lang['strloginfailed'], $e->getCode(), $e);
+ }
+ }
+
+ return $this->_connection;
+ }
+
+ /**
+ * Validate and retrieve information on a server. If the parameter isn't supplied then the currently connected
+ * server is returned.
+ *
+ * @param null|string $server_id A server identifier (host:port)
+ *
+ * @return array<array-key, mixed>|null An associative array of server properties
+ */
+ public function getServerInfo($server_id = null)
+ {
+ if (null !== $server_id) {
+ $this->_server_id = $server_id;
+ } elseif (null !== $this->_server_info) {
+ return $this->_server_info;
+ }
+
+ // Check for the server in the logged-in list
+ if (isset($_SESSION['webdbLogin'][$this->_server_id])) {
+ $this->_server_info = $_SESSION['webdbLogin'][$this->_server_id];
+
+ return $this->_server_info;
+ }
+
+ // Otherwise, look for it in the conf file
+ foreach ($this->conf['servers'] as $idx => $info) {
+ $server_string = $info['host'] . ':' . $info['port'] . ':' . $info['sslmode'];
+ $server_sha = \sha1($server_string);
+
+ if ($this->_server_id === $server_string
+ || $this->_server_id === $server_sha
+ ) {
+ if (isset($info['username'])) {
+ $this->setServerInfo(null, $info, $this->_server_id);
+ } elseif (isset($_SESSION['sharedUsername'])) {
+ $info['username'] = $_SESSION['sharedUsername'];
+ $info['password'] = $_SESSION['sharedPassword'];
+ $this->container->get('view')->setReloadBrowser(true);
+ $this->setServerInfo(null, $info, $this->_server_id);
+ }
+ $this->_server_info = $info;
+
+ return $this->_server_info;
+ }
+ }
+
+ if (null === $server_id) {
+ $this->_server_info = null;
+
+ return $this->_server_info;
+ }
+
+ // //$this->prtrace('Invalid server param');
+ $this->_server_info = null;
+ // Unable to find a matching server, are we being hacked?
+ $this->halt($this->lang['strinvalidserverparam']);
+
+ return $this->_server_info;
+ }
+
+ /**
+ * Set server information.
+ *
+ * @param null|string $key parameter name to set, or null to replace all
+ * params with the assoc-array in $value
+ * @param mixed $value the new value, or null to unset the parameter
+ * @param null|string $server_id the server identifier, or null for current server
+ */
+ public function setServerInfo($key, $value, $server_id = null): void
+ {
+ if (null === $server_id) {
+ $server_id = $this->container->request->getParam('server');
+ }
+
+ if (null === $key) {
+ if (null === $value) {
+ unset($_SESSION['webdbLogin'][$server_id]);
+ } else {
+ $_SESSION['webdbLogin'][$server_id] = $value;
+ }
+ } elseif (null === $value) {
+ unset($_SESSION['webdbLogin'][$server_id][$key]);
+ } else {
+ $_SESSION['webdbLogin'][$server_id][$key] = $value;
+ }
+ }
+
+ public function getDatabase(string $database = '')
+ {
+ if (null === $this->_server_id && !isset($_REQUEST['database'])) {
+ return null;
+ }
+
+ $server_info = $this->getServerInfo($this->_server_id);
+
+ if (null !== $this->_server_id
+ && isset($server_info['useonlydefaultdb'])
+ && true === $server_info['useonlydefaultdb']
+ && isset($server_info['defaultdb'])
+ ) {
+ $this->_database = $server_info['defaultdb'];
+ } elseif ('' !== $database) {
+ $this->_database = $database;
+ } elseif (isset($_REQUEST['database'])) {
+ // Connect to the current database
+ $this->_database = $_REQUEST['database'];
+ } elseif (isset($server_info['defaultdb'])) {
+ // or if one is not specified then connect to the default database.
+ $this->_database = $server_info['defaultdb'];
+ } else {
+ return null;
+ }
+
+ return $this->_database;
+ }
+
+ /**
+ * Set the current schema.
+ *
+ * @param string $schema The schema name
+ *
+ * @return int|string 0 on success
+ */
+ public function setCurrentSchema($schema)
+ {
+ $data = $this->getDatabaseAccessor();
+
+ $status = $data->setSchema($schema);
+
+ if (0 !== $status) {
+ return $status;
+ }
+
+ $_REQUEST['schema'] = $schema;
+ $this->container->offsetSet('schema', $schema);
+ $this->setHREF();
+
+ return 0;
+ }
+
+ /**
+ * Checks if dumps are properly set up.
+ *
+ * @param bool $all (optional) True to check pg_dumpall, false to just check pg_dump
+ *
+ * @return bool True, dumps are set up, false otherwise
+ */
+ public function isDumpEnabled($all = false)
+ {
+ $info = $this->getServerInfo();
+
+ return !empty($info[$all ? 'pg_dumpall_path' : 'pg_dump_path']);
+ }
+
+ /**
+ * Sets the href tracking variable.
+ *
+ * @return static this class instance
+ */
+ public function setHREF()
+ {
+ $this->href = $this->getHREF();
+
+ return $this;
+ }
+
+ /**
+ * Get a href query string, excluding objects below the given object type (inclusive).
+ *
+ * @param null|string $exclude_from
+ *
+ * @return string
+ */
+ public function getHREF($exclude_from = null)
+ {
+ $href = [];
+
+ $server = $this->container->server || isset($_REQUEST['server']) ? $_REQUEST['server'] : null;
+ $database = $this->container->database || isset($_REQUEST['database']) ? $_REQUEST['database'] : null;
+ $schema = $this->container->schema || isset($_REQUEST['schema']) ? $_REQUEST['schema'] : null;
+
+ if ($server && 'server' !== $exclude_from) {
+ $href[] = 'server=' . \urlencode($server);
+ }
+
+ if ($database && 'database' !== $exclude_from) {
+ $href[] = 'database=' . \urlencode($database);
+ }
+
+ if ($schema && 'schema' !== $exclude_from) {
+ $href[] = 'schema=' . \urlencode($schema);
+ }
+
+ $this->href = \htmlentities(\implode('&', $href));
+
+ return $this->href;
+ }
+
+ /**
+ * A function to recursively strip slashes. Used to
+ * enforce magic_quotes_gpc being off.
+ *
+ * @param mixed $var The variable to strip (passed by reference)
+ */
+ public function stripVar(&$var): void
+ {
+ if (\is_array($var)) {
+ foreach (\array_keys($var) as $k) {
+ $this->stripVar($var[$k]);
+
+ /* magic_quotes_gpc escape keys as well ...*/
+ if (\is_string($k)) {
+ $ek = \stripslashes($k);
+
+ if ($ek !== $k) {
+ $var[$ek] = $var[$k];
+ unset($var[$k]);
+ }
+ }
+ }
+ } else {
+ $var = \stripslashes($var);
+ }
+ }
+
+ /**
+ * Converts a PHP.INI size variable to bytes. Taken from publically available
+ * function by Chris DeRose, here: http://www.php.net/manual/en/configuration.directives.php#ini.file-uploads.
+ *
+ * @param mixed $strIniSize The PHP.INI variable
+ *
+ * @return false|float size in bytes, false on failure
+ */
+ public function inisizeToBytes($strIniSize)
+ {
+ // This function will take the string value of an ini 'size' parameter,
+ // and return a double (64-bit float) representing the number of bytes
+ // that the parameter represents. Or false if $strIniSize is unparseable.
+ $a_IniParts = [];
+
+ if (!\is_string($strIniSize)) {
+ return false;
+ }
+
+ if (!\preg_match('/^(\d+)([bkm]*)$/i', $strIniSize, $a_IniParts)) {
+ return false;
+ }
+
+ $nSize = (float) $a_IniParts[1];
+ $strUnit = \mb_strtolower($a_IniParts[2]);
+
+ switch ($strUnit) {
+ case 'm':
+ return $nSize * (float) 1048576;
+ case 'k':
+ return $nSize * (float) 1024;
+ case 'b':
+ default:
+ return $nSize;
+ }
+ }
+
+ /**
+ * @param string $subject
+ *
+ * @return (mixed|string)[]
+ *
+ * @psalm-return array{subject?: string, server?: string, database?: string, schema?: mixed}
+ */
+ public function getRequestVars($subject = '')
+ {
+ $v = [];
+
+ if (!empty($subject)) {
+ $v['subject'] = $subject;
+ }
+
+ if (null !== $this->_server_id && 'root' !== $subject) {
+ $v['server'] = $this->_server_id;
+
+ if (null !== $this->_database && 'server' !== $subject) {
+ $v['database'] = $this->_database;
+
+ if (isset($_REQUEST['schema']) && 'database' !== $subject) {
+ $v['schema'] = $_REQUEST['schema'];
+ }
+ }
+ }
+
+ return $v;
+ }
+
+ /**
+ * Function to escape command line parameters.
+ *
+ * @param string $str The string to escape
+ *
+ * @return null|string The escaped string
+ */
+ public function escapeShellArg($str): ?string
+ {
+ //$data = $this->getDatabaseAccessor();
+ $lang = $this->lang;
+
+ if ('WIN' === \mb_strtoupper(\mb_substr(\PHP_OS, 0, 3))) {
+ // Due to annoying PHP bugs, shell arguments cannot be escaped
+ // (command simply fails), so we cannot allow complex objects
+ // to be dumped.
+ if (\preg_match('/^[_.[:alnum:]]+$/', $str)) {
+ return $str;
+ }
+
+ return $this->halt($lang['strcannotdumponwindows']);
+ }
+
+ return \escapeshellarg($str);
+ }
+
+ /**
+ * Function to escape command line programs.
+ *
+ * @param string $str The string to escape
+ *
+ * @return string The escaped string
+ */
+ public function escapeShellCmd($str)
+ {
+ $data = $this->getDatabaseAccessor();
+
+ if ('WIN' === \mb_strtoupper(\mb_substr(\PHP_OS, 0, 3))) {
+ $data->fieldClean($str);
+
+ return '"' . $str . '"';
+ }
+
+ return \escapeshellcmd($str);
+ }
+
+ /**
+ * Save the given SQL script in the history
+ * of the database and server.
+ *
+ * @param string $script the SQL script to save
+ */
+ public function saveScriptHistory($script): void
+ {
+ [$usec, $sec] = \explode(' ', \microtime());
+ $time = ((float) $usec + (float) $sec);
+
+ $server = '' !== $this->container->server ? $this->container->server : $_REQUEST['server'];
+ $database = '' !== $this->container->database ? $this->container->database : $_REQUEST['database'];
+
+ $_SESSION['history'][$server][$database][\sprintf(
+ '%s',
+ $time
+ )] = [
+ 'query' => $script,
+ 'paginate' => isset($_REQUEST['paginate']) ? 't' : 'f',
+ 'queryid' => $time,
+ ];
+ }
+}