ProcessesController.php 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. <?php
  2. declare(strict_types=1);
  3. namespace PhpMyAdmin\Controllers\Server\Status;
  4. use PhpMyAdmin\DatabaseInterface;
  5. use PhpMyAdmin\Html\Generator;
  6. use PhpMyAdmin\Message;
  7. use PhpMyAdmin\Response;
  8. use PhpMyAdmin\Server\Status\Data;
  9. use PhpMyAdmin\Template;
  10. use PhpMyAdmin\Url;
  11. use PhpMyAdmin\Util;
  12. use function array_keys;
  13. use function count;
  14. use function mb_strtolower;
  15. use function strlen;
  16. use function ucfirst;
  17. class ProcessesController extends AbstractController
  18. {
  19. /** @var DatabaseInterface */
  20. private $dbi;
  21. /**
  22. * @param Response $response
  23. * @param Data $data
  24. * @param DatabaseInterface $dbi
  25. */
  26. public function __construct($response, Template $template, $data, $dbi)
  27. {
  28. parent::__construct($response, $template, $data);
  29. $this->dbi = $dbi;
  30. }
  31. public function index(): void
  32. {
  33. global $err_url;
  34. $params = [
  35. 'showExecuting' => $_POST['showExecuting'] ?? null,
  36. 'full' => $_POST['full'] ?? null,
  37. 'column_name' => $_POST['column_name'] ?? null,
  38. 'order_by_field' => $_POST['order_by_field'] ?? null,
  39. 'sort_order' => $_POST['sort_order'] ?? null,
  40. ];
  41. $err_url = Url::getFromRoute('/');
  42. if ($this->dbi->isSuperUser()) {
  43. $this->dbi->selectDb('mysql');
  44. }
  45. $this->addScriptFiles(['server/status/processes.js']);
  46. $isChecked = false;
  47. if (! empty($params['showExecuting'])) {
  48. $isChecked = true;
  49. }
  50. $urlParams = [
  51. 'ajax_request' => true,
  52. 'full' => $params['full'] ?? '',
  53. 'column_name' => $params['column_name'] ?? '',
  54. 'order_by_field' => $params['order_by_field'] ?? '',
  55. 'sort_order' => $params['sort_order'] ?? '',
  56. ];
  57. $serverProcessList = $this->getList($params);
  58. $this->render('server/status/processes/index', [
  59. 'url_params' => $urlParams,
  60. 'is_checked' => $isChecked,
  61. 'server_process_list' => $serverProcessList,
  62. ]);
  63. }
  64. /**
  65. * Only sends the process list table
  66. */
  67. public function refresh(): void
  68. {
  69. $params = [
  70. 'showExecuting' => $_POST['showExecuting'] ?? null,
  71. 'full' => $_POST['full'] ?? null,
  72. 'column_name' => $_POST['column_name'] ?? null,
  73. 'order_by_field' => $_POST['order_by_field'] ?? null,
  74. 'sort_order' => $_POST['sort_order'] ?? null,
  75. ];
  76. if (! $this->response->isAjax()) {
  77. return;
  78. }
  79. $this->response->addHTML($this->getList($params));
  80. }
  81. /**
  82. * @param array $params Request parameters
  83. */
  84. public function kill(array $params): void
  85. {
  86. if (! $this->response->isAjax()) {
  87. return;
  88. }
  89. $kill = (int) $params['id'];
  90. $query = $this->dbi->getKillQuery($kill);
  91. if ($this->dbi->tryQuery($query)) {
  92. $message = Message::success(
  93. __('Thread %s was successfully killed.')
  94. );
  95. $this->response->setRequestStatus(true);
  96. } else {
  97. $message = Message::error(
  98. __(
  99. 'phpMyAdmin was unable to kill thread %s.'
  100. . ' It probably has already been closed.'
  101. )
  102. );
  103. $this->response->setRequestStatus(false);
  104. }
  105. $message->addParam($kill);
  106. $this->response->addJSON(['message' => $message]);
  107. }
  108. /**
  109. * @param array $params Request parameters
  110. */
  111. private function getList(array $params): string
  112. {
  113. $urlParams = [];
  114. $showFullSql = ! empty($params['full']);
  115. if ($showFullSql) {
  116. $urlParams['full'] = '';
  117. } else {
  118. $urlParams['full'] = 1;
  119. }
  120. // This array contains display name and real column name of each
  121. // sortable column in the table
  122. $sortableColumns = [
  123. [
  124. 'column_name' => __('ID'),
  125. 'order_by_field' => 'Id',
  126. ],
  127. [
  128. 'column_name' => __('User'),
  129. 'order_by_field' => 'User',
  130. ],
  131. [
  132. 'column_name' => __('Host'),
  133. 'order_by_field' => 'Host',
  134. ],
  135. [
  136. 'column_name' => __('Database'),
  137. 'order_by_field' => 'db',
  138. ],
  139. [
  140. 'column_name' => __('Command'),
  141. 'order_by_field' => 'Command',
  142. ],
  143. [
  144. 'column_name' => __('Time'),
  145. 'order_by_field' => 'Time',
  146. ],
  147. [
  148. 'column_name' => __('Status'),
  149. 'order_by_field' => 'State',
  150. ],
  151. [
  152. 'column_name' => __('Progress'),
  153. 'order_by_field' => 'Progress',
  154. ],
  155. [
  156. 'column_name' => __('SQL query'),
  157. 'order_by_field' => 'Info',
  158. ],
  159. ];
  160. $sortableColCount = count($sortableColumns);
  161. $sqlQuery = $showFullSql
  162. ? 'SHOW FULL PROCESSLIST'
  163. : 'SHOW PROCESSLIST';
  164. if ((! empty($params['order_by_field'])
  165. && ! empty($params['sort_order']))
  166. || ! empty($params['showExecuting'])
  167. ) {
  168. $urlParams['order_by_field'] = $params['order_by_field'];
  169. $urlParams['sort_order'] = $params['sort_order'];
  170. $urlParams['showExecuting'] = $params['showExecuting'];
  171. $sqlQuery = 'SELECT * FROM `INFORMATION_SCHEMA`.`PROCESSLIST` ';
  172. }
  173. if (! empty($params['showExecuting'])) {
  174. $sqlQuery .= ' WHERE state != "" ';
  175. }
  176. if (! empty($params['order_by_field']) && ! empty($params['sort_order'])) {
  177. $sqlQuery .= ' ORDER BY '
  178. . Util::backquote($params['order_by_field'])
  179. . ' ' . $params['sort_order'];
  180. }
  181. $result = $this->dbi->query($sqlQuery);
  182. $columns = [];
  183. foreach ($sortableColumns as $columnKey => $column) {
  184. $is_sorted = ! empty($params['order_by_field'])
  185. && ! empty($params['sort_order'])
  186. && ($params['order_by_field'] == $column['order_by_field']);
  187. $column['sort_order'] = 'ASC';
  188. if ($is_sorted && $params['sort_order'] === 'ASC') {
  189. $column['sort_order'] = 'DESC';
  190. }
  191. if (isset($params['showExecuting'])) {
  192. $column['showExecuting'] = 'on';
  193. }
  194. $columns[$columnKey] = [
  195. 'name' => $column['column_name'],
  196. 'params' => $column,
  197. 'is_sorted' => $is_sorted,
  198. 'sort_order' => $column['sort_order'],
  199. 'has_full_query' => false,
  200. 'is_full' => false,
  201. ];
  202. if (0 !== --$sortableColCount) {
  203. continue;
  204. }
  205. $columns[$columnKey]['has_full_query'] = true;
  206. if (! $showFullSql) {
  207. continue;
  208. }
  209. $columns[$columnKey]['is_full'] = true;
  210. }
  211. $rows = [];
  212. while ($process = $this->dbi->fetchAssoc($result)) {
  213. // Array keys need to modify due to the way it has used
  214. // to display column values
  215. if ((! empty($params['order_by_field']) && ! empty($params['sort_order']))
  216. || ! empty($params['showExecuting'])
  217. ) {
  218. foreach (array_keys($process) as $key) {
  219. $newKey = ucfirst(mb_strtolower($key));
  220. if ($newKey === $key) {
  221. continue;
  222. }
  223. $process[$newKey] = $process[$key];
  224. unset($process[$key]);
  225. }
  226. }
  227. $rows[] = [
  228. 'id' => $process['Id'],
  229. 'user' => $process['User'],
  230. 'host' => $process['Host'],
  231. 'db' => ! isset($process['db']) || strlen($process['db']) === 0 ? '' : $process['db'],
  232. 'command' => $process['Command'],
  233. 'time' => $process['Time'],
  234. 'state' => ! empty($process['State']) ? $process['State'] : '---',
  235. 'progress' => ! empty($process['Progress']) ? $process['Progress'] : '---',
  236. 'info' => ! empty($process['Info']) ? Generator::formatSql(
  237. $process['Info'],
  238. ! $showFullSql
  239. ) : '---',
  240. ];
  241. }
  242. return $this->template->render('server/status/processes/list', [
  243. 'columns' => $columns,
  244. 'rows' => $rows,
  245. 'refresh_params' => $urlParams,
  246. ]);
  247. }
  248. }