FormDisplay.php 29 KB

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