PageRenderTime 44ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/phpmyfaq/src/phpMyFAQ/Permission/LargePermission.php

http://github.com/thorsten/phpMyFAQ
PHP | 885 lines | 592 code | 76 blank | 217 comment | 89 complexity | 1f127d4783bbc1d909fd398ef45182ee MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, LGPL-3.0
  1. <?php
  2. /**
  3. * The large permission class provides section rights for groups and users.
  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. * @author Thorsten Rinne <thorsten@phpmyfaq.de>
  12. * @copyright 2005-2021 phpMyFAQ Team
  13. * @license http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
  14. * @link https://www.phpmyfaq.de
  15. * @since 2005-09-17
  16. */
  17. namespace phpMyFAQ\Permission;
  18. use phpMyFAQ\Configuration;
  19. use phpMyFAQ\Database;
  20. use phpMyFAQ\User;
  21. use phpMyFAQ\User\CurrentUser;
  22. /**
  23. * Class LargePermission
  24. *
  25. * @package phpMyFAQ\Permission
  26. */
  27. class LargePermission extends MediumPermission
  28. {
  29. /**
  30. * Default data for new sections.
  31. *
  32. * @var array<string>
  33. */
  34. public $defaultSectionData = [
  35. 'name' => 'DEFAULT_SECTION',
  36. 'description' => 'Short section description.',
  37. ];
  38. /**
  39. * Constructor.
  40. *
  41. * @param Configuration $config
  42. */
  43. public function __construct(Configuration $config)
  44. {
  45. parent::__construct($config);
  46. }
  47. /**
  48. * Returns true, if the user given by $userId owns the right
  49. * specified by $right in a section. It does not matter if
  50. * the user owns this right as a user-right or because of a
  51. * group-membership in a section. The parameter $right may
  52. * be a right-ID (recommended for performance) or a right-name.
  53. *
  54. * @param int $userId
  55. * @param mixed $right
  56. *
  57. * @return bool
  58. */
  59. public function hasPermission(int $userId, $right): bool
  60. {
  61. $user = new CurrentUser($this->config);
  62. $user->getUserById($userId);
  63. if ($user->isSuperAdmin()) {
  64. return true;
  65. }
  66. // get right id
  67. if (!is_numeric($right) && is_string($right)) {
  68. $right = $this->getRightId($right);
  69. }
  70. // check user right, group right and section right
  71. if (
  72. $this->checkUserSectionRight($userId, $right)
  73. || $this->checkUserGroupRight($userId, $right)
  74. || $this->checkUserRight($userId, $right)
  75. ) {
  76. return true;
  77. }
  78. return false;
  79. }
  80. /**
  81. * Returns true if the user $userId owns the right $rightId
  82. * because of a section membership, otherwise false.
  83. *
  84. * @param int $userId
  85. * @param int $rightId
  86. *
  87. * @return bool
  88. */
  89. public function checkUserSectionRight(int $userId, int $rightId): bool
  90. {
  91. if ($userId < 0 || !is_numeric($userId) || $rightId < 0 || !is_numeric($rightId)) {
  92. return false;
  93. }
  94. $select = sprintf(
  95. '
  96. SELECT
  97. fgr.right_id
  98. FROM
  99. %sfaquser_group fug
  100. LEFT JOIN
  101. %sfaqgroup_right fgr
  102. ON
  103. fgr.group_id = fug.group_id
  104. WHERE
  105. fug.user_id = %d
  106. AND
  107. fgr.right_id = %d
  108. ',
  109. Database::getTablePrefix(),
  110. Database::getTablePrefix(),
  111. $userId,
  112. $rightId
  113. );
  114. $res = $this->config->getDb()->query($select);
  115. if (!$res) {
  116. return false;
  117. }
  118. if ($this->config->getDb()->numRows($res) > 0) {
  119. return true;
  120. }
  121. return false;
  122. }
  123. /**
  124. * Adds a new section to the database and returns the ID of the
  125. * new section. The associative array $sectionData contains the
  126. * data for the new section.
  127. *
  128. * @param array<string> $sectionData Array of section data
  129. *
  130. * @return int
  131. */
  132. public function addSection(array $sectionData): int
  133. {
  134. // check if section already exists
  135. if ($this->getSectionId($sectionData['name']) > 0) {
  136. return 0;
  137. }
  138. $nextId = $this->config->getDb()->nextId(Database::getTablePrefix() . 'faqsections', 'id');
  139. $sectionData = $this->checkSectionData($sectionData);
  140. $insert = sprintf(
  141. "
  142. INSERT INTO
  143. %sfaqsections
  144. (id, name, description)
  145. VALUES
  146. (%d, '%s', '%s')",
  147. Database::getTablePrefix(),
  148. $nextId,
  149. $sectionData['name'],
  150. $sectionData['description']
  151. );
  152. $res = $this->config->getDb()->query($insert);
  153. if (!$res) {
  154. return 0;
  155. }
  156. return $nextId;
  157. }
  158. /**
  159. * Returns the ID of the section that has the name $name. Returns
  160. * 0 if the section name cannot be found.
  161. *
  162. * @param string $name
  163. * @return int
  164. */
  165. public function getSectionId(string $name): int
  166. {
  167. $select = sprintf(
  168. '
  169. SELECT
  170. id
  171. FROM
  172. %sfaqsections
  173. WHERE
  174. name = %s',
  175. Database::getTablePrefix(),
  176. $name
  177. );
  178. $res = $this->config->getDb()->query($select);
  179. if ($this->config->getDb()->numRows($res) != 1) {
  180. return 0;
  181. }
  182. $row = $this->config->getDb()->fetchArray($res);
  183. return $row['id'];
  184. }
  185. /**
  186. * Checks the given associative array $sectionData. If a
  187. * parameter is incorrect or is missing, it will be replaced
  188. * by the default values in $this->defaultSectionData.
  189. * Returns the corrected $sectionData associative array.
  190. *
  191. * @param array<string> $sectionData
  192. * @return array<string>
  193. */
  194. public function checkSectionData(array $sectionData): array
  195. {
  196. if (!isset($sectionData['name']) || !is_string($sectionData['name'])) {
  197. $sectionData['name'] = $this->defaultSectionData['name'];
  198. }
  199. if (!isset($sectionData['description']) || !is_string($sectionData['description'])) {
  200. $sectionData['description'] = $this->defaultSectionData['description'];
  201. }
  202. return $sectionData;
  203. }
  204. /**
  205. * Changes the section data of the given section.
  206. *
  207. * @param int $sectionId
  208. * @param array<string> $sectionData
  209. * @return bool
  210. */
  211. public function changeSection(int $sectionId, array $sectionData): bool
  212. {
  213. $checkedData = $this->checkSectionData($sectionData);
  214. $set = '';
  215. $comma = '';
  216. foreach ($sectionData as $key => $val) {
  217. $set .= $comma . $key . " = '" . $this->config->getDb()->escape($checkedData[$key]) . "'";
  218. $comma = ",\n ";
  219. }
  220. $update = sprintf(
  221. '
  222. UPDATE
  223. %sfaqsections
  224. SET
  225. %s
  226. WHERE
  227. id = %d',
  228. Database::getTablePrefix(),
  229. $set,
  230. $sectionId
  231. );
  232. $res = $this->config->getDb()->query($update);
  233. if (!$res) {
  234. return false;
  235. }
  236. return true;
  237. }
  238. /**
  239. * Removes the section given by $sectionId from the database.
  240. * Returns true on success, otherwise false.
  241. *
  242. * @param int $sectionId
  243. * @return bool
  244. */
  245. public function deleteSection(int $sectionId): bool
  246. {
  247. if ($sectionId <= 0 || !is_numeric($sectionId)) {
  248. return false;
  249. }
  250. $delete = sprintf(
  251. '
  252. DELETE FROM
  253. %sfaqsections
  254. WHERE
  255. id = %d',
  256. Database::getTablePrefix(),
  257. $sectionId
  258. );
  259. $res = $this->config->getDb()->query($delete);
  260. if (!$res) {
  261. return false;
  262. }
  263. $delete = sprintf(
  264. '
  265. DELETE FROM
  266. %sfaqsection_group
  267. WHERE
  268. section_id = %d',
  269. Database::getTablePrefix(),
  270. $sectionId
  271. );
  272. $res = $this->config->getDb()->query($delete);
  273. if (!$res) {
  274. return false;
  275. }
  276. $delete = sprintf(
  277. '
  278. DELETE FROM
  279. %sfaqsection_news
  280. WHERE
  281. section_id = %d',
  282. Database::getTablePrefix(),
  283. $sectionId
  284. );
  285. $res = $this->config->getDb()->query($delete);
  286. if (!$res) {
  287. return false;
  288. }
  289. return true;
  290. }
  291. /**
  292. * Returns an array that contains the group IDs of all groups
  293. * of the section $sectionId.
  294. *
  295. * @param int $sectionId
  296. * @return array<int>
  297. */
  298. public function getSectionGroups(int $sectionId): array
  299. {
  300. if ($sectionId <= 0 || !is_numeric($sectionId)) {
  301. return [];
  302. }
  303. $select = sprintf(
  304. '
  305. SELECT
  306. %sfaqsection_group.group_id
  307. FROM
  308. %sfaqsection_group
  309. WHERE
  310. %sfaqsection_group.section_id = %d
  311. ',
  312. Database::getTablePrefix(),
  313. Database::getTablePrefix(),
  314. Database::getTablePrefix(),
  315. $sectionId
  316. );
  317. $res = $this->config->getDb()->query($select);
  318. $result = [];
  319. while ($row = $this->config->getDb()->fetchArray($res)) {
  320. $result[] = $row['group_id'];
  321. }
  322. return $result;
  323. }
  324. /**
  325. * Adds a new group $groupId to the section $sectionId.
  326. * Returns true on success, otherwise false.
  327. *
  328. * @param int $groupId
  329. * @param int $sectionId
  330. * @return bool
  331. */
  332. public function addGroupToSection(int $groupId, int $sectionId): bool
  333. {
  334. if ($sectionId <= 0 || !is_numeric($sectionId) | $groupId <= 0 || !is_numeric($groupId)) {
  335. return false;
  336. }
  337. $select = sprintf(
  338. '
  339. SELECT
  340. group_id
  341. FROM
  342. %sfaqsection_group
  343. WHERE
  344. section_id = %d
  345. AND
  346. group_id = %d
  347. ',
  348. Database::getTablePrefix(),
  349. $sectionId,
  350. $groupId
  351. );
  352. $res = $this->config->getDb()->query($select);
  353. if ($this->config->getDb()->numRows($res) > 0) {
  354. return false;
  355. }
  356. $insert = sprintf(
  357. '
  358. INSERT INTO
  359. %sfaqsection_group
  360. (section_id, group_id)
  361. VALUES
  362. (%d, %d)',
  363. Database::getTablePrefix(),
  364. $sectionId,
  365. $groupId
  366. );
  367. $res = $this->config->getDb()->query($insert);
  368. if (!$res) {
  369. return false;
  370. }
  371. return true;
  372. }
  373. /**
  374. * Removes all groups from the section $sectionId.
  375. * Returns true on success, otherwise false.
  376. *
  377. * @param int $sectionId
  378. * @return bool
  379. */
  380. public function removeAllGroupsFromSection(int $sectionId): bool
  381. {
  382. if ($sectionId <= 0 || !is_numeric($sectionId)) {
  383. return false;
  384. }
  385. $delete = sprintf(
  386. '
  387. DELETE FROM
  388. %sfaqsection_group
  389. WHERE
  390. section_id = %d',
  391. Database::getTablePrefix(),
  392. $sectionId
  393. );
  394. $res = $this->config->getDb()->query($delete);
  395. if (!$res) {
  396. return false;
  397. }
  398. return true;
  399. }
  400. /**
  401. * Returns an associative array with the section data of the section
  402. * $sectionId.
  403. *
  404. * @param int $sectionId
  405. * @return array<string>
  406. */
  407. public function getSectionData(int $sectionId): array
  408. {
  409. $select = sprintf(
  410. '
  411. SELECT
  412. *
  413. FROM
  414. %sfaqsections
  415. WHERE
  416. id = %d',
  417. Database::getTablePrefix(),
  418. $sectionId
  419. );
  420. $res = $this->config->getDb()->query($select);
  421. if ($this->config->getDb()->numRows($res) != 1) {
  422. return [];
  423. }
  424. $row = $this->config->getDb()->fetchArray($res);
  425. return $row;
  426. }
  427. /**
  428. * Returns an array with the IDs of all sections stored in the
  429. * database if no user ID is passed.
  430. *
  431. * @param int $userId
  432. * @return array<int>
  433. */
  434. public function getAllSections(int $userId = -1): array
  435. {
  436. if ($userId !== -1) {
  437. return $this->getUserSections($userId);
  438. }
  439. $select = sprintf('SELECT * FROM %sfaqsections', Database::getTablePrefix());
  440. $res = $this->config->getDb()->query($select);
  441. if (!$res || $this->config->getDb()->numRows($res) < 1) {
  442. return [];
  443. }
  444. $result = [];
  445. while ($row = $this->config->getDb()->fetchArray($res)) {
  446. $result[] = $row['id'];
  447. }
  448. return $result;
  449. }
  450. /**
  451. * Returns an array that contains the IDs of all sections in which
  452. * the user $userId is a member.
  453. *
  454. * @param int $userId
  455. * @return array<int>
  456. */
  457. public function getUserSections(int $userId): array
  458. {
  459. if ($userId <= 0 || !is_numeric($userId)) {
  460. return [-1];
  461. }
  462. $select = sprintf(
  463. '
  464. SELECT
  465. fsg.section_id
  466. FROM
  467. %sfaqsection_group fsg
  468. LEFT JOIN
  469. %sfaquser_group fug
  470. ON
  471. fug.group_id = fsg.group_id
  472. WHERE
  473. fug.user_id = %d',
  474. Database::getTablePrefix(),
  475. Database::getTablePrefix(),
  476. $userId
  477. );
  478. $res = $this->config->getDb()->query($select);
  479. if ($this->config->getDb()->numRows($res) < 1) {
  480. return [-1];
  481. }
  482. $result = [];
  483. while ($row = $this->config->getDb()->fetchArray($res)) {
  484. $result[] = $row['section_id'];
  485. }
  486. return $result;
  487. }
  488. /**
  489. * Returns an array that contains the right-IDs of all rights
  490. * the user $userId owns. User-rights and the rights the user
  491. * owns because of a section membership are taken into account.
  492. *
  493. * @param int $userId
  494. * @return array<int>
  495. */
  496. public function getAllUserRights(int $userId): array
  497. {
  498. if ($userId <= 0 || !is_numeric($userId)) {
  499. return [];
  500. }
  501. $userRights = $this->getUserRights($userId);
  502. $groupRights = $this->getUserGroupRights($userId);
  503. $sectionRights = $this->getUserSectionRights($userId);
  504. return array_unique(array_merge($userRights, $groupRights, $sectionRights));
  505. }
  506. /**
  507. * Returns an array that contains the IDs of all rights the user
  508. * $userId owns because of a section membership.
  509. *
  510. * @param int $userId
  511. * @return array<int>
  512. */
  513. public function getUserSectionRights(int $userId): array
  514. {
  515. if ($userId < 1 || !is_numeric($userId)) {
  516. return [];
  517. }
  518. $select = sprintf(
  519. '
  520. SELECT
  521. right_id
  522. FROM
  523. %sfaquser_group fug
  524. LEFT JOIN
  525. %sfaqgroup_right fgr
  526. ON
  527. fgr.group_id = fug.group_id
  528. WHERE
  529. fug.user_id = %d',
  530. Database::getTablePrefix(),
  531. Database::getTablePrefix(),
  532. $userId
  533. );
  534. $res = $this->config->getDb()->query($select);
  535. if (!$res) {
  536. return [];
  537. }
  538. $result = [];
  539. while ($row = $this->config->getDb()->fetchArray($res)) {
  540. array_push($result, $row['right_id']);
  541. }
  542. return $result;
  543. }
  544. /**
  545. * Returns the name of the section $sectionId.
  546. *
  547. * @param int $sectionId
  548. * @return string
  549. */
  550. public function getSectionName(int $sectionId): string
  551. {
  552. if (!is_numeric($sectionId) || $sectionId < 1) {
  553. return '-';
  554. }
  555. $select = sprintf(
  556. '
  557. SELECT
  558. name
  559. FROM
  560. %sfaqsections
  561. WHERE
  562. id = %d',
  563. Database::getTablePrefix(),
  564. $sectionId
  565. );
  566. $res = $this->config->getDb()->query($select);
  567. if ($this->config->getDb()->numRows($res) != 1) {
  568. return '-';
  569. }
  570. $row = $this->config->getDb()->fetchArray($res);
  571. return $row['name'];
  572. }
  573. /**
  574. * Adds a new category $categoryId to the section $sectionId.
  575. * Returns true on success, otherwise false.
  576. *
  577. * @param int $categoryId
  578. * @param int $sectionId
  579. * @return bool
  580. */
  581. public function addCategoryToSection(int $categoryId, int $sectionId): bool
  582. {
  583. if (!is_numeric($categoryId) || $categoryId < 1 || !is_numeric($sectionId) || $sectionId < 1) {
  584. return false;
  585. }
  586. $insert = sprintf(
  587. '
  588. INSERT INTO
  589. %sfaqsection_category
  590. (category_id, section_id)
  591. VALUES
  592. (%s,%s)',
  593. Database::getTablePrefix(),
  594. $categoryId,
  595. $sectionId
  596. );
  597. $res = $this->config->getDb()->query($insert);
  598. if (!$res) {
  599. return false;
  600. }
  601. return true;
  602. }
  603. /**
  604. * Removes a category $categoryId to the section $sectionId.
  605. * Returns true on success, otherwise false.
  606. *
  607. * @param int $categoryId
  608. * @param int $sectionId
  609. * @return bool
  610. */
  611. public function removeCategoryFromSection(int $categoryId, int $sectionId): bool
  612. {
  613. if (!is_numeric($categoryId) || $categoryId < 1 || !is_numeric($sectionId) || $sectionId < 1) {
  614. return false;
  615. }
  616. $delete = sprintf(
  617. '
  618. DELETE FROM
  619. %sfaqsection_category
  620. WHERE
  621. category_id = %d
  622. AND
  623. section_id = %d',
  624. Database::getTablePrefix(),
  625. $categoryId,
  626. $sectionId
  627. );
  628. $res = $this->config->getDb()->query($delete);
  629. if (!$res) {
  630. return false;
  631. }
  632. return true;
  633. }
  634. /**
  635. * Returns an array that contains the category IDs of all categories
  636. * of the section $sectionId.
  637. *
  638. * @param int $sectionId
  639. * @return array<int>
  640. */
  641. public function getSectionCategories(int $sectionId): array
  642. {
  643. if (!is_numeric($sectionId) || $sectionId < 1) {
  644. return [];
  645. }
  646. $select = sprintf(
  647. '
  648. SELECT
  649. category_id
  650. FROM
  651. %sfaqsection_category
  652. WHERE
  653. section_id = %d',
  654. Database::getTablePrefix(),
  655. $sectionId
  656. );
  657. $res = $this->config->getDb()->query($select);
  658. $result = [];
  659. while ($row = $this->config->getDb()->fetchArray($res)) {
  660. $result[] = $row['category_id'];
  661. }
  662. return $result;
  663. }
  664. /**
  665. * Removes the category $categoryId from all sections.
  666. * Returns true on success, otherwise false.
  667. *
  668. * @param int $categoryId
  669. * @return bool
  670. */
  671. public function removeCategoryFromAllSections(int $categoryId): bool
  672. {
  673. if (!is_numeric($categoryId) || $categoryId < 1) {
  674. return false;
  675. }
  676. $delete = sprintf(
  677. '
  678. DELETE FROM
  679. %sfaqsection_category
  680. WHERE
  681. category_id = %d',
  682. Database::getTablePrefix(),
  683. $categoryId
  684. );
  685. $res = $this->config->getDb()->query($delete);
  686. if (!$res) {
  687. return false;
  688. }
  689. return true;
  690. }
  691. /**
  692. * Adds a new news $newsId to the section $sectionId.
  693. * Returns true on success, otherwise false.
  694. *
  695. * @param int $newsId
  696. * @param int $sectionId
  697. * @return bool
  698. */
  699. public function addNewsToSection(int $newsId, int $sectionId): bool
  700. {
  701. if (!is_numeric($newsId) || $newsId < 1 || !is_numeric($sectionId) || $sectionId < 1) {
  702. return false;
  703. }
  704. $insert = sprintf(
  705. '
  706. INSERT INTO
  707. %sfaqsection_news
  708. (news_id, section_id)
  709. VALUES
  710. (%s,%s)',
  711. Database::getTablePrefix(),
  712. $newsId,
  713. $sectionId
  714. );
  715. $res = $this->config->getDb()->query($insert);
  716. if (!$res) {
  717. return false;
  718. }
  719. return true;
  720. }
  721. /**
  722. * Removes a news $newsId from the section $sectionId.
  723. * Returns true on success, otherwise false.
  724. *
  725. * @param int $newsId
  726. * @param int $sectionId
  727. * @return bool
  728. */
  729. public function removeNewsFromSection(int $newsId, int $sectionId): bool
  730. {
  731. if (!is_numeric($newsId) || $newsId < 1 || !is_numeric($sectionId) || $sectionId < 1) {
  732. return false;
  733. }
  734. $delete = sprintf(
  735. '
  736. DELETE FROM
  737. %sfaqsection_news
  738. WHERE
  739. news_id = %d
  740. AND
  741. section_id = %d',
  742. Database::getTablePrefix(),
  743. $newsId,
  744. $sectionId
  745. );
  746. $res = $this->config->getDb()->query($delete);
  747. if (!$res) {
  748. return false;
  749. }
  750. return true;
  751. }
  752. /**
  753. * Returns an array that contains the news IDs of all news
  754. * of the section $sectionId.
  755. *
  756. * @param int $sectionId
  757. * @return array<int>
  758. */
  759. public function getSectionNews(int $sectionId): array
  760. {
  761. if (!is_numeric($sectionId) || $sectionId < 1) {
  762. return [];
  763. }
  764. $select = sprintf(
  765. '
  766. SELECT
  767. news_id
  768. FROM
  769. %sfaqsection_news
  770. WHERE
  771. section_id = %d',
  772. Database::getTablePrefix(),
  773. $sectionId
  774. );
  775. $res = $this->config->getDb()->query($select);
  776. $result = [];
  777. while ($row = $this->config->getDb()->fetchArray($res)) {
  778. $result[] = $row['news_id'];
  779. }
  780. return $result;
  781. }
  782. /**
  783. * Removes the news $newsId from all sections.
  784. * Returns true on success, otherwise false.
  785. *
  786. * @param int $newsId
  787. * @return bool
  788. */
  789. public function removeNewsFromAllSections(int $newsId): bool
  790. {
  791. if (!is_numeric($newsId) || $newsId < 1) {
  792. return false;
  793. }
  794. $delete = sprintf(
  795. '
  796. DELETE FROM
  797. %sfaqsection_news
  798. WHERE
  799. news_id = %d',
  800. Database::getTablePrefix(),
  801. $newsId
  802. );
  803. $res = $this->config->getDb()->query($delete);
  804. if (!$res) {
  805. return false;
  806. }
  807. return true;
  808. }
  809. }