UserGroups.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. <?php
  2. /**
  3. * set of functions for user group handling
  4. */
  5. declare(strict_types=1);
  6. namespace PhpMyAdmin\ConfigStorage;
  7. use PhpMyAdmin\ConfigStorage\Features\ConfigurableMenusFeature;
  8. use PhpMyAdmin\Html\Generator;
  9. use PhpMyAdmin\Template;
  10. use PhpMyAdmin\Url;
  11. use PhpMyAdmin\Util;
  12. use function __;
  13. use function array_keys;
  14. use function htmlspecialchars;
  15. use function implode;
  16. use function in_array;
  17. use function mb_substr;
  18. use function substr;
  19. /**
  20. * PhpMyAdmin\Server\UserGroups class
  21. */
  22. class UserGroups
  23. {
  24. /**
  25. * Return HTML to list the users belonging to a given user group
  26. *
  27. * @param string $userGroup user group name
  28. *
  29. * @return string HTML to list the users belonging to a given user group
  30. */
  31. public static function getHtmlForListingUsersofAGroup(
  32. ConfigurableMenusFeature $configurableMenusFeature,
  33. string $userGroup
  34. ): string {
  35. global $dbi;
  36. $users = [];
  37. $userGroupSpecialChars = htmlspecialchars($userGroup);
  38. $usersTable = Util::backquote($configurableMenusFeature->database)
  39. . '.' . Util::backquote($configurableMenusFeature->users);
  40. $sql_query = 'SELECT `username` FROM ' . $usersTable
  41. . " WHERE `usergroup`='" . $dbi->escapeString($userGroup)
  42. . "'";
  43. $result = $dbi->tryQueryAsControlUser($sql_query);
  44. if ($result) {
  45. $i = 0;
  46. while ($row = $result->fetchRow()) {
  47. $users[] = [
  48. 'count' => ++$i,
  49. 'user' => $row[0],
  50. ];
  51. }
  52. }
  53. $template = new Template();
  54. return $template->render('server/user_groups/user_listings', [
  55. 'user_group_special_chars' => $userGroupSpecialChars,
  56. 'users' => $users,
  57. ]);
  58. }
  59. /**
  60. * Returns HTML for the 'user groups' table
  61. *
  62. * @return string HTML for the 'user groups' table
  63. */
  64. public static function getHtmlForUserGroupsTable(ConfigurableMenusFeature $configurableMenusFeature): string
  65. {
  66. global $dbi;
  67. $groupTable = Util::backquote($configurableMenusFeature->database)
  68. . '.' . Util::backquote($configurableMenusFeature->userGroups);
  69. $sql_query = 'SELECT * FROM ' . $groupTable . ' ORDER BY `usergroup` ASC';
  70. $result = $dbi->tryQueryAsControlUser($sql_query);
  71. $userGroups = [];
  72. $userGroupsValues = [];
  73. $action = Url::getFromRoute('/server/privileges');
  74. $hidden_inputs = null;
  75. if ($result && $result->numRows()) {
  76. $hidden_inputs = Url::getHiddenInputs();
  77. foreach ($result as $row) {
  78. $groupName = $row['usergroup'];
  79. if (! isset($userGroups[$groupName])) {
  80. $userGroups[$groupName] = [];
  81. }
  82. $userGroups[$groupName][$row['tab']] = $row['allowed'];
  83. }
  84. foreach ($userGroups as $groupName => $tabs) {
  85. $userGroupVal = [];
  86. $userGroupVal['name'] = $groupName;
  87. $userGroupVal['serverTab'] = self::getAllowedTabNames($tabs, 'server');
  88. $userGroupVal['dbTab'] = self::getAllowedTabNames($tabs, 'db');
  89. $userGroupVal['tableTab'] = self::getAllowedTabNames($tabs, 'table');
  90. $userGroupVal['userGroupUrl'] = Url::getFromRoute('/server/user-groups');
  91. $userGroupVal['viewUsersUrl'] = Url::getCommon(
  92. [
  93. 'viewUsers' => 1,
  94. 'userGroup' => $groupName,
  95. ],
  96. '',
  97. false
  98. );
  99. $userGroupVal['viewUsersIcon'] = Generator::getIcon('b_usrlist', __('View users'));
  100. $userGroupVal['editUsersUrl'] = Url::getCommon(
  101. [
  102. 'editUserGroup' => 1,
  103. 'userGroup' => $groupName,
  104. ],
  105. '',
  106. false
  107. );
  108. $userGroupVal['editUsersIcon'] = Generator::getIcon('b_edit', __('Edit'));
  109. $userGroupsValues[] = $userGroupVal;
  110. }
  111. }
  112. $addUserUrl = Url::getFromRoute('/server/user-groups', ['addUserGroup' => 1]);
  113. $addUserIcon = Generator::getIcon('b_usradd');
  114. $template = new Template();
  115. return $template->render('server/user_groups/user_groups', [
  116. 'action' => $action,
  117. 'hidden_inputs' => $hidden_inputs ?? '',
  118. 'has_rows' => $userGroups !== [],
  119. 'user_groups_values' => $userGroupsValues,
  120. 'add_user_url' => $addUserUrl,
  121. 'add_user_icon' => $addUserIcon,
  122. ]);
  123. }
  124. /**
  125. * Returns the list of allowed menu tab names
  126. * based on a data row from usergroup table.
  127. *
  128. * @param array $row row of usergroup table
  129. * @param string $level 'server', 'db' or 'table'
  130. *
  131. * @return string comma separated list of allowed menu tab names
  132. */
  133. public static function getAllowedTabNames(array $row, string $level): string
  134. {
  135. $tabNames = [];
  136. $tabs = Util::getMenuTabList($level);
  137. foreach ($tabs as $tab => $tabName) {
  138. if (isset($row[$level . '_' . $tab]) && $row[$level . '_' . $tab] !== 'Y') {
  139. continue;
  140. }
  141. $tabNames[] = $tabName;
  142. }
  143. return implode(', ', $tabNames);
  144. }
  145. /**
  146. * Deletes a user group
  147. *
  148. * @param string $userGroup user group name
  149. */
  150. public static function delete(ConfigurableMenusFeature $configurableMenusFeature, string $userGroup): void
  151. {
  152. global $dbi;
  153. $userTable = Util::backquote($configurableMenusFeature->database)
  154. . '.' . Util::backquote($configurableMenusFeature->users);
  155. $groupTable = Util::backquote($configurableMenusFeature->database)
  156. . '.' . Util::backquote($configurableMenusFeature->userGroups);
  157. $sql_query = 'DELETE FROM ' . $userTable
  158. . " WHERE `usergroup`='" . $dbi->escapeString($userGroup)
  159. . "'";
  160. $dbi->queryAsControlUser($sql_query);
  161. $sql_query = 'DELETE FROM ' . $groupTable
  162. . " WHERE `usergroup`='" . $dbi->escapeString($userGroup)
  163. . "'";
  164. $dbi->queryAsControlUser($sql_query);
  165. }
  166. /**
  167. * Returns HTML for add/edit user group dialog
  168. *
  169. * @param string|null $userGroup name of the user group in case of editing
  170. *
  171. * @return string HTML for add/edit user group dialog
  172. */
  173. public static function getHtmlToEditUserGroup(
  174. ConfigurableMenusFeature $configurableMenusFeature,
  175. ?string $userGroup = null
  176. ): string {
  177. global $dbi;
  178. $urlParams = [];
  179. $editUserGroupSpecialChars = '';
  180. if ($userGroup !== null) {
  181. $editUserGroupSpecialChars = htmlspecialchars($userGroup);
  182. }
  183. if ($userGroup !== null) {
  184. $urlParams['userGroup'] = $userGroup;
  185. $urlParams['editUserGroupSubmit'] = '1';
  186. } else {
  187. $urlParams['addUserGroupSubmit'] = '1';
  188. }
  189. $allowedTabs = [
  190. 'server' => [],
  191. 'db' => [],
  192. 'table' => [],
  193. ];
  194. if ($userGroup !== null) {
  195. $groupTable = Util::backquote($configurableMenusFeature->database)
  196. . '.' . Util::backquote($configurableMenusFeature->userGroups);
  197. $sql_query = 'SELECT * FROM ' . $groupTable
  198. . " WHERE `usergroup`='" . $dbi->escapeString($userGroup)
  199. . "'";
  200. $result = $dbi->tryQueryAsControlUser($sql_query);
  201. if ($result) {
  202. foreach ($result as $row) {
  203. $key = $row['tab'];
  204. $value = $row['allowed'];
  205. if (substr($key, 0, 7) === 'server_' && $value === 'Y') {
  206. $allowedTabs['server'][] = mb_substr($key, 7);
  207. } elseif (substr($key, 0, 3) === 'db_' && $value === 'Y') {
  208. $allowedTabs['db'][] = mb_substr($key, 3);
  209. } elseif (substr($key, 0, 6) === 'table_' && $value === 'Y') {
  210. $allowedTabs['table'][] = mb_substr($key, 6);
  211. }
  212. }
  213. }
  214. unset($result);
  215. }
  216. $tabList = self::getTabList(
  217. __('Server-level tabs'),
  218. 'server',
  219. $allowedTabs['server']
  220. );
  221. $tabList .= self::getTabList(
  222. __('Database-level tabs'),
  223. 'db',
  224. $allowedTabs['db']
  225. );
  226. $tabList .= self::getTabList(
  227. __('Table-level tabs'),
  228. 'table',
  229. $allowedTabs['table']
  230. );
  231. $template = new Template();
  232. return $template->render('server/user_groups/edit_user_groups', [
  233. 'user_group' => $userGroup,
  234. 'edit_user_group_special_chars' => $editUserGroupSpecialChars,
  235. 'user_group_url' => Url::getFromRoute('/server/user-groups'),
  236. 'hidden_inputs' => Url::getHiddenInputs($urlParams),
  237. 'tab_list' => $tabList,
  238. ]);
  239. }
  240. /**
  241. * Returns HTML for checkbox groups to choose
  242. * tabs of 'server', 'db' or 'table' levels.
  243. *
  244. * @param string $title title of the checkbox group
  245. * @param string $level 'server', 'db' or 'table'
  246. * @param array $selected array of selected allowed tabs
  247. *
  248. * @return string HTML for checkbox groups
  249. */
  250. public static function getTabList(string $title, string $level, array $selected): string
  251. {
  252. $tabs = Util::getMenuTabList($level);
  253. $tabDetails = [];
  254. foreach ($tabs as $tab => $tabName) {
  255. $tabDetail = [];
  256. $tabDetail['in_array'] = (in_array($tab, $selected) ? ' checked="checked"' : '');
  257. $tabDetail['tab'] = $tab;
  258. $tabDetail['tab_name'] = $tabName;
  259. $tabDetails[] = $tabDetail;
  260. }
  261. $template = new Template();
  262. return $template->render('server/user_groups/tab_list', [
  263. 'title' => $title,
  264. 'level' => $level,
  265. 'tab_details' => $tabDetails,
  266. ]);
  267. }
  268. /**
  269. * Add/update a user group with allowed menu tabs.
  270. *
  271. * @param string $userGroup user group name
  272. * @param bool $new whether this is a new user group
  273. */
  274. public static function edit(
  275. ConfigurableMenusFeature $configurableMenusFeature,
  276. string $userGroup,
  277. bool $new = false
  278. ): void {
  279. global $dbi;
  280. $tabs = Util::getMenuTabList();
  281. $groupTable = Util::backquote($configurableMenusFeature->database)
  282. . '.' . Util::backquote($configurableMenusFeature->userGroups);
  283. if (! $new) {
  284. $sql_query = 'DELETE FROM ' . $groupTable
  285. . " WHERE `usergroup`='" . $dbi->escapeString($userGroup)
  286. . "';";
  287. $dbi->queryAsControlUser($sql_query);
  288. }
  289. $sql_query = 'INSERT INTO ' . $groupTable
  290. . '(`usergroup`, `tab`, `allowed`)'
  291. . ' VALUES ';
  292. $first = true;
  293. /** @var array<string, string> $tabGroup */
  294. foreach ($tabs as $tabGroupName => $tabGroup) {
  295. foreach (array_keys($tabGroup) as $tab) {
  296. if (! $first) {
  297. $sql_query .= ', ';
  298. }
  299. $tabName = $tabGroupName . '_' . $tab;
  300. $allowed = isset($_POST[$tabName]) && $_POST[$tabName] === 'Y';
  301. $sql_query .= "('" . $dbi->escapeString($userGroup) . "', '" . $tabName . "', '"
  302. . ($allowed ? 'Y' : 'N') . "')";
  303. $first = false;
  304. }
  305. }
  306. $sql_query .= ';';
  307. $dbi->queryAsControlUser($sql_query);
  308. }
  309. }