Data.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * PhpMyAdmin\Server\Status\Data class
  5. * Used by server_status_*.php pages
  6. *
  7. * @package PhpMyAdmin
  8. */
  9. declare(strict_types=1);
  10. namespace PhpMyAdmin\Server\Status;
  11. use PhpMyAdmin\Url;
  12. /**
  13. * This class provides data about the server status
  14. *
  15. * All properties of the class are read-only
  16. *
  17. * TODO: Use lazy initialisation for some of the properties
  18. * since not all of the server_status_*.php pages need
  19. * all the data that this class provides.
  20. *
  21. * @package PhpMyAdmin
  22. */
  23. class Data
  24. {
  25. public $status;
  26. public $sections;
  27. public $variables;
  28. public $used_queries;
  29. public $allocationMap;
  30. public $links;
  31. public $db_isLocal;
  32. public $section;
  33. public $sectionUsed;
  34. public $selfUrl;
  35. public $dataLoaded;
  36. /**
  37. * An empty setter makes the above properties read-only
  38. *
  39. * @param string $a key
  40. * @param mixed $b value
  41. *
  42. * @return void
  43. */
  44. public function __set($a, $b)
  45. {
  46. // Discard everything
  47. }
  48. /**
  49. * Gets the allocations for constructor
  50. *
  51. * @return array
  52. */
  53. private function _getAllocations()
  54. {
  55. return [
  56. // variable name => section
  57. // variable names match when they begin with the given string
  58. 'Com_' => 'com',
  59. 'Innodb_' => 'innodb',
  60. 'Ndb_' => 'ndb',
  61. 'Handler_' => 'handler',
  62. 'Qcache_' => 'qcache',
  63. 'Threads_' => 'threads',
  64. 'Slow_launch_threads' => 'threads',
  65. 'Binlog_cache_' => 'binlog_cache',
  66. 'Created_tmp_' => 'created_tmp',
  67. 'Key_' => 'key',
  68. 'Delayed_' => 'delayed',
  69. 'Not_flushed_delayed_rows' => 'delayed',
  70. 'Flush_commands' => 'query',
  71. 'Last_query_cost' => 'query',
  72. 'Slow_queries' => 'query',
  73. 'Queries' => 'query',
  74. 'Prepared_stmt_count' => 'query',
  75. 'Select_' => 'select',
  76. 'Sort_' => 'sort',
  77. 'Open_tables' => 'table',
  78. 'Opened_tables' => 'table',
  79. 'Open_table_definitions' => 'table',
  80. 'Opened_table_definitions' => 'table',
  81. 'Table_locks_' => 'table',
  82. 'Rpl_status' => 'repl',
  83. 'Slave_' => 'repl',
  84. 'Tc_' => 'tc',
  85. 'Ssl_' => 'ssl',
  86. 'Open_files' => 'files',
  87. 'Open_streams' => 'files',
  88. 'Opened_files' => 'files',
  89. ];
  90. }
  91. /**
  92. * Gets the sections for constructor
  93. *
  94. * @return array
  95. */
  96. private function _getSections()
  97. {
  98. return [
  99. // section => section name (description)
  100. 'com' => 'Com',
  101. 'query' => __('SQL query'),
  102. 'innodb' => 'InnoDB',
  103. 'ndb' => 'NDB',
  104. 'handler' => __('Handler'),
  105. 'qcache' => __('Query cache'),
  106. 'threads' => __('Threads'),
  107. 'binlog_cache' => __('Binary log'),
  108. 'created_tmp' => __('Temporary data'),
  109. 'delayed' => __('Delayed inserts'),
  110. 'key' => __('Key cache'),
  111. 'select' => __('Joins'),
  112. 'repl' => __('Replication'),
  113. 'sort' => __('Sorting'),
  114. 'table' => __('Tables'),
  115. 'tc' => __('Transaction coordinator'),
  116. 'files' => __('Files'),
  117. 'ssl' => 'SSL',
  118. 'other' => __('Other'),
  119. ];
  120. }
  121. /**
  122. * Gets the links for constructor
  123. *
  124. * @return array
  125. */
  126. private function _getLinks()
  127. {
  128. $links = [];
  129. // variable or section name => (name => url)
  130. $links['table'][__('Flush (close) all tables')] = [
  131. 'url' => $this->selfUrl,
  132. 'params' => Url::getCommon(['flush' => 'TABLES'], ''),
  133. ];
  134. $links['table'][__('Show open tables')] = [
  135. 'url' => 'sql.php',
  136. 'params' => Url::getCommon([
  137. 'sql_query' => 'SHOW OPEN TABLES',
  138. 'goto' => $this->selfUrl,
  139. ], ''),
  140. ];
  141. if ($GLOBALS['replication_info']['master']['status']) {
  142. $links['repl'][__('Show slave hosts')] = [
  143. 'url' => 'sql.php',
  144. 'params' => Url::getCommon([
  145. 'sql_query' => 'SHOW SLAVE HOSTS',
  146. 'goto' => $this->selfUrl,
  147. ], ''),
  148. ];
  149. $links['repl'][__('Show master status')] = [
  150. 'url' => '#replication_master',
  151. 'params' => '',
  152. ];
  153. }
  154. if ($GLOBALS['replication_info']['slave']['status']) {
  155. $links['repl'][__('Show slave status')] = [
  156. 'url' => '#replication_slave',
  157. 'params' => '',
  158. ];
  159. }
  160. $links['repl']['doc'] = 'replication';
  161. $links['qcache'][__('Flush query cache')] = [
  162. 'url' => $this->selfUrl,
  163. 'params' => Url::getCommon(['flush' => 'QUERY CACHE'], ''),
  164. ];
  165. $links['qcache']['doc'] = 'query_cache';
  166. $links['threads']['doc'] = 'mysql_threads';
  167. $links['key']['doc'] = 'myisam_key_cache';
  168. $links['binlog_cache']['doc'] = 'binary_log';
  169. $links['Slow_queries']['doc'] = 'slow_query_log';
  170. $links['innodb'][__('Variables')] = [
  171. 'url' => 'server_engines.php',
  172. 'params' => Url::getCommon(['engine' => 'InnoDB'], ''),
  173. ];
  174. $links['innodb'][__('InnoDB Status')] = [
  175. 'url' => 'server_engines.php',
  176. 'params' => Url::getCommon([
  177. 'engine' => 'InnoDB',
  178. 'page' => 'Status',
  179. ], ''),
  180. ];
  181. $links['innodb']['doc'] = 'innodb';
  182. return $links;
  183. }
  184. /**
  185. * Calculate some values
  186. *
  187. * @param array $server_status contains results of SHOW GLOBAL STATUS
  188. * @param array $server_variables contains results of SHOW GLOBAL VARIABLES
  189. *
  190. * @return array
  191. */
  192. private function _calculateValues(array $server_status, array $server_variables)
  193. {
  194. // Key_buffer_fraction
  195. if (isset($server_status['Key_blocks_unused'])
  196. && isset($server_variables['key_cache_block_size'])
  197. && isset($server_variables['key_buffer_size'])
  198. && $server_variables['key_buffer_size'] != 0
  199. ) {
  200. $server_status['Key_buffer_fraction_%']
  201. = 100
  202. - $server_status['Key_blocks_unused']
  203. * $server_variables['key_cache_block_size']
  204. / $server_variables['key_buffer_size']
  205. * 100;
  206. } elseif (isset($server_status['Key_blocks_used'])
  207. && isset($server_variables['key_buffer_size'])
  208. && $server_variables['key_buffer_size'] != 0
  209. ) {
  210. $server_status['Key_buffer_fraction_%']
  211. = $server_status['Key_blocks_used']
  212. * 1024
  213. / $server_variables['key_buffer_size'];
  214. }
  215. // Ratio for key read/write
  216. if (isset($server_status['Key_writes'])
  217. && isset($server_status['Key_write_requests'])
  218. && $server_status['Key_write_requests'] > 0
  219. ) {
  220. $key_writes = $server_status['Key_writes'];
  221. $key_write_requests = $server_status['Key_write_requests'];
  222. $server_status['Key_write_ratio_%']
  223. = 100 * $key_writes / $key_write_requests;
  224. }
  225. if (isset($server_status['Key_reads'])
  226. && isset($server_status['Key_read_requests'])
  227. && $server_status['Key_read_requests'] > 0
  228. ) {
  229. $key_reads = $server_status['Key_reads'];
  230. $key_read_requests = $server_status['Key_read_requests'];
  231. $server_status['Key_read_ratio_%']
  232. = 100 * $key_reads / $key_read_requests;
  233. }
  234. // Threads_cache_hitrate
  235. if (isset($server_status['Threads_created'])
  236. && isset($server_status['Connections'])
  237. && $server_status['Connections'] > 0
  238. ) {
  239. $server_status['Threads_cache_hitrate_%']
  240. = 100 - $server_status['Threads_created']
  241. / $server_status['Connections'] * 100;
  242. }
  243. return $server_status;
  244. }
  245. /**
  246. * Sort variables into arrays
  247. *
  248. * @param array $server_status contains results of SHOW GLOBAL STATUS
  249. * @param array $allocations allocations for sections
  250. * @param array $allocationMap map variables to their section
  251. * @param array $sectionUsed is a section used?
  252. * @param array $used_queries used queries
  253. *
  254. * @return array ($allocationMap, $sectionUsed, $used_queries)
  255. */
  256. private function _sortVariables(
  257. array $server_status,
  258. array $allocations,
  259. array $allocationMap,
  260. array $sectionUsed,
  261. array $used_queries
  262. ) {
  263. foreach ($server_status as $name => $value) {
  264. $section_found = false;
  265. foreach ($allocations as $filter => $section) {
  266. if (mb_strpos($name, $filter) !== false) {
  267. $allocationMap[$name] = $section;
  268. $sectionUsed[$section] = true;
  269. $section_found = true;
  270. if ($section == 'com' && $value > 0) {
  271. $used_queries[$name] = $value;
  272. }
  273. break; // Only exits inner loop
  274. }
  275. }
  276. if (! $section_found) {
  277. $allocationMap[$name] = 'other';
  278. $sectionUsed['other'] = true;
  279. }
  280. }
  281. return [
  282. $allocationMap,
  283. $sectionUsed,
  284. $used_queries,
  285. ];
  286. }
  287. /**
  288. * Constructor
  289. */
  290. public function __construct()
  291. {
  292. $this->selfUrl = basename($GLOBALS['PMA_PHP_SELF']);
  293. // get status from server
  294. $server_status_result = $GLOBALS['dbi']->tryQuery('SHOW GLOBAL STATUS');
  295. $server_status = [];
  296. if ($server_status_result === false) {
  297. $this->dataLoaded = false;
  298. } else {
  299. $this->dataLoaded = true;
  300. while ($arr = $GLOBALS['dbi']->fetchRow($server_status_result)) {
  301. $server_status[$arr[0]] = $arr[1];
  302. }
  303. $GLOBALS['dbi']->freeResult($server_status_result);
  304. }
  305. // for some calculations we require also some server settings
  306. $server_variables = $GLOBALS['dbi']->fetchResult(
  307. 'SHOW GLOBAL VARIABLES',
  308. 0,
  309. 1
  310. );
  311. // cleanup of some deprecated values
  312. $server_status = self::cleanDeprecated($server_status);
  313. // calculate some values
  314. $server_status = $this->_calculateValues(
  315. $server_status,
  316. $server_variables
  317. );
  318. // split variables in sections
  319. $allocations = $this->_getAllocations();
  320. $sections = $this->_getSections();
  321. // define some needful links/commands
  322. $links = $this->_getLinks();
  323. // Variable to contain all com_ variables (query statistics)
  324. $used_queries = [];
  325. // Variable to map variable names to their respective section name
  326. // (used for js category filtering)
  327. $allocationMap = [];
  328. // Variable to mark used sections
  329. $sectionUsed = [];
  330. // sort vars into arrays
  331. list(
  332. $allocationMap, $sectionUsed, $used_queries
  333. ) = $this->_sortVariables(
  334. $server_status,
  335. $allocations,
  336. $allocationMap,
  337. $sectionUsed,
  338. $used_queries
  339. );
  340. // admin commands are not queries (e.g. they include COM_PING,
  341. // which is excluded from $server_status['Questions'])
  342. unset($used_queries['Com_admin_commands']);
  343. // Set all class properties
  344. $this->db_isLocal = false;
  345. $serverHostToLower = mb_strtolower(
  346. $GLOBALS['cfg']['Server']['host']
  347. );
  348. if ($serverHostToLower === 'localhost'
  349. || $GLOBALS['cfg']['Server']['host'] === '127.0.0.1'
  350. || $GLOBALS['cfg']['Server']['host'] === '::1'
  351. ) {
  352. $this->db_isLocal = true;
  353. }
  354. $this->status = $server_status;
  355. $this->sections = $sections;
  356. $this->variables = $server_variables;
  357. $this->used_queries = $used_queries;
  358. $this->allocationMap = $allocationMap;
  359. $this->links = $links;
  360. $this->sectionUsed = $sectionUsed;
  361. }
  362. /**
  363. * cleanup of some deprecated values
  364. *
  365. * @param array $server_status status array to process
  366. *
  367. * @return array
  368. */
  369. public static function cleanDeprecated(array $server_status)
  370. {
  371. $deprecated = [
  372. 'Com_prepare_sql' => 'Com_stmt_prepare',
  373. 'Com_execute_sql' => 'Com_stmt_execute',
  374. 'Com_dealloc_sql' => 'Com_stmt_close',
  375. ];
  376. foreach ($deprecated as $old => $new) {
  377. if (isset($server_status[$old]) && isset($server_status[$new])) {
  378. unset($server_status[$old]);
  379. }
  380. }
  381. return $server_status;
  382. }
  383. }