PageRenderTime 48ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/libraries/classes/Config/FormDisplay.php

http://github.com/phpmyadmin/phpmyadmin
PHP | 892 lines | 574 code | 103 blank | 215 comment | 70 complexity | c4b67f48a7a8109009ee190e8ec26e2a MD5 | raw file
Possible License(s): GPL-2.0, MIT, LGPL-3.0
  1. <?php
  2. /**
  3. * Form management class, displays and processes forms
  4. *
  5. * Explanation of used terms:
  6. * o work_path - original field path, eg. Servers/4/verbose
  7. * o system_path - work_path modified so that it points to the first server,
  8. * eg. Servers/1/verbose
  9. * o translated_path - work_path modified for HTML field name, a path with
  10. * slashes changed to hyphens, eg. Servers-4-verbose
  11. */
  12. declare(strict_types=1);
  13. namespace PhpMyAdmin\Config;
  14. use PhpMyAdmin\Config\Forms\User\UserFormList;
  15. use PhpMyAdmin\Html\MySQLDocumentation;
  16. use PhpMyAdmin\Sanitize;
  17. use PhpMyAdmin\Util;
  18. use function __;
  19. use function array_flip;
  20. use function array_keys;
  21. use function array_search;
  22. use function count;
  23. use function explode;
  24. use function function_exists;
  25. use function gettype;
  26. use function implode;
  27. use function is_array;
  28. use function is_bool;
  29. use function is_numeric;
  30. use function mb_substr;
  31. use function preg_match;
  32. use function settype;
  33. use function sprintf;
  34. use function str_replace;
  35. use function trigger_error;
  36. use function trim;
  37. use const E_USER_WARNING;
  38. /**
  39. * Form management class, displays and processes forms
  40. */
  41. class FormDisplay
  42. {
  43. /**
  44. * ConfigFile instance
  45. *
  46. * @var ConfigFile
  47. */
  48. private $configFile;
  49. /**
  50. * Form list
  51. *
  52. * @var Form[]
  53. */
  54. private $forms = [];
  55. /**
  56. * Stores validation errors, indexed by paths
  57. * [ Form_name ] is an array of form errors
  58. * [path] is a string storing error associated with single field
  59. *
  60. * @var array
  61. */
  62. private $errors = [];
  63. /**
  64. * Paths changed so that they can be used as HTML ids, indexed by paths
  65. *
  66. * @var array
  67. */
  68. private $translatedPaths = [];
  69. /**
  70. * Server paths change indexes so we define maps from current server
  71. * path to the first one, indexed by work path
  72. *
  73. * @var array
  74. */
  75. private $systemPaths = [];
  76. /**
  77. * Tells whether forms have been validated
  78. *
  79. * @var bool
  80. */
  81. private $isValidated = true;
  82. /**
  83. * Dictionary with user preferences keys
  84. *
  85. * @var array|null
  86. */
  87. private $userprefsKeys;
  88. /**
  89. * Dictionary with disallowed user preferences keys
  90. *
  91. * @var array
  92. */
  93. private $userprefsDisallow;
  94. /** @var FormDisplayTemplate */
  95. private $formDisplayTemplate;
  96. /**
  97. * @param ConfigFile $cf Config file instance
  98. */
  99. public function __construct(ConfigFile $cf)
  100. {
  101. $this->formDisplayTemplate = new FormDisplayTemplate($GLOBALS['config']);
  102. $this->configFile = $cf;
  103. // initialize validators
  104. Validator::getValidators($this->configFile);
  105. }
  106. /**
  107. * Returns {@link ConfigFile} associated with this instance
  108. *
  109. * @return ConfigFile
  110. */
  111. public function getConfigFile()
  112. {
  113. return $this->configFile;
  114. }
  115. /**
  116. * Registers form in form manager
  117. *
  118. * @param string $formName Form name
  119. * @param array $form Form data
  120. * @param int $serverId 0 if new server, validation; >= 1 if editing a server
  121. */
  122. public function registerForm($formName, array $form, $serverId = null): void
  123. {
  124. $this->forms[$formName] = new Form($formName, $form, $this->configFile, $serverId);
  125. $this->isValidated = false;
  126. foreach ($this->forms[$formName]->fields as $path) {
  127. $workPath = $serverId === null
  128. ? $path
  129. : str_replace('Servers/1/', 'Servers/' . $serverId . '/', $path);
  130. $this->systemPaths[$workPath] = $path;
  131. $this->translatedPaths[$workPath] = str_replace('/', '-', $workPath);
  132. }
  133. }
  134. /**
  135. * Processes forms, returns true on successful save
  136. *
  137. * @param bool $allowPartialSave allows for partial form saving
  138. * on failed validation
  139. * @param bool $checkFormSubmit whether check for $_POST['submit_save']
  140. */
  141. public function process($allowPartialSave = true, $checkFormSubmit = true): bool
  142. {
  143. if ($checkFormSubmit && ! isset($_POST['submit_save'])) {
  144. return false;
  145. }
  146. // save forms
  147. if (count($this->forms) > 0) {
  148. return $this->save(array_keys($this->forms), $allowPartialSave);
  149. }
  150. return false;
  151. }
  152. /**
  153. * Runs validation for all registered forms
  154. */
  155. private function validate(): void
  156. {
  157. if ($this->isValidated) {
  158. return;
  159. }
  160. $paths = [];
  161. $values = [];
  162. foreach ($this->forms as $form) {
  163. /** @var Form $form */
  164. $paths[] = $form->name;
  165. // collect values and paths
  166. foreach ($form->fields as $path) {
  167. $workPath = array_search($path, $this->systemPaths);
  168. $values[$path] = $this->configFile->getValue($workPath);
  169. $paths[] = $path;
  170. }
  171. }
  172. // run validation
  173. $errors = Validator::validate($this->configFile, $paths, $values, false);
  174. // change error keys from canonical paths to work paths
  175. if (is_array($errors) && count($errors) > 0) {
  176. $this->errors = [];
  177. foreach ($errors as $path => $errorList) {
  178. $workPath = array_search($path, $this->systemPaths);
  179. // field error
  180. if (! $workPath) {
  181. // form error, fix path
  182. $workPath = $path;
  183. }
  184. $this->errors[$workPath] = $errorList;
  185. }
  186. }
  187. $this->isValidated = true;
  188. }
  189. /**
  190. * Outputs HTML for forms
  191. *
  192. * @param bool $showButtons whether show submit and reset button
  193. * @param string $formAction action attribute for the form
  194. * @param array|null $hiddenFields array of form hidden fields (key: field
  195. * name)
  196. *
  197. * @return string HTML for forms
  198. */
  199. public function getDisplay(
  200. $showButtons = true,
  201. $formAction = null,
  202. $hiddenFields = null
  203. ) {
  204. $js = [];
  205. $jsDefault = [];
  206. /**
  207. * We do validation on page refresh when browser remembers field values,
  208. * add a field with known value which will be used for checks.
  209. */
  210. static $hasCheckPageRefresh = false;
  211. if (! $hasCheckPageRefresh) {
  212. $hasCheckPageRefresh = true;
  213. }
  214. $tabs = [];
  215. foreach ($this->forms as $form) {
  216. $tabs[$form->name] = Descriptions::get('Form_' . $form->name);
  217. }
  218. // validate only when we aren't displaying a "new server" form
  219. $isNewServer = false;
  220. foreach ($this->forms as $form) {
  221. /** @var Form $form */
  222. if ($form->index === 0) {
  223. $isNewServer = true;
  224. break;
  225. }
  226. }
  227. if (! $isNewServer) {
  228. $this->validate();
  229. }
  230. // user preferences
  231. $this->loadUserprefsInfo();
  232. $validators = Validator::getValidators($this->configFile);
  233. $forms = [];
  234. foreach ($this->forms as $key => $form) {
  235. $this->formDisplayTemplate->group = 0;
  236. $forms[$key] = [
  237. 'name' => $form->name,
  238. 'descriptions' => [
  239. 'name' => Descriptions::get('Form_' . $form->name, 'name'),
  240. 'desc' => Descriptions::get('Form_' . $form->name, 'desc'),
  241. ],
  242. 'errors' => $this->errors[$form->name] ?? null,
  243. 'fields_html' => '',
  244. ];
  245. foreach ($form->fields as $field => $path) {
  246. $workPath = array_search($path, $this->systemPaths);
  247. $translatedPath = $this->translatedPaths[$workPath];
  248. // always true/false for user preferences display
  249. // otherwise null
  250. $userPrefsAllow = isset($this->userprefsKeys[$path])
  251. ? ! isset($this->userprefsDisallow[$path])
  252. : null;
  253. // display input
  254. $forms[$key]['fields_html'] .= $this->displayFieldInput(
  255. $form,
  256. $field,
  257. $path,
  258. $workPath,
  259. $translatedPath,
  260. true,
  261. $userPrefsAllow,
  262. $jsDefault
  263. );
  264. // register JS validators for this field
  265. if (! isset($validators[$path])) {
  266. continue;
  267. }
  268. $this->formDisplayTemplate->addJsValidate($translatedPath, $validators[$path], $js);
  269. }
  270. }
  271. return $this->formDisplayTemplate->display([
  272. 'action' => $formAction,
  273. 'has_check_page_refresh' => $hasCheckPageRefresh,
  274. 'hidden_fields' => (array) $hiddenFields,
  275. 'tabs' => $tabs,
  276. 'forms' => $forms,
  277. 'show_buttons' => $showButtons,
  278. 'js_array' => $js,
  279. 'js_default' => $jsDefault,
  280. ]);
  281. }
  282. /**
  283. * Prepares data for input field display and outputs HTML code
  284. *
  285. * @param Form $form Form object
  286. * @param string $field field name as it appears in $form
  287. * @param string $systemPath field path, eg. Servers/1/verbose
  288. * @param string $workPath work path, eg. Servers/4/verbose
  289. * @param string $translatedPath work path changed so that it can be
  290. * used as XHTML id
  291. * @param bool $showRestoreDefault whether show "restore default" button
  292. * besides the input field
  293. * @param bool|null $userPrefsAllow whether user preferences are enabled
  294. * for this field (null - no support,
  295. * true/false - enabled/disabled)
  296. * @param array $jsDefault array which stores JavaScript code
  297. * to be displayed
  298. *
  299. * @return string|null HTML for input field
  300. */
  301. private function displayFieldInput(
  302. Form $form,
  303. $field,
  304. $systemPath,
  305. $workPath,
  306. $translatedPath,
  307. $showRestoreDefault,
  308. $userPrefsAllow,
  309. array &$jsDefault
  310. ) {
  311. $name = Descriptions::get($systemPath);
  312. $description = Descriptions::get($systemPath, 'desc');
  313. $value = $this->configFile->get($workPath);
  314. $valueDefault = $this->configFile->getDefault($systemPath);
  315. $valueIsDefault = false;
  316. if ($value === null || $value === $valueDefault) {
  317. $value = $valueDefault;
  318. $valueIsDefault = true;
  319. }
  320. $opts = [
  321. 'doc' => $this->getDocLink($systemPath),
  322. 'show_restore_default' => $showRestoreDefault,
  323. 'userprefs_allow' => $userPrefsAllow,
  324. 'userprefs_comment' => Descriptions::get($systemPath, 'cmt'),
  325. ];
  326. if (isset($form->default[$systemPath])) {
  327. $opts['setvalue'] = (string) $form->default[$systemPath];
  328. }
  329. if (isset($this->errors[$workPath])) {
  330. $opts['errors'] = $this->errors[$workPath];
  331. }
  332. $type = '';
  333. switch ($form->getOptionType($field)) {
  334. case 'string':
  335. $type = 'text';
  336. break;
  337. case 'short_string':
  338. $type = 'short_text';
  339. break;
  340. case 'double':
  341. case 'integer':
  342. $type = 'number_text';
  343. break;
  344. case 'boolean':
  345. $type = 'checkbox';
  346. break;
  347. case 'select':
  348. $type = 'select';
  349. $opts['values'] = $form->getOptionValueList($form->fields[$field]);
  350. break;
  351. case 'array':
  352. $type = 'list';
  353. $value = (array) $value;
  354. $valueDefault = (array) $valueDefault;
  355. break;
  356. case 'group':
  357. // :group:end is changed to :group:end:{unique id} in Form class
  358. $htmlOutput = '';
  359. if (mb_substr($field, 7, 4) !== 'end:') {
  360. $htmlOutput .= $this->formDisplayTemplate->displayGroupHeader(
  361. mb_substr($field, 7)
  362. );
  363. } else {
  364. $this->formDisplayTemplate->displayGroupFooter();
  365. }
  366. return $htmlOutput;
  367. case 'NULL':
  368. trigger_error('Field ' . $systemPath . ' has no type', E_USER_WARNING);
  369. return null;
  370. }
  371. // detect password fields
  372. if (
  373. $type === 'text'
  374. && (mb_substr($translatedPath, -9) === '-password'
  375. || mb_substr($translatedPath, -4) === 'pass'
  376. || mb_substr($translatedPath, -4) === 'Pass')
  377. ) {
  378. $type = 'password';
  379. }
  380. // TrustedProxies requires changes before displaying
  381. if ($systemPath === 'TrustedProxies') {
  382. foreach ($value as $ip => &$v) {
  383. if (preg_match('/^-\d+$/', $ip)) {
  384. continue;
  385. }
  386. $v = $ip . ': ' . $v;
  387. }
  388. }
  389. $this->setComments($systemPath, $opts);
  390. // send default value to form's JS
  391. $jsLine = '\'' . $translatedPath . '\': ';
  392. switch ($type) {
  393. case 'text':
  394. case 'short_text':
  395. case 'number_text':
  396. case 'password':
  397. $jsLine .= '\'' . Sanitize::escapeJsString($valueDefault) . '\'';
  398. break;
  399. case 'checkbox':
  400. $jsLine .= $valueDefault ? 'true' : 'false';
  401. break;
  402. case 'select':
  403. $valueDefaultJs = is_bool($valueDefault)
  404. ? (int) $valueDefault
  405. : $valueDefault;
  406. $jsLine .= '[\'' . Sanitize::escapeJsString($valueDefaultJs) . '\']';
  407. break;
  408. case 'list':
  409. $val = $valueDefault;
  410. if (isset($val['wrapper_params'])) {
  411. unset($val['wrapper_params']);
  412. }
  413. $jsLine .= '\'' . Sanitize::escapeJsString(implode("\n", $val))
  414. . '\'';
  415. break;
  416. }
  417. $jsDefault[] = $jsLine;
  418. return $this->formDisplayTemplate->displayInput(
  419. $translatedPath,
  420. $name,
  421. $type,
  422. $value,
  423. $description,
  424. $valueIsDefault,
  425. $opts
  426. );
  427. }
  428. /**
  429. * Displays errors
  430. *
  431. * @return string|null HTML for errors
  432. */
  433. public function displayErrors()
  434. {
  435. $this->validate();
  436. if (count($this->errors) === 0) {
  437. return null;
  438. }
  439. $htmlOutput = '';
  440. foreach ($this->errors as $systemPath => $errorList) {
  441. if (isset($this->systemPaths[$systemPath])) {
  442. $name = Descriptions::get($this->systemPaths[$systemPath]);
  443. } else {
  444. $name = Descriptions::get('Form_' . $systemPath);
  445. }
  446. $htmlOutput .= $this->formDisplayTemplate->displayErrors($name, $errorList);
  447. }
  448. return $htmlOutput;
  449. }
  450. /**
  451. * Reverts erroneous fields to their default values
  452. */
  453. public function fixErrors(): void
  454. {
  455. $this->validate();
  456. if (count($this->errors) === 0) {
  457. return;
  458. }
  459. $cf = $this->configFile;
  460. foreach (array_keys($this->errors) as $workPath) {
  461. if (! isset($this->systemPaths[$workPath])) {
  462. continue;
  463. }
  464. $canonicalPath = $this->systemPaths[$workPath];
  465. $cf->set($workPath, $cf->getDefault($canonicalPath));
  466. }
  467. }
  468. /**
  469. * Validates select field and casts $value to correct type
  470. *
  471. * @param string|bool $value Current value
  472. * @param array $allowed List of allowed values
  473. */
  474. private function validateSelect(&$value, array $allowed): bool
  475. {
  476. $valueCmp = is_bool($value)
  477. ? (int) $value
  478. : $value;
  479. foreach ($allowed as $vk => $v) {
  480. // equality comparison only if both values are numeric or not numeric
  481. // (allows to skip 0 == 'string' equalling to true)
  482. // or identity (for string-string)
  483. if (! (($vk == $value && ! (is_numeric($valueCmp) xor is_numeric($vk))) || $vk === $value)) {
  484. continue;
  485. }
  486. // keep boolean value as boolean
  487. if (! is_bool($value)) {
  488. // phpcs:ignore Generic.PHP.ForbiddenFunctions
  489. settype($value, gettype($vk));
  490. }
  491. return true;
  492. }
  493. return false;
  494. }
  495. /**
  496. * Validates and saves form data to session
  497. *
  498. * @param array|string $forms array of form names
  499. * @param bool $allowPartialSave allows for partial form saving on
  500. * failed validation
  501. */
  502. public function save($forms, $allowPartialSave = true): bool
  503. {
  504. $result = true;
  505. $forms = (array) $forms;
  506. $values = [];
  507. $toSave = [];
  508. $isSetupScript = $GLOBALS['config']->get('is_setup');
  509. if ($isSetupScript) {
  510. $this->loadUserprefsInfo();
  511. }
  512. $this->errors = [];
  513. foreach ($forms as $formName) {
  514. if (! isset($this->forms[$formName])) {
  515. continue;
  516. }
  517. /** @var Form $form */
  518. $form = $this->forms[$formName];
  519. // get current server id
  520. $changeIndex = $form->index === 0
  521. ? $this->configFile->getServerCount() + 1
  522. : false;
  523. // grab POST values
  524. foreach ($form->fields as $field => $systemPath) {
  525. $workPath = array_search($systemPath, $this->systemPaths);
  526. $key = $this->translatedPaths[$workPath];
  527. $type = (string) $form->getOptionType($field);
  528. // skip groups
  529. if ($type === 'group') {
  530. continue;
  531. }
  532. // ensure the value is set
  533. if (! isset($_POST[$key])) {
  534. // checkboxes aren't set by browsers if they're off
  535. if ($type !== 'boolean') {
  536. $this->errors[$form->name][] = sprintf(
  537. __('Missing data for %s'),
  538. '<i>' . Descriptions::get($systemPath) . '</i>'
  539. );
  540. $result = false;
  541. continue;
  542. }
  543. $_POST[$key] = false;
  544. }
  545. // user preferences allow/disallow
  546. if ($isSetupScript && isset($this->userprefsKeys[$systemPath])) {
  547. if (isset($this->userprefsDisallow[$systemPath], $_POST[$key . '-userprefs-allow'])) {
  548. unset($this->userprefsDisallow[$systemPath]);
  549. } elseif (! isset($_POST[$key . '-userprefs-allow'])) {
  550. $this->userprefsDisallow[$systemPath] = true;
  551. }
  552. }
  553. // cast variables to correct type
  554. switch ($type) {
  555. case 'double':
  556. $_POST[$key] = Util::requestString($_POST[$key]);
  557. // phpcs:ignore Generic.PHP.ForbiddenFunctions
  558. settype($_POST[$key], 'float');
  559. break;
  560. case 'boolean':
  561. case 'integer':
  562. if ($_POST[$key] !== '') {
  563. $_POST[$key] = Util::requestString($_POST[$key]);
  564. // phpcs:ignore Generic.PHP.ForbiddenFunctions
  565. settype($_POST[$key], $type);
  566. }
  567. break;
  568. case 'select':
  569. $successfullyValidated = $this->validateSelect(
  570. $_POST[$key],
  571. $form->getOptionValueList($systemPath)
  572. );
  573. if (! $successfullyValidated) {
  574. $this->errors[$workPath][] = __('Incorrect value!');
  575. $result = false;
  576. // "continue" for the $form->fields foreach-loop
  577. continue 2;
  578. }
  579. break;
  580. case 'string':
  581. case 'short_string':
  582. $_POST[$key] = Util::requestString($_POST[$key]);
  583. break;
  584. case 'array':
  585. // eliminate empty values and ensure we have an array
  586. $postValues = is_array($_POST[$key])
  587. ? $_POST[$key]
  588. : explode("\n", $_POST[$key]);
  589. $_POST[$key] = [];
  590. $this->fillPostArrayParameters($postValues, $key);
  591. break;
  592. }
  593. // now we have value with proper type
  594. $values[$systemPath] = $_POST[$key];
  595. if ($changeIndex !== false) {
  596. $workPath = str_replace(
  597. 'Servers/' . $form->index . '/',
  598. 'Servers/' . $changeIndex . '/',
  599. $workPath
  600. );
  601. }
  602. $toSave[$workPath] = $systemPath;
  603. }
  604. }
  605. // save forms
  606. if (! $allowPartialSave && ! empty($this->errors)) {
  607. // don't look for non-critical errors
  608. $this->validate();
  609. return $result;
  610. }
  611. foreach ($toSave as $workPath => $path) {
  612. // TrustedProxies requires changes before saving
  613. if ($path === 'TrustedProxies') {
  614. $proxies = [];
  615. $i = 0;
  616. foreach ($values[$path] as $value) {
  617. $matches = [];
  618. $match = preg_match('/^(.+):(?:[ ]?)(\\w+)$/', $value, $matches);
  619. if ($match) {
  620. // correct 'IP: HTTP header' pair
  621. $ip = trim($matches[1]);
  622. $proxies[$ip] = trim($matches[2]);
  623. } else {
  624. // save also incorrect values
  625. $proxies['-' . $i] = $value;
  626. $i++;
  627. }
  628. }
  629. $values[$path] = $proxies;
  630. }
  631. $this->configFile->set($workPath, $values[$path], $path);
  632. }
  633. if ($isSetupScript) {
  634. $this->configFile->set(
  635. 'UserprefsDisallow',
  636. array_keys($this->userprefsDisallow)
  637. );
  638. }
  639. // don't look for non-critical errors
  640. $this->validate();
  641. return $result;
  642. }
  643. /**
  644. * Tells whether form validation failed
  645. */
  646. public function hasErrors(): bool
  647. {
  648. return count($this->errors) > 0;
  649. }
  650. /**
  651. * Returns link to documentation
  652. *
  653. * @param string $path Path to documentation
  654. *
  655. * @return string
  656. */
  657. public function getDocLink($path)
  658. {
  659. $test = mb_substr($path, 0, 6);
  660. if ($test === 'Import' || $test === 'Export') {
  661. return '';
  662. }
  663. return MySQLDocumentation::getDocumentationLink(
  664. 'config',
  665. 'cfg_' . $this->getOptName($path),
  666. Sanitize::isSetup() ? '../' : './'
  667. );
  668. }
  669. /**
  670. * Changes path so it can be used in URLs
  671. *
  672. * @param string $path Path
  673. *
  674. * @return string
  675. */
  676. private function getOptName($path)
  677. {
  678. return str_replace(['Servers/1/', '/'], ['Servers/', '_'], $path);
  679. }
  680. /**
  681. * Fills out {@link userprefs_keys} and {@link userprefs_disallow}
  682. */
  683. private function loadUserprefsInfo(): void
  684. {
  685. if ($this->userprefsKeys !== null) {
  686. return;
  687. }
  688. $this->userprefsKeys = array_flip(UserFormList::getFields());
  689. // read real config for user preferences display
  690. $userPrefsDisallow = $GLOBALS['config']->get('is_setup')
  691. ? $this->configFile->get('UserprefsDisallow', [])
  692. : $GLOBALS['cfg']['UserprefsDisallow'];
  693. $this->userprefsDisallow = array_flip($userPrefsDisallow ?? []);
  694. }
  695. /**
  696. * Sets field comments and warnings based on current environment
  697. *
  698. * @param string $systemPath Path to settings
  699. * @param array $opts Chosen options
  700. */
  701. private function setComments($systemPath, array &$opts): void
  702. {
  703. // RecodingEngine - mark unavailable types
  704. if ($systemPath === 'RecodingEngine') {
  705. $comment = '';
  706. if (! function_exists('iconv')) {
  707. $opts['values']['iconv'] .= ' (' . __('unavailable') . ')';
  708. $comment = sprintf(
  709. __('"%s" requires %s extension'),
  710. 'iconv',
  711. 'iconv'
  712. );
  713. }
  714. if (! function_exists('recode_string')) {
  715. $opts['values']['recode'] .= ' (' . __('unavailable') . ')';
  716. $comment .= ($comment ? ', ' : '') . sprintf(
  717. __('"%s" requires %s extension'),
  718. 'recode',
  719. 'recode'
  720. );
  721. }
  722. /* mbstring is always there thanks to polyfill */
  723. $opts['comment'] = $comment;
  724. $opts['comment_warning'] = true;
  725. }
  726. // ZipDump, GZipDump, BZipDump - check function availability
  727. if ($systemPath === 'ZipDump' || $systemPath === 'GZipDump' || $systemPath === 'BZipDump') {
  728. $comment = '';
  729. $funcs = [
  730. 'ZipDump' => [
  731. 'zip_open',
  732. 'gzcompress',
  733. ],
  734. 'GZipDump' => [
  735. 'gzopen',
  736. 'gzencode',
  737. ],
  738. 'BZipDump' => [
  739. 'bzopen',
  740. 'bzcompress',
  741. ],
  742. ];
  743. if (! function_exists($funcs[$systemPath][0])) {
  744. $comment = sprintf(
  745. __(
  746. 'Compressed import will not work due to missing function %s.'
  747. ),
  748. $funcs[$systemPath][0]
  749. );
  750. }
  751. if (! function_exists($funcs[$systemPath][1])) {
  752. $comment .= ($comment ? '; ' : '') . sprintf(
  753. __(
  754. 'Compressed export will not work due to missing function %s.'
  755. ),
  756. $funcs[$systemPath][1]
  757. );
  758. }
  759. $opts['comment'] = $comment;
  760. $opts['comment_warning'] = true;
  761. }
  762. if ($GLOBALS['config']->get('is_setup')) {
  763. return;
  764. }
  765. if ($systemPath !== 'MaxDbList' && $systemPath !== 'MaxTableList' && $systemPath !== 'QueryHistoryMax') {
  766. return;
  767. }
  768. $opts['comment'] = sprintf(
  769. __('maximum %s'),
  770. $GLOBALS['cfg'][$systemPath]
  771. );
  772. }
  773. /**
  774. * Copy items of an array to $_POST variable
  775. *
  776. * @param array $postValues List of parameters
  777. * @param string $key Array key
  778. */
  779. private function fillPostArrayParameters(array $postValues, $key): void
  780. {
  781. foreach ($postValues as $v) {
  782. $v = Util::requestString($v);
  783. if ($v === '') {
  784. continue;
  785. }
  786. $_POST[$key][] = $v;
  787. }
  788. }
  789. }