1<?php
2
3/**
4 * The Ajax Service Layer.
5 *
6 * This Source Code Form is subject to the terms of the Mozilla Public License,
7 * v. 2.0. If a copy of the MPL was not distributed with this file, You can
8 * obtain one at http://mozilla.org/MPL/2.0/.
9 *
10 * @package phpMyFAQ
11 * @author Thorsten Rinne <thorsten@phpmyfaq.de>
12 * @copyright 2010-2020 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 2010-09-15
16 */
17
18define('IS_VALID_PHPMYFAQ', null);
19
20use phpMyFAQ\Captcha;
21use phpMyFAQ\Category;
22use phpMyFAQ\Comments;
23use phpMyFAQ\Entity\Comment;
24use phpMyFAQ\Entity\CommentType;
25use phpMyFAQ\Faq;
26use phpMyFAQ\Filter;
27use phpMyFAQ\Helper\FaqHelper;
28use phpMyFAQ\Helper\HttpHelper;
29use phpMyFAQ\Helper\QuestionHelper;
30use phpMyFAQ\Language;
31use phpMyFAQ\Language\Plurals;
32use phpMyFAQ\Link;
33use phpMyFAQ\Mail;
34use phpMyFAQ\Network;
35use phpMyFAQ\News;
36use phpMyFAQ\Question;
37use phpMyFAQ\Rating;
38use phpMyFAQ\Search;
39use phpMyFAQ\Search\SearchResultSet;
40use phpMyFAQ\Session;
41use phpMyFAQ\Stopwords;
42use phpMyFAQ\Strings;
43use phpMyFAQ\User;
44use phpMyFAQ\User\CurrentUser;
45use phpMyFAQ\Utils;
46use phpMyFAQ\Visits;
47
48//
49// Bootstrapping
50//
51require 'src/Bootstrap.php';
52
53$action = Filter::filterInput(INPUT_GET, 'action', FILTER_SANITIZE_STRING);
54$ajaxLang = Filter::filterInput(INPUT_POST, 'lang', FILTER_SANITIZE_STRING);
55$code = Filter::filterInput(INPUT_POST, 'captcha', FILTER_SANITIZE_STRING);
56$currentToken = Filter::filterInput(INPUT_POST, 'csrf', FILTER_SANITIZE_STRING);
57
58$Language = new Language($faqConfig);
59$languageCode = $Language->setLanguage($faqConfig->get('main.languageDetection'), $faqConfig->get('main.language'));
60require_once 'lang/language_en.php';
61$faqConfig->setLanguage($Language);
62
63if (Language::isASupportedLanguage($ajaxLang)) {
64    $languageCode = trim($ajaxLang);
65    require_once 'lang/language_' . $languageCode . '.php';
66} else {
67    $languageCode = 'en';
68    require_once 'lang/language_en.php';
69}
70
71//
72// Load plurals support for selected language
73//
74$plr = new Plurals($PMF_LANG);
75
76//
77// Initializing static string wrapper
78//
79Strings::init($languageCode);
80
81//
82// Send headers
83//
84$http = new HttpHelper();
85$http->setContentType('application/json');
86
87$faqSession = new Session($faqConfig);
88$network = new Network($faqConfig);
89$stopWords = new Stopwords($faqConfig);
90
91if (!$network->checkIp($_SERVER['REMOTE_ADDR'])) {
92    $message = ['error' => $PMF_LANG['err_bannedIP']];
93}
94
95//
96// Check, if user is logged in
97//
98$user = CurrentUser::getFromCookie($faqConfig);
99if (!$user instanceof CurrentUser) {
100    $user = CurrentUser::getFromSession($faqConfig);
101}
102if ($user instanceof CurrentUser) {
103    $isLoggedIn = true;
104} else {
105    $isLoggedIn = false;
106}
107
108//
109// Check captcha
110//
111$captcha = new Captcha($faqConfig);
112$captcha->setUserIsLoggedIn($isLoggedIn);
113
114if ('savevoting' !== $action && 'saveuserdata' !== $action && 'changepassword' !== $action &&
115    !$captcha->checkCaptchaCode($code)) {
116    $message = ['error' => $PMF_LANG['msgCaptcha']];
117}
118
119//
120// Check if logged in if FAQ is completely secured
121//
122if (false === $isLoggedIn && $faqConfig->get('security.enableLoginOnly') &&
123    'changepassword' !== $action && 'saveregistration' !== $action) {
124    $message = ['error' => $PMF_LANG['ad_msg_noauth']];
125}
126
127if (isset($message['error'])) {
128    $http->sendJsonWithHeaders($message);
129    exit();
130}
131
132// Save user generated content
133switch ($action) {
134    //
135    // Comments
136    //
137    case 'savecomment':
138
139        if (!$faqConfig->get('records.allowCommentsForGuests') &&
140            !$user->perm->checkRight($user->getUserId(), 'addcomment')) {
141            $message = ['error' => $PMF_LANG['err_NotAuth']];
142            break;
143        }
144
145        $faq = new Faq($faqConfig);
146        $oComment = new Comments($faqConfig);
147        $category = new Category($faqConfig);
148        $type = Filter::filterInput(INPUT_POST, 'type', FILTER_SANITIZE_STRING);
149        $faqId = Filter::filterInput(INPUT_POST, 'id', FILTER_VALIDATE_INT, 0);
150        $newsId = Filter::filterInput(INPUT_POST, 'newsId', FILTER_VALIDATE_INT);
151        $username = Filter::filterInput(INPUT_POST, 'user', FILTER_SANITIZE_STRING);
152        $mailer = Filter::filterInput(INPUT_POST, 'mail', FILTER_VALIDATE_EMAIL);
153        $comment = Filter::filterInput(INPUT_POST, 'comment_text', FILTER_SANITIZE_STRING);
154
155        switch ($type) {
156            case 'news':
157                $id = $newsId;
158                break;
159            case 'faq';
160                $id = $faqId;
161                break;
162        }
163
164        // If e-mail address is set to optional
165        if (!$faqConfig->get('main.optionalMailAddress') && is_null($mailer)) {
166            $mailer = $faqConfig->get('main.administrationMail');
167        }
168
169        // Check display name and e-mail address for not logged in users
170        if (false === $isLoggedIn) {
171            $user = new User($faqConfig);
172            if (true === $user->checkDisplayName($username) && true === $user->checkMailAddress($mailer)) {
173                echo json_encode(['error' => $PMF_LANG['err_SaveComment']]);
174                break;
175            }
176        }
177
178        if (!is_null($username) && !is_null($mailer) && !is_null($comment) && $stopWords->checkBannedWord(
179                $comment
180            ) && !$faq->commentDisabled(
181                $id,
182                $languageCode,
183                $type
184            )) {
185            try {
186                $faqSession->userTracking('save_comment', $id);
187            } catch (Exception $e) {
188                // @todo handle the exception
189            }
190
191            $commentEntity = new Comment();
192            $commentEntity
193                ->setRecordId($id)
194                ->setType($type)
195                ->setUsername($username)
196                ->setEmail($mailer)
197                ->setComment(nl2br($comment))
198                ->setDate($_SERVER['REQUEST_TIME']);
199
200            if ($oComment->addComment($commentEntity)) {
201                $emailTo = $faqConfig->get('main.administrationMail');
202                $title = '';
203                $urlToContent = '';
204                if ('faq' == $type) {
205                    $faq->getRecord($id);
206                    if ($faq->faqRecord['email'] != '') {
207                        $emailTo = $faq->faqRecord['email'];
208                    }
209
210                    $title = $faq->getRecordTitle($id);
211
212                    $faqUrl = sprintf(
213                        '%s?action=faq&cat=%d&id=%d&artlang=%s',
214                        $faqConfig->getDefaultUrl(),
215                        $category->getCategoryIdFromFaq($faq->faqRecord['id']),
216                        $faq->faqRecord['id'],
217                        $faq->faqRecord['lang']
218                    );
219                    $oLink = new Link($faqUrl, $faqConfig);
220                    $oLink->itemTitle = $faq->faqRecord['title'];
221                    $urlToContent = $oLink->toString();
222                } else {
223                    $news = new News($faqConfig);
224                    $newsData = $news->getNewsEntry($id);
225                    if ($newsData['authorEmail'] != '') {
226                        $emailTo = $newsData['authorEmail'];
227                    }
228
229                    $title = $newsData['header'];
230
231                    $link = sprintf(
232                        '%s?action=news&newsid=%d&newslang=%s',
233                        $faqConfig->getDefaultUrl(),
234                        $newsData['id'],
235                        $newsData['lang']
236                    );
237                    $oLink = new Link($link, $faqConfig);
238                    $oLink->itemTitle = $newsData['header'];
239                    $urlToContent = $oLink->toString();
240                }
241
242                $commentMail =
243                    'User: ' . $commentEntity->getUsername() . ', mailto:' . $commentEntity->getEmail() . "\n" .
244                    'Title: ' . $title . "\n" .
245                    'New comment posted here: ' . $urlToContent .
246                    "\n\n" .
247                    wordwrap($comment, 72);
248
249                $send = [];
250                $mailer = new Mail($faqConfig);
251                $mailer->setReplyTo($commentEntity->getEmail(), $commentEntity->getUsername());
252                $mailer->addTo($emailTo);
253
254                $send[$emailTo] = 1;
255                $send[$faqConfig->get('main.administrationMail')] = 1;
256
257                if ($type === CommentType::FAQ) {
258                    // Let the category owner of a FAQ get a copy of the message
259                    $category = new Category($faqConfig);
260                    $categories = $category->getCategoryIdsFromFaq($faq->faqRecord['id']);
261                    foreach ($categories as $_category) {
262                        $userId = $category->getOwner($_category);
263                        $catUser = new User($faqConfig);
264                        $catUser->getUserById($userId);
265                        $catOwnerEmail = $catUser->getUserData('email');
266
267                        if ($catOwnerEmail !== '') {
268                            if (!isset($send[$catOwnerEmail]) && $catOwnerEmail !== $emailTo) {
269                                $mailer->addCc($catOwnerEmail);
270                                $send[$catOwnerEmail] = 1;
271                            }
272                        }
273                    }
274                }
275
276                $mailer->subject = $faqConfig->get('main.titleFAQ') . ': New comment for "' . $title . '"';
277                $mailer->message = strip_tags($commentMail);
278
279                $result = $mailer->send();
280                unset($mailer);
281
282                $message = ['success' => $PMF_LANG['msgCommentThanks']];
283            } else {
284                try {
285                    $faqSession->userTracking('error_save_comment', $id);
286                } catch (Exception $e) {
287                    // @todo handle the exception
288                }
289                $message = ['error' => $PMF_LANG['err_SaveComment']];
290            }
291        } else {
292            $message = ['error' => 'Please add your name, your e-mail address and a comment!'];
293        }
294        break;
295
296    case 'savefaq':
297
298        if (!$faqConfig->get('records.allowNewFaqsForGuests') &&
299            !$user->perm->checkRight($user->getUserId(), 'addfaq')) {
300            $message = ['error' => $PMF_LANG['err_NotAuth']];
301            break;
302        }
303
304        $faq = new Faq($faqConfig);
305        $category = new Category($faqConfig);
306        $questionObject = new Question($faqConfig);
307        $author = Filter::filterInput(INPUT_POST, 'name', FILTER_SANITIZE_STRING);
308        $email = Filter::filterInput(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
309        $faqId = Filter::filterInput(INPUT_POST, 'faqid', FILTER_VALIDATE_INT);
310        $faqLanguage = Filter::filterInput(INPUT_POST, 'faqlanguage', FILTER_SANITIZE_STRING);
311        $question = Filter::filterInput(INPUT_POST, 'question', FILTER_SANITIZE_STRIPPED);
312        if ($faqConfig->get('main.enableWysiwygEditorFrontend')) {
313            $answer = Filter::filterInput(INPUT_POST, 'answer', FILTER_SANITIZE_SPECIAL_CHARS);
314            $answer = html_entity_decode($answer);
315        } else {
316            $answer = Filter::filterInput(INPUT_POST, 'answer', FILTER_SANITIZE_STRIPPED);
317            $answer = nl2br($answer);
318        }
319        $translatedAnswer = Filter::filterInput(INPUT_POST, 'translated_answer', FILTER_SANITIZE_STRING);
320        $contentLink = Filter::filterInput(INPUT_POST, 'contentlink', FILTER_SANITIZE_STRING);
321        $contentLink = Filter::filterVar($contentLink, FILTER_VALIDATE_URL);
322        $keywords = Filter::filterInput(INPUT_POST, 'keywords', FILTER_SANITIZE_STRIPPED);
323        $categories = Filter::filterInputArray(
324            INPUT_POST,
325            [
326                'rubrik' => [
327                    'filter' => FILTER_VALIDATE_INT,
328                    'flags' => FILTER_REQUIRE_ARRAY,
329                ],
330            ]
331        );
332
333        // Check on translation
334        if (empty($answer) && !is_null($translatedAnswer)) {
335            $answer = $translatedAnswer;
336        }
337
338        if (!is_null($author) && !is_null($email) && !is_null($question) && $stopWords->checkBannedWord(strip_tags($question)) &&
339            !is_null($answer) && $stopWords->checkBannedWord(strip_tags($answer)) &&
340            ((is_null($faqId) && !is_null($categories['rubrik'])) || (!is_null($faqId) && !is_null($faqLanguage) &&
341                    Language::isASupportedLanguage($faqLanguage)))) {
342            $isNew = true;
343            if (!is_null($faqId)) {
344                $isNew = false;
345                try {
346                    $faqSession->userTracking('save_new_translation_entry', 0);
347                } catch (Exception $e) {
348                    // @todo handle the exception
349                }
350            } else {
351                try {
352                    $faqSession->userTracking('save_new_entry', 0);
353                } catch (Exception $e) {
354                    // @todo handle the exception
355                }
356            }
357
358            $isTranslation = false;
359            if (!is_null($faqLanguage)) {
360                $isTranslation = true;
361                $newLanguage = $faqLanguage;
362            }
363
364            if (Strings::substr($contentLink, 7) != '') {
365                $answer = sprintf(
366                    '%s<br><div id="newFAQContentLink">%s<a href="http://%s" target="_blank">%s</a></div>',
367                    $answer,
368                    $PMF_LANG['msgInfo'],
369                    Strings::substr($contentLink, 7),
370                    $contentLink
371                );
372            }
373
374            $autoActivate = $faqConfig->get('records.defaultActivation');
375
376            $newData = [
377                'lang' => ($isTranslation === true ? $newLanguage : $languageCode),
378                'thema' => $question,
379                'active' => ($autoActivate ? FAQ_SQL_ACTIVE_YES : FAQ_SQL_ACTIVE_NO),
380                'sticky' => 0,
381                'content' => $answer,
382                'keywords' => $keywords,
383                'author' => $author,
384                'email' => $email,
385                'comment' => 'y',
386                'date' => date('YmdHis'),
387                'dateStart' => '00000000000000',
388                'dateEnd' => '99991231235959',
389                'linkState' => '',
390                'linkDateCheck' => 0,
391                'notes' => ''
392            ];
393
394            if ($isNew) {
395                $categories = $categories['rubrik'];
396            } else {
397                $newData['id'] = $faqId;
398                $categories = $category->getCategoryIdsFromFaq($newData['id']);
399            }
400
401            $recordId = $faq->addRecord($newData, $isNew);
402
403            $faq->addCategoryRelations($categories, $recordId, $newData['lang']);
404
405            $openQuestionId = Filter::filterInput(INPUT_POST, 'openQuestionID', FILTER_VALIDATE_INT);
406            if ($openQuestionId) {
407                if ($faqConfig->get('records.enableDeleteQuestion')) {
408                    $questionObject->deleteQuestion($openQuestionId);
409                } else { // adds this faq record id to the related open question
410                    $questionObject->updateQuestionAnswer($openQuestionId, $recordId, $categories[0]);
411                }
412            }
413
414            // Activate visits
415            $visits = new Visits($faqConfig);
416            $visits->logViews($recordId);
417
418            // Set permissions
419            $userPermissions = $category->getPermissions('user', $categories);
420            // Add user permissions
421            $faq->addPermission('user', $recordId, $userPermissions);
422            $category->addPermission('user', $categories, $userPermissions);
423            // Add group permission
424            if ($faqConfig->get('security.permLevel') !== 'basic') {
425                $groupPermissions = $category->getPermissions('group', $categories);
426                $faq->addPermission('group', $recordId, $groupPermissions);
427                $category->addPermission('group', $categories, $groupPermissions);
428            }
429
430            // Let the PMF Administrator and the Entity Owner to be informed by email of this new entry
431            $send = [];
432            $mailer = new Mail($faqConfig);
433            $mailer->setReplyTo($email, $author);
434            $mailer->addTo($faqConfig->get('main.administrationMail'));
435            $send[$faqConfig->get('main.administrationMail')] = 1;
436
437            foreach ($categories as $_category) {
438                $userId = $category->getOwner($_category);
439                $groupId = $category->getModeratorGroupId($_category);
440
441                // @todo Move this code to Entityhp
442                $oUser = new User($faqConfig);
443                $oUser->getUserById($userId);
444                $catOwnerEmail = $oUser->getUserData('email');
445
446                // Avoid to send multiple emails to the same owner
447                if (!empty($catOwnerEmail) && !isset($send[$catOwnerEmail])) {
448                    $mailer->addCc($catOwnerEmail);
449                    $send[$catOwnerEmail] = 1;
450                }
451
452                if ($groupId > 0) {
453                    $moderators = $oUser->perm->getGroupMembers($groupId);
454                    foreach ($moderators as $moderator) {
455                        $oUser->getUserById($moderator);
456                        $moderatorEmail = $oUser->getUserData('email');
457
458                        // Avoid to send multiple emails to the same moderator
459                        if (!empty($moderatorEmail) && !isset($send[$moderatorEmail])) {
460                            $mailer->addCc($moderatorEmail);
461                            $send[$moderatorEmail] = 1;
462                        }
463                    }
464                }
465            }
466
467            $mailer->subject = $faqConfig->get('main.titleFAQ') . ': New FAQ was added.';
468
469            // @todo let the email contains the faq article both as plain text and as HTML
470            $mailer->message = html_entity_decode(
471                    $PMF_LANG['msgMailCheck']
472                ) . "\n\n" .
473                $faqConfig->get('main.titleFAQ') . ': ' .
474                $faqConfig->getDefaultUrl() . 'admin/?action=editentry&id=' . $recordId . '&lang=' . $faqLanguage;
475            $result = $mailer->send();
476            unset($mailer);
477
478            $message = [
479                'success' => ($isNew ? $PMF_LANG['msgNewContentThanks'] : $PMF_LANG['msgNewTranslationThanks']),
480            ];
481        } else {
482            $message = [
483                'error' => $PMF_LANG['err_SaveEntries']
484            ];
485        }
486
487        break;
488
489    //
490    // Add question
491    //
492    case 'savequestion':
493
494        if (!$faqConfig->get('records.allowQuestionsForGuests') &&
495            !$user->perm->checkRight($user->getUserId(), 'addquestion')) {
496            $message = ['error' => $PMF_LANG['err_NotAuth']];
497            break;
498        }
499
500        $faq = new Faq($faqConfig);
501        $cat = new Category($faqConfig);
502        $categories = $cat->getAllCategories();
503        $author = Filter::filterInput(INPUT_POST, 'name', FILTER_SANITIZE_STRING);
504        $email = Filter::filterInput(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
505        $ucategory = Filter::filterInput(INPUT_POST, 'category', FILTER_VALIDATE_INT);
506        $question = Filter::filterInput(INPUT_POST, 'question', FILTER_SANITIZE_STRIPPED);
507        $save = Filter::filterInput(INPUT_POST, 'save', FILTER_VALIDATE_INT, 0);
508
509        // If e-mail address is set to optional
510        if (!$faqConfig->get('main.optionalMailAddress') && is_null($email)) {
511            $email = $faqConfig->get('main.administrationMail');
512        }
513
514        // If smart answering is disabled, save question immediately
515        if (false === $faqConfig->get('main.enableSmartAnswering')) {
516            $save = true;
517        }
518
519        if (!is_null($author) && !is_null($email) && !is_null($question) && $stopWords->checkBannedWord(
520                Strings::htmlspecialchars($question)
521            )) {
522            if ($faqConfig->get('records.enableVisibilityQuestions')) {
523                $visibility = 'N';
524            } else {
525                $visibility = 'Y';
526            }
527
528            $questionData = [
529                'username' => $author,
530                'email' => $email,
531                'category_id' => $ucategory,
532                'question' => $question,
533                'is_visible' => $visibility
534            ];
535
536            if (false === (boolean)$save) {
537                $cleanQuestion = $stopWords->clean($question);
538
539                $user = new CurrentUser($faqConfig);
540                $faqSearch = new Search($faqConfig);
541                $faqSearch->setCategory(new Category($faqConfig));
542                $faqSearch->setCategoryId($ucategory);
543                $faqSearchResult = new SearchResultSet($user, $faq, $faqConfig);
544                $searchResult = [];
545                $mergedResult = [];
546
547                foreach ($cleanQuestion as $word) {
548                    if (!empty($word)) {
549                        $searchResult[] = $faqSearch->search($word, false);
550                    }
551                }
552                foreach ($searchResult as $resultSet) {
553                    foreach ($resultSet as $result) {
554                        $mergedResult[] = $result;
555                    }
556                }
557                $faqSearchResult->reviewResultSet($mergedResult);
558
559                if (0 < $faqSearchResult->getNumberOfResults()) {
560                    $response = sprintf(
561                        '<p>%s</p>',
562                        $plr->getMsg('plmsgSearchAmount', $faqSearchResult->getNumberOfResults())
563                    );
564
565                    $response .= '<ul>';
566
567                    $faqHelper = new FaqHelper($faqConfig);
568                    foreach ($faqSearchResult->getResultSet() as $result) {
569                        $url = sprintf(
570                            '%sindex.php?action=faq&cat=%d&id=%d&artlang=%s',
571                            $faqConfig->getDefaultUrl(),
572                            $result->category_id,
573                            $result->id,
574                            $result->lang
575                        );
576                        $oLink = new Link($url, $faqConfig);
577                        $oLink->text = Utils::chopString($result->question, 15);
578                        $oLink->itemTitle = $result->question;
579
580                        try {
581                            $response .= sprintf(
582                                '<li>%s<br><div class="searchpreview">%s...</div></li>',
583                                $oLink->toHtmlAnchor(),
584                                $faqHelper->renderAnswerPreview($result->answer, 10)
585                            );
586                        } catch (Exception $e) {
587                            // handle exception
588                        }
589                    }
590                    $response .= '</ul>';
591
592                    $message = ['result' => $response];
593                } else {
594                    $questionHelper = new QuestionHelper($faqConfig, $cat);
595                    $questionHelper->sendSuccessMail($questionData, $categories);
596                    $message = ['success' => $PMF_LANG['msgAskThx4Mail']];
597                }
598            } else {
599                $questionHelper = new QuestionHelper($faqConfig, $cat);
600                $questionHelper->sendSuccessMail($questionData, $categories);
601                $message = ['success' => $PMF_LANG['msgAskThx4Mail']];
602            }
603        } else {
604            $message = ['error' => $PMF_LANG['err_SaveQuestion']];
605        }
606
607        break;
608
609    case 'saveregistration':
610
611        $realname = Filter::filterInput(INPUT_POST, 'realname', FILTER_SANITIZE_STRING);
612        $loginName = Filter::filterInput(INPUT_POST, 'name', FILTER_SANITIZE_STRING);
613        $email = Filter::filterInput(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
614
615        if (!is_null($loginName) && !is_null($email) && !is_null($realname)) {
616            $message = [];
617            $user = new User($faqConfig);
618
619            // Create user account (login and password)
620            // Note: password be automatically generated and sent by email as soon if admin switch user to "active"
621            if (!$user->createUser($loginName, null)) {
622                $message = ['error' => $user->error()];
623            } else {
624                $user->userdata->set(
625                    ['display_name', 'email'],
626                    [$realname, $email]
627                );
628                // set user status
629                $user->setStatus('blocked');
630
631                if (!$faqConfig->get('spam.manualActivation')) {
632                    $isNowActive = $user->activateUser();
633                } else {
634                    $isNowActive = false;
635                }
636
637                if ($isNowActive) {
638                    $adminMessage = 'This user has been automatically activated, you can still' .
639                        ' modify the users permissions or decline membership by visiting the admin section';
640                } else {
641                    $adminMessage = 'To activate this user please use';
642                }
643
644                $text = sprintf(
645                    "New user has been registrated:\n\nName: %s\nLogin name: %s\n\n" .
646                    '%s the administration interface at %s.',
647                    $realname,
648                    $loginName,
649                    $adminMessage,
650                    $faqConfig->getDefaultUrl()
651                );
652
653                $mailer = new Mail($faqConfig);
654                $mailer->setReplyTo($email, $realname);
655                $mailer->addTo($faqConfig->get('main.administrationMail'));
656                $mailer->subject = Utils::resolveMarkers($PMF_LANG['emailRegSubject'], $faqConfig);
657                $mailer->message = $text;
658                $result = $mailer->send();
659                unset($mailer);
660
661                $message = [
662                    'success' => trim($PMF_LANG['successMessage']) .
663                        ' ' .
664                        trim($PMF_LANG['msgRegThankYou']),
665                ];
666            }
667        } else {
668            $message = ['error' => $PMF_LANG['err_sendMail']];
669        }
670        break;
671
672    case 'savevoting':
673
674        $faq = new Faq($faqConfig);
675        $rating = new Rating($faqConfig);
676        $type = Filter::filterInput(INPUT_POST, 'type', FILTER_SANITIZE_STRING, 'faq');
677        $recordId = Filter::filterInput(INPUT_POST, 'id', FILTER_VALIDATE_INT, 0);
678        $vote = Filter::filterInput(INPUT_POST, 'vote', FILTER_VALIDATE_INT);
679        $userIp = Filter::filterVar($_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP);
680
681        if (isset($vote) && $rating->check($recordId, $userIp) && $vote > 0 && $vote < 6) {
682            try {
683                $faqSession->userTracking('save_voting', $recordId);
684            } catch (Exception $e) {
685                // @todo handle the exception
686            }
687
688            $votingData = [
689                'record_id' => $recordId,
690                'vote' => $vote,
691                'user_ip' => $userIp,
692            ];
693
694            if (!$rating->getNumberOfVotings($recordId)) {
695                $rating->addVoting($votingData);
696            } else {
697                $rating->update($votingData);
698            }
699            $message = [
700                'success' => $PMF_LANG['msgVoteThanks'],
701                'rating' => $rating->getVotingResult($recordId),
702            ];
703        } elseif (!$rating->check($recordId, $userIp)) {
704            try {
705                $faqSession->userTracking('error_save_voting', $recordId);
706            } catch (Exception $e) {
707                // @todo handle the exception
708            }
709            $message = ['error' => $PMF_LANG['err_VoteTooMuch']];
710        } else {
711            try {
712                $faqSession->userTracking('error_save_voting', $recordId);
713            } catch (Exception $e) {
714                // @todo handle the exception
715            }
716            $message = ['error' => $PMF_LANG['err_noVote']];
717        }
718
719        break;
720
721    // Send user generated mails
722    case 'sendcontact':
723
724        $author = Filter::filterInput(INPUT_POST, 'name', FILTER_SANITIZE_STRING);
725        $email = Filter::filterInput(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
726        $question = Filter::filterInput(INPUT_POST, 'question', FILTER_SANITIZE_STRIPPED);
727
728        // If e-mail address is set to optional
729        if (!$faqConfig->get('main.optionalMailAddress') && is_null($email)) {
730            $email = $faqConfig->get('main.administrationMail');
731        }
732
733        if (!is_null($author) && !is_null($email) && !is_null($question) &&
734            !empty($question) && $stopWords->checkBannedWord(Strings::htmlspecialchars($question))) {
735            $question = sprintf(
736                "%s %s\n%s %s\n\n %s",
737                $PMF_LANG['msgNewContentName'],
738                $author,
739                $PMF_LANG['msgNewContentMail'],
740                $email,
741                $question
742            );
743
744            $mailer = new Mail($faqConfig);
745            $mailer->setReplyTo($email, $author);
746            $mailer->addTo($faqConfig->get('main.administrationMail'));
747            $mailer->subject = Utils::resolveMarkers('Feedback: %sitename%', $faqConfig);
748            $mailer->message = $question;
749            $result = $mailer->send();
750
751            unset($mailer);
752
753            if ($result) {
754                $message = ['success' => $PMF_LANG['msgMailContact']];
755            } else {
756                $message = ['error' => $PMF_LANG['err_sendMail']];
757            }
758        } else {
759            $message = ['error' => $PMF_LANG['err_sendMail']];
760        }
761        break;
762
763    // Send mails to friends
764    case 'sendtofriends':
765
766        $author = Filter::filterInput(INPUT_POST, 'name', FILTER_SANITIZE_STRING);
767        $email = Filter::filterInput(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
768        $link = Filter::filterInput(INPUT_POST, 'link', FILTER_VALIDATE_URL);
769        $attached = Filter::filterInput(INPUT_POST, 'message', FILTER_SANITIZE_STRIPPED);
770        $mailto = Filter::filterInputArray(
771            INPUT_POST,
772            [
773                'mailto' => [
774                    'filter' => FILTER_VALIDATE_EMAIL,
775                    'flags' => FILTER_REQUIRE_ARRAY | FILTER_NULL_ON_FAILURE,
776                ],
777            ]
778        );
779
780        if (!is_null($author) && !is_null($email) && is_array($mailto) && !empty($mailto['mailto'][0]) &&
781            $stopWords->checkBannedWord(Strings::htmlspecialchars($attached))) {
782            foreach ($mailto['mailto'] as $recipient) {
783                $recipient = trim(strip_tags($recipient));
784                if (!empty($recipient)) {
785                    $mailer = new Mail($faqConfig);
786                    $mailer->setReplyTo($email, $author);
787                    $mailer->addTo($recipient);
788                    $mailer->subject = $PMF_LANG['msgS2FMailSubject'] . $author;
789                    $mailer->message = sprintf(
790                        "%s\r\n\r\n%s\r\n%s\r\n\r\n%s",
791                        $faqConfig->get('main.send2friendText'),
792                        $PMF_LANG['msgS2FText2'],
793                        $link,
794                        $attached
795                    );
796
797                    // Send the email
798                    $result = $mailer->send();
799                    unset($mailer);
800                    usleep(250);
801                }
802            }
803
804            $message = ['success' => $PMF_LANG['msgS2FThx']];
805        } else {
806            $message = ['error' => $PMF_LANG['err_sendMail']];
807        }
808        break;
809
810    // Save user data from UCP
811    case 'saveuserdata':
812
813        if (!isset($_SESSION['phpmyfaq_csrf_token']) || $_SESSION['phpmyfaq_csrf_token'] !== $currentToken) {
814            $message = ['error' => $PMF_LANG['ad_msg_noauth']];
815            break;
816        }
817
818        $userId = Filter::filterInput(INPUT_POST, 'userid', FILTER_VALIDATE_INT);
819        $author = Filter::filterInput(INPUT_POST, 'name', FILTER_SANITIZE_STRING);
820        $email = Filter::filterInput(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
821        $password = Filter::filterInput(INPUT_POST, 'password', FILTER_SANITIZE_STRING);
822        $confirm = Filter::filterInput(INPUT_POST, 'password_confirm', FILTER_SANITIZE_STRING);
823
824        $user = CurrentUser::getFromSession($faqConfig);
825
826        if ($userId !== $user->getUserId()) {
827            $message = ['error' => 'User ID mismatch!'];
828            break;
829        }
830
831        if ($password !== $confirm) {
832            $message = ['error' => $PMF_LANG['ad_user_error_passwordsDontMatch']];
833            break;
834        }
835
836        $userData = [
837            'display_name' => $author,
838            'email' => $email,
839        ];
840        $success = $user->setUserData($userData);
841
842        if (0 !== strlen($password) && 0 !== strlen($confirm)) {
843            foreach ($user->getAuthContainer() as $author => $auth) {
844                if ($auth->setReadOnly()) {
845                    continue;
846                }
847                if (!$auth->changePassword($user->getLogin(), $password)) {
848                    $message = ['error' => $auth->error()];
849                    $success = false;
850                } else {
851                    $success = true;
852                }
853            }
854        }
855
856        if ($success) {
857            $message = ['success' => $PMF_LANG['ad_entry_savedsuc']];
858        } else {
859            $message = ['error' => $PMF_LANG['ad_entry_savedfail']];
860        }
861        break;
862
863    case 'changepassword':
864
865        $username = Filter::filterInput(INPUT_POST, 'username', FILTER_SANITIZE_STRING);
866        $email = Filter::filterInput(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
867
868        if (!is_null($username) && !is_null($email)) {
869            $user = new CurrentUser($faqConfig);
870            $loginExist = $user->getUserByLogin($username);
871
872            if ($loginExist && ($email == $user->getUserData('email'))) {
873                $newPassword = $user->createPassword();
874                $user->changePassword($newPassword);
875                $text = $PMF_LANG['lostpwd_text_1'] . "\nUsername: " . $username . "\nNew Password: " . $newPassword . "\n\n" . $PMF_LANG['lostpwd_text_2'];
876
877                $mailer = new Mail($faqConfig);
878                $mailer->addTo($email);
879                $mailer->subject = Utils::resolveMarkers('[%sitename%] Username / password request', $faqConfig);
880                $mailer->message = $text;
881                $result = $mailer->send();
882                unset($mailer);
883                // Trust that the email has been sent
884                $message = ['success' => $PMF_LANG['lostpwd_mail_okay']];
885            } else {
886                $message = ['error' => $PMF_LANG['lostpwd_err_1']];
887            }
888        } else {
889            $message = ['error' => $PMF_LANG['lostpwd_err_2']];
890        }
891        break;
892
893    case 'request-removal':
894
895        $author = Filter::filterInput(INPUT_POST, 'name', FILTER_SANITIZE_STRING);
896        $loginName = Filter::filterInput(INPUT_POST, 'loginname', FILTER_SANITIZE_STRING);
897        $email = Filter::filterInput(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
898        $question = Filter::filterInput(INPUT_POST, 'question', FILTER_SANITIZE_STRIPPED);
899
900        // If e-mail address is set to optional
901        if (!$faqConfig->get('main.optionalMailAddress') && is_null($email)) {
902            $email = $faqConfig->get('main.administrationMail');
903        }
904
905        if (!is_null($author) && !is_null($email) && !is_null($question) &&
906            !empty($question) && $stopWords->checkBannedWord(Strings::htmlspecialchars($question))) {
907            $question = sprintf(
908                "%s %s\n%s %s\n%s %s\n\n %s",
909                $PMF_LANG['ad_user_loginname'],
910                $loginName,
911                $PMF_LANG['msgNewContentName'],
912                $author,
913                $PMF_LANG['msgNewContentMail'],
914                $email,
915                $question
916            );
917
918            $mailer = new Mail($faqConfig);
919            $mailer->setReplyTo($email, $author);
920            $mailer->addTo($faqConfig->get('main.administrationMail'));
921            $mailer->subject = $faqConfig->get('main.titleFAQ') . ': Remove User Request';
922            $mailer->message = $question;
923            $result = $mailer->send();
924            unset($mailer);
925
926            $message = ['success' => $PMF_LANG['msgMailContact']];
927        } else {
928            $message = ['error' => $PMF_LANG['err_sendMail']];
929        }
930        break;
931}
932
933$http->sendJsonWithHeaders($message);
934exit();
935