PageRenderTime 48ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/phpmyfaq/ajaxservice.php

http://github.com/thorsten/phpMyFAQ
PHP | 871 lines | 691 code | 108 blank | 72 comment | 130 complexity | 3bee942a4646704ded7b622748851ea1 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, LGPL-3.0
  1. <?php
  2. /**
  3. * The Ajax Service Layer.
  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 Thorsten Rinne <thorsten@phpmyfaq.de>
  11. * @copyright 2010-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 2010-09-15
  15. */
  16. const IS_VALID_PHPMYFAQ = null;
  17. use phpMyFAQ\Captcha;
  18. use phpMyFAQ\Category;
  19. use phpMyFAQ\Comments;
  20. use phpMyFAQ\Entity\Comment;
  21. use phpMyFAQ\Entity\CommentType;
  22. use phpMyFAQ\Faq;
  23. use phpMyFAQ\Faq\FaqMetaData;
  24. use phpMyFAQ\Faq\FaqPermission;
  25. use phpMyFAQ\Filter;
  26. use phpMyFAQ\Helper\CategoryHelper;
  27. use phpMyFAQ\Helper\FaqHelper;
  28. use phpMyFAQ\Helper\HttpHelper;
  29. use phpMyFAQ\Helper\QuestionHelper;
  30. use phpMyFAQ\Helper\RegistrationHelper;
  31. use phpMyFAQ\Language;
  32. use phpMyFAQ\Language\Plurals;
  33. use phpMyFAQ\Link;
  34. use phpMyFAQ\Mail;
  35. use phpMyFAQ\Network;
  36. use phpMyFAQ\News;
  37. use phpMyFAQ\Notification;
  38. use phpMyFAQ\Question;
  39. use phpMyFAQ\Rating;
  40. use phpMyFAQ\Search;
  41. use phpMyFAQ\Search\SearchResultSet;
  42. use phpMyFAQ\Session;
  43. use phpMyFAQ\Stopwords;
  44. use phpMyFAQ\Strings;
  45. use phpMyFAQ\User;
  46. use phpMyFAQ\User\CurrentUser;
  47. use phpMyFAQ\Utils;
  48. //
  49. // Bootstrapping
  50. //
  51. require 'src/Bootstrap.php';
  52. $action = Filter::filterInput(INPUT_GET, 'action', FILTER_UNSAFE_RAW);
  53. $ajaxLang = Filter::filterInput(INPUT_POST, 'lang', FILTER_UNSAFE_RAW);
  54. $code = Filter::filterInput(INPUT_POST, 'captcha', FILTER_UNSAFE_RAW);
  55. $currentToken = Filter::filterInput(INPUT_POST, 'csrf', FILTER_UNSAFE_RAW);
  56. $Language = new Language($faqConfig);
  57. $languageCode = $Language->setLanguage($faqConfig->get('main.languageDetection'), $faqConfig->get('main.language'));
  58. require_once 'lang/language_en.php';
  59. $faqConfig->setLanguage($Language);
  60. if (Language::isASupportedLanguage($ajaxLang)) {
  61. $languageCode = trim($ajaxLang);
  62. require_once 'lang/language_' . $languageCode . '.php';
  63. } else {
  64. $languageCode = 'en';
  65. require_once 'lang/language_en.php';
  66. }
  67. //
  68. // Load plurals support for selected language
  69. //
  70. $plr = new Plurals($PMF_LANG);
  71. //
  72. // Initializing static string wrapper
  73. //
  74. Strings::init($languageCode);
  75. //
  76. // Send headers
  77. //
  78. $http = new HttpHelper();
  79. $http->setContentType('application/json');
  80. $faqSession = new Session($faqConfig);
  81. $network = new Network($faqConfig);
  82. $stopWords = new Stopwords($faqConfig);
  83. if (!$network->checkIp($_SERVER['REMOTE_ADDR'])) {
  84. $message = ['error' => $PMF_LANG['err_bannedIP']];
  85. }
  86. //
  87. // Check, if user is logged in
  88. //
  89. $user = CurrentUser::getFromCookie($faqConfig);
  90. if (!$user instanceof CurrentUser) {
  91. $user = CurrentUser::getFromSession($faqConfig);
  92. }
  93. if ($user instanceof CurrentUser) {
  94. $isLoggedIn = true;
  95. } else {
  96. $isLoggedIn = false;
  97. }
  98. //
  99. // Check captcha
  100. //
  101. $captcha = new Captcha($faqConfig);
  102. $captcha->setUserIsLoggedIn($isLoggedIn);
  103. if (
  104. 'savevoting' !== $action && 'saveuserdata' !== $action && 'changepassword' !== $action && !is_null($code) &&
  105. !$captcha->checkCaptchaCode($code)
  106. ) {
  107. $message = ['error' => $PMF_LANG['msgCaptcha']];
  108. }
  109. //
  110. // Check if logged in if FAQ is completely secured
  111. //
  112. if (
  113. false === $isLoggedIn && $faqConfig->get('security.enableLoginOnly') &&
  114. 'changepassword' !== $action && 'saveregistration' !== $action
  115. ) {
  116. $message = ['error' => $PMF_LANG['ad_msg_noauth']];
  117. }
  118. if (isset($message['error'])) {
  119. $http->sendJsonWithHeaders($message);
  120. exit();
  121. }
  122. // Save user generated content
  123. switch ($action) {
  124. //
  125. // Comments
  126. //
  127. case 'savecomment':
  128. if (
  129. !$faqConfig->get('records.allowCommentsForGuests') &&
  130. !$user->perm->hasPermission($user->getUserId(), 'addcomment')
  131. ) {
  132. $message = ['error' => $PMF_LANG['err_NotAuth']];
  133. break;
  134. }
  135. $faq = new Faq($faqConfig);
  136. $oComment = new Comments($faqConfig);
  137. $category = new Category($faqConfig);
  138. $type = Filter::filterInput(INPUT_POST, 'type', FILTER_UNSAFE_RAW);
  139. $faqId = Filter::filterInput(INPUT_POST, 'id', FILTER_VALIDATE_INT, 0);
  140. $newsId = Filter::filterInput(INPUT_POST, 'newsId', FILTER_VALIDATE_INT);
  141. $username = Filter::filterInput(INPUT_POST, 'name', FILTER_UNSAFE_RAW);
  142. $mailer = Filter::filterInput(INPUT_POST, 'mail', FILTER_VALIDATE_EMAIL);
  143. $comment = Filter::filterInput(INPUT_POST, 'comment_text', FILTER_UNSAFE_RAW);
  144. switch ($type) {
  145. case 'news':
  146. $id = $newsId;
  147. break;
  148. case 'faq';
  149. $id = $faqId;
  150. break;
  151. }
  152. // If e-mail address is set to optional
  153. if (!$faqConfig->get('main.optionalMailAddress') && is_null($mailer)) {
  154. $mailer = $faqConfig->getAdminEmail();
  155. }
  156. // Check display name and e-mail address for not logged in users
  157. if (false === $isLoggedIn) {
  158. $user = new User($faqConfig);
  159. if (true === $user->checkDisplayName($username) && true === $user->checkMailAddress($mailer)) {
  160. $message = ['error' => '-' . $PMF_LANG['err_SaveComment']];
  161. break;
  162. }
  163. }
  164. if (
  165. !is_null($username) && !is_null($mailer) && !is_null($comment) && $stopWords->checkBannedWord(
  166. $comment
  167. ) && !$faq->commentDisabled(
  168. $id,
  169. $languageCode,
  170. $type
  171. )
  172. ) {
  173. try {
  174. $faqSession->userTracking('save_comment', $id);
  175. } catch (Exception $e) {
  176. // @todo handle the exception
  177. }
  178. $commentEntity = new Comment();
  179. $commentEntity
  180. ->setRecordId($id)
  181. ->setType($type)
  182. ->setUsername($username)
  183. ->setEmail($mailer)
  184. ->setComment(nl2br($comment))
  185. ->setDate($_SERVER['REQUEST_TIME']);
  186. if ($oComment->addComment($commentEntity)) {
  187. $emailTo = $faqConfig->getAdminEmail();
  188. $title = '';
  189. $urlToContent = '';
  190. if ('faq' == $type) {
  191. $faq->getRecord($id);
  192. if ($faq->faqRecord['email'] != '') {
  193. $emailTo = $faq->faqRecord['email'];
  194. }
  195. $title = $faq->getRecordTitle($id);
  196. $faqUrl = sprintf(
  197. '%s?action=faq&cat=%d&id=%d&artlang=%s',
  198. $faqConfig->getDefaultUrl(),
  199. $category->getCategoryIdFromFaq($faq->faqRecord['id']),
  200. $faq->faqRecord['id'],
  201. $faq->faqRecord['lang']
  202. );
  203. $oLink = new Link($faqUrl, $faqConfig);
  204. $oLink->itemTitle = $faq->faqRecord['title'];
  205. $urlToContent = $oLink->toString();
  206. } else {
  207. $news = new News($faqConfig);
  208. $newsData = $news->getNewsEntry($id);
  209. if ($newsData['authorEmail'] != '') {
  210. $emailTo = $newsData['authorEmail'];
  211. }
  212. $title = $newsData['header'];
  213. $link = sprintf(
  214. '%s?action=news&newsid=%d&newslang=%s',
  215. $faqConfig->getDefaultUrl(),
  216. $newsData['id'],
  217. $newsData['lang']
  218. );
  219. $oLink = new Link($link, $faqConfig);
  220. $oLink->itemTitle = $newsData['header'];
  221. $urlToContent = $oLink->toString();
  222. }
  223. $commentMail =
  224. 'User: ' . $commentEntity->getUsername() . ', mailto:' . $commentEntity->getEmail() . "\n" .
  225. 'Title: ' . $title . "\n" .
  226. 'New comment posted here: ' . $urlToContent .
  227. "\n\n" .
  228. wordwrap($comment, 72);
  229. $send = [];
  230. $mailer = new Mail($faqConfig);
  231. $mailer->setReplyTo($commentEntity->getEmail(), $commentEntity->getUsername());
  232. $mailer->addTo($emailTo);
  233. $send[$emailTo] = 1;
  234. $send[$faqConfig->getAdminEmail()] = 1;
  235. if ($type === CommentType::FAQ) {
  236. // Let the category owner of a FAQ get a copy of the message
  237. $category = new Category($faqConfig);
  238. $categories = $category->getCategoryIdsFromFaq($faq->faqRecord['id']);
  239. foreach ($categories as $_category) {
  240. $userId = $category->getOwner($_category);
  241. $catUser = new User($faqConfig);
  242. $catUser->getUserById($userId);
  243. $catOwnerEmail = $catUser->getUserData('email');
  244. if ($catOwnerEmail !== '') {
  245. if (!isset($send[$catOwnerEmail]) && $catOwnerEmail !== $emailTo) {
  246. $mailer->addCc($catOwnerEmail);
  247. $send[$catOwnerEmail] = 1;
  248. }
  249. }
  250. }
  251. }
  252. $mailer->subject = $faqConfig->getTitle() . ': New comment for "' . $title . '"';
  253. $mailer->message = strip_tags($commentMail);
  254. $result = $mailer->send();
  255. unset($mailer);
  256. $message = ['success' => $PMF_LANG['msgCommentThanks']];
  257. } else {
  258. try {
  259. $faqSession->userTracking('error_save_comment', $id);
  260. } catch (Exception $e) {
  261. // @todo handle the exception
  262. }
  263. $message = ['error' => $PMF_LANG['err_SaveComment']];
  264. }
  265. } else {
  266. $message = ['error' => 'Please add your name, your e-mail address and a comment!'];
  267. }
  268. break;
  269. case 'savefaq':
  270. if (
  271. !$faqConfig->get('records.allowNewFaqsForGuests') &&
  272. !$user->perm->hasPermission($user->getUserId(), 'addfaq')
  273. ) {
  274. $message = ['error' => $PMF_LANG['err_NotAuth']];
  275. break;
  276. }
  277. $faq = new Faq($faqConfig);
  278. $category = new Category($faqConfig);
  279. $questionObject = new Question($faqConfig);
  280. $author = Filter::filterInput(INPUT_POST, 'name', FILTER_UNSAFE_RAW);
  281. $email = Filter::filterInput(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
  282. $faqId = Filter::filterInput(INPUT_POST, 'faqid', FILTER_VALIDATE_INT);
  283. $faqLanguage = Filter::filterInput(INPUT_POST, 'faqlanguage', FILTER_UNSAFE_RAW);
  284. $question = Filter::filterInput(INPUT_POST, 'question', FILTER_UNSAFE_RAW);
  285. if ($faqConfig->get('main.enableWysiwygEditorFrontend')) {
  286. $answer = Filter::filterInput(INPUT_POST, 'answer', FILTER_SANITIZE_SPECIAL_CHARS);
  287. $answer = html_entity_decode($answer);
  288. } else {
  289. $answer = Filter::filterInput(INPUT_POST, 'answer', FILTER_UNSAFE_RAW);
  290. $answer = nl2br($answer);
  291. }
  292. $translatedAnswer = Filter::filterInput(INPUT_POST, 'translated_answer', FILTER_UNSAFE_RAW);
  293. $contentLink = Filter::filterInput(INPUT_POST, 'contentlink', FILTER_UNSAFE_RAW);
  294. $contentLink = Filter::filterVar($contentLink, FILTER_VALIDATE_URL);
  295. $keywords = Filter::filterInput(INPUT_POST, 'keywords', FILTER_UNSAFE_RAW);
  296. $categories = Filter::filterInputArray(
  297. INPUT_POST,
  298. [
  299. 'rubrik' => [
  300. 'filter' => FILTER_VALIDATE_INT,
  301. 'flags' => FILTER_REQUIRE_ARRAY,
  302. ],
  303. ]
  304. );
  305. // Check on translation
  306. if (empty($answer) && !is_null($translatedAnswer)) {
  307. $answer = $translatedAnswer;
  308. }
  309. if (
  310. !is_null($author) && !is_null($email) && !is_null($question) &&
  311. $stopWords->checkBannedWord(strip_tags($question)) &&
  312. !is_null($answer) && $stopWords->checkBannedWord(strip_tags($answer)) &&
  313. ((is_null($faqId) && !is_null($categories['rubrik'])) || (!is_null($faqId) && !is_null($faqLanguage) &&
  314. Language::isASupportedLanguage($faqLanguage)))
  315. ) {
  316. $isNew = true;
  317. $newLanguage = '';
  318. if (!is_null($faqId)) {
  319. $isNew = false;
  320. try {
  321. $faqSession->userTracking('save_new_translation_entry', 0);
  322. } catch (Exception $e) {
  323. // @todo handle the exception
  324. }
  325. } else {
  326. try {
  327. $faqSession->userTracking('save_new_entry', 0);
  328. } catch (Exception $e) {
  329. // @todo handle the exception
  330. }
  331. }
  332. $isTranslation = false;
  333. if (!is_null($faqLanguage)) {
  334. $isTranslation = true;
  335. $newLanguage = $faqLanguage;
  336. }
  337. if (!is_null($contentLink) && Strings::substr($contentLink, 7) !== '') {
  338. $answer = sprintf(
  339. '%s<br><div id="newFAQContentLink">%s<a href="http://%s" target="_blank">%s</a></div>',
  340. $answer,
  341. $PMF_LANG['msgInfo'],
  342. Strings::substr($contentLink, 7),
  343. $contentLink
  344. );
  345. }
  346. $autoActivate = $faqConfig->get('records.defaultActivation');
  347. $newData = [
  348. 'lang' => ($isTranslation === true ? $newLanguage : $languageCode),
  349. 'thema' => $question,
  350. 'active' => ($autoActivate ? FAQ_SQL_ACTIVE_YES : FAQ_SQL_ACTIVE_NO),
  351. 'sticky' => 0,
  352. 'content' => $answer,
  353. 'keywords' => $keywords,
  354. 'author' => $author,
  355. 'email' => $email,
  356. 'comment' => 'y',
  357. 'date' => date('YmdHis'),
  358. 'dateStart' => '00000000000000',
  359. 'dateEnd' => '99991231235959',
  360. 'linkState' => '',
  361. 'linkDateCheck' => 0,
  362. 'notes' => ''
  363. ];
  364. if ($isNew) {
  365. $categories = $categories['rubrik'];
  366. } else {
  367. $newData['id'] = $faqId;
  368. $categories = $category->getCategoryIdsFromFaq($newData['id']);
  369. }
  370. $recordId = $faq->addRecord($newData, $isNew);
  371. $openQuestionId = Filter::filterInput(INPUT_POST, 'openQuestionID', FILTER_VALIDATE_INT);
  372. if ($openQuestionId) {
  373. if ($faqConfig->get('records.enableDeleteQuestion')) {
  374. $questionObject->deleteQuestion($openQuestionId);
  375. } else { // adds this faq record id to the related open question
  376. $questionObject->updateQuestionAnswer($openQuestionId, $recordId, $categories[0]);
  377. }
  378. }
  379. $faqMetaData = new FaqMetaData($faqConfig);
  380. $faqMetaData
  381. ->setFaqId($recordId)
  382. ->setFaqLanguage($newData['lang'])
  383. ->setCategories($categories)
  384. ->save();
  385. // Let the admin and the category owners to be informed by email of this new entry
  386. $categoryHelper = new CategoryHelper();
  387. $categoryHelper
  388. ->setCategory($category)
  389. ->setConfiguration($faqConfig);
  390. $moderators = $categoryHelper->getModerators($categories);
  391. $notification = new Notification($faqConfig);
  392. $notification->sendNewFaqAdded($moderators, $recordId, $faqLanguage);
  393. $message = [
  394. 'success' => ($isNew ? $PMF_LANG['msgNewContentThanks'] : $PMF_LANG['msgNewTranslationThanks']),
  395. ];
  396. } else {
  397. $message = [
  398. 'error' => $PMF_LANG['err_SaveEntries']
  399. ];
  400. }
  401. break;
  402. //
  403. // Add question
  404. //
  405. case 'savequestion':
  406. if (
  407. !$faqConfig->get('records.allowQuestionsForGuests') &&
  408. !$user->perm->hasPermission($user->getUserId(), 'addquestion')
  409. ) {
  410. $message = ['error' => $PMF_LANG['err_NotAuth']];
  411. break;
  412. }
  413. $faq = new Faq($faqConfig);
  414. $cat = new Category($faqConfig);
  415. $categories = $cat->getAllCategories();
  416. $author = Filter::filterInput(INPUT_POST, 'name', FILTER_UNSAFE_RAW);
  417. $email = Filter::filterInput(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
  418. $ucategory = Filter::filterInput(INPUT_POST, 'category', FILTER_VALIDATE_INT);
  419. $question = Filter::filterInput(INPUT_POST, 'question', FILTER_UNSAFE_RAW);
  420. $save = Filter::filterInput(INPUT_POST, 'save', FILTER_VALIDATE_INT, 0);
  421. // If e-mail address is set to optional
  422. if (!$faqConfig->get('main.optionalMailAddress') && is_null($email)) {
  423. $email = $faqConfig->getAdminEmail();
  424. }
  425. // If smart answering is disabled, save question immediately
  426. if (false === $faqConfig->get('main.enableSmartAnswering')) {
  427. $save = true;
  428. }
  429. if (
  430. !is_null($author) && !is_null($email) && !is_null($question) && $stopWords->checkBannedWord(
  431. Strings::htmlspecialchars($question)
  432. )
  433. ) {
  434. if ($faqConfig->get('records.enableVisibilityQuestions')) {
  435. $visibility = 'Y';
  436. } else {
  437. $visibility = 'N';
  438. }
  439. $questionData = [
  440. 'username' => $author,
  441. 'email' => $email,
  442. 'category_id' => $ucategory,
  443. 'question' => $question,
  444. 'is_visible' => $visibility
  445. ];
  446. if (false === (bool)$save) {
  447. $cleanQuestion = $stopWords->clean($question);
  448. $user = new CurrentUser($faqConfig);
  449. $faqSearch = new Search($faqConfig);
  450. $faqSearch->setCategory(new Category($faqConfig));
  451. $faqSearch->setCategoryId((int) $ucategory);
  452. $faqPermission = new FaqPermission($faqConfig);
  453. $faqSearchResult = new SearchResultSet($user, $faqPermission, $faqConfig);
  454. $searchResult = [];
  455. $mergedResult = [];
  456. foreach ($cleanQuestion as $word) {
  457. if (!empty($word)) {
  458. $searchResult[] = $faqSearch->search($word, false);
  459. }
  460. }
  461. foreach ($searchResult as $resultSet) {
  462. foreach ($resultSet as $result) {
  463. $mergedResult[] = $result;
  464. }
  465. }
  466. $faqSearchResult->reviewResultSet($mergedResult);
  467. if (0 < $faqSearchResult->getNumberOfResults()) {
  468. $response = sprintf(
  469. '<p>%s</p>',
  470. $plr->getMsg('plmsgSearchAmount', $faqSearchResult->getNumberOfResults())
  471. );
  472. $response .= '<ul>';
  473. $faqHelper = new FaqHelper($faqConfig);
  474. foreach ($faqSearchResult->getResultSet() as $result) {
  475. $url = sprintf(
  476. '%sindex.php?action=faq&cat=%d&id=%d&artlang=%s',
  477. $faqConfig->getDefaultUrl(),
  478. $result->category_id,
  479. $result->id,
  480. $result->lang
  481. );
  482. $oLink = new Link($url, $faqConfig);
  483. $oLink->text = Utils::chopString($result->question, 15);
  484. $oLink->itemTitle = $result->question;
  485. try {
  486. $response .= sprintf(
  487. '<li>%s<br><div class="searchpreview">%s...</div></li>',
  488. $oLink->toHtmlAnchor(),
  489. $faqHelper->renderAnswerPreview($result->answer, 10)
  490. );
  491. } catch (Exception $e) {
  492. // handle exception
  493. }
  494. }
  495. $response .= '</ul>';
  496. $message = ['result' => $response];
  497. } else {
  498. $questionHelper = new QuestionHelper($faqConfig, $cat);
  499. $questionHelper->sendSuccessMail($questionData, $categories);
  500. $message = ['success' => $PMF_LANG['msgAskThx4Mail']];
  501. }
  502. } else {
  503. $questionHelper = new QuestionHelper($faqConfig, $cat);
  504. $questionHelper->sendSuccessMail($questionData, $categories);
  505. $message = ['success' => $PMF_LANG['msgAskThx4Mail']];
  506. }
  507. } else {
  508. $message = ['error' => $PMF_LANG['err_SaveQuestion']];
  509. }
  510. break;
  511. case 'saveregistration':
  512. $registration = new RegistrationHelper($faqConfig);
  513. $fullName = Filter::filterInput(INPUT_POST, 'realname', FILTER_UNSAFE_RAW);
  514. $userName = Filter::filterInput(INPUT_POST, 'name', FILTER_UNSAFE_RAW);
  515. $email = Filter::filterInput(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
  516. $isVisible = Filter::filterInput(INPUT_POST, 'is_visible', FILTER_UNSAFE_RAW) ?? false;
  517. if (!$registration->isDomainWhitelisted($email)) {
  518. $message = ['error' => 'The domain is not whitelisted.'];
  519. break;
  520. }
  521. if (!is_null($userName) && !is_null($email) && !is_null($fullName)) {
  522. $message = $registration->createUser($userName, $fullName, $email, $isVisible);
  523. } else {
  524. $message = ['error' => $PMF_LANG['err_sendMail']];
  525. }
  526. break;
  527. case 'savevoting':
  528. $faq = new Faq($faqConfig);
  529. $rating = new Rating($faqConfig);
  530. $type = Filter::filterInput(INPUT_POST, 'type', FILTER_UNSAFE_RAW, 'faq');
  531. $recordId = Filter::filterInput(INPUT_POST, 'id', FILTER_VALIDATE_INT, 0);
  532. $vote = Filter::filterInput(INPUT_POST, 'vote', FILTER_VALIDATE_INT);
  533. $userIp = Filter::filterVar($_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP);
  534. if (isset($vote) && $rating->check($recordId, $userIp) && $vote > 0 && $vote < 6) {
  535. try {
  536. $faqSession->userTracking('save_voting', $recordId);
  537. } catch (Exception $e) {
  538. // @todo handle the exception
  539. }
  540. $votingData = [
  541. 'record_id' => $recordId,
  542. 'vote' => $vote,
  543. 'user_ip' => $userIp,
  544. ];
  545. if (!$rating->getNumberOfVotings($recordId)) {
  546. $rating->addVoting($votingData);
  547. } else {
  548. $rating->update($votingData);
  549. }
  550. $message = [
  551. 'success' => $PMF_LANG['msgVoteThanks'],
  552. 'rating' => $rating->getVotingResult($recordId),
  553. ];
  554. } elseif (!$rating->check($recordId, $userIp)) {
  555. try {
  556. $faqSession->userTracking('error_save_voting', $recordId);
  557. } catch (Exception $e) {
  558. // @todo handle the exception
  559. }
  560. $message = ['error' => $PMF_LANG['err_VoteTooMuch']];
  561. } else {
  562. try {
  563. $faqSession->userTracking('error_save_voting', $recordId);
  564. } catch (Exception $e) {
  565. // @todo handle the exception
  566. }
  567. $message = ['error' => $PMF_LANG['err_noVote']];
  568. }
  569. break;
  570. // Send user generated mails
  571. case 'sendcontact':
  572. $author = Filter::filterInput(INPUT_POST, 'name', FILTER_UNSAFE_RAW);
  573. $email = Filter::filterInput(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
  574. $question = Filter::filterInput(INPUT_POST, 'question', FILTER_UNSAFE_RAW);
  575. // If e-mail address is set to optional
  576. if (!$faqConfig->get('main.optionalMailAddress') && is_null($email)) {
  577. $email = $faqConfig->getAdminEmail();
  578. }
  579. if (
  580. !is_null($author) && !is_null($email) && !is_null($question) && !empty($question) &&
  581. $stopWords->checkBannedWord(Strings::htmlspecialchars($question))
  582. ) {
  583. $question = sprintf(
  584. "%s %s\n%s %s\n\n %s",
  585. $PMF_LANG['msgNewContentName'],
  586. $author,
  587. $PMF_LANG['msgNewContentMail'],
  588. $email,
  589. $question
  590. );
  591. $mailer = new Mail($faqConfig);
  592. $mailer->setReplyTo($email, $author);
  593. $mailer->addTo($faqConfig->getAdminEmail());
  594. $mailer->subject = Utils::resolveMarkers('Feedback: %sitename%', $faqConfig);
  595. $mailer->message = $question;
  596. $mailer->send();
  597. unset($mailer);
  598. $message = ['success' => $PMF_LANG['msgMailContact']];
  599. } else {
  600. $message = ['error' => $PMF_LANG['err_sendMail']];
  601. }
  602. break;
  603. // Send mails to friends
  604. case 'sendtofriends':
  605. $author = Filter::filterInput(INPUT_POST, 'name', FILTER_UNSAFE_RAW);
  606. $email = Filter::filterInput(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
  607. $link = Filter::filterInput(INPUT_POST, 'link', FILTER_VALIDATE_URL);
  608. $attached = Filter::filterInput(INPUT_POST, 'message', FILTER_UNSAFE_RAW);
  609. $mailto = Filter::filterInputArray(
  610. INPUT_POST,
  611. [
  612. 'mailto' => [
  613. 'filter' => FILTER_VALIDATE_EMAIL,
  614. 'flags' => FILTER_REQUIRE_ARRAY | FILTER_NULL_ON_FAILURE,
  615. ],
  616. ]
  617. );
  618. if (
  619. !is_null($author) && !is_null($email) && is_array($mailto) && !empty($mailto['mailto'][0]) &&
  620. $stopWords->checkBannedWord(Strings::htmlspecialchars($attached))
  621. ) {
  622. foreach ($mailto['mailto'] as $recipient) {
  623. $recipient = trim(strip_tags($recipient));
  624. if (!empty($recipient)) {
  625. $mailer = new Mail($faqConfig);
  626. $mailer->setReplyTo($email, $author);
  627. $mailer->addTo($recipient);
  628. $mailer->subject = $PMF_LANG['msgS2FMailSubject'] . $author;
  629. $mailer->message = sprintf(
  630. "%s\r\n\r\n%s\r\n%s\r\n\r\n%s",
  631. $faqConfig->get('main.send2friendText'),
  632. $PMF_LANG['msgS2FText2'],
  633. $link,
  634. $attached
  635. );
  636. // Send the email
  637. $result = $mailer->send();
  638. unset($mailer);
  639. usleep(250);
  640. }
  641. }
  642. $message = ['success' => $PMF_LANG['msgS2FThx']];
  643. } else {
  644. $message = ['error' => $PMF_LANG['err_sendMail']];
  645. }
  646. break;
  647. //
  648. // Save user data from UCP
  649. //
  650. case 'saveuserdata':
  651. if (!isset($_SESSION['phpmyfaq_csrf_token']) || $_SESSION['phpmyfaq_csrf_token'] !== $currentToken) {
  652. $message = ['error' => $PMF_LANG['ad_msg_noauth']];
  653. break;
  654. }
  655. $userId = Filter::filterInput(INPUT_POST, 'userid', FILTER_VALIDATE_INT);
  656. $userName = Filter::filterInput(INPUT_POST, 'name', FILTER_UNSAFE_RAW);
  657. $email = Filter::filterInput(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
  658. $isVisible = Filter::filterInput(INPUT_POST, 'is_visible', FILTER_UNSAFE_RAW);
  659. $password = Filter::filterInput(INPUT_POST, 'password', FILTER_UNSAFE_RAW);
  660. $confirm = Filter::filterInput(INPUT_POST, 'password_confirm', FILTER_UNSAFE_RAW);
  661. $user = CurrentUser::getFromSession($faqConfig);
  662. if ($userId !== $user->getUserId()) {
  663. $message = ['error' => 'User ID mismatch!'];
  664. break;
  665. }
  666. if ($password !== $confirm) {
  667. $message = ['error' => $PMF_LANG['ad_user_error_passwordsDontMatch']];
  668. break;
  669. }
  670. $userData = [
  671. 'display_name' => $userName,
  672. 'email' => $email,
  673. 'is_visible' => $isVisible === 'on' ? 1 : 0
  674. ];
  675. $success = $user->setUserData($userData);
  676. if (0 !== strlen($password) && 0 !== strlen($confirm)) {
  677. foreach ($user->getAuthContainer() as $author => $auth) {
  678. if ($auth->setReadOnly()) {
  679. continue;
  680. }
  681. if (!$auth->update($user->getLogin(), $password)) {
  682. $message = ['error' => $auth->error()];
  683. $success = false;
  684. } else {
  685. $success = true;
  686. }
  687. }
  688. }
  689. if ($success) {
  690. $message = ['success' => $PMF_LANG['ad_entry_savedsuc']];
  691. } else {
  692. $message = ['error' => $PMF_LANG['ad_entry_savedfail']];
  693. }
  694. break;
  695. //
  696. // Change password
  697. //
  698. case 'changepassword':
  699. $username = Filter::filterInput(INPUT_POST, 'username', FILTER_UNSAFE_RAW);
  700. $email = Filter::filterInput(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
  701. if (!is_null($username) && !is_null($email)) {
  702. $user = new CurrentUser($faqConfig);
  703. $loginExist = $user->getUserByLogin($username);
  704. if ($loginExist && ($email == $user->getUserData('email'))) {
  705. $newPassword = $user->createPassword();
  706. $user->changePassword($newPassword);
  707. $text = $PMF_LANG['lostpwd_text_1'] . "\nUsername: " . $username . "\nNew Password: " . $newPassword . "\n\n" . $PMF_LANG['lostpwd_text_2'];
  708. $mailer = new Mail($faqConfig);
  709. $mailer->addTo($email);
  710. $mailer->subject = Utils::resolveMarkers('[%sitename%] Username / password request', $faqConfig);
  711. $mailer->message = $text;
  712. $result = $mailer->send();
  713. unset($mailer);
  714. // Trust that the email has been sent
  715. $message = ['success' => $PMF_LANG['lostpwd_mail_okay']];
  716. } else {
  717. $message = ['error' => $PMF_LANG['lostpwd_err_1']];
  718. }
  719. } else {
  720. $message = ['error' => $PMF_LANG['lostpwd_err_2']];
  721. }
  722. break;
  723. //
  724. // Request removal of user
  725. //
  726. case 'request-removal':
  727. $author = Filter::filterInput(INPUT_POST, 'name', FILTER_UNSAFE_RAW);
  728. $loginName = Filter::filterInput(INPUT_POST, 'loginname', FILTER_UNSAFE_RAW);
  729. $email = Filter::filterInput(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
  730. $question = Filter::filterInput(INPUT_POST, 'question', FILTER_UNSAFE_RAW);
  731. // If e-mail address is set to optional
  732. if (!$faqConfig->get('main.optionalMailAddress') && is_null($email)) {
  733. $email = $faqConfig->getAdminEmail();
  734. }
  735. if (
  736. !is_null($author) && !is_null($email) && !is_null($question) &&
  737. !empty($question) && $stopWords->checkBannedWord(Strings::htmlspecialchars($question))
  738. ) {
  739. $question = sprintf(
  740. "%s %s\n%s %s\n%s %s\n\n %s",
  741. $PMF_LANG['ad_user_loginname'],
  742. $loginName,
  743. $PMF_LANG['msgNewContentName'],
  744. $author,
  745. $PMF_LANG['msgNewContentMail'],
  746. $email,
  747. $question
  748. );
  749. $mailer = new Mail($faqConfig);
  750. $mailer->setReplyTo($email, $author);
  751. $mailer->addTo($faqConfig->getAdminEmail());
  752. $mailer->subject = $faqConfig->getTitle() . ': Remove User Request';
  753. $mailer->message = $question;
  754. $result = $mailer->send();
  755. unset($mailer);
  756. $message = ['success' => $PMF_LANG['msgMailContact']];
  757. } else {
  758. $message = ['error' => $PMF_LANG['err_sendMail']];
  759. }
  760. break;
  761. }
  762. $http->sendJsonWithHeaders($message);
  763. exit();