PageRenderTime 50ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/phpmyfaq/src/phpMyFAQ/Permission/BasicPermission.php

http://github.com/thorsten/phpMyFAQ
PHP | 469 lines | 281 code | 48 blank | 140 comment | 26 complexity | 7818ec0301f21fee8ceb06183ebfff36 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, LGPL-3.0
  1. <?php
  2. /**
  3. * The basic permission class provides user rights.
  4. *
  5. * This Source Code Form is subject to the terms of the Mozilla Public License,
  6. * v. 2.0. If a copy of the MPL was not distributed with this file, You can
  7. * obtain one at http://mozilla.org/MPL/2.0/.
  8. *
  9. * @package phpMyFAQ
  10. * @author Lars Tiedemann <php@larstiedemann.de>
  11. * @copyright 2005-2021 phpMyFAQ Team
  12. * @license http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
  13. * @link https://www.phpmyfaq.de
  14. * @since 2005-09-17
  15. */
  16. namespace phpMyFAQ\Permission;
  17. use phpMyFAQ\Configuration;
  18. use phpMyFAQ\Database;
  19. use phpMyFAQ\Permission;
  20. use phpMyFAQ\User\CurrentUser;
  21. /**
  22. * Class BasicPermission
  23. *
  24. * @package phpMyFAQ\Permission
  25. */
  26. class BasicPermission extends Permission
  27. {
  28. /**
  29. * Default right data stored when a new right is created.
  30. *
  31. * @var array<string, string|bool>
  32. */
  33. public $defaultRightData = [
  34. 'name' => 'DEFAULT_RIGHT',
  35. 'description' => 'Short description.',
  36. 'for_users' => true,
  37. 'for_groups' => true,
  38. 'for_sections' => true
  39. ];
  40. /**
  41. * Constructor.
  42. *
  43. * @param Configuration $config
  44. */
  45. public function __construct(Configuration $config)
  46. {
  47. parent::__construct($config);
  48. }
  49. /**
  50. * Gives the user a new user-right.
  51. * Returns true on success, otherwise false.
  52. *
  53. * @param int $userId User ID
  54. * @param int $rightId Right ID
  55. * @return bool
  56. */
  57. public function grantUserRight(int $userId, int $rightId): bool
  58. {
  59. // is right for users?
  60. $rightData = $this->getRightData($rightId);
  61. if (!isset($rightData['for_users'])) {
  62. return false;
  63. }
  64. $insert = sprintf(
  65. '
  66. INSERT INTO
  67. %sfaquser_right
  68. (user_id, right_id)
  69. VALUES
  70. (%d, %d)',
  71. Database::getTablePrefix(),
  72. $userId,
  73. $rightId
  74. );
  75. $res = $this->config->getDb()->query($insert);
  76. if (!$res) {
  77. return false;
  78. }
  79. return true;
  80. }
  81. /**
  82. * Returns an associative array with all data stored for in the
  83. * database for the specified right. The keys of the returned
  84. * array are the field names.
  85. *
  86. * @param int $rightId
  87. * @return array<string, bool>
  88. */
  89. public function getRightData(int $rightId): array
  90. {
  91. // get right data
  92. $select = sprintf(
  93. '
  94. SELECT
  95. right_id,
  96. name,
  97. description,
  98. for_users,
  99. for_groups,
  100. for_sections
  101. FROM
  102. %sfaqright
  103. WHERE
  104. right_id = %d',
  105. Database::getTablePrefix(),
  106. $rightId
  107. );
  108. $res = $this->config->getDb()->query($select);
  109. if ($this->config->getDb()->numRows($res) != 1) {
  110. return [];
  111. }
  112. // process right data
  113. $rightData = $this->config->getDb()->fetchArray($res);
  114. $rightData['for_users'] = (bool)$rightData['for_users'];
  115. $rightData['for_groups'] = (bool)$rightData['for_groups'];
  116. $rightData['for_sections'] = (bool)$rightData['for_sections'];
  117. return $rightData;
  118. }
  119. /**
  120. * Returns true if the user given by user_id has the right,
  121. * otherwise false. Unlike checkUserRight(), right may be a
  122. * right-ID or a right-name. Another difference is, that also
  123. * group-rights are taken into account.
  124. *
  125. * @param int $userId User ID
  126. * @param mixed $right Right ID or right name
  127. *
  128. * @return bool
  129. */
  130. public function hasPermission(int $userId, $right): bool
  131. {
  132. $user = new CurrentUser($this->config);
  133. $user->getUserById($userId);
  134. if ($user->isSuperAdmin()) {
  135. return true;
  136. }
  137. if (!is_numeric($right) and is_string($right)) {
  138. $right = $this->getRightId($right);
  139. }
  140. return $this->checkUserRight($user->getUserId(), $right);
  141. }
  142. /**
  143. * Returns the right-ID of the right with the name $name.
  144. *
  145. * @param string $name Name
  146. *
  147. * @return int
  148. */
  149. public function getRightId(string $name): int
  150. {
  151. // get right id
  152. $select = sprintf(
  153. "
  154. SELECT
  155. right_id
  156. FROM
  157. %sfaqright
  158. WHERE
  159. name = '%s'",
  160. Database::getTablePrefix(),
  161. $this->config->getDb()->escape($name)
  162. );
  163. $res = $this->config->getDb()->query($select);
  164. if ($this->config->getDb()->numRows($res) != 1) {
  165. return 0;
  166. }
  167. $row = $this->config->getDb()->fetchArray($res);
  168. return $row['right_id'];
  169. }
  170. /**
  171. * Returns true if the user given by user_id has the right
  172. * specified by right_id, otherwise false.
  173. *
  174. * @param int $userId User ID
  175. * @param int $rightId Right ID
  176. *
  177. * @return bool
  178. */
  179. public function checkUserRight(int $userId, int $rightId): bool
  180. {
  181. // check right id
  182. if ($rightId <= 0) {
  183. return false;
  184. }
  185. // check right
  186. $select = sprintf(
  187. '
  188. SELECT
  189. fr.right_id AS right_id
  190. FROM
  191. %sfaqright fr,
  192. %sfaquser_right fur,
  193. %sfaquser fu
  194. WHERE
  195. fr.right_id = %d AND
  196. fr.right_id = fur.right_id AND
  197. fu.user_id = %d AND
  198. fu.user_id = fur.user_id',
  199. Database::getTablePrefix(),
  200. Database::getTablePrefix(),
  201. Database::getTablePrefix(),
  202. $rightId,
  203. $userId
  204. );
  205. $res = $this->config->getDb()->query($select);
  206. if ($this->config->getDb()->numRows($res) == 1) {
  207. return true;
  208. }
  209. return false;
  210. }
  211. /**
  212. * Returns an array that contains the IDs of all user-rights
  213. * the user owns.
  214. *
  215. * @param int $userId User ID
  216. *
  217. * @return array<int>
  218. */
  219. public function getAllUserRights(int $userId): array
  220. {
  221. return $this->getUserRights($userId);
  222. }
  223. /**
  224. * Returns an array with the IDs of all user-rights the user
  225. * specified by user_id owns. Group rights are not taken into
  226. * account.
  227. *
  228. * @param int $userId User ID
  229. *
  230. * @return array<int>
  231. */
  232. public function getUserRights(int $userId): array
  233. {
  234. // get user rights
  235. $select = sprintf(
  236. '
  237. SELECT
  238. fr.right_id AS right_id
  239. FROM
  240. %sfaqright fr,
  241. %sfaquser_right fur,
  242. %sfaquser fu
  243. WHERE
  244. fr.right_id = fur.right_id AND
  245. fu.user_id = %d AND
  246. fu.user_id = fur.user_id',
  247. Database::getTablePrefix(),
  248. Database::getTablePrefix(),
  249. Database::getTablePrefix(),
  250. $userId
  251. );
  252. $res = $this->config->getDb()->query($select);
  253. $result = [];
  254. while ($row = $this->config->getDb()->fetchArray($res)) {
  255. $result[] = $row['right_id'];
  256. }
  257. return $result;
  258. }
  259. /**
  260. * Adds a new right into the database. Returns the ID of the
  261. * new right. The associative array right_data contains the right
  262. * data stored in the rights table.
  263. *
  264. * @param array<string> $rightData Array if rights
  265. * @return int
  266. */
  267. public function addRight(array $rightData): int
  268. {
  269. if ($this->getRightId($rightData['name']) > 0) {
  270. return 0;
  271. }
  272. $nextId = $this->config->getDb()->nextId(Database::getTablePrefix() . 'faqright', 'right_id');
  273. $rightData = $this->checkRightData($rightData);
  274. $insert = sprintf(
  275. "
  276. INSERT INTO
  277. %sfaqright
  278. (right_id, name, description, for_users, for_groups, for_sections)
  279. VALUES
  280. (%d, '%s', '%s', %d, %d, %d)",
  281. Database::getTablePrefix(),
  282. $nextId,
  283. $rightData['name'],
  284. $rightData['description'],
  285. isset($rightData['for_users']) ? (int)$rightData['for_users'] : 1,
  286. isset($rightData['for_groups']) ? (int)$rightData['for_groups'] : 1,
  287. isset($rightData['for_sections']) ? (int)$rightData['for_sections'] : 1
  288. );
  289. if (!$this->config->getDb()->query($insert)) {
  290. return 0;
  291. }
  292. return $nextId;
  293. }
  294. /**
  295. * Checks the given associative array $right_data. If a
  296. * parameter is incorrect or is missing, it will be replaced
  297. * by the default values in $this->default_right_data.
  298. * Returns the corrected $right_data associative array.
  299. *
  300. * @param array<string> $rightData Array of rights
  301. *
  302. * @return array<string, int>
  303. */
  304. public function checkRightData(array $rightData): array
  305. {
  306. if (!isset($rightData['name']) || !is_string($rightData['name'])) {
  307. $rightData['name'] = $this->defaultRightData['name'];
  308. }
  309. if (!isset($rightData['description']) || !is_string($rightData['description'])) {
  310. $rightData['description'] = $this->defaultRightData['description'];
  311. }
  312. if (!isset($rightData['for_users'])) {
  313. $rightData['for_users'] = $this->defaultRightData['for_users'];
  314. }
  315. if (!isset($rightData['for_groups'])) {
  316. $rightData['for_groups'] = $this->defaultRightData['for_groups'];
  317. }
  318. if (!isset($rightData['for_sections'])) {
  319. $rightData['for_sections'] = $this->defaultRightData['for_sections'];
  320. }
  321. $rightData['for_users'] = (int)$rightData['for_users'];
  322. $rightData['for_groups'] = (int)$rightData['for_groups'];
  323. $rightData['for_sections'] = (int)$rightData['for_sections'];
  324. return $rightData;
  325. }
  326. /**
  327. * Renames rights, only used for updates.
  328. *
  329. * @param string $oldName
  330. * @param string $newName
  331. * @return bool
  332. */
  333. public function renameRight(string $oldName, string $newName): bool
  334. {
  335. $rightId = $this->getRightId($oldName);
  336. if ($rightId === 0) {
  337. return false;
  338. }
  339. $update = sprintf(
  340. '
  341. UPDATE
  342. %sfaqright
  343. SET
  344. name = \'%s\'
  345. WHERE
  346. right_id = %d',
  347. Database::getTablePrefix(),
  348. $newName,
  349. $rightId
  350. );
  351. if (!$this->config->getDb()->query($update)) {
  352. return false;
  353. }
  354. return true;
  355. }
  356. /**
  357. * Returns an array that contains all rights stored in the
  358. * database. Each array element is an associative array with
  359. * the complete right-data. By passing the optional parameter
  360. * $order, the order of the array may be specified. Default is
  361. * $order = 'right_id ASC'.
  362. *
  363. * @param string $order Ordering
  364. *
  365. * @return array<int, array>
  366. */
  367. public function getAllRightsData(string $order = 'ASC'): array
  368. {
  369. $select = sprintf(
  370. '
  371. SELECT
  372. right_id,
  373. name,
  374. description,
  375. for_users,
  376. for_groups,
  377. for_sections
  378. FROM
  379. %sfaqright
  380. ORDER BY
  381. right_id %s',
  382. Database::getTablePrefix(),
  383. $order
  384. );
  385. $res = $this->config->getDb()->query($select);
  386. $result = [];
  387. $i = 0;
  388. if ($res) {
  389. while ($row = $this->config->getDb()->fetchArray($res)) {
  390. $result[$i] = $row;
  391. ++$i;
  392. }
  393. }
  394. return $result;
  395. }
  396. /**
  397. * Refuses all user rights.
  398. * Returns true on success, otherwise false.
  399. *
  400. * @param int $userId User ID
  401. *
  402. * @return bool
  403. */
  404. public function refuseAllUserRights(int $userId): bool
  405. {
  406. $delete = sprintf(
  407. '
  408. DELETE FROM
  409. %sfaquser_right
  410. WHERE
  411. user_id = %d',
  412. Database::getTablePrefix(),
  413. $userId
  414. );
  415. $res = $this->config->getDb()->query($delete);
  416. if (!$res) {
  417. return false;
  418. }
  419. return true;
  420. }
  421. }