Update website
This commit is contained in:
parent
4413528994
commit
1d90fbf296
6865 changed files with 1091082 additions and 0 deletions
522
admin/phpMyAdmin/libraries/classes/Config/ConfigFile.php
Normal file
522
admin/phpMyAdmin/libraries/classes/Config/ConfigFile.php
Normal file
|
@ -0,0 +1,522 @@
|
|||
<?php
|
||||
/**
|
||||
* Config file management
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config;
|
||||
|
||||
use PhpMyAdmin\Core;
|
||||
|
||||
use function array_diff;
|
||||
use function array_flip;
|
||||
use function array_keys;
|
||||
use function count;
|
||||
use function is_array;
|
||||
use function preg_replace;
|
||||
|
||||
/**
|
||||
* Config file management class.
|
||||
* Stores its data in $_SESSION
|
||||
*/
|
||||
class ConfigFile
|
||||
{
|
||||
/**
|
||||
* Stores default phpMyAdmin config
|
||||
*
|
||||
* @see Settings
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $defaultCfg;
|
||||
|
||||
/**
|
||||
* Stores allowed values for non-standard fields
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $cfgDb;
|
||||
|
||||
/**
|
||||
* Stores original PMA config, not modified by user preferences
|
||||
*
|
||||
* @var array|null
|
||||
*/
|
||||
private $baseCfg;
|
||||
|
||||
/**
|
||||
* Whether we are currently working in PMA Setup context
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $isInSetup;
|
||||
|
||||
/**
|
||||
* Keys which will be always written to config file
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $persistKeys = [];
|
||||
|
||||
/**
|
||||
* Changes keys while updating config in {@link updateWithGlobalConfig()}
|
||||
* or reading by {@link getConfig()} or {@link getConfigArray()}
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $cfgUpdateReadMapping = [];
|
||||
|
||||
/**
|
||||
* Key filter for {@link set()}
|
||||
*
|
||||
* @var array|null
|
||||
*/
|
||||
private $setFilter;
|
||||
|
||||
/**
|
||||
* Instance id (key in $_SESSION array, separate for each server -
|
||||
* ConfigFile{server id})
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @param array|null $baseConfig base configuration read from
|
||||
* {@link PhpMyAdmin\Config::$base_config},
|
||||
* use only when not in PMA Setup
|
||||
*/
|
||||
public function __construct($baseConfig = null)
|
||||
{
|
||||
// load default config values
|
||||
$settings = new Settings([]);
|
||||
$this->defaultCfg = $settings->toArray();
|
||||
|
||||
// load additional config information
|
||||
$this->cfgDb = include ROOT_PATH . 'libraries/config.values.php';
|
||||
|
||||
// apply default values overrides
|
||||
if (count($this->cfgDb['_overrides'])) {
|
||||
foreach ($this->cfgDb['_overrides'] as $path => $value) {
|
||||
Core::arrayWrite($path, $this->defaultCfg, $value);
|
||||
}
|
||||
}
|
||||
|
||||
$this->baseCfg = $baseConfig;
|
||||
$this->isInSetup = $baseConfig === null;
|
||||
$this->id = 'ConfigFile' . $GLOBALS['server'];
|
||||
if (isset($_SESSION[$this->id])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$_SESSION[$this->id] = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets names of config options which will be placed in config file even if
|
||||
* they are set to their default values (use only full paths)
|
||||
*
|
||||
* @param array $keys the names of the config options
|
||||
*/
|
||||
public function setPersistKeys(array $keys): void
|
||||
{
|
||||
// checking key presence is much faster than searching so move values
|
||||
// to keys
|
||||
$this->persistKeys = array_flip($keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns flipped array set by {@link setPersistKeys()}
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getPersistKeysMap()
|
||||
{
|
||||
return $this->persistKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* By default ConfigFile allows setting of all configuration keys, use
|
||||
* this method to set up a filter on {@link set()} method
|
||||
*
|
||||
* @param array|null $keys array of allowed keys or null to remove filter
|
||||
*/
|
||||
public function setAllowedKeys($keys): void
|
||||
{
|
||||
if ($keys === null) {
|
||||
$this->setFilter = null;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// checking key presence is much faster than searching so move values
|
||||
// to keys
|
||||
$this->setFilter = array_flip($keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets path mapping for updating config in
|
||||
* {@link updateWithGlobalConfig()} or reading
|
||||
* by {@link getConfig()} or {@link getConfigArray()}
|
||||
*
|
||||
* @param array $mapping Contains the mapping of "Server/config options"
|
||||
* to "Server/1/config options"
|
||||
*/
|
||||
public function setCfgUpdateReadMapping(array $mapping): void
|
||||
{
|
||||
$this->cfgUpdateReadMapping = $mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets configuration data
|
||||
*/
|
||||
public function resetConfigData(): void
|
||||
{
|
||||
$_SESSION[$this->id] = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets configuration data (overrides old data)
|
||||
*
|
||||
* @param array $cfg Configuration options
|
||||
*/
|
||||
public function setConfigData(array $cfg): void
|
||||
{
|
||||
$_SESSION[$this->id] = $cfg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets config value
|
||||
*
|
||||
* @param string $path Path
|
||||
* @param mixed $value Value
|
||||
* @param string $canonicalPath Canonical path
|
||||
*/
|
||||
public function set($path, $value, $canonicalPath = null): void
|
||||
{
|
||||
if ($canonicalPath === null) {
|
||||
$canonicalPath = $this->getCanonicalPath($path);
|
||||
}
|
||||
|
||||
if ($this->setFilter !== null && ! isset($this->setFilter[$canonicalPath])) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if the path isn't protected it may be removed
|
||||
if (isset($this->persistKeys[$canonicalPath])) {
|
||||
Core::arrayWrite($path, $_SESSION[$this->id], $value);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$defaultValue = $this->getDefault($canonicalPath);
|
||||
$removePath = $value === $defaultValue;
|
||||
if ($this->isInSetup) {
|
||||
// remove if it has a default value or is empty
|
||||
$removePath = $removePath
|
||||
|| (empty($value) && empty($defaultValue));
|
||||
} else {
|
||||
// get original config values not overwritten by user
|
||||
// preferences to allow for overwriting options set in
|
||||
// config.inc.php with default values
|
||||
$instanceDefaultValue = Core::arrayRead($canonicalPath, $this->baseCfg);
|
||||
// remove if it has a default value and base config (config.inc.php)
|
||||
// uses default value
|
||||
$removePath = $removePath
|
||||
&& ($instanceDefaultValue === $defaultValue);
|
||||
}
|
||||
|
||||
if ($removePath) {
|
||||
Core::arrayRemove($path, $_SESSION[$this->id]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Core::arrayWrite($path, $_SESSION[$this->id], $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flattens multidimensional array, changes indices to paths
|
||||
* (eg. 'key/subkey').
|
||||
*
|
||||
* @param array $array Multidimensional array
|
||||
* @param string $prefix Prefix
|
||||
*/
|
||||
private function getFlatArray(array $array, string $prefix = ''): array
|
||||
{
|
||||
$result = [];
|
||||
foreach ($array as $key => $value) {
|
||||
if (is_array($value) && ! isset($value[0])) {
|
||||
$result += $this->getFlatArray($value, $prefix . $key . '/');
|
||||
} else {
|
||||
$result[$prefix . $key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns default config in a flattened array
|
||||
*/
|
||||
public function getFlatDefaultConfig(): array
|
||||
{
|
||||
return $this->getFlatArray($this->defaultCfg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates config with values read from given array
|
||||
* (config will contain differences to defaults from {@see \PhpMyAdmin\Config\Settings}).
|
||||
*
|
||||
* @param array $cfg Configuration
|
||||
*/
|
||||
public function updateWithGlobalConfig(array $cfg): void
|
||||
{
|
||||
// load config array and flatten it
|
||||
$flatConfig = $this->getFlatArray($cfg);
|
||||
|
||||
// save values map for translating a few user preferences paths,
|
||||
// should be complemented by code reading from generated config
|
||||
// to perform inverse mapping
|
||||
foreach ($flatConfig as $path => $value) {
|
||||
if (isset($this->cfgUpdateReadMapping[$path])) {
|
||||
$path = $this->cfgUpdateReadMapping[$path];
|
||||
}
|
||||
|
||||
$this->set($path, $value, $path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns config value or $default if it's not set
|
||||
*
|
||||
* @param string $path Path of config file
|
||||
* @param mixed $default Default values
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($path, $default = null)
|
||||
{
|
||||
return Core::arrayRead($path, $_SESSION[$this->id], $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns default config value or $default it it's not set ie. it doesn't
|
||||
* exist in {@see \PhpMyAdmin\Config\Settings} ($cfg) and config.values.php
|
||||
* ($_cfg_db['_overrides'])
|
||||
*
|
||||
* @param string $canonicalPath Canonical path
|
||||
* @param mixed $default Default value
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDefault($canonicalPath, $default = null)
|
||||
{
|
||||
return Core::arrayRead($canonicalPath, $this->defaultCfg, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns config value, if it's not set uses the default one; returns
|
||||
* $default if the path isn't set and doesn't contain a default value
|
||||
*
|
||||
* @param string $path Path
|
||||
* @param mixed $default Default value
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getValue($path, $default = null)
|
||||
{
|
||||
$v = Core::arrayRead($path, $_SESSION[$this->id], null);
|
||||
if ($v !== null) {
|
||||
return $v;
|
||||
}
|
||||
|
||||
$path = $this->getCanonicalPath($path);
|
||||
|
||||
return $this->getDefault($path, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns canonical path
|
||||
*
|
||||
* @param string $path Path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCanonicalPath($path)
|
||||
{
|
||||
return preg_replace('#^Servers/([\d]+)/#', 'Servers/1/', $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns config database entry for $path
|
||||
*
|
||||
* @param string $path path of the variable in config db
|
||||
* @param mixed $default default value
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDbEntry($path, $default = null)
|
||||
{
|
||||
return Core::arrayRead($path, $this->cfgDb, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns server count
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getServerCount()
|
||||
{
|
||||
return isset($_SESSION[$this->id]['Servers'])
|
||||
? count($_SESSION[$this->id]['Servers'])
|
||||
: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns server list
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getServers(): array
|
||||
{
|
||||
return $_SESSION[$this->id]['Servers'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns DSN of given server
|
||||
*
|
||||
* @param int $server server index
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getServerDSN($server)
|
||||
{
|
||||
if (! isset($_SESSION[$this->id]['Servers'][$server])) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$path = 'Servers/' . $server;
|
||||
$dsn = 'mysqli://';
|
||||
if ($this->getValue($path . '/auth_type') === 'config') {
|
||||
$dsn .= $this->getValue($path . '/user');
|
||||
if (! empty($this->getValue($path . '/password'))) {
|
||||
$dsn .= ':***';
|
||||
}
|
||||
|
||||
$dsn .= '@';
|
||||
}
|
||||
|
||||
if ($this->getValue($path . '/host') !== 'localhost') {
|
||||
$dsn .= $this->getValue($path . '/host');
|
||||
$port = $this->getValue($path . '/port');
|
||||
if ($port) {
|
||||
$dsn .= ':' . $port;
|
||||
}
|
||||
} else {
|
||||
$dsn .= $this->getValue($path . '/socket');
|
||||
}
|
||||
|
||||
return $dsn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns server name
|
||||
*
|
||||
* @param int $id server index
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getServerName($id)
|
||||
{
|
||||
if (! isset($_SESSION[$this->id]['Servers'][$id])) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$verbose = $this->get('Servers/' . $id . '/verbose');
|
||||
if (! empty($verbose)) {
|
||||
return $verbose;
|
||||
}
|
||||
|
||||
$host = $this->get('Servers/' . $id . '/host');
|
||||
|
||||
return empty($host) ? 'localhost' : $host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes server
|
||||
*
|
||||
* @param int $server server index
|
||||
*/
|
||||
public function removeServer($server): void
|
||||
{
|
||||
if (! isset($_SESSION[$this->id]['Servers'][$server])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$lastServer = $this->getServerCount();
|
||||
|
||||
for ($i = $server; $i < $lastServer; $i++) {
|
||||
$_SESSION[$this->id]['Servers'][$i] = $_SESSION[$this->id]['Servers'][$i + 1];
|
||||
}
|
||||
|
||||
unset($_SESSION[$this->id]['Servers'][$lastServer]);
|
||||
|
||||
if (! isset($_SESSION[$this->id]['ServerDefault']) || $_SESSION[$this->id]['ServerDefault'] != $lastServer) {
|
||||
return;
|
||||
}
|
||||
|
||||
unset($_SESSION[$this->id]['ServerDefault']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns configuration array (full, multidimensional format)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getConfig()
|
||||
{
|
||||
$c = $_SESSION[$this->id];
|
||||
foreach ($this->cfgUpdateReadMapping as $mapTo => $mapFrom) {
|
||||
// if the key $c exists in $map_to
|
||||
if (Core::arrayRead($mapTo, $c) === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Core::arrayWrite($mapTo, $c, Core::arrayRead($mapFrom, $c));
|
||||
Core::arrayRemove($mapFrom, $c);
|
||||
}
|
||||
|
||||
return $c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns configuration array (flat format)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getConfigArray()
|
||||
{
|
||||
$c = $this->getFlatArray($_SESSION[$this->id]);
|
||||
|
||||
$persistKeys = array_diff(
|
||||
array_keys($this->persistKeys),
|
||||
array_keys($c)
|
||||
);
|
||||
foreach ($persistKeys as $k) {
|
||||
$c[$k] = $this->getDefault($this->getCanonicalPath($k));
|
||||
}
|
||||
|
||||
foreach ($this->cfgUpdateReadMapping as $mapTo => $mapFrom) {
|
||||
if (! isset($c[$mapFrom])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$c[$mapTo] = $c[$mapFrom];
|
||||
unset($c[$mapFrom]);
|
||||
}
|
||||
|
||||
return $c;
|
||||
}
|
||||
}
|
1015
admin/phpMyAdmin/libraries/classes/Config/Descriptions.php
Normal file
1015
admin/phpMyAdmin/libraries/classes/Config/Descriptions.php
Normal file
File diff suppressed because it is too large
Load diff
312
admin/phpMyAdmin/libraries/classes/Config/Form.php
Normal file
312
admin/phpMyAdmin/libraries/classes/Config/Form.php
Normal file
|
@ -0,0 +1,312 @@
|
|||
<?php
|
||||
/**
|
||||
* Form handling code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config;
|
||||
|
||||
use function array_combine;
|
||||
use function array_shift;
|
||||
use function array_walk;
|
||||
use function count;
|
||||
use function gettype;
|
||||
use function is_array;
|
||||
use function is_bool;
|
||||
use function is_int;
|
||||
use function is_string;
|
||||
use function ltrim;
|
||||
use function mb_strpos;
|
||||
use function mb_strrpos;
|
||||
use function mb_substr;
|
||||
use function str_replace;
|
||||
use function trigger_error;
|
||||
|
||||
use const E_USER_ERROR;
|
||||
|
||||
/**
|
||||
* Base class for forms, loads default configuration options, checks allowed
|
||||
* values etc.
|
||||
*/
|
||||
class Form
|
||||
{
|
||||
/**
|
||||
* Form name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* Arbitrary index, doesn't affect class' behavior
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $index;
|
||||
|
||||
/**
|
||||
* Form fields (paths), filled by {@link readFormPaths()}, indexed by field name
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $fields;
|
||||
|
||||
/**
|
||||
* Stores default values for some fields (eg. pmadb tables)
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $default;
|
||||
|
||||
/**
|
||||
* Caches field types, indexed by field names
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $fieldsTypes;
|
||||
|
||||
/**
|
||||
* ConfigFile instance
|
||||
*
|
||||
* @var ConfigFile
|
||||
*/
|
||||
private $configFile;
|
||||
|
||||
/**
|
||||
* A counter for the number of groups
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private static $groupCounter = 0;
|
||||
|
||||
/**
|
||||
* Reads default config values
|
||||
*
|
||||
* @param string $formName Form name
|
||||
* @param array $form Form data
|
||||
* @param ConfigFile $cf Config file instance
|
||||
* @param int $index arbitrary index, stored in Form::$index
|
||||
*/
|
||||
public function __construct(
|
||||
$formName,
|
||||
array $form,
|
||||
ConfigFile $cf,
|
||||
$index = null
|
||||
) {
|
||||
$this->index = $index;
|
||||
$this->configFile = $cf;
|
||||
$this->loadForm($formName, $form);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns type of given option
|
||||
*
|
||||
* @param string $optionName path or field name
|
||||
*
|
||||
* @return string|null one of: boolean, integer, double, string, select, array
|
||||
*/
|
||||
public function getOptionType($optionName)
|
||||
{
|
||||
$key = ltrim(
|
||||
mb_substr(
|
||||
$optionName,
|
||||
(int) mb_strrpos($optionName, '/')
|
||||
),
|
||||
'/'
|
||||
);
|
||||
|
||||
return $this->fieldsTypes[$key] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns allowed values for select fields
|
||||
*
|
||||
* @param string $optionPath Option path
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getOptionValueList($optionPath)
|
||||
{
|
||||
$value = $this->configFile->getDbEntry($optionPath);
|
||||
if ($value === null) {
|
||||
trigger_error($optionPath . ' - select options not defined', E_USER_ERROR);
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
if (! is_array($value)) {
|
||||
trigger_error($optionPath . ' - not a static value list', E_USER_ERROR);
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
// convert array('#', 'a', 'b') to array('a', 'b')
|
||||
if (isset($value[0]) && $value[0] === '#') {
|
||||
// remove first element ('#')
|
||||
array_shift($value);
|
||||
|
||||
// $value has keys and value names, return it
|
||||
return $value;
|
||||
}
|
||||
|
||||
// convert value list array('a', 'b') to array('a' => 'a', 'b' => 'b')
|
||||
$hasStringKeys = false;
|
||||
$keys = [];
|
||||
for ($i = 0, $nb = count($value); $i < $nb; $i++) {
|
||||
if (! isset($value[$i])) {
|
||||
$hasStringKeys = true;
|
||||
break;
|
||||
}
|
||||
|
||||
$keys[] = is_bool($value[$i]) ? (int) $value[$i] : $value[$i];
|
||||
}
|
||||
|
||||
if (! $hasStringKeys) {
|
||||
/** @var array $value */
|
||||
$value = array_combine($keys, $value);
|
||||
}
|
||||
|
||||
// $value has keys and value names, return it
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* array_walk callback function, reads path of form fields from
|
||||
* array (see docs for \PhpMyAdmin\Config\Forms\BaseForm::getForms)
|
||||
*
|
||||
* @param mixed $value Value
|
||||
* @param mixed $key Key
|
||||
* @param mixed $prefix Prefix
|
||||
*/
|
||||
private function readFormPathsCallback($value, $key, $prefix): void
|
||||
{
|
||||
if (is_array($value)) {
|
||||
$prefix .= $key . '/';
|
||||
array_walk(
|
||||
$value,
|
||||
function ($value, $key, $prefix): void {
|
||||
$this->readFormPathsCallback($value, $key, $prefix);
|
||||
},
|
||||
$prefix
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (! is_int($key)) {
|
||||
$this->default[$prefix . $key] = $value;
|
||||
$value = $key;
|
||||
}
|
||||
|
||||
// add unique id to group ends
|
||||
if ($value === ':group:end') {
|
||||
$value .= ':' . self::$groupCounter++;
|
||||
}
|
||||
|
||||
$this->fields[] = $prefix . $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the group counter, function for testing purposes
|
||||
*/
|
||||
public static function resetGroupCounter(): void
|
||||
{
|
||||
self::$groupCounter = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads form paths to {@link $fields}
|
||||
*
|
||||
* @param array $form Form
|
||||
*/
|
||||
protected function readFormPaths(array $form): void
|
||||
{
|
||||
// flatten form fields' paths and save them to $fields
|
||||
$this->fields = [];
|
||||
array_walk(
|
||||
$form,
|
||||
function ($value, $key, $prefix): void {
|
||||
$this->readFormPathsCallback($value, $key, $prefix);
|
||||
},
|
||||
''
|
||||
);
|
||||
|
||||
// $this->fields is an array of the form: [0..n] => 'field path'
|
||||
// change numeric indexes to contain field names (last part of the path)
|
||||
$paths = $this->fields;
|
||||
$this->fields = [];
|
||||
foreach ($paths as $path) {
|
||||
$key = ltrim(
|
||||
mb_substr($path, (int) mb_strrpos($path, '/')),
|
||||
'/'
|
||||
);
|
||||
$this->fields[$key] = $path;
|
||||
}
|
||||
// now $this->fields is an array of the form: 'field name' => 'field path'
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads fields' types to $this->fieldsTypes
|
||||
*/
|
||||
protected function readTypes(): void
|
||||
{
|
||||
$cf = $this->configFile;
|
||||
foreach ($this->fields as $name => $path) {
|
||||
if (mb_strpos((string) $name, ':group:') === 0) {
|
||||
$this->fieldsTypes[$name] = 'group';
|
||||
continue;
|
||||
}
|
||||
|
||||
$v = $cf->getDbEntry($path);
|
||||
if ($v !== null) {
|
||||
$type = is_array($v) ? 'select' : $v;
|
||||
} else {
|
||||
$type = gettype($cf->getDefault($path));
|
||||
}
|
||||
|
||||
$this->fieldsTypes[$name] = $type;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove slashes from group names
|
||||
*
|
||||
* @see issue #15836
|
||||
*
|
||||
* @param array $form The form data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function cleanGroupPaths(array $form): array
|
||||
{
|
||||
foreach ($form as &$name) {
|
||||
if (! is_string($name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mb_strpos($name, ':group:') !== 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$name = str_replace('/', '-', $name);
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads form settings and prepares class to work with given subset of
|
||||
* config file
|
||||
*
|
||||
* @param string $formName Form name
|
||||
* @param array $form Form
|
||||
*/
|
||||
public function loadForm($formName, array $form): void
|
||||
{
|
||||
$this->name = $formName;
|
||||
$form = $this->cleanGroupPaths($form);
|
||||
$this->readFormPaths($form);
|
||||
$this->readTypes();
|
||||
}
|
||||
}
|
889
admin/phpMyAdmin/libraries/classes/Config/FormDisplay.php
Normal file
889
admin/phpMyAdmin/libraries/classes/Config/FormDisplay.php
Normal file
|
@ -0,0 +1,889 @@
|
|||
<?php
|
||||
/**
|
||||
* Form management class, displays and processes forms
|
||||
*
|
||||
* Explanation of used terms:
|
||||
* o work_path - original field path, eg. Servers/4/verbose
|
||||
* o system_path - work_path modified so that it points to the first server,
|
||||
* eg. Servers/1/verbose
|
||||
* o translated_path - work_path modified for HTML field name, a path with
|
||||
* slashes changed to hyphens, eg. Servers-4-verbose
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\User\UserFormList;
|
||||
use PhpMyAdmin\Html\MySQLDocumentation;
|
||||
use PhpMyAdmin\Sanitize;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function __;
|
||||
use function array_flip;
|
||||
use function array_keys;
|
||||
use function array_search;
|
||||
use function count;
|
||||
use function explode;
|
||||
use function function_exists;
|
||||
use function gettype;
|
||||
use function implode;
|
||||
use function is_array;
|
||||
use function is_bool;
|
||||
use function is_numeric;
|
||||
use function mb_substr;
|
||||
use function preg_match;
|
||||
use function settype;
|
||||
use function sprintf;
|
||||
use function str_replace;
|
||||
use function trigger_error;
|
||||
use function trim;
|
||||
|
||||
use const E_USER_WARNING;
|
||||
|
||||
/**
|
||||
* Form management class, displays and processes forms
|
||||
*/
|
||||
class FormDisplay
|
||||
{
|
||||
/**
|
||||
* ConfigFile instance
|
||||
*
|
||||
* @var ConfigFile
|
||||
*/
|
||||
private $configFile;
|
||||
|
||||
/**
|
||||
* Form list
|
||||
*
|
||||
* @var Form[]
|
||||
*/
|
||||
private $forms = [];
|
||||
|
||||
/**
|
||||
* Stores validation errors, indexed by paths
|
||||
* [ Form_name ] is an array of form errors
|
||||
* [path] is a string storing error associated with single field
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $errors = [];
|
||||
|
||||
/**
|
||||
* Paths changed so that they can be used as HTML ids, indexed by paths
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $translatedPaths = [];
|
||||
|
||||
/**
|
||||
* Server paths change indexes so we define maps from current server
|
||||
* path to the first one, indexed by work path
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $systemPaths = [];
|
||||
|
||||
/**
|
||||
* Tells whether forms have been validated
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $isValidated = true;
|
||||
|
||||
/**
|
||||
* Dictionary with user preferences keys
|
||||
*
|
||||
* @var array|null
|
||||
*/
|
||||
private $userprefsKeys;
|
||||
|
||||
/**
|
||||
* Dictionary with disallowed user preferences keys
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $userprefsDisallow;
|
||||
|
||||
/** @var FormDisplayTemplate */
|
||||
private $formDisplayTemplate;
|
||||
|
||||
/**
|
||||
* @param ConfigFile $cf Config file instance
|
||||
*/
|
||||
public function __construct(ConfigFile $cf)
|
||||
{
|
||||
$this->formDisplayTemplate = new FormDisplayTemplate($GLOBALS['config']);
|
||||
$this->configFile = $cf;
|
||||
// initialize validators
|
||||
Validator::getValidators($this->configFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link ConfigFile} associated with this instance
|
||||
*
|
||||
* @return ConfigFile
|
||||
*/
|
||||
public function getConfigFile()
|
||||
{
|
||||
return $this->configFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers form in form manager
|
||||
*
|
||||
* @param string $formName Form name
|
||||
* @param array $form Form data
|
||||
* @param int $serverId 0 if new server, validation; >= 1 if editing a server
|
||||
*/
|
||||
public function registerForm($formName, array $form, $serverId = null): void
|
||||
{
|
||||
$this->forms[$formName] = new Form($formName, $form, $this->configFile, $serverId);
|
||||
$this->isValidated = false;
|
||||
foreach ($this->forms[$formName]->fields as $path) {
|
||||
$workPath = $serverId === null
|
||||
? $path
|
||||
: str_replace('Servers/1/', 'Servers/' . $serverId . '/', $path);
|
||||
$this->systemPaths[$workPath] = $path;
|
||||
$this->translatedPaths[$workPath] = str_replace('/', '-', $workPath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes forms, returns true on successful save
|
||||
*
|
||||
* @param bool $allowPartialSave allows for partial form saving
|
||||
* on failed validation
|
||||
* @param bool $checkFormSubmit whether check for $_POST['submit_save']
|
||||
*/
|
||||
public function process($allowPartialSave = true, $checkFormSubmit = true): bool
|
||||
{
|
||||
if ($checkFormSubmit && ! isset($_POST['submit_save'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// save forms
|
||||
if (count($this->forms) > 0) {
|
||||
return $this->save(array_keys($this->forms), $allowPartialSave);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs validation for all registered forms
|
||||
*/
|
||||
private function validate(): void
|
||||
{
|
||||
if ($this->isValidated) {
|
||||
return;
|
||||
}
|
||||
|
||||
$paths = [];
|
||||
$values = [];
|
||||
foreach ($this->forms as $form) {
|
||||
$paths[] = $form->name;
|
||||
// collect values and paths
|
||||
foreach ($form->fields as $path) {
|
||||
$workPath = array_search($path, $this->systemPaths);
|
||||
$values[$path] = $this->configFile->getValue($workPath);
|
||||
$paths[] = $path;
|
||||
}
|
||||
}
|
||||
|
||||
// run validation
|
||||
$errors = Validator::validate($this->configFile, $paths, $values, false);
|
||||
|
||||
// change error keys from canonical paths to work paths
|
||||
if (is_array($errors) && count($errors) > 0) {
|
||||
$this->errors = [];
|
||||
foreach ($errors as $path => $errorList) {
|
||||
$workPath = array_search($path, $this->systemPaths);
|
||||
// field error
|
||||
if (! $workPath) {
|
||||
// form error, fix path
|
||||
$workPath = $path;
|
||||
}
|
||||
|
||||
$this->errors[$workPath] = $errorList;
|
||||
}
|
||||
}
|
||||
|
||||
$this->isValidated = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs HTML for forms
|
||||
*
|
||||
* @param bool $showButtons whether show submit and reset button
|
||||
* @param string $formAction action attribute for the form
|
||||
* @param array|null $hiddenFields array of form hidden fields (key: field
|
||||
* name)
|
||||
*
|
||||
* @return string HTML for forms
|
||||
*/
|
||||
public function getDisplay(
|
||||
$showButtons = true,
|
||||
$formAction = null,
|
||||
$hiddenFields = null
|
||||
) {
|
||||
$js = [];
|
||||
$jsDefault = [];
|
||||
|
||||
/**
|
||||
* We do validation on page refresh when browser remembers field values,
|
||||
* add a field with known value which will be used for checks.
|
||||
*/
|
||||
static $hasCheckPageRefresh = false;
|
||||
if (! $hasCheckPageRefresh) {
|
||||
$hasCheckPageRefresh = true;
|
||||
}
|
||||
|
||||
$tabs = [];
|
||||
foreach ($this->forms as $form) {
|
||||
$tabs[$form->name] = Descriptions::get('Form_' . $form->name);
|
||||
}
|
||||
|
||||
// validate only when we aren't displaying a "new server" form
|
||||
$isNewServer = false;
|
||||
foreach ($this->forms as $form) {
|
||||
if ($form->index === 0) {
|
||||
$isNewServer = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! $isNewServer) {
|
||||
$this->validate();
|
||||
}
|
||||
|
||||
// user preferences
|
||||
$this->loadUserprefsInfo();
|
||||
|
||||
$validators = Validator::getValidators($this->configFile);
|
||||
$forms = [];
|
||||
|
||||
foreach ($this->forms as $key => $form) {
|
||||
$this->formDisplayTemplate->group = 0;
|
||||
$forms[$key] = [
|
||||
'name' => $form->name,
|
||||
'descriptions' => [
|
||||
'name' => Descriptions::get('Form_' . $form->name, 'name'),
|
||||
'desc' => Descriptions::get('Form_' . $form->name, 'desc'),
|
||||
],
|
||||
'errors' => $this->errors[$form->name] ?? null,
|
||||
'fields_html' => '',
|
||||
];
|
||||
|
||||
foreach ($form->fields as $field => $path) {
|
||||
$workPath = array_search($path, $this->systemPaths);
|
||||
$translatedPath = $this->translatedPaths[$workPath];
|
||||
// always true/false for user preferences display
|
||||
// otherwise null
|
||||
$userPrefsAllow = isset($this->userprefsKeys[$path])
|
||||
? ! isset($this->userprefsDisallow[$path])
|
||||
: null;
|
||||
// display input
|
||||
$forms[$key]['fields_html'] .= $this->displayFieldInput(
|
||||
$form,
|
||||
$field,
|
||||
$path,
|
||||
$workPath,
|
||||
$translatedPath,
|
||||
true,
|
||||
$userPrefsAllow,
|
||||
$jsDefault
|
||||
);
|
||||
// register JS validators for this field
|
||||
if (! isset($validators[$path])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->formDisplayTemplate->addJsValidate($translatedPath, $validators[$path], $js);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->formDisplayTemplate->display([
|
||||
'action' => $formAction,
|
||||
'has_check_page_refresh' => $hasCheckPageRefresh,
|
||||
'hidden_fields' => (array) $hiddenFields,
|
||||
'tabs' => $tabs,
|
||||
'forms' => $forms,
|
||||
'show_buttons' => $showButtons,
|
||||
'js_array' => $js,
|
||||
'js_default' => $jsDefault,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares data for input field display and outputs HTML code
|
||||
*
|
||||
* @param Form $form Form object
|
||||
* @param string $field field name as it appears in $form
|
||||
* @param string $systemPath field path, eg. Servers/1/verbose
|
||||
* @param string $workPath work path, eg. Servers/4/verbose
|
||||
* @param string $translatedPath work path changed so that it can be
|
||||
* used as XHTML id
|
||||
* @param bool $showRestoreDefault whether show "restore default" button
|
||||
* besides the input field
|
||||
* @param bool|null $userPrefsAllow whether user preferences are enabled
|
||||
* for this field (null - no support,
|
||||
* true/false - enabled/disabled)
|
||||
* @param array $jsDefault array which stores JavaScript code
|
||||
* to be displayed
|
||||
*
|
||||
* @return string|null HTML for input field
|
||||
*/
|
||||
private function displayFieldInput(
|
||||
Form $form,
|
||||
$field,
|
||||
$systemPath,
|
||||
$workPath,
|
||||
$translatedPath,
|
||||
$showRestoreDefault,
|
||||
$userPrefsAllow,
|
||||
array &$jsDefault
|
||||
) {
|
||||
$name = Descriptions::get($systemPath);
|
||||
$description = Descriptions::get($systemPath, 'desc');
|
||||
|
||||
$value = $this->configFile->get($workPath);
|
||||
$valueDefault = $this->configFile->getDefault($systemPath);
|
||||
$valueIsDefault = false;
|
||||
if ($value === null || $value === $valueDefault) {
|
||||
$value = $valueDefault;
|
||||
$valueIsDefault = true;
|
||||
}
|
||||
|
||||
$opts = [
|
||||
'doc' => $this->getDocLink($systemPath),
|
||||
'show_restore_default' => $showRestoreDefault,
|
||||
'userprefs_allow' => $userPrefsAllow,
|
||||
'userprefs_comment' => Descriptions::get($systemPath, 'cmt'),
|
||||
];
|
||||
if (isset($form->default[$systemPath])) {
|
||||
$opts['setvalue'] = (string) $form->default[$systemPath];
|
||||
}
|
||||
|
||||
if (isset($this->errors[$workPath])) {
|
||||
$opts['errors'] = $this->errors[$workPath];
|
||||
}
|
||||
|
||||
$type = '';
|
||||
switch ($form->getOptionType($field)) {
|
||||
case 'string':
|
||||
$type = 'text';
|
||||
break;
|
||||
case 'short_string':
|
||||
$type = 'short_text';
|
||||
break;
|
||||
case 'double':
|
||||
case 'integer':
|
||||
$type = 'number_text';
|
||||
break;
|
||||
case 'boolean':
|
||||
$type = 'checkbox';
|
||||
break;
|
||||
case 'select':
|
||||
$type = 'select';
|
||||
$opts['values'] = $form->getOptionValueList($form->fields[$field]);
|
||||
break;
|
||||
case 'array':
|
||||
$type = 'list';
|
||||
$value = (array) $value;
|
||||
$valueDefault = (array) $valueDefault;
|
||||
break;
|
||||
case 'group':
|
||||
// :group:end is changed to :group:end:{unique id} in Form class
|
||||
$htmlOutput = '';
|
||||
if (mb_substr($field, 7, 4) !== 'end:') {
|
||||
$htmlOutput .= $this->formDisplayTemplate->displayGroupHeader(
|
||||
mb_substr($field, 7)
|
||||
);
|
||||
} else {
|
||||
$this->formDisplayTemplate->displayGroupFooter();
|
||||
}
|
||||
|
||||
return $htmlOutput;
|
||||
|
||||
case 'NULL':
|
||||
trigger_error('Field ' . $systemPath . ' has no type', E_USER_WARNING);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// detect password fields
|
||||
if (
|
||||
$type === 'text'
|
||||
&& (mb_substr($translatedPath, -9) === '-password'
|
||||
|| mb_substr($translatedPath, -4) === 'pass'
|
||||
|| mb_substr($translatedPath, -4) === 'Pass')
|
||||
) {
|
||||
$type = 'password';
|
||||
}
|
||||
|
||||
// TrustedProxies requires changes before displaying
|
||||
if ($systemPath === 'TrustedProxies') {
|
||||
foreach ($value as $ip => &$v) {
|
||||
if (preg_match('/^-\d+$/', $ip)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$v = $ip . ': ' . $v;
|
||||
}
|
||||
}
|
||||
|
||||
$this->setComments($systemPath, $opts);
|
||||
|
||||
// send default value to form's JS
|
||||
$jsLine = '\'' . $translatedPath . '\': ';
|
||||
switch ($type) {
|
||||
case 'text':
|
||||
case 'short_text':
|
||||
case 'number_text':
|
||||
case 'password':
|
||||
$jsLine .= '\'' . Sanitize::escapeJsString($valueDefault) . '\'';
|
||||
break;
|
||||
case 'checkbox':
|
||||
$jsLine .= $valueDefault ? 'true' : 'false';
|
||||
break;
|
||||
case 'select':
|
||||
$valueDefaultJs = is_bool($valueDefault)
|
||||
? (int) $valueDefault
|
||||
: $valueDefault;
|
||||
$jsLine .= '[\'' . Sanitize::escapeJsString($valueDefaultJs) . '\']';
|
||||
break;
|
||||
case 'list':
|
||||
$val = $valueDefault;
|
||||
if (isset($val['wrapper_params'])) {
|
||||
unset($val['wrapper_params']);
|
||||
}
|
||||
|
||||
$jsLine .= '\'' . Sanitize::escapeJsString(implode("\n", $val))
|
||||
. '\'';
|
||||
break;
|
||||
}
|
||||
|
||||
$jsDefault[] = $jsLine;
|
||||
|
||||
return $this->formDisplayTemplate->displayInput(
|
||||
$translatedPath,
|
||||
$name,
|
||||
$type,
|
||||
$value,
|
||||
$description,
|
||||
$valueIsDefault,
|
||||
$opts
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays errors
|
||||
*
|
||||
* @return string|null HTML for errors
|
||||
*/
|
||||
public function displayErrors()
|
||||
{
|
||||
$this->validate();
|
||||
if (count($this->errors) === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$htmlOutput = '';
|
||||
|
||||
foreach ($this->errors as $systemPath => $errorList) {
|
||||
if (isset($this->systemPaths[$systemPath])) {
|
||||
$name = Descriptions::get($this->systemPaths[$systemPath]);
|
||||
} else {
|
||||
$name = Descriptions::get('Form_' . $systemPath);
|
||||
}
|
||||
|
||||
$htmlOutput .= $this->formDisplayTemplate->displayErrors($name, $errorList);
|
||||
}
|
||||
|
||||
return $htmlOutput;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverts erroneous fields to their default values
|
||||
*/
|
||||
public function fixErrors(): void
|
||||
{
|
||||
$this->validate();
|
||||
if (count($this->errors) === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$cf = $this->configFile;
|
||||
foreach (array_keys($this->errors) as $workPath) {
|
||||
if (! isset($this->systemPaths[$workPath])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$canonicalPath = $this->systemPaths[$workPath];
|
||||
$cf->set($workPath, $cf->getDefault($canonicalPath));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates select field and casts $value to correct type
|
||||
*
|
||||
* @param string|bool $value Current value
|
||||
* @param array $allowed List of allowed values
|
||||
*/
|
||||
private function validateSelect(&$value, array $allowed): bool
|
||||
{
|
||||
$valueCmp = is_bool($value)
|
||||
? (int) $value
|
||||
: $value;
|
||||
foreach (array_keys($allowed) as $vk) {
|
||||
// equality comparison only if both values are numeric or not numeric
|
||||
// (allows to skip 0 == 'string' equalling to true)
|
||||
// or identity (for string-string)
|
||||
if (! (($vk == $value && ! (is_numeric($valueCmp) xor is_numeric($vk))) || $vk === $value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// keep boolean value as boolean
|
||||
if (! is_bool($value)) {
|
||||
// phpcs:ignore Generic.PHP.ForbiddenFunctions
|
||||
settype($value, gettype($vk));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates and saves form data to session
|
||||
*
|
||||
* @param array|string $forms array of form names
|
||||
* @param bool $allowPartialSave allows for partial form saving on
|
||||
* failed validation
|
||||
*/
|
||||
public function save($forms, $allowPartialSave = true): bool
|
||||
{
|
||||
$result = true;
|
||||
$forms = (array) $forms;
|
||||
|
||||
$values = [];
|
||||
$toSave = [];
|
||||
$isSetupScript = $GLOBALS['config']->get('is_setup');
|
||||
if ($isSetupScript) {
|
||||
$this->loadUserprefsInfo();
|
||||
}
|
||||
|
||||
$this->errors = [];
|
||||
foreach ($forms as $formName) {
|
||||
if (! isset($this->forms[$formName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$form = $this->forms[$formName];
|
||||
// get current server id
|
||||
$changeIndex = $form->index === 0
|
||||
? $this->configFile->getServerCount() + 1
|
||||
: false;
|
||||
// grab POST values
|
||||
foreach ($form->fields as $field => $systemPath) {
|
||||
$workPath = array_search($systemPath, $this->systemPaths);
|
||||
$key = $this->translatedPaths[$workPath];
|
||||
$type = (string) $form->getOptionType($field);
|
||||
|
||||
// skip groups
|
||||
if ($type === 'group') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// ensure the value is set
|
||||
if (! isset($_POST[$key])) {
|
||||
// checkboxes aren't set by browsers if they're off
|
||||
if ($type !== 'boolean') {
|
||||
$this->errors[$form->name][] = sprintf(
|
||||
__('Missing data for %s'),
|
||||
'<i>' . Descriptions::get($systemPath) . '</i>'
|
||||
);
|
||||
$result = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
$_POST[$key] = false;
|
||||
}
|
||||
|
||||
// user preferences allow/disallow
|
||||
if ($isSetupScript && isset($this->userprefsKeys[$systemPath])) {
|
||||
if (isset($this->userprefsDisallow[$systemPath], $_POST[$key . '-userprefs-allow'])) {
|
||||
unset($this->userprefsDisallow[$systemPath]);
|
||||
} elseif (! isset($_POST[$key . '-userprefs-allow'])) {
|
||||
$this->userprefsDisallow[$systemPath] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// cast variables to correct type
|
||||
switch ($type) {
|
||||
case 'double':
|
||||
$_POST[$key] = Util::requestString($_POST[$key]);
|
||||
// phpcs:ignore Generic.PHP.ForbiddenFunctions
|
||||
settype($_POST[$key], 'float');
|
||||
break;
|
||||
case 'boolean':
|
||||
case 'integer':
|
||||
if ($_POST[$key] !== '') {
|
||||
$_POST[$key] = Util::requestString($_POST[$key]);
|
||||
// phpcs:ignore Generic.PHP.ForbiddenFunctions
|
||||
settype($_POST[$key], $type);
|
||||
}
|
||||
|
||||
break;
|
||||
case 'select':
|
||||
$successfullyValidated = $this->validateSelect(
|
||||
$_POST[$key],
|
||||
$form->getOptionValueList($systemPath)
|
||||
);
|
||||
if (! $successfullyValidated) {
|
||||
$this->errors[$workPath][] = __('Incorrect value!');
|
||||
$result = false;
|
||||
// "continue" for the $form->fields foreach-loop
|
||||
continue 2;
|
||||
}
|
||||
|
||||
break;
|
||||
case 'string':
|
||||
case 'short_string':
|
||||
$_POST[$key] = Util::requestString($_POST[$key]);
|
||||
break;
|
||||
case 'array':
|
||||
// eliminate empty values and ensure we have an array
|
||||
$postValues = is_array($_POST[$key])
|
||||
? $_POST[$key]
|
||||
: explode("\n", $_POST[$key]);
|
||||
$_POST[$key] = [];
|
||||
$this->fillPostArrayParameters($postValues, $key);
|
||||
break;
|
||||
}
|
||||
|
||||
// now we have value with proper type
|
||||
$values[$systemPath] = $_POST[$key];
|
||||
if ($changeIndex !== false) {
|
||||
$workPath = str_replace(
|
||||
'Servers/' . $form->index . '/',
|
||||
'Servers/' . $changeIndex . '/',
|
||||
$workPath
|
||||
);
|
||||
}
|
||||
|
||||
$toSave[$workPath] = $systemPath;
|
||||
}
|
||||
}
|
||||
|
||||
// save forms
|
||||
if (! $allowPartialSave && ! empty($this->errors)) {
|
||||
// don't look for non-critical errors
|
||||
$this->validate();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
foreach ($toSave as $workPath => $path) {
|
||||
// TrustedProxies requires changes before saving
|
||||
if ($path === 'TrustedProxies') {
|
||||
$proxies = [];
|
||||
$i = 0;
|
||||
foreach ($values[$path] as $value) {
|
||||
$matches = [];
|
||||
$match = preg_match('/^(.+):(?:[ ]?)(\\w+)$/', $value, $matches);
|
||||
if ($match) {
|
||||
// correct 'IP: HTTP header' pair
|
||||
$ip = trim($matches[1]);
|
||||
$proxies[$ip] = trim($matches[2]);
|
||||
} else {
|
||||
// save also incorrect values
|
||||
$proxies['-' . $i] = $value;
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
$values[$path] = $proxies;
|
||||
}
|
||||
|
||||
$this->configFile->set($workPath, $values[$path], $path);
|
||||
}
|
||||
|
||||
if ($isSetupScript) {
|
||||
$this->configFile->set(
|
||||
'UserprefsDisallow',
|
||||
array_keys($this->userprefsDisallow)
|
||||
);
|
||||
}
|
||||
|
||||
// don't look for non-critical errors
|
||||
$this->validate();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether form validation failed
|
||||
*/
|
||||
public function hasErrors(): bool
|
||||
{
|
||||
return count($this->errors) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns link to documentation
|
||||
*
|
||||
* @param string $path Path to documentation
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDocLink($path)
|
||||
{
|
||||
$test = mb_substr($path, 0, 6);
|
||||
if ($test === 'Import' || $test === 'Export') {
|
||||
return '';
|
||||
}
|
||||
|
||||
return MySQLDocumentation::getDocumentationLink(
|
||||
'config',
|
||||
'cfg_' . $this->getOptName($path),
|
||||
Sanitize::isSetup() ? '../' : './'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes path so it can be used in URLs
|
||||
*
|
||||
* @param string $path Path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getOptName($path)
|
||||
{
|
||||
return str_replace(['Servers/1/', '/'], ['Servers/', '_'], $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills out {@link userprefs_keys} and {@link userprefs_disallow}
|
||||
*/
|
||||
private function loadUserprefsInfo(): void
|
||||
{
|
||||
if ($this->userprefsKeys !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->userprefsKeys = array_flip(UserFormList::getFields());
|
||||
// read real config for user preferences display
|
||||
$userPrefsDisallow = $GLOBALS['config']->get('is_setup')
|
||||
? $this->configFile->get('UserprefsDisallow', [])
|
||||
: $GLOBALS['cfg']['UserprefsDisallow'];
|
||||
$this->userprefsDisallow = array_flip($userPrefsDisallow ?? []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets field comments and warnings based on current environment
|
||||
*
|
||||
* @param string $systemPath Path to settings
|
||||
* @param array $opts Chosen options
|
||||
*/
|
||||
private function setComments($systemPath, array &$opts): void
|
||||
{
|
||||
// RecodingEngine - mark unavailable types
|
||||
if ($systemPath === 'RecodingEngine') {
|
||||
$comment = '';
|
||||
if (! function_exists('iconv')) {
|
||||
$opts['values']['iconv'] .= ' (' . __('unavailable') . ')';
|
||||
$comment = sprintf(
|
||||
__('"%s" requires %s extension'),
|
||||
'iconv',
|
||||
'iconv'
|
||||
);
|
||||
}
|
||||
|
||||
if (! function_exists('recode_string')) {
|
||||
$opts['values']['recode'] .= ' (' . __('unavailable') . ')';
|
||||
$comment .= ($comment ? ', ' : '') . sprintf(
|
||||
__('"%s" requires %s extension'),
|
||||
'recode',
|
||||
'recode'
|
||||
);
|
||||
}
|
||||
|
||||
/* mbstring is always there thanks to polyfill */
|
||||
$opts['comment'] = $comment;
|
||||
$opts['comment_warning'] = true;
|
||||
}
|
||||
|
||||
// ZipDump, GZipDump, BZipDump - check function availability
|
||||
if ($systemPath === 'ZipDump' || $systemPath === 'GZipDump' || $systemPath === 'BZipDump') {
|
||||
$comment = '';
|
||||
$funcs = [
|
||||
'ZipDump' => [
|
||||
'zip_open',
|
||||
'gzcompress',
|
||||
],
|
||||
'GZipDump' => [
|
||||
'gzopen',
|
||||
'gzencode',
|
||||
],
|
||||
'BZipDump' => [
|
||||
'bzopen',
|
||||
'bzcompress',
|
||||
],
|
||||
];
|
||||
if (! function_exists($funcs[$systemPath][0])) {
|
||||
$comment = sprintf(
|
||||
__(
|
||||
'Compressed import will not work due to missing function %s.'
|
||||
),
|
||||
$funcs[$systemPath][0]
|
||||
);
|
||||
}
|
||||
|
||||
if (! function_exists($funcs[$systemPath][1])) {
|
||||
$comment .= ($comment ? '; ' : '') . sprintf(
|
||||
__(
|
||||
'Compressed export will not work due to missing function %s.'
|
||||
),
|
||||
$funcs[$systemPath][1]
|
||||
);
|
||||
}
|
||||
|
||||
$opts['comment'] = $comment;
|
||||
$opts['comment_warning'] = true;
|
||||
}
|
||||
|
||||
if ($GLOBALS['config']->get('is_setup')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($systemPath !== 'MaxDbList' && $systemPath !== 'MaxTableList' && $systemPath !== 'QueryHistoryMax') {
|
||||
return;
|
||||
}
|
||||
|
||||
$opts['comment'] = sprintf(
|
||||
__('maximum %s'),
|
||||
$GLOBALS['cfg'][$systemPath]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy items of an array to $_POST variable
|
||||
*
|
||||
* @param array $postValues List of parameters
|
||||
* @param string $key Array key
|
||||
*/
|
||||
private function fillPostArrayParameters(array $postValues, $key): void
|
||||
{
|
||||
foreach ($postValues as $v) {
|
||||
$v = Util::requestString($v);
|
||||
if ($v === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$_POST[$key][] = $v;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
<?php
|
||||
/**
|
||||
* Form templates
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config;
|
||||
|
||||
use PhpMyAdmin\Config;
|
||||
use PhpMyAdmin\Sanitize;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
use function array_shift;
|
||||
use function implode;
|
||||
|
||||
/**
|
||||
* PhpMyAdmin\Config\FormDisplayTemplate class
|
||||
*/
|
||||
class FormDisplayTemplate
|
||||
{
|
||||
/** @var int */
|
||||
public $group;
|
||||
|
||||
/** @var Config */
|
||||
protected $config;
|
||||
|
||||
/** @var Template */
|
||||
public $template;
|
||||
|
||||
/**
|
||||
* @param Config $config Config instance
|
||||
*/
|
||||
public function __construct(Config $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->template = new Template();
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays input field
|
||||
*
|
||||
* $opts keys:
|
||||
* o doc - (string) documentation link
|
||||
* o errors - error array
|
||||
* o setvalue - (string) shows button allowing to set predefined value
|
||||
* o show_restore_default - (boolean) whether show "restore default" button
|
||||
* o userprefs_allow - whether user preferences are enabled for this field
|
||||
* (null - no support, true/false - enabled/disabled)
|
||||
* o userprefs_comment - (string) field comment
|
||||
* o values - key - value pairs for <select> fields
|
||||
* o values_escaped - (boolean) tells whether values array is already escaped
|
||||
* (defaults to false)
|
||||
* o values_disabled - (array)list of disabled values (keys from values)
|
||||
* o comment - (string) tooltip comment
|
||||
* o comment_warning - (bool) whether this comments warns about something
|
||||
*
|
||||
* @param string $path config option path
|
||||
* @param string $name config option name
|
||||
* @param string $type type of config option
|
||||
* @param mixed $value current value
|
||||
* @param string $description verbose description
|
||||
* @param bool $valueIsDefault whether value is default
|
||||
* @param array|null $opts see above description
|
||||
*/
|
||||
public function displayInput(
|
||||
$path,
|
||||
$name,
|
||||
$type,
|
||||
$value,
|
||||
$description = '',
|
||||
$valueIsDefault = true,
|
||||
$opts = null
|
||||
): string {
|
||||
$isSetupScript = $this->config->get('is_setup');
|
||||
$optionIsDisabled = ! $isSetupScript && isset($opts['userprefs_allow']) && ! $opts['userprefs_allow'];
|
||||
$trClass = $this->group > 0 ? 'group-field group-field-' . $this->group : '';
|
||||
if (isset($opts['setvalue']) && $opts['setvalue'] === ':group') {
|
||||
unset($opts['setvalue']);
|
||||
$this->group++;
|
||||
$trClass = 'group-header-field group-header-' . $this->group;
|
||||
}
|
||||
|
||||
return $this->template->render('config/form_display/input', [
|
||||
'is_setup' => $isSetupScript,
|
||||
'allows_customization' => $opts['userprefs_allow'] ?? null,
|
||||
'path' => $path,
|
||||
'has_errors' => isset($opts['errors']) && ! empty($opts['errors']),
|
||||
'errors' => $opts['errors'] ?? [],
|
||||
'show_restore_default' => $opts['show_restore_default'] ?? null,
|
||||
'set_value' => $opts['setvalue'] ?? null,
|
||||
'tr_class' => $trClass,
|
||||
'name' => $name,
|
||||
'doc' => $opts['doc'] ?? '',
|
||||
'option_is_disabled' => $optionIsDisabled,
|
||||
'description' => $description,
|
||||
'comment' => $opts['userprefs_comment'] ?? null,
|
||||
'type' => $type,
|
||||
'value' => $value,
|
||||
'value_is_default' => $valueIsDefault,
|
||||
'select_values' => $opts['values'] ?? [],
|
||||
'select_values_disabled' => $opts['values_disabled'] ?? [],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display group header
|
||||
*
|
||||
* @param string $headerText Text of header
|
||||
*/
|
||||
public function displayGroupHeader(string $headerText): string
|
||||
{
|
||||
$this->group++;
|
||||
if ($headerText === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
$colspan = $this->config->get('is_setup') ? 3 : 2;
|
||||
|
||||
return $this->template->render('config/form_display/group_header', [
|
||||
'group' => $this->group,
|
||||
'colspan' => $colspan,
|
||||
'header_text' => $headerText,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display group footer
|
||||
*/
|
||||
public function displayGroupFooter(): void
|
||||
{
|
||||
$this->group--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends JS validation code to $js_array
|
||||
*
|
||||
* @param string $fieldId ID of field to validate
|
||||
* @param string|array $validators validators callback
|
||||
* @param array $jsArray will be updated with javascript code
|
||||
*/
|
||||
public function addJsValidate($fieldId, $validators, array &$jsArray): void
|
||||
{
|
||||
foreach ((array) $validators as $validator) {
|
||||
$validator = (array) $validator;
|
||||
$vName = array_shift($validator);
|
||||
$vArgs = [];
|
||||
foreach ($validator as $arg) {
|
||||
$vArgs[] = Sanitize::escapeJsString($arg);
|
||||
}
|
||||
|
||||
$vArgs = $vArgs ? ", ['" . implode("', '", $vArgs) . "']" : '';
|
||||
$jsArray[] = "registerFieldValidator('" . $fieldId . "', '" . $vName . "', true" . $vArgs . ')';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays error list
|
||||
*
|
||||
* @param string $name Name of item with errors
|
||||
* @param array $errorList List of errors to show
|
||||
*
|
||||
* @return string HTML for errors
|
||||
*/
|
||||
public function displayErrors($name, array $errorList): string
|
||||
{
|
||||
return $this->template->render('config/form_display/errors', [
|
||||
'name' => $name,
|
||||
'error_list' => $errorList,
|
||||
]);
|
||||
}
|
||||
|
||||
public function display(array $data): string
|
||||
{
|
||||
return $this->template->render('config/form_display/display', $data);
|
||||
}
|
||||
}
|
86
admin/phpMyAdmin/libraries/classes/Config/Forms/BaseForm.php
Normal file
86
admin/phpMyAdmin/libraries/classes/Config/Forms/BaseForm.php
Normal file
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
/**
|
||||
* Base class for preferences.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Forms;
|
||||
|
||||
use PhpMyAdmin\Config\ConfigFile;
|
||||
use PhpMyAdmin\Config\FormDisplay;
|
||||
|
||||
use function is_int;
|
||||
|
||||
/**
|
||||
* Base form for user preferences
|
||||
*/
|
||||
abstract class BaseForm extends FormDisplay
|
||||
{
|
||||
/**
|
||||
* @param ConfigFile $cf Config file instance
|
||||
* @param int|null $serverId 0 if new server, validation; >= 1 if editing a server
|
||||
*/
|
||||
final public function __construct(ConfigFile $cf, $serverId = null)
|
||||
{
|
||||
parent::__construct($cf);
|
||||
foreach (static::getForms() as $formName => $form) {
|
||||
$this->registerForm($formName, $form, $serverId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* List of available forms, each form is described as an array of fields to display.
|
||||
* Fields MUST have their counterparts in the $cfg array.
|
||||
*
|
||||
* To define form field, use the notation below:
|
||||
* $forms['Form group']['Form name'] = array('Option/path');
|
||||
*
|
||||
* You can assign default values set by special button ("set value: ..."), eg.:
|
||||
* 'Servers/1/pmadb' => 'phpmyadmin'
|
||||
*
|
||||
* To group options, use:
|
||||
* ':group:' . __('group name') // just define a group
|
||||
* or
|
||||
* 'option' => ':group' // group starting from this option
|
||||
* End group blocks with:
|
||||
* ':group:end'
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @todo This should be abstract, but that does not work in PHP 5
|
||||
*/
|
||||
public static function getForms()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of fields used in the form.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function getFields()
|
||||
{
|
||||
$names = [];
|
||||
foreach (static::getForms() as $form) {
|
||||
foreach ($form as $k => $v) {
|
||||
$names[] = is_int($k) ? $v : $k;
|
||||
}
|
||||
}
|
||||
|
||||
return $names;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns name of the form
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @todo This should be abstract, but that does not work in PHP 5
|
||||
*/
|
||||
public static function getName()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
155
admin/phpMyAdmin/libraries/classes/Config/Forms/BaseFormList.php
Normal file
155
admin/phpMyAdmin/libraries/classes/Config/Forms/BaseFormList.php
Normal file
|
@ -0,0 +1,155 @@
|
|||
<?php
|
||||
/**
|
||||
* User preferences form
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Forms;
|
||||
|
||||
use PhpMyAdmin\Config\ConfigFile;
|
||||
|
||||
use function array_merge;
|
||||
use function class_exists;
|
||||
use function in_array;
|
||||
|
||||
class BaseFormList
|
||||
{
|
||||
/**
|
||||
* List of all forms
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected static $all = [];
|
||||
|
||||
/** @var string */
|
||||
protected static $ns = 'PhpMyAdmin\\Config\\Forms\\';
|
||||
|
||||
/** @var array */
|
||||
private $forms;
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public static function getAll()
|
||||
{
|
||||
return static::$all;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name Name
|
||||
*/
|
||||
public static function isValid($name): bool
|
||||
{
|
||||
return in_array($name, static::$all);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name Name
|
||||
*
|
||||
* @return string|null
|
||||
* @psalm-return class-string<BaseForm>|null
|
||||
*/
|
||||
public static function get($name)
|
||||
{
|
||||
if (static::isValid($name)) {
|
||||
/** @var class-string<BaseForm> $class */
|
||||
$class = static::$ns . $name . 'Form';
|
||||
|
||||
return $class;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ConfigFile $cf Config file instance
|
||||
*/
|
||||
final public function __construct(ConfigFile $cf)
|
||||
{
|
||||
$this->forms = [];
|
||||
foreach (static::$all as $form) {
|
||||
$class = (string) static::get($form);
|
||||
if (! class_exists($class)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->forms[] = new $class($cf);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes forms, returns true on successful save
|
||||
*
|
||||
* @param bool $allowPartialSave allows for partial form saving
|
||||
* on failed validation
|
||||
* @param bool $checkFormSubmit whether check for $_POST['submit_save']
|
||||
*/
|
||||
public function process($allowPartialSave = true, $checkFormSubmit = true): bool
|
||||
{
|
||||
$ret = true;
|
||||
foreach ($this->forms as $form) {
|
||||
$ret = $ret && $form->process($allowPartialSave, $checkFormSubmit);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays errors
|
||||
*
|
||||
* @return string HTML for errors
|
||||
*/
|
||||
public function displayErrors()
|
||||
{
|
||||
$ret = '';
|
||||
foreach ($this->forms as $form) {
|
||||
$ret .= $form->displayErrors();
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverts erroneous fields to their default values
|
||||
*/
|
||||
public function fixErrors(): void
|
||||
{
|
||||
foreach ($this->forms as $form) {
|
||||
$form->fixErrors();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether form validation failed
|
||||
*/
|
||||
public function hasErrors(): bool
|
||||
{
|
||||
$ret = false;
|
||||
foreach ($this->forms as $form) {
|
||||
$ret = $ret || $form->hasErrors();
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of fields used in the form.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function getFields()
|
||||
{
|
||||
$names = [];
|
||||
foreach (static::$all as $form) {
|
||||
$class = (string) static::get($form);
|
||||
if (! class_exists($class)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$names = array_merge($names, $class::getFields());
|
||||
}
|
||||
|
||||
return $names;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
/**
|
||||
* User preferences form
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Forms\Page;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseForm;
|
||||
use PhpMyAdmin\Config\Forms\User\MainForm;
|
||||
|
||||
class BrowseForm extends BaseForm
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getForms()
|
||||
{
|
||||
return [
|
||||
'Browse' => MainForm::getForms()['Browse'],
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
/**
|
||||
* User preferences form
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Forms\Page;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseForm;
|
||||
use PhpMyAdmin\Config\Forms\User\MainForm;
|
||||
|
||||
class DbStructureForm extends BaseForm
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getForms()
|
||||
{
|
||||
return [
|
||||
'DbStructure' => MainForm::getForms()['DbStructure'],
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
/**
|
||||
* User preferences form
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Forms\Page;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseForm;
|
||||
use PhpMyAdmin\Config\Forms\User\FeaturesForm;
|
||||
use PhpMyAdmin\Config\Forms\User\MainForm;
|
||||
|
||||
class EditForm extends BaseForm
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getForms()
|
||||
{
|
||||
return [
|
||||
'Edit' => MainForm::getForms()['Edit'],
|
||||
'Text_fields' => FeaturesForm::getForms()['Text_fields'],
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
/**
|
||||
* User preferences form
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Forms\Page;
|
||||
|
||||
class ExportForm extends \PhpMyAdmin\Config\Forms\User\ExportForm
|
||||
{
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
/**
|
||||
* User preferences form
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Forms\Page;
|
||||
|
||||
class ImportForm extends \PhpMyAdmin\Config\Forms\User\ImportForm
|
||||
{
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
/**
|
||||
* User preferences form
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Forms\Page;
|
||||
|
||||
class NaviForm extends \PhpMyAdmin\Config\Forms\User\NaviForm
|
||||
{
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
/**
|
||||
* Page preferences form
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Forms\Page;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseFormList;
|
||||
|
||||
class PageFormList extends BaseFormList
|
||||
{
|
||||
/** @var string[] */
|
||||
protected static $all = [
|
||||
'Browse',
|
||||
'DbStructure',
|
||||
'Edit',
|
||||
'Export',
|
||||
'Import',
|
||||
'Navi',
|
||||
'Sql',
|
||||
'TableStructure',
|
||||
];
|
||||
/** @var string */
|
||||
protected static $ns = 'PhpMyAdmin\\Config\\Forms\\Page\\';
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
/**
|
||||
* User preferences form
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Forms\Page;
|
||||
|
||||
class SqlForm extends \PhpMyAdmin\Config\Forms\User\SqlForm
|
||||
{
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
/**
|
||||
* User preferences form
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Forms\Page;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseForm;
|
||||
use PhpMyAdmin\Config\Forms\User\MainForm;
|
||||
|
||||
class TableStructureForm extends BaseForm
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getForms()
|
||||
{
|
||||
return [
|
||||
'TableStructure' => MainForm::getForms()['TableStructure'],
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
/**
|
||||
* User preferences form
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Forms\Setup;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseForm;
|
||||
|
||||
class ConfigForm extends BaseForm
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getForms()
|
||||
{
|
||||
return [
|
||||
'Config' => [
|
||||
'DefaultLang',
|
||||
'ServerDefault',
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
/**
|
||||
* User preferences form
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Forms\Setup;
|
||||
|
||||
class ExportForm extends \PhpMyAdmin\Config\Forms\User\ExportForm
|
||||
{
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
/**
|
||||
* User preferences form
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Forms\Setup;
|
||||
|
||||
use function array_diff;
|
||||
|
||||
class FeaturesForm extends \PhpMyAdmin\Config\Forms\User\FeaturesForm
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getForms()
|
||||
{
|
||||
// phpcs:disable Squiz.Arrays.ArrayDeclaration.KeySpecified,Squiz.Arrays.ArrayDeclaration.NoKeySpecified
|
||||
$result = parent::getForms();
|
||||
/* Remove only_db/hide_db, we have proper Server form in setup */
|
||||
$result['Databases'] = array_diff(
|
||||
$result['Databases'],
|
||||
[
|
||||
'Servers/1/only_db',
|
||||
'Servers/1/hide_db',
|
||||
]
|
||||
);
|
||||
/* Following are not available to user */
|
||||
$result['Import_export'] = [
|
||||
'UploadDir',
|
||||
'SaveDir',
|
||||
'RecodingEngine' => ':group',
|
||||
'IconvExtraParams',
|
||||
':group:end',
|
||||
'ZipDump',
|
||||
'GZipDump',
|
||||
'BZipDump',
|
||||
'CompressOnFly',
|
||||
];
|
||||
$result['Security'] = [
|
||||
'blowfish_secret',
|
||||
'CheckConfigurationPermissions',
|
||||
'TrustedProxies',
|
||||
'AllowUserDropDatabase',
|
||||
'AllowArbitraryServer',
|
||||
'ArbitraryServerRegexp',
|
||||
'LoginCookieRecall',
|
||||
'LoginCookieStore',
|
||||
'LoginCookieDeleteAll',
|
||||
'CaptchaLoginPublicKey',
|
||||
'CaptchaLoginPrivateKey',
|
||||
'CaptchaSiteVerifyURL',
|
||||
];
|
||||
$result['Developer'] = [
|
||||
'UserprefsDeveloperTab',
|
||||
'DBG/sql',
|
||||
];
|
||||
$result['Other_core_settings'] = [
|
||||
'OBGzip',
|
||||
'PersistentConnections',
|
||||
'ExecTimeLimit',
|
||||
'MemoryLimit',
|
||||
'UseDbSearch',
|
||||
'ProxyUrl',
|
||||
'ProxyUser',
|
||||
'ProxyPass',
|
||||
'AllowThirdPartyFraming',
|
||||
'ZeroConf',
|
||||
];
|
||||
|
||||
return $result;
|
||||
|
||||
// phpcs:enable
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
/**
|
||||
* User preferences form
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Forms\Setup;
|
||||
|
||||
class ImportForm extends \PhpMyAdmin\Config\Forms\User\ImportForm
|
||||
{
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
/**
|
||||
* User preferences form
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Forms\Setup;
|
||||
|
||||
class MainForm extends \PhpMyAdmin\Config\Forms\User\MainForm
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getForms()
|
||||
{
|
||||
$result = parent::getForms();
|
||||
/* Following are not available to user */
|
||||
$result['Startup'][] = 'ShowPhpInfo';
|
||||
$result['Startup'][] = 'ShowChgPassword';
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
/**
|
||||
* User preferences form
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Forms\Setup;
|
||||
|
||||
class NaviForm extends \PhpMyAdmin\Config\Forms\User\NaviForm
|
||||
{
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
<?php
|
||||
/**
|
||||
* User preferences form
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Forms\Setup;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseForm;
|
||||
|
||||
use function __;
|
||||
|
||||
class ServersForm extends BaseForm
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getForms()
|
||||
{
|
||||
// phpcs:disable Squiz.Arrays.ArrayDeclaration.KeySpecified,Squiz.Arrays.ArrayDeclaration.NoKeySpecified
|
||||
return [
|
||||
'Server' => [
|
||||
'Servers' => [
|
||||
1 => [
|
||||
'verbose',
|
||||
'host',
|
||||
'port',
|
||||
'socket',
|
||||
'ssl',
|
||||
'compress',
|
||||
],
|
||||
],
|
||||
],
|
||||
'Server_auth' => [
|
||||
'Servers' => [
|
||||
1 => [
|
||||
'auth_type',
|
||||
':group:' . __('Config authentication'),
|
||||
'user',
|
||||
'password',
|
||||
':group:end',
|
||||
':group:' . __('HTTP authentication'),
|
||||
'auth_http_realm',
|
||||
':group:end',
|
||||
':group:' . __('Signon authentication'),
|
||||
'SignonSession',
|
||||
'SignonURL',
|
||||
'LogoutURL',
|
||||
],
|
||||
],
|
||||
],
|
||||
'Server_config' => [
|
||||
'Servers' => [
|
||||
1 => [
|
||||
'only_db',
|
||||
'hide_db',
|
||||
'AllowRoot',
|
||||
'AllowNoPassword',
|
||||
'DisableIS',
|
||||
'AllowDeny/order',
|
||||
'AllowDeny/rules',
|
||||
'SessionTimeZone',
|
||||
],
|
||||
],
|
||||
],
|
||||
'Server_pmadb' => [
|
||||
'Servers' => [
|
||||
1 => [
|
||||
'pmadb' => 'phpmyadmin',
|
||||
'controlhost',
|
||||
'controlport',
|
||||
'controluser',
|
||||
'controlpass',
|
||||
'bookmarktable' => 'pma__bookmark',
|
||||
'relation' => 'pma__relation',
|
||||
'userconfig' => 'pma__userconfig',
|
||||
'users' => 'pma__users',
|
||||
'usergroups' => 'pma__usergroups',
|
||||
'navigationhiding' => 'pma__navigationhiding',
|
||||
'table_info' => 'pma__table_info',
|
||||
'column_info' => 'pma__column_info',
|
||||
'history' => 'pma__history',
|
||||
'recent' => 'pma__recent',
|
||||
'favorite' => 'pma__favorite',
|
||||
'table_uiprefs' => 'pma__table_uiprefs',
|
||||
'tracking' => 'pma__tracking',
|
||||
'table_coords' => 'pma__table_coords',
|
||||
'pdf_pages' => 'pma__pdf_pages',
|
||||
'savedsearches' => 'pma__savedsearches',
|
||||
'central_columns' => 'pma__central_columns',
|
||||
'designer_settings' => 'pma__designer_settings',
|
||||
'export_templates' => 'pma__export_templates',
|
||||
'MaxTableUiprefs' => 100,
|
||||
],
|
||||
],
|
||||
],
|
||||
'Server_tracking' => [
|
||||
'Servers' => [
|
||||
1 => [
|
||||
'tracking_version_auto_create',
|
||||
'tracking_default_statements',
|
||||
'tracking_add_drop_view',
|
||||
'tracking_add_drop_table',
|
||||
'tracking_add_drop_database',
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
// phpcs:enable
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
/**
|
||||
* Setup preferences form
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Forms\Setup;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseFormList;
|
||||
|
||||
class SetupFormList extends BaseFormList
|
||||
{
|
||||
/** @var string[] */
|
||||
protected static $all = [
|
||||
'Config',
|
||||
'Export',
|
||||
'Features',
|
||||
'Import',
|
||||
'Main',
|
||||
'Navi',
|
||||
'Servers',
|
||||
'Sql',
|
||||
];
|
||||
/** @var string */
|
||||
protected static $ns = 'PhpMyAdmin\\Config\\Forms\\Setup\\';
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
/**
|
||||
* User preferences form
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Forms\Setup;
|
||||
|
||||
class SqlForm extends \PhpMyAdmin\Config\Forms\User\SqlForm
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getForms()
|
||||
{
|
||||
$result = parent::getForms();
|
||||
/* Following are not available to user */
|
||||
$result['Sql_queries'][] = 'QueryHistoryDB';
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
<?php
|
||||
/**
|
||||
* User preferences form
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Forms\User;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseForm;
|
||||
|
||||
use function __;
|
||||
|
||||
class ExportForm extends BaseForm
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getForms()
|
||||
{
|
||||
// phpcs:disable Squiz.Arrays.ArrayDeclaration.KeySpecified,Squiz.Arrays.ArrayDeclaration.NoKeySpecified
|
||||
return [
|
||||
'Export_defaults' => [
|
||||
'Export/method',
|
||||
':group:' . __('Quick'),
|
||||
'Export/quick_export_onserver',
|
||||
'Export/quick_export_onserver_overwrite',
|
||||
':group:end',
|
||||
':group:' . __('Custom'),
|
||||
'Export/format',
|
||||
'Export/compression',
|
||||
'Export/charset',
|
||||
'Export/lock_tables',
|
||||
'Export/as_separate_files',
|
||||
'Export/asfile' => ':group',
|
||||
'Export/onserver',
|
||||
'Export/onserver_overwrite',
|
||||
':group:end',
|
||||
'Export/file_template_table',
|
||||
'Export/file_template_database',
|
||||
'Export/file_template_server',
|
||||
],
|
||||
'Sql' => [
|
||||
'Export/sql_include_comments' => ':group',
|
||||
'Export/sql_dates',
|
||||
'Export/sql_relation',
|
||||
'Export/sql_mime',
|
||||
':group:end',
|
||||
'Export/sql_use_transaction',
|
||||
'Export/sql_disable_fk',
|
||||
'Export/sql_views_as_tables',
|
||||
'Export/sql_metadata',
|
||||
'Export/sql_compatibility',
|
||||
'Export/sql_structure_or_data',
|
||||
':group:' . __('Structure'),
|
||||
'Export/sql_drop_database',
|
||||
'Export/sql_create_database',
|
||||
'Export/sql_drop_table',
|
||||
'Export/sql_create_table' => ':group',
|
||||
'Export/sql_if_not_exists',
|
||||
'Export/sql_auto_increment',
|
||||
':group:end',
|
||||
'Export/sql_create_view' => ':group',
|
||||
'Export/sql_view_current_user',
|
||||
'Export/sql_or_replace_view',
|
||||
':group:end',
|
||||
'Export/sql_procedure_function',
|
||||
'Export/sql_create_trigger',
|
||||
'Export/sql_backquotes',
|
||||
':group:end',
|
||||
':group:' . __('Data'),
|
||||
'Export/sql_delayed',
|
||||
'Export/sql_ignore',
|
||||
'Export/sql_type',
|
||||
'Export/sql_insert_syntax',
|
||||
'Export/sql_max_query_size',
|
||||
'Export/sql_hex_for_binary',
|
||||
'Export/sql_utc_time',
|
||||
],
|
||||
'CodeGen' => ['Export/codegen_format'],
|
||||
'Csv' => [
|
||||
':group:' . __('CSV'),
|
||||
'Export/csv_separator',
|
||||
'Export/csv_enclosed',
|
||||
'Export/csv_escaped',
|
||||
'Export/csv_terminated',
|
||||
'Export/csv_null',
|
||||
'Export/csv_removeCRLF',
|
||||
'Export/csv_columns',
|
||||
':group:end',
|
||||
':group:' . __('CSV for MS Excel'),
|
||||
'Export/excel_null',
|
||||
'Export/excel_removeCRLF',
|
||||
'Export/excel_columns',
|
||||
'Export/excel_edition',
|
||||
],
|
||||
'Latex' => [
|
||||
'Export/latex_caption',
|
||||
'Export/latex_structure_or_data',
|
||||
':group:' . __('Structure'),
|
||||
'Export/latex_structure_caption',
|
||||
'Export/latex_structure_continued_caption',
|
||||
'Export/latex_structure_label',
|
||||
'Export/latex_relation',
|
||||
'Export/latex_comments',
|
||||
'Export/latex_mime',
|
||||
':group:end',
|
||||
':group:' . __('Data'),
|
||||
'Export/latex_columns',
|
||||
'Export/latex_data_caption',
|
||||
'Export/latex_data_continued_caption',
|
||||
'Export/latex_data_label',
|
||||
'Export/latex_null',
|
||||
],
|
||||
'Microsoft_Office' => [
|
||||
':group:' . __('Microsoft Word 2000'),
|
||||
'Export/htmlword_structure_or_data',
|
||||
'Export/htmlword_null',
|
||||
'Export/htmlword_columns',
|
||||
],
|
||||
'Open_Document' => [
|
||||
':group:' . __('OpenDocument Spreadsheet'),
|
||||
'Export/ods_columns',
|
||||
'Export/ods_null',
|
||||
':group:end',
|
||||
':group:' . __('OpenDocument Text'),
|
||||
'Export/odt_structure_or_data',
|
||||
':group:' . __('Structure'),
|
||||
'Export/odt_relation',
|
||||
'Export/odt_comments',
|
||||
'Export/odt_mime',
|
||||
':group:end',
|
||||
':group:' . __('Data'),
|
||||
'Export/odt_columns',
|
||||
'Export/odt_null',
|
||||
],
|
||||
'Texy' => [
|
||||
'Export/texytext_structure_or_data',
|
||||
':group:' . __('Data'),
|
||||
'Export/texytext_null',
|
||||
'Export/texytext_columns',
|
||||
],
|
||||
];
|
||||
|
||||
// phpcs:enable
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function getName()
|
||||
{
|
||||
return __('Export');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
/**
|
||||
* User preferences form
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Forms\User;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseForm;
|
||||
|
||||
use function __;
|
||||
|
||||
class FeaturesForm extends BaseForm
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getForms()
|
||||
{
|
||||
$result = [
|
||||
'General' => [
|
||||
'VersionCheck',
|
||||
'NaturalOrder',
|
||||
'InitialSlidersState',
|
||||
'LoginCookieValidity',
|
||||
'SkipLockedTables',
|
||||
'DisableMultiTableMaintenance',
|
||||
'ShowHint',
|
||||
'SendErrorReports',
|
||||
'ConsoleEnterExecutes',
|
||||
'DisableShortcutKeys',
|
||||
'FirstDayOfCalendar',
|
||||
],
|
||||
'Databases' => [
|
||||
'Servers/1/only_db', // saves to Server/only_db
|
||||
'Servers/1/hide_db', // saves to Server/hide_db
|
||||
'MaxDbList',
|
||||
'MaxTableList',
|
||||
'DefaultConnectionCollation',
|
||||
],
|
||||
'Text_fields' => [
|
||||
'CharEditing',
|
||||
'MinSizeForInputField',
|
||||
'MaxSizeForInputField',
|
||||
'CharTextareaCols',
|
||||
'CharTextareaRows',
|
||||
'TextareaCols',
|
||||
'TextareaRows',
|
||||
'LongtextDoubleTextarea',
|
||||
],
|
||||
'Page_titles' => [
|
||||
'TitleDefault',
|
||||
'TitleTable',
|
||||
'TitleDatabase',
|
||||
'TitleServer',
|
||||
],
|
||||
'Warnings' => [
|
||||
'PmaNoRelation_DisableWarning',
|
||||
'SuhosinDisableWarning',
|
||||
'LoginCookieValidityDisableWarning',
|
||||
'ReservedWordDisableWarning',
|
||||
],
|
||||
'Console' => [
|
||||
'Console/Mode',
|
||||
'Console/StartHistory',
|
||||
'Console/AlwaysExpand',
|
||||
'Console/CurrentQuery',
|
||||
'Console/EnterExecutes',
|
||||
'Console/DarkTheme',
|
||||
'Console/Height',
|
||||
'Console/GroupQueries',
|
||||
'Console/OrderBy',
|
||||
'Console/Order',
|
||||
],
|
||||
];
|
||||
// skip Developer form if no setting is available
|
||||
if ($GLOBALS['cfg']['UserprefsDeveloperTab']) {
|
||||
$result['Developer'] = ['DBG/sql'];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function getName()
|
||||
{
|
||||
return __('Features');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
/**
|
||||
* User preferences form
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Forms\User;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseForm;
|
||||
|
||||
use function __;
|
||||
|
||||
class ImportForm extends BaseForm
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getForms()
|
||||
{
|
||||
return [
|
||||
'Import_defaults' => [
|
||||
'Import/format',
|
||||
'Import/charset',
|
||||
'Import/allow_interrupt',
|
||||
'Import/skip_queries',
|
||||
'enable_drag_drop_import',
|
||||
],
|
||||
'Sql' => [
|
||||
'Import/sql_compatibility',
|
||||
'Import/sql_no_auto_value_on_zero',
|
||||
'Import/sql_read_as_multibytes',
|
||||
],
|
||||
'Csv' => [
|
||||
':group:' . __('CSV'),
|
||||
'Import/csv_replace',
|
||||
'Import/csv_ignore',
|
||||
'Import/csv_terminated',
|
||||
'Import/csv_enclosed',
|
||||
'Import/csv_escaped',
|
||||
'Import/csv_col_names',
|
||||
':group:end',
|
||||
':group:' . __('CSV using LOAD DATA'),
|
||||
'Import/ldi_replace',
|
||||
'Import/ldi_ignore',
|
||||
'Import/ldi_terminated',
|
||||
'Import/ldi_enclosed',
|
||||
'Import/ldi_escaped',
|
||||
'Import/ldi_local_option',
|
||||
],
|
||||
'Open_Document' => [
|
||||
':group:' . __('OpenDocument Spreadsheet'),
|
||||
'Import/ods_col_names',
|
||||
'Import/ods_empty_rows',
|
||||
'Import/ods_recognize_percentages',
|
||||
'Import/ods_recognize_currency',
|
||||
],
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function getName()
|
||||
{
|
||||
return __('Import');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
/**
|
||||
* User preferences form
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Forms\User;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseForm;
|
||||
|
||||
use function __;
|
||||
|
||||
class MainForm extends BaseForm
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getForms()
|
||||
{
|
||||
return [
|
||||
'Startup' => [
|
||||
'ShowCreateDb',
|
||||
'ShowStats',
|
||||
'ShowServerInfo',
|
||||
],
|
||||
'DbStructure' => [
|
||||
'ShowDbStructureCharset',
|
||||
'ShowDbStructureComment',
|
||||
'ShowDbStructureCreation',
|
||||
'ShowDbStructureLastUpdate',
|
||||
'ShowDbStructureLastCheck',
|
||||
],
|
||||
'TableStructure' => [
|
||||
'HideStructureActions',
|
||||
'ShowColumnComments',
|
||||
':group:' . __('Default transformations'),
|
||||
'DefaultTransformations/Hex',
|
||||
'DefaultTransformations/Substring',
|
||||
'DefaultTransformations/Bool2Text',
|
||||
'DefaultTransformations/External',
|
||||
'DefaultTransformations/PreApPend',
|
||||
'DefaultTransformations/DateFormat',
|
||||
'DefaultTransformations/Inline',
|
||||
'DefaultTransformations/TextImageLink',
|
||||
'DefaultTransformations/TextLink',
|
||||
':group:end',
|
||||
],
|
||||
'Browse' => [
|
||||
'TableNavigationLinksMode',
|
||||
'ActionLinksMode',
|
||||
'ShowAll',
|
||||
'MaxRows',
|
||||
'Order',
|
||||
'BrowsePointerEnable',
|
||||
'BrowseMarkerEnable',
|
||||
'GridEditing',
|
||||
'SaveCellsAtOnce',
|
||||
'RepeatCells',
|
||||
'LimitChars',
|
||||
'RowActionLinks',
|
||||
'RowActionLinksWithoutUnique',
|
||||
'TablePrimaryKeyOrder',
|
||||
'RememberSorting',
|
||||
'RelationalDisplay',
|
||||
],
|
||||
'Edit' => [
|
||||
'ProtectBinary',
|
||||
'ShowFunctionFields',
|
||||
'ShowFieldTypesInDataEditView',
|
||||
'InsertRows',
|
||||
'ForeignKeyDropdownOrder',
|
||||
'ForeignKeyMaxLimit',
|
||||
],
|
||||
'Tabs' => [
|
||||
'TabsMode',
|
||||
'DefaultTabServer',
|
||||
'DefaultTabDatabase',
|
||||
'DefaultTabTable',
|
||||
],
|
||||
'DisplayRelationalSchema' => ['PDFDefaultPageSize'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function getName()
|
||||
{
|
||||
return __('Main panel');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
/**
|
||||
* User preferences form
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Forms\User;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseForm;
|
||||
|
||||
use function __;
|
||||
|
||||
class NaviForm extends BaseForm
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getForms()
|
||||
{
|
||||
return [
|
||||
'Navi_panel' => [
|
||||
'ShowDatabasesNavigationAsTree',
|
||||
'NavigationLinkWithMainPanel',
|
||||
'NavigationDisplayLogo',
|
||||
'NavigationLogoLink',
|
||||
'NavigationLogoLinkWindow',
|
||||
'NavigationTreePointerEnable',
|
||||
'FirstLevelNavigationItems',
|
||||
'NavigationTreeDisplayItemFilterMinimum',
|
||||
'NumRecentTables',
|
||||
'NumFavoriteTables',
|
||||
'NavigationWidth',
|
||||
],
|
||||
'Navi_tree' => [
|
||||
'MaxNavigationItems',
|
||||
'NavigationTreeEnableGrouping',
|
||||
'NavigationTreeEnableExpansion',
|
||||
'NavigationTreeShowTables',
|
||||
'NavigationTreeShowViews',
|
||||
'NavigationTreeShowFunctions',
|
||||
'NavigationTreeShowProcedures',
|
||||
'NavigationTreeShowEvents',
|
||||
'NavigationTreeAutoexpandSingleDb',
|
||||
],
|
||||
'Navi_servers' => [
|
||||
'NavigationDisplayServers',
|
||||
'DisplayServersList',
|
||||
],
|
||||
'Navi_databases' => [
|
||||
'NavigationTreeDisplayDbFilterMinimum',
|
||||
'NavigationTreeDbSeparator',
|
||||
],
|
||||
'Navi_tables' => [
|
||||
'NavigationTreeDefaultTabTable',
|
||||
'NavigationTreeDefaultTabTable2',
|
||||
'NavigationTreeTableSeparator',
|
||||
'NavigationTreeTableLevel',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function getName()
|
||||
{
|
||||
return __('Navigation panel');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
/**
|
||||
* User preferences form
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Forms\User;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseForm;
|
||||
|
||||
use function __;
|
||||
|
||||
class SqlForm extends BaseForm
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getForms()
|
||||
{
|
||||
return [
|
||||
'Sql_queries' => [
|
||||
'ShowSQL',
|
||||
'Confirm',
|
||||
'QueryHistoryMax',
|
||||
'IgnoreMultiSubmitErrors',
|
||||
'MaxCharactersInDisplayedSQL',
|
||||
'RetainQueryBox',
|
||||
'CodemirrorEnable',
|
||||
'LintEnable',
|
||||
'EnableAutocompleteForTablesAndColumns',
|
||||
'DefaultForeignKeyChecks',
|
||||
],
|
||||
'Sql_box' => [
|
||||
'SQLQuery/Edit',
|
||||
'SQLQuery/Explain',
|
||||
'SQLQuery/ShowAsPHP',
|
||||
'SQLQuery/Refresh',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function getName()
|
||||
{
|
||||
return __('SQL queries');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
/**
|
||||
* User preferences form
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Forms\User;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseFormList;
|
||||
|
||||
class UserFormList extends BaseFormList
|
||||
{
|
||||
/** @var string[] */
|
||||
protected static $all = [
|
||||
'Features',
|
||||
'Sql',
|
||||
'Navi',
|
||||
'Main',
|
||||
'Export',
|
||||
'Import',
|
||||
];
|
||||
/** @var string */
|
||||
protected static $ns = 'PhpMyAdmin\\Config\\Forms\\User\\';
|
||||
}
|
193
admin/phpMyAdmin/libraries/classes/Config/PageSettings.php
Normal file
193
admin/phpMyAdmin/libraries/classes/Config/PageSettings.php
Normal file
|
@ -0,0 +1,193 @@
|
|||
<?php
|
||||
/**
|
||||
* Page-related settings
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\Page\PageFormList;
|
||||
use PhpMyAdmin\Core;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\UserPreferences;
|
||||
|
||||
use function __;
|
||||
|
||||
/**
|
||||
* Page-related settings
|
||||
*/
|
||||
class PageSettings
|
||||
{
|
||||
/**
|
||||
* Contains id of the form element
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $elemId = 'page_settings_modal';
|
||||
|
||||
/**
|
||||
* Name of the group to show
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $groupName = '';
|
||||
|
||||
/**
|
||||
* Contains HTML of errors
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $errorHTML = '';
|
||||
|
||||
/**
|
||||
* Contains HTML of settings
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $HTML = '';
|
||||
|
||||
/** @var UserPreferences */
|
||||
private $userPreferences;
|
||||
|
||||
/**
|
||||
* @param string $formGroupName The name of config form group to display
|
||||
* @param string $elemId Id of the div containing settings
|
||||
*/
|
||||
public function __construct($formGroupName, $elemId = null)
|
||||
{
|
||||
$this->userPreferences = new UserPreferences();
|
||||
|
||||
$formClass = PageFormList::get($formGroupName);
|
||||
if ($formClass === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($_REQUEST['printview']) && $_REQUEST['printview'] == '1') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! empty($elemId)) {
|
||||
$this->elemId = $elemId;
|
||||
}
|
||||
|
||||
$this->groupName = $formGroupName;
|
||||
|
||||
$cf = new ConfigFile($GLOBALS['config']->baseSettings);
|
||||
$this->userPreferences->pageInit($cf);
|
||||
|
||||
$formDisplay = new $formClass($cf);
|
||||
|
||||
// Process form
|
||||
$error = null;
|
||||
if (isset($_POST['submit_save']) && $_POST['submit_save'] == $formGroupName) {
|
||||
$this->processPageSettings($formDisplay, $cf, $error);
|
||||
}
|
||||
|
||||
// Display forms
|
||||
$this->HTML = $this->getPageSettingsDisplay($formDisplay, $error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process response to form
|
||||
*
|
||||
* @param FormDisplay $formDisplay Form
|
||||
* @param ConfigFile $cf Configuration file
|
||||
* @param Message|null $error Error message
|
||||
*/
|
||||
private function processPageSettings(&$formDisplay, &$cf, &$error): void
|
||||
{
|
||||
if (! $formDisplay->process(false) || $formDisplay->hasErrors()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// save settings
|
||||
$result = $this->userPreferences->save($cf->getConfigArray());
|
||||
if ($result === true) {
|
||||
// reload page
|
||||
$response = ResponseRenderer::getInstance();
|
||||
Core::sendHeaderLocation(
|
||||
$response->getFooter()->getSelfUrl()
|
||||
);
|
||||
exit;
|
||||
}
|
||||
|
||||
$error = $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store errors in _errorHTML
|
||||
*
|
||||
* @param FormDisplay $formDisplay Form
|
||||
* @param Message|null $error Error message
|
||||
*/
|
||||
private function storeError(&$formDisplay, &$error): void
|
||||
{
|
||||
$retval = '';
|
||||
if ($error) {
|
||||
$retval .= $error->getDisplay();
|
||||
}
|
||||
|
||||
if ($formDisplay->hasErrors()) {
|
||||
// form has errors
|
||||
$retval .= '<div class="alert alert-danger config-form" role="alert">'
|
||||
. '<b>' . __('Cannot save settings, submitted configuration form contains errors!') . '</b>'
|
||||
. $formDisplay->displayErrors()
|
||||
. '</div>';
|
||||
}
|
||||
|
||||
$this->errorHTML = $retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display page-related settings
|
||||
*
|
||||
* @param FormDisplay $formDisplay Form
|
||||
* @param Message $error Error message
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getPageSettingsDisplay(&$formDisplay, &$error)
|
||||
{
|
||||
$response = ResponseRenderer::getInstance();
|
||||
|
||||
$retval = '';
|
||||
|
||||
$this->storeError($formDisplay, $error);
|
||||
|
||||
$retval .= '<div id="' . $this->elemId . '">';
|
||||
$retval .= '<div class="page_settings">';
|
||||
$retval .= $formDisplay->getDisplay(
|
||||
false,
|
||||
$response->getFooter()->getSelfUrl(),
|
||||
[
|
||||
'submit_save' => $this->groupName,
|
||||
]
|
||||
);
|
||||
$retval .= '</div>';
|
||||
$retval .= '</div>';
|
||||
|
||||
return $retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get HTML output
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getHTML()
|
||||
{
|
||||
return $this->HTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get error HTML output
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getErrorHTML()
|
||||
{
|
||||
return $this->errorHTML;
|
||||
}
|
||||
}
|
522
admin/phpMyAdmin/libraries/classes/Config/ServerConfigChecks.php
Normal file
522
admin/phpMyAdmin/libraries/classes/Config/ServerConfigChecks.php
Normal file
|
@ -0,0 +1,522 @@
|
|||
<?php
|
||||
/**
|
||||
* Server config checks management
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config;
|
||||
|
||||
use PhpMyAdmin\Core;
|
||||
use PhpMyAdmin\Sanitize;
|
||||
use PhpMyAdmin\Setup\Index as SetupIndex;
|
||||
use PhpMyAdmin\Url;
|
||||
|
||||
use function __;
|
||||
use function function_exists;
|
||||
use function htmlspecialchars;
|
||||
use function ini_get;
|
||||
use function is_string;
|
||||
use function mb_strlen;
|
||||
use function sodium_crypto_secretbox_keygen;
|
||||
use function sprintf;
|
||||
|
||||
use const SODIUM_CRYPTO_SECRETBOX_KEYBYTES;
|
||||
|
||||
/**
|
||||
* Performs various compatibility, security and consistency checks on current config
|
||||
*
|
||||
* Outputs results to message list, must be called between SetupIndex::messagesBegin()
|
||||
* and SetupIndex::messagesEnd()
|
||||
*/
|
||||
class ServerConfigChecks
|
||||
{
|
||||
/** @var ConfigFile configurations being checked */
|
||||
protected $cfg;
|
||||
|
||||
/**
|
||||
* @param ConfigFile $cfg Configuration
|
||||
*/
|
||||
public function __construct(ConfigFile $cfg)
|
||||
{
|
||||
$this->cfg = $cfg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform config checks
|
||||
*/
|
||||
public function performConfigChecks(): void
|
||||
{
|
||||
$blowfishSecret = $this->cfg->get('blowfish_secret');
|
||||
$blowfishSecretSet = false;
|
||||
$cookieAuthUsed = false;
|
||||
|
||||
[$cookieAuthUsed, $blowfishSecret, $blowfishSecretSet] = $this->performConfigChecksServers(
|
||||
$cookieAuthUsed,
|
||||
$blowfishSecret,
|
||||
$blowfishSecretSet
|
||||
);
|
||||
|
||||
$this->performConfigChecksCookieAuthUsed($cookieAuthUsed, $blowfishSecretSet, $blowfishSecret);
|
||||
|
||||
// $cfg['AllowArbitraryServer']
|
||||
// should be disabled
|
||||
if ($this->cfg->getValue('AllowArbitraryServer')) {
|
||||
$sAllowArbitraryServerWarn = sprintf(
|
||||
__(
|
||||
'This %soption%s should be disabled as it allows attackers to '
|
||||
. 'bruteforce login to any MySQL server. If you feel this is necessary, '
|
||||
. 'use %srestrict login to MySQL server%s or %strusted proxies list%s. '
|
||||
. 'However, IP-based protection with trusted proxies list may not be '
|
||||
. 'reliable if your IP belongs to an ISP where thousands of users, '
|
||||
. 'including you, are connected to.'
|
||||
),
|
||||
'[a@' . Url::getCommon(['page' => 'form', 'formset' => 'Features']) . '#tab_Security]',
|
||||
'[/a]',
|
||||
'[a@' . Url::getCommon(['page' => 'form', 'formset' => 'Features']) . '#tab_Security]',
|
||||
'[/a]',
|
||||
'[a@' . Url::getCommon(['page' => 'form', 'formset' => 'Features']) . '#tab_Security]',
|
||||
'[/a]'
|
||||
);
|
||||
SetupIndex::messagesSet(
|
||||
'notice',
|
||||
'AllowArbitraryServer',
|
||||
Descriptions::get('AllowArbitraryServer'),
|
||||
Sanitize::sanitizeMessage($sAllowArbitraryServerWarn)
|
||||
);
|
||||
}
|
||||
|
||||
$this->performConfigChecksLoginCookie();
|
||||
|
||||
$sDirectoryNotice = __(
|
||||
'This value should be double checked to ensure that this directory is '
|
||||
. 'neither world accessible nor readable or writable by other users on '
|
||||
. 'your server.'
|
||||
);
|
||||
|
||||
// $cfg['SaveDir']
|
||||
// should not be world-accessible
|
||||
if ($this->cfg->getValue('SaveDir') != '') {
|
||||
SetupIndex::messagesSet(
|
||||
'notice',
|
||||
'SaveDir',
|
||||
Descriptions::get('SaveDir'),
|
||||
Sanitize::sanitizeMessage($sDirectoryNotice)
|
||||
);
|
||||
}
|
||||
|
||||
// $cfg['TempDir']
|
||||
// should not be world-accessible
|
||||
if ($this->cfg->getValue('TempDir') != '') {
|
||||
SetupIndex::messagesSet(
|
||||
'notice',
|
||||
'TempDir',
|
||||
Descriptions::get('TempDir'),
|
||||
Sanitize::sanitizeMessage($sDirectoryNotice)
|
||||
);
|
||||
}
|
||||
|
||||
$this->performConfigChecksZips();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check config of servers
|
||||
*
|
||||
* @param bool $cookieAuthUsed Cookie auth is used
|
||||
* @param string $blowfishSecret Blowfish secret
|
||||
* @param bool $blowfishSecretSet Blowfish secret set
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function performConfigChecksServers(
|
||||
$cookieAuthUsed,
|
||||
$blowfishSecret,
|
||||
$blowfishSecretSet
|
||||
) {
|
||||
$serverCnt = $this->cfg->getServerCount();
|
||||
$isCookieAuthUsed = (int) $cookieAuthUsed;
|
||||
for ($i = 1; $i <= $serverCnt; $i++) {
|
||||
$cookieAuthServer = ($this->cfg->getValue('Servers/' . $i . '/auth_type') === 'cookie');
|
||||
$isCookieAuthUsed |= (int) $cookieAuthServer;
|
||||
$serverName = $this->performConfigChecksServersGetServerName(
|
||||
$this->cfg->getServerName($i),
|
||||
$i
|
||||
);
|
||||
$serverName = htmlspecialchars($serverName);
|
||||
|
||||
[$blowfishSecret, $blowfishSecretSet] = $this->performConfigChecksServersSetBlowfishSecret(
|
||||
$blowfishSecret,
|
||||
$cookieAuthServer,
|
||||
$blowfishSecretSet
|
||||
);
|
||||
|
||||
// $cfg['Servers'][$i]['ssl']
|
||||
// should be enabled if possible
|
||||
if (! $this->cfg->getValue('Servers/' . $i . '/ssl')) {
|
||||
$title = Descriptions::get('Servers/1/ssl') . ' (' . $serverName . ')';
|
||||
SetupIndex::messagesSet(
|
||||
'notice',
|
||||
'Servers/' . $i . '/ssl',
|
||||
$title,
|
||||
__(
|
||||
'You should use SSL connections if your database server supports it.'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$sSecurityInfoMsg = Sanitize::sanitizeMessage(sprintf(
|
||||
__(
|
||||
'If you feel this is necessary, use additional protection settings - '
|
||||
. '%1$shost authentication%2$s settings and %3$strusted proxies list%4$s. '
|
||||
. 'However, IP-based protection may not be reliable if your IP belongs '
|
||||
. 'to an ISP where thousands of users, including you, are connected to.'
|
||||
),
|
||||
'[a@' . Url::getCommon(['page' => 'servers', 'mode' => 'edit', 'id' => $i]) . '#tab_Server_config]',
|
||||
'[/a]',
|
||||
'[a@' . Url::getCommon(['page' => 'form', 'formset' => 'Features']) . '#tab_Security]',
|
||||
'[/a]'
|
||||
));
|
||||
|
||||
// $cfg['Servers'][$i]['auth_type']
|
||||
// warn about full user credentials if 'auth_type' is 'config'
|
||||
if (
|
||||
$this->cfg->getValue('Servers/' . $i . '/auth_type') === 'config'
|
||||
&& $this->cfg->getValue('Servers/' . $i . '/user') != ''
|
||||
&& $this->cfg->getValue('Servers/' . $i . '/password') != ''
|
||||
) {
|
||||
$title = Descriptions::get('Servers/1/auth_type')
|
||||
. ' (' . $serverName . ')';
|
||||
SetupIndex::messagesSet(
|
||||
'notice',
|
||||
'Servers/' . $i . '/auth_type',
|
||||
$title,
|
||||
Sanitize::sanitizeMessage(sprintf(
|
||||
__(
|
||||
'You set the [kbd]config[/kbd] authentication type and included '
|
||||
. 'username and password for auto-login, which is not a desirable '
|
||||
. 'option for live hosts. Anyone who knows or guesses your phpMyAdmin '
|
||||
. 'URL can directly access your phpMyAdmin panel. Set %1$sauthentication '
|
||||
. 'type%2$s to [kbd]cookie[/kbd] or [kbd]http[/kbd].'
|
||||
),
|
||||
'[a@' . Url::getCommon(['page' => 'servers', 'mode' => 'edit', 'id' => $i]) . '#tab_Server]',
|
||||
'[/a]'
|
||||
))
|
||||
. ' ' . $sSecurityInfoMsg
|
||||
);
|
||||
}
|
||||
|
||||
// $cfg['Servers'][$i]['AllowRoot']
|
||||
// $cfg['Servers'][$i]['AllowNoPassword']
|
||||
// serious security flaw
|
||||
if (
|
||||
! $this->cfg->getValue('Servers/' . $i . '/AllowRoot')
|
||||
|| ! $this->cfg->getValue('Servers/' . $i . '/AllowNoPassword')
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$title = Descriptions::get('Servers/1/AllowNoPassword')
|
||||
. ' (' . $serverName . ')';
|
||||
SetupIndex::messagesSet(
|
||||
'notice',
|
||||
'Servers/' . $i . '/AllowNoPassword',
|
||||
$title,
|
||||
__('You allow for connecting to the server without a password.')
|
||||
. ' ' . $sSecurityInfoMsg
|
||||
);
|
||||
}
|
||||
|
||||
return [
|
||||
(bool) $isCookieAuthUsed,
|
||||
$blowfishSecret,
|
||||
$blowfishSecretSet,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set blowfish secret
|
||||
*
|
||||
* @param string|null $blowfishSecret Blowfish secret
|
||||
* @param bool $cookieAuthServer Cookie auth is used
|
||||
* @param bool $blowfishSecretSet Blowfish secret set
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function performConfigChecksServersSetBlowfishSecret(
|
||||
$blowfishSecret,
|
||||
$cookieAuthServer,
|
||||
$blowfishSecretSet
|
||||
): array {
|
||||
if (
|
||||
$cookieAuthServer
|
||||
&& (! is_string($blowfishSecret) || mb_strlen($blowfishSecret, '8bit') !== SODIUM_CRYPTO_SECRETBOX_KEYBYTES)
|
||||
) {
|
||||
$blowfishSecretSet = true;
|
||||
$this->cfg->set('blowfish_secret', sodium_crypto_secretbox_keygen());
|
||||
}
|
||||
|
||||
return [
|
||||
$blowfishSecret,
|
||||
$blowfishSecretSet,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Define server name
|
||||
*
|
||||
* @param string $serverName Server name
|
||||
* @param int $serverId Server id
|
||||
*
|
||||
* @return string Server name
|
||||
*/
|
||||
protected function performConfigChecksServersGetServerName(
|
||||
$serverName,
|
||||
$serverId
|
||||
) {
|
||||
if ($serverName === 'localhost') {
|
||||
return $serverName . ' [' . $serverId . ']';
|
||||
}
|
||||
|
||||
return $serverName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform config checks for zip part.
|
||||
*/
|
||||
protected function performConfigChecksZips(): void
|
||||
{
|
||||
$this->performConfigChecksServerGZipdump();
|
||||
$this->performConfigChecksServerBZipdump();
|
||||
$this->performConfigChecksServersZipdump();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform config checks for zip part.
|
||||
*/
|
||||
protected function performConfigChecksServersZipdump(): void
|
||||
{
|
||||
// $cfg['ZipDump']
|
||||
// requires zip_open in import
|
||||
if ($this->cfg->getValue('ZipDump') && ! $this->functionExists('zip_open')) {
|
||||
SetupIndex::messagesSet(
|
||||
'error',
|
||||
'ZipDump_import',
|
||||
Descriptions::get('ZipDump'),
|
||||
Sanitize::sanitizeMessage(sprintf(
|
||||
__(
|
||||
'%sZip decompression%s requires functions (%s) which are unavailable on this system.'
|
||||
),
|
||||
'[a@' . Url::getCommon(['page' => 'form', 'formset' => 'Features']) . '#tab_Import_export]',
|
||||
'[/a]',
|
||||
'zip_open'
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
// $cfg['ZipDump']
|
||||
// requires gzcompress in export
|
||||
if (! $this->cfg->getValue('ZipDump') || $this->functionExists('gzcompress')) {
|
||||
return;
|
||||
}
|
||||
|
||||
SetupIndex::messagesSet(
|
||||
'error',
|
||||
'ZipDump_export',
|
||||
Descriptions::get('ZipDump'),
|
||||
Sanitize::sanitizeMessage(sprintf(
|
||||
__(
|
||||
'%sZip compression%s requires functions (%s) which are unavailable on this system.'
|
||||
),
|
||||
'[a@' . Url::getCommon(['page' => 'form', 'formset' => 'Features']) . '#tab_Import_export]',
|
||||
'[/a]',
|
||||
'gzcompress'
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check config of servers
|
||||
*
|
||||
* @param bool $cookieAuthUsed Cookie auth is used
|
||||
* @param bool $blowfishSecretSet Blowfish secret set
|
||||
* @param string $blowfishSecret Blowfish secret
|
||||
*/
|
||||
protected function performConfigChecksCookieAuthUsed(
|
||||
$cookieAuthUsed,
|
||||
$blowfishSecretSet,
|
||||
$blowfishSecret
|
||||
): void {
|
||||
// $cfg['blowfish_secret']
|
||||
// it's required for 'cookie' authentication
|
||||
if (! $cookieAuthUsed || ! $blowfishSecretSet) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 'cookie' auth used, blowfish_secret was generated
|
||||
SetupIndex::messagesSet(
|
||||
'notice',
|
||||
'blowfish_secret_created',
|
||||
Descriptions::get('blowfish_secret'),
|
||||
Sanitize::sanitizeMessage(__(
|
||||
'You didn\'t have blowfish secret set and have enabled '
|
||||
. '[kbd]cookie[/kbd] authentication, so a key was automatically '
|
||||
. 'generated for you. It is used to encrypt cookies; you don\'t need to '
|
||||
. 'remember it.'
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check configuration for login cookie
|
||||
*/
|
||||
protected function performConfigChecksLoginCookie(): void
|
||||
{
|
||||
// $cfg['LoginCookieValidity']
|
||||
// value greater than session.gc_maxlifetime will cause
|
||||
// random session invalidation after that time
|
||||
$loginCookieValidity = $this->cfg->getValue('LoginCookieValidity');
|
||||
if ($loginCookieValidity > ini_get('session.gc_maxlifetime')) {
|
||||
SetupIndex::messagesSet(
|
||||
'error',
|
||||
'LoginCookieValidity',
|
||||
Descriptions::get('LoginCookieValidity'),
|
||||
Sanitize::sanitizeMessage(sprintf(
|
||||
__(
|
||||
'%1$sLogin cookie validity%2$s greater than %3$ssession.gc_maxlifetime%4$s may '
|
||||
. 'cause random session invalidation (currently session.gc_maxlifetime '
|
||||
. 'is %5$d).'
|
||||
),
|
||||
'[a@' . Url::getCommon(['page' => 'form', 'formset' => 'Features']) . '#tab_Security]',
|
||||
'[/a]',
|
||||
'[a@' . Core::getPHPDocLink('session.configuration.php#ini.session.gc-maxlifetime') . ']',
|
||||
'[/a]',
|
||||
ini_get('session.gc_maxlifetime')
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
// $cfg['LoginCookieValidity']
|
||||
// should be at most 1800 (30 min)
|
||||
if ($loginCookieValidity > 1800) {
|
||||
SetupIndex::messagesSet(
|
||||
'notice',
|
||||
'LoginCookieValidity',
|
||||
Descriptions::get('LoginCookieValidity'),
|
||||
Sanitize::sanitizeMessage(sprintf(
|
||||
__(
|
||||
'%sLogin cookie validity%s should be set to 1800 seconds (30 minutes) '
|
||||
. 'at most. Values larger than 1800 may pose a security risk such as '
|
||||
. 'impersonation.'
|
||||
),
|
||||
'[a@' . Url::getCommon(['page' => 'form', 'formset' => 'Features']) . '#tab_Security]',
|
||||
'[/a]'
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
// $cfg['LoginCookieValidity']
|
||||
// $cfg['LoginCookieStore']
|
||||
// LoginCookieValidity must be less or equal to LoginCookieStore
|
||||
if (
|
||||
($this->cfg->getValue('LoginCookieStore') == 0)
|
||||
|| ($loginCookieValidity <= $this->cfg->getValue('LoginCookieStore'))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
SetupIndex::messagesSet(
|
||||
'error',
|
||||
'LoginCookieValidity',
|
||||
Descriptions::get('LoginCookieValidity'),
|
||||
Sanitize::sanitizeMessage(sprintf(
|
||||
__(
|
||||
'If using [kbd]cookie[/kbd] authentication and %sLogin cookie store%s '
|
||||
. 'is not 0, %sLogin cookie validity%s must be set to a value less or '
|
||||
. 'equal to it.'
|
||||
),
|
||||
'[a@' . Url::getCommon(['page' => 'form', 'formset' => 'Features']) . '#tab_Security]',
|
||||
'[/a]',
|
||||
'[a@' . Url::getCommon(['page' => 'form', 'formset' => 'Features']) . '#tab_Security]',
|
||||
'[/a]'
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check GZipDump configuration
|
||||
*/
|
||||
protected function performConfigChecksServerBZipdump(): void
|
||||
{
|
||||
// $cfg['BZipDump']
|
||||
// requires bzip2 functions
|
||||
if (
|
||||
! $this->cfg->getValue('BZipDump')
|
||||
|| ($this->functionExists('bzopen') && $this->functionExists('bzcompress'))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$functions = $this->functionExists('bzopen')
|
||||
? '' :
|
||||
'bzopen';
|
||||
$functions .= $this->functionExists('bzcompress')
|
||||
? ''
|
||||
: ($functions ? ', ' : '') . 'bzcompress';
|
||||
SetupIndex::messagesSet(
|
||||
'error',
|
||||
'BZipDump',
|
||||
Descriptions::get('BZipDump'),
|
||||
Sanitize::sanitizeMessage(
|
||||
sprintf(
|
||||
__(
|
||||
'%1$sBzip2 compression and decompression%2$s requires functions (%3$s) which '
|
||||
. 'are unavailable on this system.'
|
||||
),
|
||||
'[a@' . Url::getCommon(['page' => 'form', 'formset' => 'Features']) . '#tab_Import_export]',
|
||||
'[/a]',
|
||||
$functions
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check GZipDump configuration
|
||||
*/
|
||||
protected function performConfigChecksServerGZipdump(): void
|
||||
{
|
||||
// $cfg['GZipDump']
|
||||
// requires zlib functions
|
||||
if (
|
||||
! $this->cfg->getValue('GZipDump')
|
||||
|| ($this->functionExists('gzopen') && $this->functionExists('gzencode'))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
SetupIndex::messagesSet(
|
||||
'error',
|
||||
'GZipDump',
|
||||
Descriptions::get('GZipDump'),
|
||||
Sanitize::sanitizeMessage(sprintf(
|
||||
__(
|
||||
'%1$sGZip compression and decompression%2$s requires functions (%3$s) which '
|
||||
. 'are unavailable on this system.'
|
||||
),
|
||||
'[a@' . Url::getCommon(['page' => 'form', 'formset' => 'Features']) . '#tab_Import_export]',
|
||||
'[/a]',
|
||||
'gzencode'
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around function_exists to allow mock in test
|
||||
*
|
||||
* @param string $name Function name
|
||||
*/
|
||||
protected function functionExists($name): bool
|
||||
{
|
||||
return function_exists($name);
|
||||
}
|
||||
}
|
4596
admin/phpMyAdmin/libraries/classes/Config/Settings.php
Normal file
4596
admin/phpMyAdmin/libraries/classes/Config/Settings.php
Normal file
File diff suppressed because it is too large
Load diff
205
admin/phpMyAdmin/libraries/classes/Config/Settings/Console.php
Normal file
205
admin/phpMyAdmin/libraries/classes/Config/Settings/Console.php
Normal file
|
@ -0,0 +1,205 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Settings;
|
||||
|
||||
use function in_array;
|
||||
|
||||
// phpcs:disable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
|
||||
|
||||
/**
|
||||
* @psalm-immutable
|
||||
*/
|
||||
final class Console
|
||||
{
|
||||
/** @var bool */
|
||||
public $StartHistory;
|
||||
|
||||
/** @var bool */
|
||||
public $AlwaysExpand;
|
||||
|
||||
/** @var bool */
|
||||
public $CurrentQuery;
|
||||
|
||||
/** @var bool */
|
||||
public $EnterExecutes;
|
||||
|
||||
/** @var bool */
|
||||
public $DarkTheme;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @psalm-var 'info'|'show'|'collapse'
|
||||
*/
|
||||
public $Mode;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
* @psalm-var positive-int
|
||||
*/
|
||||
public $Height;
|
||||
|
||||
/** @var bool */
|
||||
public $GroupQueries;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @psalm-var 'exec'|'time'|'count'
|
||||
*/
|
||||
public $OrderBy;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @psalm-var 'asc'|'desc'
|
||||
*/
|
||||
public $Order;
|
||||
|
||||
/**
|
||||
* @param mixed[] $console
|
||||
*/
|
||||
public function __construct(array $console = [])
|
||||
{
|
||||
$this->StartHistory = $this->setStartHistory($console);
|
||||
$this->AlwaysExpand = $this->setAlwaysExpand($console);
|
||||
$this->CurrentQuery = $this->setCurrentQuery($console);
|
||||
$this->EnterExecutes = $this->setEnterExecutes($console);
|
||||
$this->DarkTheme = $this->setDarkTheme($console);
|
||||
$this->Mode = $this->setMode($console);
|
||||
$this->Height = $this->setHeight($console);
|
||||
$this->GroupQueries = $this->setGroupQueries($console);
|
||||
$this->OrderBy = $this->setOrderBy($console);
|
||||
$this->Order = $this->setOrder($console);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $console
|
||||
*/
|
||||
private function setStartHistory(array $console): bool
|
||||
{
|
||||
if (isset($console['StartHistory'])) {
|
||||
return (bool) $console['StartHistory'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $console
|
||||
*/
|
||||
private function setAlwaysExpand(array $console): bool
|
||||
{
|
||||
if (isset($console['AlwaysExpand'])) {
|
||||
return (bool) $console['AlwaysExpand'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $console
|
||||
*/
|
||||
private function setCurrentQuery(array $console): bool
|
||||
{
|
||||
if (isset($console['CurrentQuery'])) {
|
||||
return (bool) $console['CurrentQuery'];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $console
|
||||
*/
|
||||
private function setEnterExecutes(array $console): bool
|
||||
{
|
||||
if (isset($console['EnterExecutes'])) {
|
||||
return (bool) $console['EnterExecutes'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $console
|
||||
*/
|
||||
private function setDarkTheme(array $console): bool
|
||||
{
|
||||
if (isset($console['DarkTheme'])) {
|
||||
return (bool) $console['DarkTheme'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $console
|
||||
*
|
||||
* @psalm-return 'info'|'show'|'collapse'
|
||||
*/
|
||||
private function setMode(array $console): string
|
||||
{
|
||||
if (isset($console['Mode']) && in_array($console['Mode'], ['show', 'collapse'], true)) {
|
||||
return $console['Mode'];
|
||||
}
|
||||
|
||||
return 'info';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $console
|
||||
*
|
||||
* @psalm-return positive-int
|
||||
*/
|
||||
private function setHeight(array $console): int
|
||||
{
|
||||
if (isset($console['Height'])) {
|
||||
$height = (int) $console['Height'];
|
||||
if ($height >= 1) {
|
||||
return $height;
|
||||
}
|
||||
}
|
||||
|
||||
return 92;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $console
|
||||
*/
|
||||
private function setGroupQueries(array $console): bool
|
||||
{
|
||||
if (isset($console['GroupQueries'])) {
|
||||
return (bool) $console['GroupQueries'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $console
|
||||
*
|
||||
* @psalm-return 'exec'|'time'|'count'
|
||||
*/
|
||||
private function setOrderBy(array $console): string
|
||||
{
|
||||
if (isset($console['OrderBy']) && in_array($console['OrderBy'], ['time', 'count'], true)) {
|
||||
return $console['OrderBy'];
|
||||
}
|
||||
|
||||
return 'exec';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $console
|
||||
*
|
||||
* @psalm-return 'asc'|'desc'
|
||||
*/
|
||||
private function setOrder(array $console): string
|
||||
{
|
||||
if (isset($console['Order']) && $console['Order'] === 'desc') {
|
||||
return 'desc';
|
||||
}
|
||||
|
||||
return 'asc';
|
||||
}
|
||||
}
|
82
admin/phpMyAdmin/libraries/classes/Config/Settings/Debug.php
Normal file
82
admin/phpMyAdmin/libraries/classes/Config/Settings/Debug.php
Normal file
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Settings;
|
||||
|
||||
/**
|
||||
* @psalm-immutable
|
||||
*/
|
||||
final class Debug
|
||||
{
|
||||
/**
|
||||
* Output executed queries and their execution times.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $sql;
|
||||
|
||||
/**
|
||||
* Log executed queries and their execution times to syslog.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $sqllog;
|
||||
|
||||
/**
|
||||
* Enable to let server present itself as demo server.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $demo;
|
||||
|
||||
/**
|
||||
* Enable Simple two-factor authentication.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $simple2fa;
|
||||
|
||||
/**
|
||||
* @param mixed[] $debug
|
||||
*/
|
||||
public function __construct(array $debug = [])
|
||||
{
|
||||
$this->sql = $this->setSql($debug);
|
||||
$this->sqllog = $this->setSqlLog($debug);
|
||||
$this->demo = $this->setDemo($debug);
|
||||
$this->simple2fa = $this->setSimple2fa($debug);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $debug
|
||||
*/
|
||||
private function setSql(array $debug): bool
|
||||
{
|
||||
return isset($debug['sql']) && $debug['sql'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $debug
|
||||
*/
|
||||
private function setSqlLog(array $debug): bool
|
||||
{
|
||||
return isset($debug['sqllog']) && $debug['sqllog'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $debug
|
||||
*/
|
||||
private function setDemo(array $debug): bool
|
||||
{
|
||||
return isset($debug['demo']) && $debug['demo'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $debug
|
||||
*/
|
||||
private function setSimple2fa(array $debug): bool
|
||||
{
|
||||
return isset($debug['simple2fa']) && $debug['simple2fa'];
|
||||
}
|
||||
}
|
2027
admin/phpMyAdmin/libraries/classes/Config/Settings/Export.php
Normal file
2027
admin/phpMyAdmin/libraries/classes/Config/Settings/Export.php
Normal file
File diff suppressed because it is too large
Load diff
489
admin/phpMyAdmin/libraries/classes/Config/Settings/Import.php
Normal file
489
admin/phpMyAdmin/libraries/classes/Config/Settings/Import.php
Normal file
|
@ -0,0 +1,489 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Settings;
|
||||
|
||||
// phpcs:disable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
|
||||
|
||||
use function in_array;
|
||||
|
||||
/**
|
||||
* @psalm-immutable
|
||||
*/
|
||||
final class Import
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
* @psalm-var 'csv'|'docsql'|'ldi'|'sql'
|
||||
*/
|
||||
public $format;
|
||||
|
||||
/**
|
||||
* Default charset for import.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $charset;
|
||||
|
||||
/** @var bool */
|
||||
public $allow_interrupt;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
* @psalm-var 0|positive-int
|
||||
*/
|
||||
public $skip_queries;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @psalm-var 'NONE'|'ANSI'|'DB2'|'MAXDB'|'MYSQL323'|'MYSQL40'|'MSSQL'|'ORACLE'|'TRADITIONAL'
|
||||
*/
|
||||
public $sql_compatibility;
|
||||
|
||||
/** @var bool */
|
||||
public $sql_no_auto_value_on_zero;
|
||||
|
||||
/** @var bool */
|
||||
public $sql_read_as_multibytes;
|
||||
|
||||
/** @var bool */
|
||||
public $csv_replace;
|
||||
|
||||
/** @var bool */
|
||||
public $csv_ignore;
|
||||
|
||||
/** @var string */
|
||||
public $csv_terminated;
|
||||
|
||||
/** @var string */
|
||||
public $csv_enclosed;
|
||||
|
||||
/** @var string */
|
||||
public $csv_escaped;
|
||||
|
||||
/** @var string */
|
||||
public $csv_new_line;
|
||||
|
||||
/** @var string */
|
||||
public $csv_columns;
|
||||
|
||||
/** @var bool */
|
||||
public $csv_col_names;
|
||||
|
||||
/** @var bool */
|
||||
public $ldi_replace;
|
||||
|
||||
/** @var bool */
|
||||
public $ldi_ignore;
|
||||
|
||||
/** @var string */
|
||||
public $ldi_terminated;
|
||||
|
||||
/** @var string */
|
||||
public $ldi_enclosed;
|
||||
|
||||
/** @var string */
|
||||
public $ldi_escaped;
|
||||
|
||||
/** @var string */
|
||||
public $ldi_new_line;
|
||||
|
||||
/** @var string */
|
||||
public $ldi_columns;
|
||||
|
||||
/**
|
||||
* 'auto' for auto-detection, true or false for forcing
|
||||
*
|
||||
* @var string|bool
|
||||
* @psalm-var 'auto'|bool
|
||||
*/
|
||||
public $ldi_local_option;
|
||||
|
||||
/** @var bool */
|
||||
public $ods_col_names;
|
||||
|
||||
/** @var bool */
|
||||
public $ods_empty_rows;
|
||||
|
||||
/** @var bool */
|
||||
public $ods_recognize_percentages;
|
||||
|
||||
/** @var bool */
|
||||
public $ods_recognize_currency;
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $import
|
||||
*/
|
||||
public function __construct(array $import = [])
|
||||
{
|
||||
$this->format = $this->setFormat($import);
|
||||
$this->charset = $this->setCharset($import);
|
||||
$this->allow_interrupt = $this->setAllowInterrupt($import);
|
||||
$this->skip_queries = $this->setSkipQueries($import);
|
||||
$this->sql_compatibility = $this->setSqlCompatibility($import);
|
||||
$this->sql_no_auto_value_on_zero = $this->setSqlNoAutoValueOnZero($import);
|
||||
$this->sql_read_as_multibytes = $this->setSqlReadAsMultibytes($import);
|
||||
$this->csv_replace = $this->setCsvReplace($import);
|
||||
$this->csv_ignore = $this->setCsvIgnore($import);
|
||||
$this->csv_terminated = $this->setCsvTerminated($import);
|
||||
$this->csv_enclosed = $this->setCsvEnclosed($import);
|
||||
$this->csv_escaped = $this->setCsvEscaped($import);
|
||||
$this->csv_new_line = $this->setCsvNewLine($import);
|
||||
$this->csv_columns = $this->setCsvColumns($import);
|
||||
$this->csv_col_names = $this->setCsvColNames($import);
|
||||
$this->ldi_replace = $this->setLdiReplace($import);
|
||||
$this->ldi_ignore = $this->setLdiIgnore($import);
|
||||
$this->ldi_terminated = $this->setLdiTerminated($import);
|
||||
$this->ldi_enclosed = $this->setLdiEnclosed($import);
|
||||
$this->ldi_escaped = $this->setLdiEscaped($import);
|
||||
$this->ldi_new_line = $this->setLdiNewLine($import);
|
||||
$this->ldi_columns = $this->setLdiColumns($import);
|
||||
$this->ldi_local_option = $this->setLdiLocalOption($import);
|
||||
$this->ods_col_names = $this->setOdsColNames($import);
|
||||
$this->ods_empty_rows = $this->setOdsEmptyRows($import);
|
||||
$this->ods_recognize_percentages = $this->setOdsRecognizePercentages($import);
|
||||
$this->ods_recognize_currency = $this->setOdsRecognizeCurrency($import);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $import
|
||||
*
|
||||
* @psalm-return 'csv'|'docsql'|'ldi'|'sql'
|
||||
*/
|
||||
private function setFormat(array $import): string
|
||||
{
|
||||
if (! isset($import['format']) || ! in_array($import['format'], ['csv', 'docsql', 'ldi'], true)) {
|
||||
return 'sql';
|
||||
}
|
||||
|
||||
return $import['format'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $import
|
||||
*/
|
||||
private function setCharset(array $import): string
|
||||
{
|
||||
if (! isset($import['charset'])) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return (string) $import['charset'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $import
|
||||
*/
|
||||
private function setAllowInterrupt(array $import): bool
|
||||
{
|
||||
if (! isset($import['allow_interrupt'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (bool) $import['allow_interrupt'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $import
|
||||
*
|
||||
* @psalm-return 0|positive-int
|
||||
*/
|
||||
private function setSkipQueries(array $import): int
|
||||
{
|
||||
if (! isset($import['skip_queries'])) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$skipQueries = (int) $import['skip_queries'];
|
||||
|
||||
return $skipQueries >= 1 ? $skipQueries : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $import
|
||||
*
|
||||
* @psalm-return 'NONE'|'ANSI'|'DB2'|'MAXDB'|'MYSQL323'|'MYSQL40'|'MSSQL'|'ORACLE'|'TRADITIONAL'
|
||||
*/
|
||||
private function setSqlCompatibility(array $import): string
|
||||
{
|
||||
if (
|
||||
! isset($import['sql_compatibility']) || ! in_array(
|
||||
$import['sql_compatibility'],
|
||||
['ANSI', 'DB2', 'MAXDB', 'MYSQL323', 'MYSQL40', 'MSSQL', 'ORACLE', 'TRADITIONAL'],
|
||||
true
|
||||
)
|
||||
) {
|
||||
return 'NONE';
|
||||
}
|
||||
|
||||
return $import['sql_compatibility'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $import
|
||||
*/
|
||||
private function setSqlNoAutoValueOnZero(array $import): bool
|
||||
{
|
||||
if (! isset($import['sql_no_auto_value_on_zero'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (bool) $import['sql_no_auto_value_on_zero'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $import
|
||||
*/
|
||||
private function setSqlReadAsMultibytes(array $import): bool
|
||||
{
|
||||
if (! isset($import['sql_read_as_multibytes'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool) $import['sql_read_as_multibytes'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $import
|
||||
*/
|
||||
private function setCsvReplace(array $import): bool
|
||||
{
|
||||
if (! isset($import['csv_replace'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool) $import['csv_replace'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $import
|
||||
*/
|
||||
private function setCsvIgnore(array $import): bool
|
||||
{
|
||||
if (! isset($import['csv_ignore'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool) $import['csv_ignore'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $import
|
||||
*/
|
||||
private function setCsvTerminated(array $import): string
|
||||
{
|
||||
if (! isset($import['csv_terminated'])) {
|
||||
return ',';
|
||||
}
|
||||
|
||||
return (string) $import['csv_terminated'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $import
|
||||
*/
|
||||
private function setCsvEnclosed(array $import): string
|
||||
{
|
||||
if (! isset($import['csv_enclosed'])) {
|
||||
return '"';
|
||||
}
|
||||
|
||||
return (string) $import['csv_enclosed'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $import
|
||||
*/
|
||||
private function setCsvEscaped(array $import): string
|
||||
{
|
||||
if (! isset($import['csv_escaped'])) {
|
||||
return '"';
|
||||
}
|
||||
|
||||
return (string) $import['csv_escaped'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $import
|
||||
*/
|
||||
private function setCsvNewLine(array $import): string
|
||||
{
|
||||
if (! isset($import['csv_new_line'])) {
|
||||
return 'auto';
|
||||
}
|
||||
|
||||
return (string) $import['csv_new_line'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $import
|
||||
*/
|
||||
private function setCsvColumns(array $import): string
|
||||
{
|
||||
if (! isset($import['csv_columns'])) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return (string) $import['csv_columns'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $import
|
||||
*/
|
||||
private function setCsvColNames(array $import): bool
|
||||
{
|
||||
if (! isset($import['csv_col_names'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool) $import['csv_col_names'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $import
|
||||
*/
|
||||
private function setLdiReplace(array $import): bool
|
||||
{
|
||||
if (! isset($import['ldi_replace'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool) $import['ldi_replace'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $import
|
||||
*/
|
||||
private function setLdiIgnore(array $import): bool
|
||||
{
|
||||
if (! isset($import['ldi_ignore'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool) $import['ldi_ignore'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $import
|
||||
*/
|
||||
private function setLdiTerminated(array $import): string
|
||||
{
|
||||
if (! isset($import['ldi_terminated'])) {
|
||||
return ';';
|
||||
}
|
||||
|
||||
return (string) $import['ldi_terminated'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $import
|
||||
*/
|
||||
private function setLdiEnclosed(array $import): string
|
||||
{
|
||||
if (! isset($import['ldi_enclosed'])) {
|
||||
return '"';
|
||||
}
|
||||
|
||||
return (string) $import['ldi_enclosed'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $import
|
||||
*/
|
||||
private function setLdiEscaped(array $import): string
|
||||
{
|
||||
if (! isset($import['ldi_escaped'])) {
|
||||
return '\\';
|
||||
}
|
||||
|
||||
return (string) $import['ldi_escaped'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $import
|
||||
*/
|
||||
private function setLdiNewLine(array $import): string
|
||||
{
|
||||
if (! isset($import['ldi_new_line'])) {
|
||||
return 'auto';
|
||||
}
|
||||
|
||||
return (string) $import['ldi_new_line'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $import
|
||||
*/
|
||||
private function setLdiColumns(array $import): string
|
||||
{
|
||||
if (! isset($import['ldi_columns'])) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return (string) $import['ldi_columns'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $import
|
||||
*
|
||||
* @return bool|string
|
||||
* @psalm-return 'auto'|bool
|
||||
*/
|
||||
private function setLdiLocalOption(array $import)
|
||||
{
|
||||
if (! isset($import['ldi_local_option']) || $import['ldi_local_option'] === 'auto') {
|
||||
return 'auto';
|
||||
}
|
||||
|
||||
return (bool) $import['ldi_local_option'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $import
|
||||
*/
|
||||
private function setOdsColNames(array $import): bool
|
||||
{
|
||||
if (! isset($import['ods_col_names'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool) $import['ods_col_names'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $import
|
||||
*/
|
||||
private function setOdsEmptyRows(array $import): bool
|
||||
{
|
||||
if (! isset($import['ods_empty_rows'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (bool) $import['ods_empty_rows'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $import
|
||||
*/
|
||||
private function setOdsRecognizePercentages(array $import): bool
|
||||
{
|
||||
if (! isset($import['ods_recognize_percentages'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (bool) $import['ods_recognize_percentages'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $import
|
||||
*/
|
||||
private function setOdsRecognizeCurrency(array $import): bool
|
||||
{
|
||||
if (! isset($import['ods_recognize_currency'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (bool) $import['ods_recognize_currency'];
|
||||
}
|
||||
}
|
369
admin/phpMyAdmin/libraries/classes/Config/Settings/Schema.php
Normal file
369
admin/phpMyAdmin/libraries/classes/Config/Settings/Schema.php
Normal file
|
@ -0,0 +1,369 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Settings;
|
||||
|
||||
// phpcs:disable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
|
||||
|
||||
use function in_array;
|
||||
|
||||
/**
|
||||
* @psalm-immutable
|
||||
*/
|
||||
final class Schema
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
* @psalm-var 'pdf'|'eps'|'dia'|'svg'
|
||||
*/
|
||||
public $format;
|
||||
|
||||
/** @var bool */
|
||||
public $pdf_show_color;
|
||||
|
||||
/** @var bool */
|
||||
public $pdf_show_keys;
|
||||
|
||||
/** @var bool */
|
||||
public $pdf_all_tables_same_width;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @psalm-var 'L'|'P'
|
||||
*/
|
||||
public $pdf_orientation;
|
||||
|
||||
/** @var string */
|
||||
public $pdf_paper;
|
||||
|
||||
/** @var bool */
|
||||
public $pdf_show_grid;
|
||||
|
||||
/** @var bool */
|
||||
public $pdf_with_doc;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @psalm-var ''|'name_asc'|'name_desc'
|
||||
*/
|
||||
public $pdf_table_order;
|
||||
|
||||
/** @var bool */
|
||||
public $dia_show_color;
|
||||
|
||||
/** @var bool */
|
||||
public $dia_show_keys;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @psalm-var 'L'|'P'
|
||||
*/
|
||||
public $dia_orientation;
|
||||
|
||||
/** @var string */
|
||||
public $dia_paper;
|
||||
|
||||
/** @var bool */
|
||||
public $eps_show_color;
|
||||
|
||||
/** @var bool */
|
||||
public $eps_show_keys;
|
||||
|
||||
/** @var bool */
|
||||
public $eps_all_tables_same_width;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @psalm-var 'L'|'P'
|
||||
*/
|
||||
public $eps_orientation;
|
||||
|
||||
/** @var bool */
|
||||
public $svg_show_color;
|
||||
|
||||
/** @var bool */
|
||||
public $svg_show_keys;
|
||||
|
||||
/** @var bool */
|
||||
public $svg_all_tables_same_width;
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $schema
|
||||
*/
|
||||
public function __construct(array $schema = [])
|
||||
{
|
||||
$this->format = $this->setFormat($schema);
|
||||
$this->pdf_show_color = $this->setPdfShowColor($schema);
|
||||
$this->pdf_show_keys = $this->setPdfShowKeys($schema);
|
||||
$this->pdf_all_tables_same_width = $this->setPdfAllTablesSameWidth($schema);
|
||||
$this->pdf_orientation = $this->setPdfOrientation($schema);
|
||||
$this->pdf_paper = $this->setPdfPaper($schema);
|
||||
$this->pdf_show_grid = $this->setPdfShowGrid($schema);
|
||||
$this->pdf_with_doc = $this->setPdfWithDoc($schema);
|
||||
$this->pdf_table_order = $this->setPdfTableOrder($schema);
|
||||
$this->dia_show_color = $this->setDiaShowColor($schema);
|
||||
$this->dia_show_keys = $this->setDiaShowKeys($schema);
|
||||
$this->dia_orientation = $this->setDiaOrientation($schema);
|
||||
$this->dia_paper = $this->setDiaPaper($schema);
|
||||
$this->eps_show_color = $this->setEpsShowColor($schema);
|
||||
$this->eps_show_keys = $this->setEpsShowKeys($schema);
|
||||
$this->eps_all_tables_same_width = $this->setEpsAllTablesSameWidth($schema);
|
||||
$this->eps_orientation = $this->setEpsOrientation($schema);
|
||||
$this->svg_show_color = $this->setSvgShowColor($schema);
|
||||
$this->svg_show_keys = $this->setSvgShowKeys($schema);
|
||||
$this->svg_all_tables_same_width = $this->setSvgAllTablesSameWidth($schema);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $schema
|
||||
*
|
||||
* @psalm-return 'pdf'|'eps'|'dia'|'svg'
|
||||
*/
|
||||
private function setFormat(array $schema): string
|
||||
{
|
||||
if (isset($schema['format']) && in_array($schema['format'], ['eps', 'dia', 'svg'], true)) {
|
||||
return $schema['format'];
|
||||
}
|
||||
|
||||
return 'pdf';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $schema
|
||||
*/
|
||||
private function setPdfShowColor(array $schema): bool
|
||||
{
|
||||
if (isset($schema['pdf_show_color'])) {
|
||||
return (bool) $schema['pdf_show_color'];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $schema
|
||||
*/
|
||||
private function setPdfShowKeys(array $schema): bool
|
||||
{
|
||||
if (isset($schema['pdf_show_keys'])) {
|
||||
return (bool) $schema['pdf_show_keys'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $schema
|
||||
*/
|
||||
private function setPdfAllTablesSameWidth(array $schema): bool
|
||||
{
|
||||
if (isset($schema['pdf_all_tables_same_width'])) {
|
||||
return (bool) $schema['pdf_all_tables_same_width'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $schema
|
||||
*
|
||||
* @psalm-return 'L'|'P'
|
||||
*/
|
||||
private function setPdfOrientation(array $schema): string
|
||||
{
|
||||
if (isset($schema['pdf_orientation']) && $schema['pdf_orientation'] === 'P') {
|
||||
return 'P';
|
||||
}
|
||||
|
||||
return 'L';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $schema
|
||||
*/
|
||||
private function setPdfPaper(array $schema): string
|
||||
{
|
||||
if (isset($schema['pdf_paper'])) {
|
||||
return (string) $schema['pdf_paper'];
|
||||
}
|
||||
|
||||
return 'A4';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $schema
|
||||
*/
|
||||
private function setPdfShowGrid(array $schema): bool
|
||||
{
|
||||
if (isset($schema['pdf_show_grid'])) {
|
||||
return (bool) $schema['pdf_show_grid'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $schema
|
||||
*/
|
||||
private function setPdfWithDoc(array $schema): bool
|
||||
{
|
||||
if (isset($schema['pdf_with_doc'])) {
|
||||
return (bool) $schema['pdf_with_doc'];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $schema
|
||||
*
|
||||
* @psalm-return ''|'name_asc'|'name_desc'
|
||||
*/
|
||||
private function setPdfTableOrder(array $schema): string
|
||||
{
|
||||
if (
|
||||
isset($schema['pdf_table_order']) && in_array($schema['pdf_table_order'], ['name_asc', 'name_desc'], true)
|
||||
) {
|
||||
return $schema['pdf_table_order'];
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $schema
|
||||
*/
|
||||
private function setDiaShowColor(array $schema): bool
|
||||
{
|
||||
if (isset($schema['dia_show_color'])) {
|
||||
return (bool) $schema['dia_show_color'];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $schema
|
||||
*/
|
||||
private function setDiaShowKeys(array $schema): bool
|
||||
{
|
||||
if (isset($schema['dia_show_keys'])) {
|
||||
return (bool) $schema['dia_show_keys'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $schema
|
||||
*
|
||||
* @psalm-return 'L'|'P'
|
||||
*/
|
||||
private function setDiaOrientation(array $schema): string
|
||||
{
|
||||
if (isset($schema['dia_orientation']) && $schema['dia_orientation'] === 'P') {
|
||||
return 'P';
|
||||
}
|
||||
|
||||
return 'L';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $schema
|
||||
*/
|
||||
private function setDiaPaper(array $schema): string
|
||||
{
|
||||
if (isset($schema['dia_paper'])) {
|
||||
return (string) $schema['dia_paper'];
|
||||
}
|
||||
|
||||
return 'A4';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $schema
|
||||
*/
|
||||
private function setEpsShowColor(array $schema): bool
|
||||
{
|
||||
if (isset($schema['eps_show_color'])) {
|
||||
return (bool) $schema['eps_show_color'];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $schema
|
||||
*/
|
||||
private function setEpsShowKeys(array $schema): bool
|
||||
{
|
||||
if (isset($schema['eps_show_keys'])) {
|
||||
return (bool) $schema['eps_show_keys'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $schema
|
||||
*/
|
||||
private function setEpsAllTablesSameWidth(array $schema): bool
|
||||
{
|
||||
if (isset($schema['eps_all_tables_same_width'])) {
|
||||
return (bool) $schema['eps_all_tables_same_width'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $schema
|
||||
*
|
||||
* @psalm-return 'L'|'P'
|
||||
*/
|
||||
private function setEpsOrientation(array $schema): string
|
||||
{
|
||||
if (isset($schema['eps_orientation']) && $schema['eps_orientation'] === 'P') {
|
||||
return 'P';
|
||||
}
|
||||
|
||||
return 'L';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $schema
|
||||
*/
|
||||
private function setSvgShowColor(array $schema): bool
|
||||
{
|
||||
if (isset($schema['svg_show_color'])) {
|
||||
return (bool) $schema['svg_show_color'];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $schema
|
||||
*/
|
||||
private function setSvgShowKeys(array $schema): bool
|
||||
{
|
||||
if (isset($schema['svg_show_keys'])) {
|
||||
return (bool) $schema['svg_show_keys'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $schema
|
||||
*/
|
||||
private function setSvgAllTablesSameWidth(array $schema): bool
|
||||
{
|
||||
if (isset($schema['svg_all_tables_same_width'])) {
|
||||
return (bool) $schema['svg_all_tables_same_width'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
1398
admin/phpMyAdmin/libraries/classes/Config/Settings/Server.php
Normal file
1398
admin/phpMyAdmin/libraries/classes/Config/Settings/Server.php
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Settings;
|
||||
|
||||
// phpcs:disable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
|
||||
|
||||
/**
|
||||
* @psalm-immutable
|
||||
*/
|
||||
final class SqlQueryBox
|
||||
{
|
||||
/**
|
||||
* Display an "Edit" link on the results page to change a query.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $Edit;
|
||||
|
||||
/**
|
||||
* Display an "Explain SQL" link on the results page.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $Explain;
|
||||
|
||||
/**
|
||||
* Display a "Create PHP code" link on the results page to wrap a query in PHP.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $ShowAsPHP;
|
||||
|
||||
/**
|
||||
* Display a "Refresh" link on the results page.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $Refresh;
|
||||
|
||||
/**
|
||||
* @param mixed[] $sqlQueryBox
|
||||
*/
|
||||
public function __construct(array $sqlQueryBox = [])
|
||||
{
|
||||
$this->Edit = $this->setEdit($sqlQueryBox);
|
||||
$this->Explain = $this->setExplain($sqlQueryBox);
|
||||
$this->ShowAsPHP = $this->setShowAsPHP($sqlQueryBox);
|
||||
$this->Refresh = $this->setRefresh($sqlQueryBox);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $sqlQueryBox
|
||||
*/
|
||||
private function setEdit(array $sqlQueryBox): bool
|
||||
{
|
||||
return ! isset($sqlQueryBox['Edit']) || $sqlQueryBox['Edit'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $sqlQueryBox
|
||||
*/
|
||||
private function setExplain(array $sqlQueryBox): bool
|
||||
{
|
||||
return ! isset($sqlQueryBox['Explain']) || $sqlQueryBox['Explain'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $sqlQueryBox
|
||||
*/
|
||||
private function setShowAsPHP(array $sqlQueryBox): bool
|
||||
{
|
||||
return ! isset($sqlQueryBox['ShowAsPHP']) || $sqlQueryBox['ShowAsPHP'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $sqlQueryBox
|
||||
*/
|
||||
private function setRefresh(array $sqlQueryBox): bool
|
||||
{
|
||||
return ! isset($sqlQueryBox['Refresh']) || $sqlQueryBox['Refresh'];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,391 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config\Settings;
|
||||
|
||||
use function is_array;
|
||||
|
||||
// phpcs:disable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
|
||||
|
||||
/**
|
||||
* @psalm-immutable
|
||||
*/
|
||||
final class Transformations
|
||||
{
|
||||
/**
|
||||
* Displays a part of a string.
|
||||
* - The first option is the number of characters to skip from the beginning of the string (Default 0).
|
||||
* - The second option is the number of characters to return (Default: until end of string).
|
||||
* - The third option is the string to append and/or prepend when truncation occurs (Default: "…").
|
||||
*
|
||||
* @var array<int, int|string>
|
||||
* @psalm-var array{0: int, 1: 'all'|int, 2: string}
|
||||
*/
|
||||
public $Substring;
|
||||
|
||||
/**
|
||||
* Converts Boolean values to text (default 'T' and 'F').
|
||||
* - First option is for TRUE, second for FALSE. Nonzero=true.
|
||||
*
|
||||
* @var string[]
|
||||
* @psalm-var array{0: string, 1: string}
|
||||
*/
|
||||
public $Bool2Text;
|
||||
|
||||
/**
|
||||
* LINUX ONLY: Launches an external application and feeds it the column data via standard input.
|
||||
* Returns the standard output of the application. The default is Tidy, to pretty-print HTML code.
|
||||
* For security reasons, you have to manually edit the file
|
||||
* libraries/classes/Plugins/Transformations/Abs/ExternalTransformationsPlugin.php and list the tools
|
||||
* you want to make available.
|
||||
* - The first option is then the number of the program you want to use.
|
||||
* - The second option should be blank for historical reasons.
|
||||
* - The third option, if set to 1, will convert the output using htmlspecialchars() (Default 1).
|
||||
* - The fourth option, if set to 1, will prevent wrapping and ensure that the output appears
|
||||
* all on one line (Default 1).
|
||||
*
|
||||
* @var array<int, int|string>
|
||||
* @psalm-var array{0: int, 1: string, 2: int, 3: int}
|
||||
*/
|
||||
public $External;
|
||||
|
||||
/**
|
||||
* Prepends and/or Appends text to a string.
|
||||
* - First option is text to be prepended. second is appended (enclosed in single quotes, default empty string).
|
||||
*
|
||||
* @var string[]
|
||||
* @psalm-var array{0: string, 1: string}
|
||||
*/
|
||||
public $PreApPend;
|
||||
|
||||
/**
|
||||
* Displays hexadecimal representation of data.
|
||||
* Optional first parameter specifies how often space will be added (defaults to 2 nibbles).
|
||||
*
|
||||
* @var string[]
|
||||
* @psalm-var array{0: 0|positive-int}
|
||||
*/
|
||||
public $Hex;
|
||||
|
||||
/**
|
||||
* Displays a TIME, TIMESTAMP, DATETIME or numeric unix timestamp column as formatted date.
|
||||
* - The first option is the offset (in hours) which will be added to the timestamp (Default: 0).
|
||||
* - Use second option to specify a different date/time format string.
|
||||
* - Third option determines whether you want to see local date or UTC one (use "local" or "utc" strings) for that.
|
||||
* According to that, date format has different value - for "local" see the documentation
|
||||
* for PHP's strftime() function and for "utc" it is done using gmdate() function.
|
||||
*
|
||||
* @var array<int, int|string>
|
||||
* @psalm-var array{0: 0|positive-int, 1: string, 2: 'local'|'utc'}
|
||||
*/
|
||||
public $DateFormat;
|
||||
|
||||
/**
|
||||
* Displays a clickable thumbnail.
|
||||
* The options are the maximum width and height in pixels.
|
||||
* The original aspect ratio is preserved.
|
||||
*
|
||||
* @var array<(int|string), (int|string|array<string, string>|null)>
|
||||
* @psalm-var array{
|
||||
* 0: 0|positive-int,
|
||||
* 1: 0|positive-int,
|
||||
* wrapper_link: string|null,
|
||||
* wrapper_params: array<array-key, string>
|
||||
* }
|
||||
*/
|
||||
public $Inline;
|
||||
|
||||
/**
|
||||
* Displays an image and a link; the column contains the filename.
|
||||
* - The first option is a URL prefix like "https://www.example.com/".
|
||||
* - The second and third options are the width and the height in pixels.
|
||||
*
|
||||
* @var array<int, int|string|null>
|
||||
* @psalm-var array{0: string|null, 1: 0|positive-int, 2: 0|positive-int}
|
||||
*/
|
||||
public $TextImageLink;
|
||||
|
||||
/**
|
||||
* Displays a link; the column contains the filename.
|
||||
* - The first option is a URL prefix like "https://www.example.com/".
|
||||
* - The second option is a title for the link.
|
||||
*
|
||||
* @var array<int, string|null>
|
||||
* @psalm-var array{0: string|null, 1: string|null, 2: bool|null}
|
||||
*/
|
||||
public $TextLink;
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $transformations
|
||||
*/
|
||||
public function __construct(array $transformations = [])
|
||||
{
|
||||
$this->Substring = $this->setSubstring($transformations);
|
||||
$this->Bool2Text = $this->setBool2Text($transformations);
|
||||
$this->External = $this->setExternal($transformations);
|
||||
$this->PreApPend = $this->setPreApPend($transformations);
|
||||
$this->Hex = $this->setHex($transformations);
|
||||
$this->DateFormat = $this->setDateFormat($transformations);
|
||||
$this->Inline = $this->setInline($transformations);
|
||||
$this->TextImageLink = $this->setTextImageLink($transformations);
|
||||
$this->TextLink = $this->setTextLink($transformations);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $transformations
|
||||
*
|
||||
* @return array<int, int|string>
|
||||
* @psalm-return array{0: int, 1: 'all'|int, 2: string}
|
||||
*/
|
||||
private function setSubstring(array $transformations): array
|
||||
{
|
||||
$substring = [0, 'all', '…'];
|
||||
if (isset($transformations['Substring']) && is_array($transformations['Substring'])) {
|
||||
if (isset($transformations['Substring'][0])) {
|
||||
$substring[0] = (int) $transformations['Substring'][0];
|
||||
}
|
||||
|
||||
if (isset($transformations['Substring'][1]) && $transformations['Substring'][1] !== 'all') {
|
||||
$substring[1] = (int) $transformations['Substring'][1];
|
||||
}
|
||||
|
||||
if (isset($transformations['Substring'][2])) {
|
||||
$substring[2] = (string) $transformations['Substring'][2];
|
||||
}
|
||||
}
|
||||
|
||||
return $substring;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $transformations
|
||||
*
|
||||
* @return string[]
|
||||
* @psalm-return array{0: string, 1: string}
|
||||
*/
|
||||
private function setBool2Text(array $transformations): array
|
||||
{
|
||||
$bool2Text = ['T', 'F'];
|
||||
if (isset($transformations['Bool2Text']) && is_array($transformations['Bool2Text'])) {
|
||||
if (isset($transformations['Bool2Text'][0])) {
|
||||
$bool2Text[0] = (string) $transformations['Bool2Text'][0];
|
||||
}
|
||||
|
||||
if (isset($transformations['Bool2Text'][1])) {
|
||||
$bool2Text[1] = (string) $transformations['Bool2Text'][1];
|
||||
}
|
||||
}
|
||||
|
||||
return $bool2Text;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $transformations
|
||||
*
|
||||
* @return array<int, int|string>
|
||||
* @psalm-return array{0: int, 1: string, 2: int, 3: int}
|
||||
*/
|
||||
private function setExternal(array $transformations): array
|
||||
{
|
||||
$external = [0, '-f /dev/null -i -wrap -q', 1, 1];
|
||||
if (isset($transformations['External']) && is_array($transformations['External'])) {
|
||||
if (isset($transformations['External'][0])) {
|
||||
$external[0] = (int) $transformations['External'][0];
|
||||
}
|
||||
|
||||
if (isset($transformations['External'][1])) {
|
||||
$external[1] = (string) $transformations['External'][1];
|
||||
}
|
||||
|
||||
if (isset($transformations['External'][2])) {
|
||||
$external[2] = (int) $transformations['External'][2];
|
||||
}
|
||||
|
||||
if (isset($transformations['External'][3])) {
|
||||
$external[3] = (int) $transformations['External'][3];
|
||||
}
|
||||
}
|
||||
|
||||
return $external;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $transformations
|
||||
*
|
||||
* @return string[]
|
||||
* @psalm-return array{0: string, 1: string}
|
||||
*/
|
||||
private function setPreApPend(array $transformations): array
|
||||
{
|
||||
$preApPend = ['', ''];
|
||||
if (isset($transformations['PreApPend']) && is_array($transformations['PreApPend'])) {
|
||||
if (isset($transformations['PreApPend'][0])) {
|
||||
$preApPend[0] = (string) $transformations['PreApPend'][0];
|
||||
}
|
||||
|
||||
if (isset($transformations['PreApPend'][1])) {
|
||||
$preApPend[1] = (string) $transformations['PreApPend'][1];
|
||||
}
|
||||
}
|
||||
|
||||
return $preApPend;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $transformations
|
||||
*
|
||||
* @return string[]
|
||||
* @psalm-return array{0: 0|positive-int}
|
||||
*/
|
||||
private function setHex(array $transformations): array
|
||||
{
|
||||
if (isset($transformations['Hex']) && is_array($transformations['Hex'])) {
|
||||
if (isset($transformations['Hex'][0])) {
|
||||
$length = (int) $transformations['Hex'][0];
|
||||
if ($length >= 0) {
|
||||
return [$length];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [2];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $transformations
|
||||
*
|
||||
* @return array<int, int|string>
|
||||
* @psalm-return array{0: 0|positive-int, 1: string, 2: 'local'|'utc'}
|
||||
*/
|
||||
private function setDateFormat(array $transformations): array
|
||||
{
|
||||
$dateFormat = [0, '', 'local'];
|
||||
if (isset($transformations['DateFormat']) && is_array($transformations['DateFormat'])) {
|
||||
if (isset($transformations['DateFormat'][0])) {
|
||||
$offset = (int) $transformations['DateFormat'][0];
|
||||
if ($offset >= 1) {
|
||||
$dateFormat[0] = $offset;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($transformations['DateFormat'][1])) {
|
||||
$dateFormat[1] = (string) $transformations['DateFormat'][1];
|
||||
}
|
||||
|
||||
if (isset($transformations['DateFormat'][2]) && $transformations['DateFormat'][2] === 'utc') {
|
||||
$dateFormat[2] = 'utc';
|
||||
}
|
||||
}
|
||||
|
||||
return $dateFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $transformations
|
||||
*
|
||||
* @return array<(int|string), (int|string|array<string, string>|null)>
|
||||
* @psalm-return array{
|
||||
* 0: 0|positive-int,
|
||||
* 1: 0|positive-int,
|
||||
* wrapper_link: string|null,
|
||||
* wrapper_params: array<array-key, string>
|
||||
* }
|
||||
*/
|
||||
private function setInline(array $transformations): array
|
||||
{
|
||||
$inline = [100, 100, 'wrapper_link' => null, 'wrapper_params' => []];
|
||||
if (isset($transformations['Inline']) && is_array($transformations['Inline'])) {
|
||||
if (isset($transformations['Inline'][0])) {
|
||||
$width = (int) $transformations['Inline'][0];
|
||||
if ($width >= 0) {
|
||||
$inline[0] = $width;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($transformations['Inline'][1])) {
|
||||
$height = (int) $transformations['Inline'][1];
|
||||
if ($height >= 0) {
|
||||
$inline[1] = $height;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($transformations['Inline']['wrapper_link'])) {
|
||||
$inline['wrapper_link'] = (string) $transformations['Inline']['wrapper_link'];
|
||||
}
|
||||
|
||||
if (
|
||||
isset($transformations['Inline']['wrapper_params'])
|
||||
&& is_array($transformations['Inline']['wrapper_params'])
|
||||
) {
|
||||
/**
|
||||
* @var int|string $key
|
||||
* @var mixed $value
|
||||
*/
|
||||
foreach ($transformations['Inline']['wrapper_params'] as $key => $value) {
|
||||
$inline['wrapper_params'][$key] = (string) $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $inline;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $transformations
|
||||
*
|
||||
* @return array<int, int|string|null>
|
||||
* @psalm-return array{0: string|null, 1: 0|positive-int, 2: 0|positive-int}
|
||||
*/
|
||||
private function setTextImageLink(array $transformations): array
|
||||
{
|
||||
$textImageLink = [null, 100, 50];
|
||||
if (isset($transformations['TextImageLink']) && is_array($transformations['TextImageLink'])) {
|
||||
if (isset($transformations['TextImageLink'][0])) {
|
||||
$textImageLink[0] = (string) $transformations['TextImageLink'][0];
|
||||
}
|
||||
|
||||
if (isset($transformations['TextImageLink'][1])) {
|
||||
$width = (int) $transformations['TextImageLink'][1];
|
||||
if ($width >= 0) {
|
||||
$textImageLink[1] = $width;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($transformations['TextImageLink'][2])) {
|
||||
$height = (int) $transformations['TextImageLink'][2];
|
||||
if ($height >= 0) {
|
||||
$textImageLink[2] = $height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $textImageLink;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $transformations
|
||||
*
|
||||
* @return array<int, string|null>
|
||||
* @psalm-return array{0: string|null, 1: string|null, 2: bool|null}
|
||||
*/
|
||||
private function setTextLink(array $transformations): array
|
||||
{
|
||||
$textLink = [null, null, null];
|
||||
if (isset($transformations['TextLink']) && is_array($transformations['TextLink'])) {
|
||||
if (isset($transformations['TextLink'][0])) {
|
||||
$textLink[0] = (string) $transformations['TextLink'][0];
|
||||
}
|
||||
|
||||
if (isset($transformations['TextLink'][1])) {
|
||||
$textLink[1] = (string) $transformations['TextLink'][1];
|
||||
}
|
||||
|
||||
if (isset($transformations['TextLink'][2])) {
|
||||
$textLink[2] = (bool) $transformations['TextLink'][2];
|
||||
}
|
||||
}
|
||||
|
||||
return $textLink;
|
||||
}
|
||||
}
|
486
admin/phpMyAdmin/libraries/classes/Config/SpecialSchemaLinks.php
Normal file
486
admin/phpMyAdmin/libraries/classes/Config/SpecialSchemaLinks.php
Normal file
|
@ -0,0 +1,486 @@
|
|||
<?php
|
||||
/**
|
||||
* Links configuration for MySQL system tables
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config;
|
||||
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
class SpecialSchemaLinks
|
||||
{
|
||||
/**
|
||||
* This array represent the details for generating links inside
|
||||
* special schemas like mysql, information_schema etc.
|
||||
* Major element represent a schema.
|
||||
* All the strings in this array represented in lower case
|
||||
*
|
||||
* Array structure ex:
|
||||
* array(
|
||||
* // Database name is the major element
|
||||
* 'mysql' => array(
|
||||
* // Table name
|
||||
* 'db' => array(
|
||||
* // Column name
|
||||
* 'user' => array(
|
||||
* // Main url param (can be an array where represent sql)
|
||||
* 'link_param' => 'username',
|
||||
* // Other url params
|
||||
* 'link_dependancy_params' => array(
|
||||
* 0 => array(
|
||||
* // URL parameter name
|
||||
* // (can be array where url param has static value)
|
||||
* 'param_info' => 'hostname',
|
||||
* // Column name related to url param
|
||||
* 'column_name' => 'host'
|
||||
* )
|
||||
* ),
|
||||
* // Page to link
|
||||
* 'default_page' => './' . Url::getFromRoute('/server/privileges')
|
||||
* )
|
||||
* )
|
||||
* )
|
||||
* );
|
||||
*
|
||||
* @return array<string,array<string,array<string,array<string,array<int,array<string,string>>|string>>>>
|
||||
* @phpstan-return array<
|
||||
* string, array<
|
||||
* string, array<
|
||||
* string,
|
||||
* array{
|
||||
* 'link_param': string,
|
||||
* 'link_dependancy_params'?: array<
|
||||
* int,
|
||||
* array{'param_info': string, 'column_name': string}
|
||||
* >,
|
||||
* 'default_page': string
|
||||
* }>
|
||||
* >
|
||||
* >
|
||||
* }
|
||||
*/
|
||||
public static function get(): array
|
||||
{
|
||||
global $cfg;
|
||||
|
||||
$defaultPageDatabase = './' . Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database');
|
||||
$defaultPageTable = './' . Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table');
|
||||
|
||||
return [
|
||||
'mysql' => [
|
||||
'columns_priv' => [
|
||||
'user' => [
|
||||
'link_param' => 'username',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'hostname',
|
||||
'column_name' => 'host',
|
||||
],
|
||||
],
|
||||
'default_page' => './' . Url::getFromRoute('/server/privileges'),
|
||||
],
|
||||
'table_name' => [
|
||||
'link_param' => 'table',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'db',
|
||||
'column_name' => 'Db',
|
||||
],
|
||||
],
|
||||
'default_page' => $defaultPageTable,
|
||||
],
|
||||
'column_name' => [
|
||||
'link_param' => 'field',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'db',
|
||||
'column_name' => 'Db',
|
||||
],
|
||||
1 => [
|
||||
'param_info' => 'table',
|
||||
'column_name' => 'Table_name',
|
||||
],
|
||||
],
|
||||
'default_page' => './' . Url::getFromRoute('/table/structure/change', ['change_column' => 1]),
|
||||
],
|
||||
],
|
||||
'db' => [
|
||||
'user' => [
|
||||
'link_param' => 'username',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'hostname',
|
||||
'column_name' => 'host',
|
||||
],
|
||||
],
|
||||
'default_page' => './' . Url::getFromRoute('/server/privileges'),
|
||||
],
|
||||
],
|
||||
'event' => [
|
||||
'name' => [
|
||||
'link_param' => 'item_name',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'db',
|
||||
'column_name' => 'db',
|
||||
],
|
||||
],
|
||||
'default_page' => './' . Url::getFromRoute('/database/events', ['edit_item' => 1]),
|
||||
],
|
||||
|
||||
],
|
||||
'innodb_index_stats' => [
|
||||
'table_name' => [
|
||||
'link_param' => 'table',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'db',
|
||||
'column_name' => 'database_name',
|
||||
],
|
||||
],
|
||||
'default_page' => $defaultPageTable,
|
||||
],
|
||||
'index_name' => [
|
||||
'link_param' => 'index',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'db',
|
||||
'column_name' => 'database_name',
|
||||
],
|
||||
1 => [
|
||||
'param_info' => 'table',
|
||||
'column_name' => 'table_name',
|
||||
],
|
||||
],
|
||||
'default_page' => './' . Url::getFromRoute('/table/structure'),
|
||||
],
|
||||
],
|
||||
'innodb_table_stats' => [
|
||||
'table_name' => [
|
||||
'link_param' => 'table',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'db',
|
||||
'column_name' => 'database_name',
|
||||
],
|
||||
],
|
||||
'default_page' => $defaultPageTable,
|
||||
],
|
||||
],
|
||||
'proc' => [
|
||||
'name' => [
|
||||
'link_param' => 'item_name',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'db',
|
||||
'column_name' => 'db',
|
||||
],
|
||||
1 => [
|
||||
'param_info' => 'item_type',
|
||||
'column_name' => 'type',
|
||||
],
|
||||
],
|
||||
'default_page' => './' . Url::getFromRoute('/database/routines', ['edit_item' => 1]),
|
||||
],
|
||||
'specific_name' => [
|
||||
'link_param' => 'item_name',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'db',
|
||||
'column_name' => 'db',
|
||||
],
|
||||
1 => [
|
||||
'param_info' => 'item_type',
|
||||
'column_name' => 'type',
|
||||
],
|
||||
],
|
||||
'default_page' => './' . Url::getFromRoute('/database/routines', ['edit_item' => 1]),
|
||||
],
|
||||
],
|
||||
'proc_priv' => [
|
||||
'user' => [
|
||||
'link_param' => 'username',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'hostname',
|
||||
'column_name' => 'Host',
|
||||
],
|
||||
],
|
||||
'default_page' => './' . Url::getFromRoute('/server/privileges'),
|
||||
],
|
||||
'routine_name' => [
|
||||
'link_param' => 'item_name',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'db',
|
||||
'column_name' => 'Db',
|
||||
],
|
||||
1 => [
|
||||
'param_info' => 'item_type',
|
||||
'column_name' => 'Routine_type',
|
||||
],
|
||||
],
|
||||
'default_page' => './' . Url::getFromRoute('/database/routines', ['edit_item' => 1]),
|
||||
],
|
||||
],
|
||||
'proxies_priv' => [
|
||||
'user' => [
|
||||
'link_param' => 'username',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'hostname',
|
||||
'column_name' => 'Host',
|
||||
],
|
||||
],
|
||||
'default_page' => './' . Url::getFromRoute('/server/privileges'),
|
||||
],
|
||||
],
|
||||
'tables_priv' => [
|
||||
'user' => [
|
||||
'link_param' => 'username',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'hostname',
|
||||
'column_name' => 'Host',
|
||||
],
|
||||
],
|
||||
'default_page' => './' . Url::getFromRoute('/server/privileges'),
|
||||
],
|
||||
'table_name' => [
|
||||
'link_param' => 'table',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'db',
|
||||
'column_name' => 'Db',
|
||||
],
|
||||
],
|
||||
'default_page' => $defaultPageTable,
|
||||
],
|
||||
],
|
||||
'user' => [
|
||||
'user' => [
|
||||
'link_param' => 'username',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'hostname',
|
||||
'column_name' => 'host',
|
||||
],
|
||||
],
|
||||
'default_page' => './' . Url::getFromRoute('/server/privileges'),
|
||||
],
|
||||
],
|
||||
],
|
||||
'information_schema' => [
|
||||
'columns' => [
|
||||
'table_name' => [
|
||||
'link_param' => 'table',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'db',
|
||||
'column_name' => 'table_schema',
|
||||
],
|
||||
],
|
||||
'default_page' => $defaultPageTable,
|
||||
],
|
||||
'column_name' => [
|
||||
'link_param' => 'field',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'db',
|
||||
'column_name' => 'table_schema',
|
||||
],
|
||||
1 => [
|
||||
'param_info' => 'table',
|
||||
'column_name' => 'table_name',
|
||||
],
|
||||
],
|
||||
'default_page' => './' . Url::getFromRoute('/table/structure/change', ['change_column' => 1]),
|
||||
],
|
||||
],
|
||||
'key_column_usage' => [
|
||||
'table_name' => [
|
||||
'link_param' => 'table',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'db',
|
||||
'column_name' => 'constraint_schema',
|
||||
],
|
||||
],
|
||||
'default_page' => $defaultPageTable,
|
||||
],
|
||||
'column_name' => [
|
||||
'link_param' => 'field',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'db',
|
||||
'column_name' => 'table_schema',
|
||||
],
|
||||
1 => [
|
||||
'param_info' => 'table',
|
||||
'column_name' => 'table_name',
|
||||
],
|
||||
],
|
||||
'default_page' => './' . Url::getFromRoute('/table/structure/change', ['change_column' => 1]),
|
||||
],
|
||||
'referenced_table_name' => [
|
||||
'link_param' => 'table',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'db',
|
||||
'column_name' => 'referenced_table_schema',
|
||||
],
|
||||
],
|
||||
'default_page' => $defaultPageTable,
|
||||
],
|
||||
'referenced_column_name' => [
|
||||
'link_param' => 'field',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'db',
|
||||
'column_name' => 'referenced_table_schema',
|
||||
],
|
||||
1 => [
|
||||
'param_info' => 'table',
|
||||
'column_name' => 'referenced_table_name',
|
||||
],
|
||||
],
|
||||
'default_page' => './' . Url::getFromRoute('/table/structure/change', ['change_column' => 1]),
|
||||
],
|
||||
],
|
||||
'partitions' => [
|
||||
'table_name' => [
|
||||
'link_param' => 'table',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'db',
|
||||
'column_name' => 'table_schema',
|
||||
],
|
||||
],
|
||||
'default_page' => $defaultPageTable,
|
||||
],
|
||||
],
|
||||
'processlist' => [
|
||||
'user' => [
|
||||
'link_param' => 'username',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'hostname',
|
||||
'column_name' => 'host',
|
||||
],
|
||||
],
|
||||
'default_page' => './' . Url::getFromRoute('/server/privileges'),
|
||||
],
|
||||
],
|
||||
'referential_constraints' => [
|
||||
'table_name' => [
|
||||
'link_param' => 'table',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'db',
|
||||
'column_name' => 'constraint_schema',
|
||||
],
|
||||
],
|
||||
'default_page' => $defaultPageTable,
|
||||
],
|
||||
'referenced_table_name' => [
|
||||
'link_param' => 'table',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'db',
|
||||
'column_name' => 'constraint_schema',
|
||||
],
|
||||
],
|
||||
'default_page' => $defaultPageTable,
|
||||
],
|
||||
],
|
||||
'routines' => [
|
||||
'routine_name' => [
|
||||
'link_param' => 'item_name',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'db',
|
||||
'column_name' => 'routine_schema',
|
||||
],
|
||||
1 => [
|
||||
'param_info' => 'item_type',
|
||||
'column_name' => 'routine_type',
|
||||
],
|
||||
],
|
||||
'default_page' => './' . Url::getFromRoute('/database/routines'),
|
||||
],
|
||||
],
|
||||
'schemata' => [
|
||||
'schema_name' => [
|
||||
'link_param' => 'db',
|
||||
'default_page' => $defaultPageDatabase,
|
||||
],
|
||||
],
|
||||
'statistics' => [
|
||||
'table_name' => [
|
||||
'link_param' => 'table',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'db',
|
||||
'column_name' => 'table_schema',
|
||||
],
|
||||
],
|
||||
'default_page' => $defaultPageTable,
|
||||
],
|
||||
'column_name' => [
|
||||
'link_param' => 'field',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'db',
|
||||
'column_name' => 'table_schema',
|
||||
],
|
||||
1 => [
|
||||
'param_info' => 'table',
|
||||
'column_name' => 'table_name',
|
||||
],
|
||||
],
|
||||
'default_page' => './' . Url::getFromRoute('/table/structure/change', ['change_column' => 1]),
|
||||
],
|
||||
],
|
||||
'tables' => [
|
||||
'table_name' => [
|
||||
'link_param' => 'table',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'db',
|
||||
'column_name' => 'table_schema',
|
||||
],
|
||||
],
|
||||
'default_page' => $defaultPageTable,
|
||||
],
|
||||
],
|
||||
'table_constraints' => [
|
||||
'table_name' => [
|
||||
'link_param' => 'table',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'db',
|
||||
'column_name' => 'table_schema',
|
||||
],
|
||||
],
|
||||
'default_page' => $defaultPageTable,
|
||||
],
|
||||
],
|
||||
'views' => [
|
||||
'table_name' => [
|
||||
'link_param' => 'table',
|
||||
'link_dependancy_params' => [
|
||||
0 => [
|
||||
'param_info' => 'db',
|
||||
'column_name' => 'table_schema',
|
||||
],
|
||||
],
|
||||
'default_page' => $defaultPageTable,
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
613
admin/phpMyAdmin/libraries/classes/Config/Validator.php
Normal file
613
admin/phpMyAdmin/libraries/classes/Config/Validator.php
Normal file
|
@ -0,0 +1,613 @@
|
|||
<?php
|
||||
/**
|
||||
* Form validation for configuration editor
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Config;
|
||||
|
||||
use PhpMyAdmin\Core;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function __;
|
||||
use function array_map;
|
||||
use function array_merge;
|
||||
use function array_shift;
|
||||
use function call_user_func_array;
|
||||
use function count;
|
||||
use function error_clear_last;
|
||||
use function error_get_last;
|
||||
use function explode;
|
||||
use function filter_var;
|
||||
use function htmlspecialchars;
|
||||
use function intval;
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
use function mb_strpos;
|
||||
use function mb_substr;
|
||||
use function mysqli_close;
|
||||
use function mysqli_connect;
|
||||
use function mysqli_report;
|
||||
use function preg_match;
|
||||
use function preg_replace;
|
||||
use function sprintf;
|
||||
use function str_replace;
|
||||
use function trim;
|
||||
|
||||
use const FILTER_FLAG_IPV4;
|
||||
use const FILTER_FLAG_IPV6;
|
||||
use const FILTER_VALIDATE_IP;
|
||||
use const MYSQLI_REPORT_OFF;
|
||||
use const PHP_INT_MAX;
|
||||
|
||||
/**
|
||||
* Validation class for various validation functions
|
||||
*
|
||||
* Validation function takes two argument: id for which it is called
|
||||
* and array of fields' values (usually values for entire formset).
|
||||
* The function must always return an array with an error (or error array)
|
||||
* assigned to a form element (formset name or field path). Even if there are
|
||||
* no errors, key must be set with an empty value.
|
||||
*
|
||||
* Validation functions are assigned in $cfg_db['_validators'] (config.values.php).
|
||||
*/
|
||||
class Validator
|
||||
{
|
||||
/**
|
||||
* Returns validator list
|
||||
*
|
||||
* @param ConfigFile $cf Config file instance
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getValidators(ConfigFile $cf)
|
||||
{
|
||||
static $validators = null;
|
||||
|
||||
if ($validators !== null) {
|
||||
return $validators;
|
||||
}
|
||||
|
||||
$validators = $cf->getDbEntry('_validators', []);
|
||||
if ($GLOBALS['config']->get('is_setup')) {
|
||||
return $validators;
|
||||
}
|
||||
|
||||
// not in setup script: load additional validators for user
|
||||
// preferences we need original config values not overwritten
|
||||
// by user preferences, creating a new PhpMyAdmin\Config instance is a
|
||||
// better idea than hacking into its code
|
||||
$uvs = $cf->getDbEntry('_userValidators', []);
|
||||
foreach ($uvs as $field => $uvList) {
|
||||
$uvList = (array) $uvList;
|
||||
foreach ($uvList as &$uv) {
|
||||
if (! is_array($uv)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for ($i = 1, $nb = count($uv); $i < $nb; $i++) {
|
||||
if (mb_substr($uv[$i], 0, 6) !== 'value:') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$uv[$i] = Core::arrayRead(
|
||||
mb_substr($uv[$i], 6),
|
||||
$GLOBALS['config']->baseSettings
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$validators[$field] = isset($validators[$field])
|
||||
? array_merge((array) $validators[$field], $uvList)
|
||||
: $uvList;
|
||||
}
|
||||
|
||||
return $validators;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs validation $validator_id on values $values and returns error list.
|
||||
*
|
||||
* Return values:
|
||||
* o array, keys - field path or formset id, values - array of errors
|
||||
* when $isPostSource is true values is an empty array to allow for error list
|
||||
* cleanup in HTML document
|
||||
* o false - when no validators match name(s) given by $validator_id
|
||||
*
|
||||
* @param ConfigFile $cf Config file instance
|
||||
* @param string|array $validatorId ID of validator(s) to run
|
||||
* @param array $values Values to validate
|
||||
* @param bool $isPostSource tells whether $values are directly from
|
||||
* POST request
|
||||
*
|
||||
* @return bool|array
|
||||
*/
|
||||
public static function validate(
|
||||
ConfigFile $cf,
|
||||
$validatorId,
|
||||
array &$values,
|
||||
$isPostSource
|
||||
) {
|
||||
// find validators
|
||||
$validatorId = (array) $validatorId;
|
||||
$validators = static::getValidators($cf);
|
||||
$vids = [];
|
||||
foreach ($validatorId as &$vid) {
|
||||
$vid = $cf->getCanonicalPath($vid);
|
||||
if (! isset($validators[$vid])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$vids[] = $vid;
|
||||
}
|
||||
|
||||
if (empty($vids)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// create argument list with canonical paths and remember path mapping
|
||||
$arguments = [];
|
||||
$keyMap = [];
|
||||
foreach ($values as $k => $v) {
|
||||
$k2 = $isPostSource ? str_replace('-', '/', $k) : $k;
|
||||
$k2 = mb_strpos($k2, '/')
|
||||
? $cf->getCanonicalPath($k2)
|
||||
: $k2;
|
||||
$keyMap[$k2] = $k;
|
||||
$arguments[$k2] = $v;
|
||||
}
|
||||
|
||||
// validate
|
||||
$result = [];
|
||||
foreach ($vids as $vid) {
|
||||
// call appropriate validation functions
|
||||
foreach ((array) $validators[$vid] as $validator) {
|
||||
$vdef = (array) $validator;
|
||||
$vname = array_shift($vdef);
|
||||
/** @var callable $vname */
|
||||
$vname = 'PhpMyAdmin\Config\Validator::' . $vname;
|
||||
$args = array_merge([$vid, &$arguments], $vdef);
|
||||
$r = call_user_func_array($vname, $args);
|
||||
|
||||
// merge results
|
||||
if (! is_array($r)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($r as $key => $errorList) {
|
||||
// skip empty values if $isPostSource is false
|
||||
if (! $isPostSource && empty($errorList)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! isset($result[$key])) {
|
||||
$result[$key] = [];
|
||||
}
|
||||
|
||||
$errorList = array_map('PhpMyAdmin\Sanitize::sanitizeMessage', (array) $errorList);
|
||||
$result[$key] = array_merge($result[$key], $errorList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// restore original paths
|
||||
$newResult = [];
|
||||
foreach ($result as $k => $v) {
|
||||
$k2 = $keyMap[$k] ?? $k;
|
||||
$newResult[$k2] = $v;
|
||||
}
|
||||
|
||||
return empty($newResult) ? true : $newResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test database connection
|
||||
*
|
||||
* @param string $host host name
|
||||
* @param string $port tcp port to use
|
||||
* @param string $socket socket to use
|
||||
* @param string $user username to use
|
||||
* @param string $pass password to use
|
||||
* @param string $errorKey key to use in return array
|
||||
*
|
||||
* @return bool|array
|
||||
*/
|
||||
public static function testDBConnection(
|
||||
$host,
|
||||
$port,
|
||||
$socket,
|
||||
$user,
|
||||
$pass = null,
|
||||
$errorKey = 'Server'
|
||||
) {
|
||||
if ($GLOBALS['cfg']['DBG']['demo']) {
|
||||
// Connection test disabled on the demo server!
|
||||
return true;
|
||||
}
|
||||
|
||||
$error = null;
|
||||
$host = Core::sanitizeMySQLHost($host);
|
||||
|
||||
error_clear_last();
|
||||
|
||||
/** @var string $socket */
|
||||
$socket = empty($socket) ? null : $socket;
|
||||
/** @var int $port */
|
||||
$port = empty($port) ? null : (int) $port;
|
||||
|
||||
mysqli_report(MYSQLI_REPORT_OFF);
|
||||
|
||||
$conn = @mysqli_connect($host, $user, (string) $pass, '', $port, $socket);
|
||||
if (! $conn) {
|
||||
$error = __('Could not connect to the database server!');
|
||||
} else {
|
||||
mysqli_close($conn);
|
||||
}
|
||||
|
||||
if ($error !== null) {
|
||||
$lastError = error_get_last();
|
||||
if ($lastError !== null) {
|
||||
$error .= ' - ' . $lastError['message'];
|
||||
}
|
||||
}
|
||||
|
||||
return $error === null ? true : [$errorKey => $error];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate server config
|
||||
*
|
||||
* @param string $path path to config, not used
|
||||
* keep this parameter since the method is invoked using
|
||||
* reflection along with other similar methods
|
||||
* @param array $values config values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function validateServer($path, array $values)
|
||||
{
|
||||
$result = [
|
||||
'Server' => '',
|
||||
'Servers/1/user' => '',
|
||||
'Servers/1/SignonSession' => '',
|
||||
'Servers/1/SignonURL' => '',
|
||||
];
|
||||
$error = false;
|
||||
if (empty($values['Servers/1/auth_type'])) {
|
||||
$values['Servers/1/auth_type'] = '';
|
||||
$result['Servers/1/auth_type'] = __('Invalid authentication type!');
|
||||
$error = true;
|
||||
}
|
||||
|
||||
if ($values['Servers/1/auth_type'] === 'config' && empty($values['Servers/1/user'])) {
|
||||
$result['Servers/1/user'] = __('Empty username while using [kbd]config[/kbd] authentication method!');
|
||||
$error = true;
|
||||
}
|
||||
|
||||
if ($values['Servers/1/auth_type'] === 'signon' && empty($values['Servers/1/SignonSession'])) {
|
||||
$result['Servers/1/SignonSession'] = __(
|
||||
'Empty signon session name while using [kbd]signon[/kbd] authentication method!'
|
||||
);
|
||||
$error = true;
|
||||
}
|
||||
|
||||
if ($values['Servers/1/auth_type'] === 'signon' && empty($values['Servers/1/SignonURL'])) {
|
||||
$result['Servers/1/SignonURL'] = __(
|
||||
'Empty signon URL while using [kbd]signon[/kbd] authentication method!'
|
||||
);
|
||||
$error = true;
|
||||
}
|
||||
|
||||
if (! $error && $values['Servers/1/auth_type'] === 'config') {
|
||||
$password = '';
|
||||
if (! empty($values['Servers/1/password'])) {
|
||||
$password = $values['Servers/1/password'];
|
||||
}
|
||||
|
||||
$test = static::testDBConnection(
|
||||
empty($values['Servers/1/host']) ? '' : $values['Servers/1/host'],
|
||||
empty($values['Servers/1/port']) ? '' : $values['Servers/1/port'],
|
||||
empty($values['Servers/1/socket']) ? '' : $values['Servers/1/socket'],
|
||||
empty($values['Servers/1/user']) ? '' : $values['Servers/1/user'],
|
||||
$password,
|
||||
'Server'
|
||||
);
|
||||
|
||||
if (is_array($test)) {
|
||||
$result = array_merge($result, $test);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate pmadb config
|
||||
*
|
||||
* @param string $path path to config, not used
|
||||
* keep this parameter since the method is invoked using
|
||||
* reflection along with other similar methods
|
||||
* @param array $values config values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function validatePMAStorage($path, array $values)
|
||||
{
|
||||
$result = [
|
||||
'Server_pmadb' => '',
|
||||
'Servers/1/controluser' => '',
|
||||
'Servers/1/controlpass' => '',
|
||||
];
|
||||
$error = false;
|
||||
|
||||
if (empty($values['Servers/1/pmadb'])) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$result = [];
|
||||
if (empty($values['Servers/1/controluser'])) {
|
||||
$result['Servers/1/controluser'] = __(
|
||||
'Empty phpMyAdmin control user while using phpMyAdmin configuration storage!'
|
||||
);
|
||||
$error = true;
|
||||
}
|
||||
|
||||
if (empty($values['Servers/1/controlpass'])) {
|
||||
$result['Servers/1/controlpass'] = __(
|
||||
'Empty phpMyAdmin control user password while using phpMyAdmin configuration storage!'
|
||||
);
|
||||
$error = true;
|
||||
}
|
||||
|
||||
if (! $error) {
|
||||
$test = static::testDBConnection(
|
||||
empty($values['Servers/1/host']) ? '' : $values['Servers/1/host'],
|
||||
empty($values['Servers/1/port']) ? '' : $values['Servers/1/port'],
|
||||
empty($values['Servers/1/socket']) ? '' : $values['Servers/1/socket'],
|
||||
empty($values['Servers/1/controluser']) ? '' : $values['Servers/1/controluser'],
|
||||
empty($values['Servers/1/controlpass']) ? '' : $values['Servers/1/controlpass'],
|
||||
'Server_pmadb'
|
||||
);
|
||||
if (is_array($test)) {
|
||||
$result = array_merge($result, $test);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates regular expression
|
||||
*
|
||||
* @param string $path path to config
|
||||
* @param array $values config values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function validateRegex($path, array $values)
|
||||
{
|
||||
$result = [$path => ''];
|
||||
|
||||
if (empty($values[$path])) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
error_clear_last();
|
||||
|
||||
$matches = [];
|
||||
// in libraries/ListDatabase.php _checkHideDatabase(),
|
||||
// a '/' is used as the delimiter for hide_db
|
||||
@preg_match('/' . Util::requestString($values[$path]) . '/', '', $matches);
|
||||
|
||||
$currentError = error_get_last();
|
||||
|
||||
if ($currentError !== null) {
|
||||
$error = preg_replace('/^preg_match\(\): /', '', $currentError['message']);
|
||||
|
||||
return [$path => $error];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates TrustedProxies field
|
||||
*
|
||||
* @param string $path path to config
|
||||
* @param array $values config values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function validateTrustedProxies($path, array $values)
|
||||
{
|
||||
$result = [$path => []];
|
||||
|
||||
if (empty($values[$path])) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
if (is_array($values[$path]) || is_object($values[$path])) {
|
||||
// value already processed by FormDisplay::save
|
||||
$lines = [];
|
||||
foreach ($values[$path] as $ip => $v) {
|
||||
$v = Util::requestString($v);
|
||||
$lines[] = preg_match('/^-\d+$/', $ip)
|
||||
? $v
|
||||
: $ip . ': ' . $v;
|
||||
}
|
||||
} else {
|
||||
// AJAX validation
|
||||
$lines = explode("\n", $values[$path]);
|
||||
}
|
||||
|
||||
foreach ($lines as $line) {
|
||||
$line = trim($line);
|
||||
$matches = [];
|
||||
// we catch anything that may (or may not) be an IP
|
||||
if (! preg_match('/^(.+):(?:[ ]?)\\w+$/', $line, $matches)) {
|
||||
$result[$path][] = __('Incorrect value:') . ' '
|
||||
. htmlspecialchars($line);
|
||||
continue;
|
||||
}
|
||||
|
||||
// now let's check whether we really have an IP address
|
||||
if (
|
||||
filter_var($matches[1], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false
|
||||
&& filter_var($matches[1], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false
|
||||
) {
|
||||
$ip = htmlspecialchars(trim($matches[1]));
|
||||
$result[$path][] = sprintf(__('Incorrect IP address: %s'), $ip);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests integer value
|
||||
*
|
||||
* @param string $path path to config
|
||||
* @param array $values config values
|
||||
* @param bool $allowNegative allow negative values
|
||||
* @param bool $allowZero allow zero
|
||||
* @param int $maxValue max allowed value
|
||||
* @param string $errorString error message string
|
||||
*
|
||||
* @return string empty string if test is successful
|
||||
*/
|
||||
public static function validateNumber(
|
||||
$path,
|
||||
array $values,
|
||||
$allowNegative,
|
||||
$allowZero,
|
||||
$maxValue,
|
||||
$errorString
|
||||
) {
|
||||
if (empty($values[$path])) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$value = Util::requestString($values[$path]);
|
||||
|
||||
if (
|
||||
intval($value) != $value
|
||||
|| (! $allowNegative && $value < 0)
|
||||
|| (! $allowZero && $value == 0)
|
||||
|| $value > $maxValue
|
||||
) {
|
||||
return $errorString;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates port number
|
||||
*
|
||||
* @param string $path path to config
|
||||
* @param array $values config values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function validatePortNumber($path, array $values)
|
||||
{
|
||||
return [
|
||||
$path => static::validateNumber(
|
||||
$path,
|
||||
$values,
|
||||
false,
|
||||
false,
|
||||
65535,
|
||||
__('Not a valid port number!')
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates positive number
|
||||
*
|
||||
* @param string $path path to config
|
||||
* @param array $values config values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function validatePositiveNumber($path, array $values)
|
||||
{
|
||||
return [
|
||||
$path => static::validateNumber(
|
||||
$path,
|
||||
$values,
|
||||
false,
|
||||
false,
|
||||
PHP_INT_MAX,
|
||||
__('Not a positive number!')
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates non-negative number
|
||||
*
|
||||
* @param string $path path to config
|
||||
* @param array $values config values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function validateNonNegativeNumber($path, array $values)
|
||||
{
|
||||
return [
|
||||
$path => static::validateNumber(
|
||||
$path,
|
||||
$values,
|
||||
false,
|
||||
true,
|
||||
PHP_INT_MAX,
|
||||
__('Not a non-negative number!')
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates value according to given regular expression
|
||||
* Pattern and modifiers must be a valid for PCRE <b>and</b> JavaScript RegExp
|
||||
*
|
||||
* @param string $path path to config
|
||||
* @param array $values config values
|
||||
* @param string $regex regular expression to match
|
||||
*
|
||||
* @return array|string
|
||||
*/
|
||||
public static function validateByRegex($path, array $values, $regex)
|
||||
{
|
||||
if (! isset($values[$path])) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$result = preg_match($regex, Util::requestString($values[$path]));
|
||||
|
||||
return [$path => $result ? '' : __('Incorrect value!')];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates upper bound for numeric inputs
|
||||
*
|
||||
* @param string $path path to config
|
||||
* @param array $values config values
|
||||
* @param int $maxValue maximal allowed value
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function validateUpperBound($path, array $values, $maxValue)
|
||||
{
|
||||
$result = $values[$path] <= $maxValue;
|
||||
|
||||
return [
|
||||
$path => $result ? '' : sprintf(
|
||||
__('Value must be less than or equal to %s!'),
|
||||
$maxValue
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue