VariablesController.php 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * Holds the PhpMyAdmin\Controllers\Server\VariablesController
  5. *
  6. * @package PhpMyAdmin\Controllers
  7. */
  8. declare(strict_types=1);
  9. namespace PhpMyAdmin\Controllers\Server;
  10. use PhpMyAdmin\Controllers\AbstractController;
  11. use PhpMyAdmin\Util;
  12. use Williamdes\MariaDBMySQLKBS\KBException;
  13. use Williamdes\MariaDBMySQLKBS\Search as KBSearch;
  14. /**
  15. * Handles viewing and editing server variables
  16. *
  17. * @package PhpMyAdmin\Controllers
  18. */
  19. class VariablesController extends AbstractController
  20. {
  21. /**
  22. * Index action
  23. *
  24. * @param array $params Request parameters
  25. *
  26. * @return string
  27. */
  28. public function index(array $params): string
  29. {
  30. include ROOT_PATH . 'libraries/server_common.inc.php';
  31. $filterValue = ! empty($params['filter']) ? $params['filter'] : '';
  32. $header = $this->response->getHeader();
  33. $scripts = $header->getScripts();
  34. $scripts->addFile('server/variables.js');
  35. $variables = [];
  36. $serverVarsResult = $this->dbi->tryQuery('SHOW SESSION VARIABLES;');
  37. if ($serverVarsResult !== false) {
  38. $serverVarsSession = [];
  39. while ($arr = $this->dbi->fetchRow($serverVarsResult)) {
  40. $serverVarsSession[$arr[0]] = $arr[1];
  41. }
  42. $this->dbi->freeResult($serverVarsResult);
  43. $serverVars = $this->dbi->fetchResult('SHOW GLOBAL VARIABLES;', 0, 1);
  44. // list of static (i.e. non-editable) system variables
  45. $staticVariables = KBSearch::getStaticVariables();
  46. foreach ($serverVars as $name => $value) {
  47. $hasSessionValue = isset($serverVarsSession[$name])
  48. && $serverVarsSession[$name] !== $value;
  49. $docLink = Util::linkToVarDocumentation(
  50. $name,
  51. $this->dbi->isMariaDB(),
  52. str_replace('_', '&nbsp;', $name)
  53. );
  54. list($formattedValue, $isEscaped) = $this->formatVariable($name, $value);
  55. if ($hasSessionValue) {
  56. list($sessionFormattedValue, ) = $this->formatVariable(
  57. $name,
  58. $serverVarsSession[$name]
  59. );
  60. }
  61. $variables[] = [
  62. 'name' => $name,
  63. 'is_editable' => ! in_array(strtolower($name), $staticVariables),
  64. 'doc_link' => $docLink,
  65. 'value' => $formattedValue,
  66. 'is_escaped' => $isEscaped,
  67. 'has_session_value' => $hasSessionValue,
  68. 'session_value' => $sessionFormattedValue ?? null,
  69. ];
  70. }
  71. }
  72. return $this->template->render('server/variables/index', [
  73. 'variables' => $variables,
  74. 'filter_value' => $filterValue,
  75. 'is_superuser' => $this->dbi->isSuperuser(),
  76. 'is_mariadb' => $this->dbi->isMariaDB(),
  77. ]);
  78. }
  79. /**
  80. * Handle the AJAX request for a single variable value
  81. *
  82. * @param array $params Request parameters
  83. *
  84. * @return array
  85. */
  86. public function getValue(array $params): array
  87. {
  88. // Send with correct charset
  89. header('Content-Type: text/html; charset=UTF-8');
  90. // Do not use double quotes inside the query to avoid a problem
  91. // when server is running in ANSI_QUOTES sql_mode
  92. $varValue = $this->dbi->fetchSingleRow(
  93. 'SHOW GLOBAL VARIABLES WHERE Variable_name=\''
  94. . $this->dbi->escapeString($params['varName']) . '\';',
  95. 'NUM'
  96. );
  97. $json = [];
  98. try {
  99. $type = KBSearch::getVariableType($params['varName']);
  100. if ($type === 'byte') {
  101. $json['message'] = implode(
  102. ' ',
  103. Util::formatByteDown($varValue[1], 3, 3)
  104. );
  105. } else {
  106. throw new KBException("Not a type=byte");
  107. }
  108. } catch (KBException $e) {
  109. $json['message'] = $varValue[1];
  110. }
  111. return $json;
  112. }
  113. /**
  114. * Handle the AJAX request for setting value for a single variable
  115. *
  116. * @param array $params Request parameters
  117. *
  118. * @return array
  119. */
  120. public function setValue(array $params): array
  121. {
  122. $value = $params['varValue'];
  123. $matches = [];
  124. try {
  125. $type = KBSearch::getVariableType($params['varName']);
  126. if ($type === 'byte' && preg_match(
  127. '/^\s*(\d+(\.\d+)?)\s*(mb|kb|mib|kib|gb|gib)\s*$/i',
  128. $value,
  129. $matches
  130. )) {
  131. $exp = [
  132. 'kb' => 1,
  133. 'kib' => 1,
  134. 'mb' => 2,
  135. 'mib' => 2,
  136. 'gb' => 3,
  137. 'gib' => 3,
  138. ];
  139. $value = floatval($matches[1]) * pow(
  140. 1024,
  141. $exp[mb_strtolower($matches[3])]
  142. );
  143. } else {
  144. throw new KBException("Not a type=byte or regex not matching");
  145. }
  146. } catch (KBException $e) {
  147. $value = $this->dbi->escapeString($value);
  148. }
  149. if (! is_numeric($value)) {
  150. $value = "'" . $value . "'";
  151. }
  152. $json = [];
  153. if (! preg_match("/[^a-zA-Z0-9_]+/", $params['varName'])
  154. && $this->dbi->query(
  155. 'SET GLOBAL ' . $params['varName'] . ' = ' . $value
  156. )
  157. ) {
  158. // Some values are rounded down etc.
  159. $varValue = $this->dbi->fetchSingleRow(
  160. 'SHOW GLOBAL VARIABLES WHERE Variable_name="'
  161. . $this->dbi->escapeString($params['varName'])
  162. . '";',
  163. 'NUM'
  164. );
  165. list($formattedValue, $isHtmlFormatted) = $this->formatVariable(
  166. $params['varName'],
  167. $varValue[1]
  168. );
  169. if ($isHtmlFormatted === false) {
  170. $json['variable'] = htmlspecialchars($formattedValue);
  171. } else {
  172. $json['variable'] = $formattedValue;
  173. }
  174. } else {
  175. $this->response->setRequestStatus(false);
  176. $json['error'] = __('Setting variable failed');
  177. }
  178. return $json;
  179. }
  180. /**
  181. * Format Variable
  182. *
  183. * @param string $name variable name
  184. * @param integer $value variable value
  185. *
  186. * @return array formatted string and bool if string is HTML formatted
  187. */
  188. private function formatVariable($name, $value)
  189. {
  190. $isHtmlFormatted = false;
  191. $formattedValue = $value;
  192. if (is_numeric($value)) {
  193. try {
  194. $type = KBSearch::getVariableType($name);
  195. if ($type === 'byte') {
  196. $isHtmlFormatted = true;
  197. $formattedValue = '<abbr title="'
  198. . htmlspecialchars(Util::formatNumber($value, 0)) . '">'
  199. . htmlspecialchars(
  200. implode(' ', Util::formatByteDown($value, 3, 3))
  201. )
  202. . '</abbr>';
  203. } else {
  204. throw new KBException("Not a type=byte or regex not matching");
  205. }
  206. } catch (KBException $e) {
  207. $formattedValue = Util::formatNumber($value, 0);
  208. }
  209. }
  210. return [
  211. $formattedValue,
  212. $isHtmlFormatted,
  213. ];
  214. }
  215. }