1<?php
2
3/**
4 * The main admin backend index file.
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 * @author Bastian Poettner <bastian@poettner.net>
13 * @author Meikel Katzengreis <meikel@katzengreis.com>
14 * @author Minoru TODA <todam@netjapan.co.jp>
15 * @author Matteo Scaramuccia <matteo@phpmyfaq.de>
16 * @copyright 2002-2020 phpMyFAQ Team
17 * @license http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
18 * @link https://www.phpmyfaq.de
19 * @since 2002-09-16
20 */
21
22use phpMyFAQ\Attachment\AttachmentFactory;
23use phpMyFAQ\Auth\AuthLdap;
24use phpMyFAQ\Auth\AuthSso;
25use phpMyFAQ\Faq;
26use phpMyFAQ\Filter;
27use phpMyFAQ\Helper\HttpHelper;
28use phpMyFAQ\Language;
29use phpMyFAQ\Logging;
30use phpMyFAQ\Permission\MediumPermission;
31use phpMyFAQ\Strings;
32use phpMyFAQ\System;
33use phpMyFAQ\Template;
34use phpMyFAQ\User\CurrentUser;
35
36define('PMF_ROOT_DIR', dirname(__DIR__));
37
38//
39// Define the named constant used as a check by any included PHP file
40//
41define('IS_VALID_PHPMYFAQ', null);
42
43//
44// Bootstrapping
45//
46require PMF_ROOT_DIR.'/src/Bootstrap.php';
47
48// get language (default: english)
49$Language = new Language($faqConfig);
50$faqLangCode = $Language->setLanguage($faqConfig->get('main.languageDetection'), $faqConfig->get('main.language'));
51// Preload English strings
52require PMF_ROOT_DIR.'/lang/language_en.php';
53$faqConfig->setLanguage($Language);
54
55if (isset($faqLangCode) && Language::isASupportedLanguage($faqLangCode)) {
56    // Overwrite English strings with the ones we have in the current language
57    if (!file_exists(PMF_ROOT_DIR.'/lang/language_'.$faqLangCode.'.php')) {
58        $faqLangCode = 'en';
59    }
60    require PMF_ROOT_DIR.'/lang/language_'.$faqLangCode.'.php';
61} else {
62    $faqLangCode = 'en';
63}
64
65//
66// Initalizing static string wrapper
67//
68Strings::init($faqLangCode);
69
70//
71// Set actual template set name
72//
73Template::setTplSetName($faqConfig->get('main.templateSet'));
74
75//
76// Initialize attachment factory
77//
78AttachmentFactory::init(
79    $faqConfig->get('records.attachmentsStorageType'),
80    $faqConfig->get('records.defaultAttachmentEncKey'),
81    $faqConfig->get('records.enableAttachmentEncryption')
82);
83
84//
85// Create a new phpMyFAQ system object
86//
87$faqSystem = new System();
88
89//
90// Create a new HTTP Helper
91//
92$http = new HttpHelper();
93
94//
95// Create a new FAQ object
96//
97$faq = new Faq($faqConfig);
98
99//
100// use mbstring extension if available and when possible
101//
102$validMbStrings = array('ja', 'en', 'uni');
103$mbLanguage = ($PMF_LANG['metaLanguage'] != 'ja') ? 'uni' : $PMF_LANG['metaLanguage'];
104if (function_exists('mb_language') && in_array($mbLanguage, $validMbStrings)) {
105    mb_language($mbLanguage);
106    mb_internal_encoding('utf-8');
107}
108
109//
110// Get user action
111//
112$action = Filter::filterInput(INPUT_GET, 'action', FILTER_SANITIZE_STRING);
113if (is_null($action)) {
114    $action = Filter::filterInput(INPUT_POST, 'action', FILTER_SANITIZE_STRING);
115}
116
117//
118// Get possible redirect action
119//
120$redirectAction = Filter::filterInput(INPUT_POST, 'redirect-action', FILTER_SANITIZE_STRING);
121if (is_null($action) && '' !== $redirectAction && 'logout' !== $redirectAction) {
122    $action = $redirectAction;
123}
124
125// authenticate current user
126$auth = null;
127$error = '';
128$faqusername = Filter::filterInput(INPUT_POST, 'faqusername', FILTER_SANITIZE_STRING);
129$faqpassword = Filter::filterInput(INPUT_POST, 'faqpassword', FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES);
130$faqremember = Filter::filterInput(INPUT_POST, 'faqrememberme', FILTER_SANITIZE_STRING);
131
132// Set username via SSO
133if ($faqConfig->get('security.ssoSupport') && isset($_SERVER['REMOTE_USER'])) {
134    $faqusername = trim($_SERVER['REMOTE_USER']);
135    $faqpassword = '';
136}
137
138// Login via local DB or LDAP or SSO
139if (!is_null($faqusername) && !is_null($faqpassword)) {
140    $user = new CurrentUser($faqConfig);
141    if (!is_null($faqremember) && 'rememberMe' === $faqremember) {
142        $user->enableRememberMe();
143    }
144    if ($faqConfig->get('ldap.ldapSupport') && function_exists('ldap_connect')) {
145        try {
146            $authLdap = new AuthLdap($faqConfig);
147            $user->addAuth($authLdap, 'ldap');
148        } catch (Exception $e) {
149            $error = $e->getMessage().'<br>';
150        }
151    }
152    if ($faqConfig->get('security.ssoSupport')) {
153        $authSso = new AuthSso($faqConfig);
154        $user->addAuth($authSso, 'sso');
155    }
156    if ($user->login($faqusername, $faqpassword)) {
157        // login, if user account is NOT blocked
158        if ($user->getStatus() != 'blocked') {
159            $auth = true;
160        } else {
161            $error = $error.$PMF_LANG['ad_auth_fail'];
162        }
163    } else {
164        // error
165        $logging = new Logging($faqConfig);
166        $logging->logAdmin($user, 'Loginerror\nLogin: '.$faqusername.'\nErrors: '.implode(', ', $user->errors));
167        $error = $error.$PMF_LANG['ad_auth_fail'];
168    }
169} else {
170    // Try to authenticate with cookie information
171    $user = CurrentUser::getFromCookie($faqConfig);
172    // authenticate with session information
173    if (!$user instanceof CurrentUser) {
174        $user = CurrentUser::getFromSession($faqConfig);
175    }
176    if ($user instanceof CurrentUser) {
177        $auth = true;
178    } else {
179        $user = new CurrentUser($faqConfig);
180    }
181}
182
183// logout
184if ($action == 'logout' && $auth) {
185    $user->deleteFromSession(true);
186    $auth = null;
187    $ssoLogout = $faqConfig->get('security.ssoLogoutRedirect');
188    if ($faqConfig->get('security.ssoSupport') && !empty($ssoLogout)) {
189        $http->redirect($ssoLogout);
190    }
191}
192
193//
194// Get current admin user and group id - default: -1
195//
196if (isset($user) && is_object($user)) {
197    $currentAdminUser = $user->getUserId();
198    if ($user->perm instanceof MediumPermission) {
199        $currentAdminGroups = $user->perm->getUserGroups($currentAdminUser);
200    } else {
201        $currentAdminGroups = array(-1);
202    }
203    if (0 === count($currentAdminGroups)) {
204        $currentAdminGroups = array(-1);
205    }
206}
207
208//
209// Get action from _GET and _POST first
210$ajax = Filter::filterInput(INPUT_GET, 'ajax', FILTER_SANITIZE_STRING);
211if (is_null($ajax)) {
212    $ajax = Filter::filterInput(INPUT_POST, 'ajax', FILTER_SANITIZE_STRING);
213}
214
215// if performing AJAX operation, needs to branch before header.php
216if (isset($auth) && (count($user->perm->getAllUserRights($user->getUserId())) > 0 || $user->isSuperAdmin())) {
217    if (isset($action) && isset($ajax)) {
218        if ('ajax' === $action) {
219            switch ($ajax) {
220                // Attachments
221                case 'att':           require 'ajax.attachment.php'; break;
222                // Link verification
223                case 'verifyURL':     require 'ajax.verifyurl.php'; break;
224                case 'onDemandURL':   require 'ajax.ondemandurl.php'; break;
225                // Categories
226                case 'categories':    require 'ajax.category.php'; break;
227                // Configuration management
228                case 'config_list':   require 'ajax.config_list.php'; break;
229                case 'config':        require 'ajax.config.php'; break;
230                case 'elasticsearch': require 'ajax.elasticsearch.php'; break;
231                // Tags management
232                case 'tags':          require 'ajax.tags.php'; break;
233                // Comments
234                case 'comment':       require 'ajax.comment.php'; break;
235                // Records
236                case 'records':       require 'ajax.records.php'; break;
237                case 'recordSave':    require 'record.save.php'; break;
238                case 'recordAdd':     require 'record.add.php'; break;
239                case 'autosave':      require 'ajax.autosave.php'; break;
240                case 'markdown':      require 'ajax.markdown.php'; break;
241                // Search
242                case 'search':        require 'ajax.search.php'; break;
243                // Users
244                case 'user':          require 'ajax.user.php'; break;
245                // Groups
246                case 'group':         require 'ajax.group.php'; break;
247                // Sections
248                case 'section':       require 'ajax.section.php'; break;
249                // Interface translation
250                case 'trans':         require 'ajax.trans.php'; break;
251                // Image upload
252                case 'image':         require 'ajax.image.php'; break;
253            }
254            exit();
255        }
256    }
257}
258
259// are we running a PMF export file request?
260switch ($action) {
261    case 'exportfile':
262        require 'export.file.php';
263        exit();
264        break;
265    case 'reportexport':
266        require 'report.export.php';
267        exit();
268        break;
269}
270
271// Header of the admin page including the navigation
272require 'header.php';
273
274$numRights = count($user->perm->getAllUserRights($user->getUserId()));
275
276// User is authenticated
277if (isset($auth) && ($numRights > 0 || $user->isSuperAdmin())) {
278    if (!is_null($action)) {
279        // the various sections of the admin area
280        switch ($action) {
281            // functions for user administration
282            case 'user':              require 'user.php'; break;
283            case 'group':             require 'group.php'; break;
284            case 'section':           require 'section.php'; break;
285            // functions for content administration
286            case 'viewinactive':
287            case 'viewactive':
288            case 'view':              require 'record.show.php'; break;
289            case 'searchfaqs':        require 'record.search.php'; break;
290            case 'takequestion':
291            case 'editentry':
292            case 'copyentry':
293            case 'editpreview':       require 'record.edit.php'; break;
294            case 'insertentry':       require 'record.add.php'; break;
295            case 'saveentry':         require 'record.save.php'; break;
296            case 'delatt':            require 'record.delatt.php'; break;
297            case 'question':          require 'record.questions.php'; break;
298            case 'comments':          require 'record.comments.php'; break;
299            // functions for tags
300            case 'tags':
301            case 'delete-tag':        require 'tags.php'; break;
302            // news administration
303            case 'news':
304            case 'add-news':
305            case 'edit-news':
306            case 'save-news':
307            case 'update-news':
308            case 'delete-news':       require 'news.php'; break;
309            // category administration
310            case 'content':
311            case 'category':
312            case 'savecategory':
313            case 'updatecategory':
314            case 'removecategory':
315            case 'changecategory':
316            case 'pastecategory':     require 'category.main.php'; break;
317            case 'addcategory':       require 'category.add.php'; break;
318            case 'editcategory':      require 'category.edit.php'; break;
319            case 'translatecategory': require 'category.translate.php'; break;
320            case 'deletecategory':    require 'category.delete.php'; break;
321            case 'cutcategory':       require 'category.cut.php'; break;
322            case 'movecategory':      require 'category.move.php'; break;
323            case 'showcategory':      require 'category.showstructure.php'; break;
324            // glossary
325            case 'glossary':
326            case 'saveglossary':
327            case 'updateglossary':
328            case 'deleteglossary':    require 'glossary.main.php'; break;
329            case 'addglossary':       require 'glossary.add.php'; break;
330            case 'editglossary':      require 'glossary.edit.php'; break;
331            // functions for password administration
332            case 'passwd':            require 'pwd.change.php'; break;
333            // functions for session administration
334            case 'adminlog':
335            case 'deleteadminlog':    require 'stat.adminlog.php'; break;
336            case 'viewsessions':
337            case 'clear-visits':      require 'stat.main.php'; break;
338            case 'sessionbrowse':     require 'stat.browser.php'; break;
339            case 'viewsession':       require 'stat.show.php'; break;
340            case 'clear-statistics':
341            case 'statistics':        require 'stat.ratings.php'; break;
342            case 'truncatesearchterms':
343            case 'searchstats':       require 'stat.search.php'; break;
344            // Reports
345            case 'reports':           require 'report.main.php'; break;
346            case 'reportview':        require 'report.view.php'; break;
347            // Config administration
348            case 'config':            require 'configuration.php'; break;
349            case 'system':            require 'system.php'; break;
350            case 'updateinstance':
351            case 'instances':         require 'instances.php'; break;
352            case 'editinstance':      require 'instances.edit.php'; break;
353            case 'stopwordsconfig':   require 'stopwords.php'; break;
354            case 'elasticsearch':     require 'elasticsearch.php'; break;
355            case 'meta':
356            case 'meta.update'; require 'meta.php'; break;
357            case 'meta.edit':         require 'meta.edit.php'; break;
358            // functions for backup administration
359            case 'backup':            require 'backup.main.php'; break;
360            case 'restore':           require 'backup.import.php'; break;
361            // functions for FAQ export
362            case 'export':            require 'export.main.php'; break;
363            // attachment administration
364            case 'attachments':       require 'attachments.php'; break;
365
366            default:                  echo 'Dave, this conversation can serve no purpose anymore. Goodbye.'; break;
367        }
368    } else {
369        require 'dashboard.php';
370    }
371// User is authenticated, but has no rights
372} elseif (isset($auth) && $numRights === 0) {
373    require 'noperm.php';
374// User is NOT authenticated
375} else {
376    require 'loginform.php';
377}
378
379require 'footer.php';
380
381$faqConfig->getDb()->close();
382