PageRenderTime 111ms CodeModel.GetById 85ms app.highlight 20ms RepoModel.GetById 1ms app.codeStats 0ms

/phpmyfaq/inc/PMF/Installer.php

https://github.com/NHLH-ITM/phpMyFAQ-kindeditor
PHP | 907 lines | 717 code | 57 blank | 133 comment | 51 complexity | fb5d14d523be26671f317b52cbf54858 MD5 | raw file
  1<?php
  2/**
  3 * The Installer class installs phpMyFAQ. Classy.
  4 *
  5 * PHP Version 5.4
  6 *
  7 * This Source Code Form is subject to the terms of the Mozilla Public License,
  8 * v. 2.0. If a copy of the MPL was not distributed with this file, You can
  9 * obtain one at http://mozilla.org/MPL/2.0/.
 10 *
 11 * @category  phpMyFAQ
 12 * @package   Installer
 13 * @author    Florian Anderiasch <florian@phpmyfaq.net>
 14 * @copyright 2002-2014 phpMyFAQ Team
 15 * @license   http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
 16 * @link      http://www.phpmyfaq.de
 17 * @since     2012-08-27
 18 */
 19
 20if (!defined('IS_VALID_PHPMYFAQ')) {
 21    exit();
 22}
 23
 24/**
 25 * Installer
 26 *
 27 * @category  phpMyFAQ
 28 * @package   Installer
 29 * @author    Florian Anderiasch <florian@phpmyfaq.net>
 30 * @copyright 2002-2014 phpMyFAQ Team
 31 * @license   http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
 32 * @link      http://www.phpmyfaq.de
 33 * @since     2012-08-27
 34 */
 35
 36class PMF_Installer
 37{
 38    /**
 39     * PMF_System object
 40     *
 41     * @var PMF_System
 42     */
 43    protected $_system;
 44
 45    /**
 46     * Array with user rights
 47     * @var array
 48     */
 49    protected $_mainRights = array(
 50        //1 => "adduser",
 51        array(
 52            'name' => 'adduser',
 53            'description' => 'Right to add user accounts'
 54        ),
 55        //2 => "edituser",
 56        array(
 57            'name' => 'edituser',
 58            'description' => 'Right to edit user accounts'
 59        ),
 60        //3 => "deluser",
 61        array(
 62            'name' => 'deluser',
 63            'description' => 'Right to delete user accounts'
 64        ),
 65        //4 => "addbt",
 66        array(
 67            'name' => 'addbt',
 68            'description' => 'Right to add faq entries'
 69        ),
 70        //5 => "editbt",
 71        array(
 72            'name' => 'editbt',
 73            'description' => 'Right to edit faq entries'
 74        ),
 75        //6 => "delbt",
 76        array(
 77            'name' => 'delbt',
 78            'description' => 'Right to delete faq entries'
 79        ),
 80        //7 => "viewlog",
 81        array(
 82            'name' => 'viewlog',
 83            'description' => 'Right to view logfiles'
 84        ),
 85        //8 => "adminlog",
 86        array(
 87            'name' => 'adminlog',
 88            'description' => 'Right to view admin log'
 89        ),
 90        //9 => "delcomment",
 91        array(
 92            'name' => 'delcomment',
 93            'description' => 'Right to delete comments'
 94        ),
 95        //10 => "addnews",
 96        array(
 97            'name' => 'addnews',
 98            'description' => 'Right to add news'
 99        ),
100        //11 => "editnews",
101        array(
102            'name' => 'editnews',
103            'description' => 'Right to edit news'
104        ),
105        //12 => "delnews",
106        array(
107            'name' => 'delnews',
108            'description' => 'Right to delete news'
109        ),
110        //13 => "addcateg",
111        array(
112            'name' => 'addcateg',
113            'description' => 'Right to add categories'
114        ),
115        //14 => "editcateg",
116        array(
117            'name' => 'editcateg',
118            'description' => 'Right to edit categories'
119        ),
120        //15 => "delcateg",
121        array(
122            'name' => 'delcateg',
123            'description' => 'Right to delete categories'
124        ),
125        //16 => "passwd",
126        array(
127            'name' => 'passwd',
128            'description' => 'Right to change passwords'
129        ),
130        //17 => "editconfig",
131        array(
132            'name' => 'editconfig',
133            'description' => 'Right to edit configuration'
134        ),
135        //18 => "addatt", // Duplicate, removed with 2.7.3
136        //array(
137        //    'name' => 'addatt',
138        //    'description' => 'Right to add attachments'
139        //),
140        //19 => "backup delatt", // Duplicate, removed with 2.7.3
141        //array(
142        //    'name' => 'delatt',
143        //    'description' => 'Right to delete attachments'
144        //),
145        //20 => "backup",
146        array(
147            'name' => 'backup',
148            'description' => 'Right to save backups'
149        ),
150        //21 => "restore",
151        array(
152            'name' => 'restore',
153            'description' => 'Right to load backups'
154        ),
155        //22 => "delquestion",
156        array(
157            'name' => 'delquestion',
158            'description' => 'Right to delete questions'
159        ),
160        //23 => 'addglossary',
161        array(
162            'name' => 'addglossary',
163            'description' => 'Right to add glossary entries'
164        ),
165        //24 => 'editglossary',
166        array(
167            'name' => 'editglossary',
168            'description' => 'Right to edit glossary entries'
169        ),
170        //25 => 'delglossary'
171        array(
172            'name' => 'delglossary',
173            'description' => 'Right to delete glossary entries'
174        ),
175        //26 => 'changebtrevs'
176        array(
177            'name' => 'changebtrevs',
178            'description' => 'Right to edit revisions'
179        ),
180        //27 => "addgroup",
181        array(
182            'name' => 'addgroup',
183            'description' => 'Right to add group accounts'
184        ),
185        //28 => "editgroup",
186        array(
187            'name' => 'editgroup',
188            'description' => 'Right to edit group accounts'
189        ),
190        //29 => "delgroup",
191        array(
192            'name' => 'delgroup',
193            'description' => 'Right to delete group accounts'
194        ),
195        //30 => "addtranslation",
196        array(
197            'name' => 'addtranslation',
198            'description' => 'Right to add translation'
199        ),
200        //31 => "edittranslation",
201        array(
202            'name' => 'edittranslation',
203            'description' => 'Right to edit translations'
204        ),
205        //32 => "deltranslation",
206        array(
207            'name' => 'deltranslation',
208            'description' => 'Right to delete translations'
209        ),
210        // 33 => 'approverec'
211        array(
212            'name' => 'approverec',
213            'description' => 'Right to approve records'
214        ),
215        // 34 => 'addattachment'
216        array(
217            'name' => 'addattachment',
218            'description' => 'Right to add attachments'
219        ),
220        // 35 => 'editattachment'
221        array(
222            'name' => 'editattachment',
223            'description' => 'Right to edit attachments'
224        ),
225        // 36 => 'delattachment'
226        array(
227            'name' => 'delattachment',
228            'description' => 'Right to delete attachments'
229        ),
230        // 37 => 'dlattachment'
231        array(
232            'name' => 'dlattachment',
233            'description' => 'Right to download attachments'
234        ),
235        // 38 => 'dlattachment'
236        array(
237            'name' => 'reports',
238            'description' => 'Right to generate reports'
239        ),
240        // 39 => 'addfaq'
241        array(
242            'name' => 'addfaq',
243            'description' => 'Right to add FAQs in frontend'
244        ),
245        // 40 => 'addquestion'
246        array(
247            'name' => 'addquestion',
248            'description' => 'Right to add questions in frontend'
249        ),
250        // 41 => 'addcomment'
251        array(
252            'name' => 'addcomment',
253            'description' => 'Right to add comments in frontend'
254        ),
255        // 42 => 'editinstances'
256        array(
257            'name' => 'editinstances',
258            'description' => 'Right to edit multi-site instances'
259        ),
260        // 43 => 'addinstances'
261        array(
262            'name' => 'addinstances',
263            'description' => 'Right to add multi-site instances'
264        ),
265        // 44 => 'delinstances'
266        array(
267            'name' => 'delinstances',
268            'description' => 'Right to delete multi-site instances'
269        ),
270        // 45 => 'export'
271        array(
272            'name' => 'export',
273            'description' => 'Right to export the complete FAQ'
274        ),
275    );
276
277    /**
278     * Configuration array
279     *
280     * @var array
281     */
282    protected $_mainConfig = array(
283        'main.currentVersion'                     => null,
284        'main.currentApiVersion'                  => null,
285        'main.language'                           => '__PHPMYFAQ_LANGUAGE__',
286        'main.languageDetection'                  => 'true',
287        'main.phpMyFAQToken'                      => null,
288        'main.referenceURL'                       => '__PHPMYFAQ_REFERENCE_URL__',
289        'main.administrationMail'                 => 'webmaster@example.org',
290        'main.contactInformations'                => '',
291        'main.enableAdminLog'                     => 'true',
292        'main.enableRewriteRules'                 => 'false',
293        'main.enableUserTracking'                 => 'true',
294        'main.metaDescription'                    => 'phpMyFAQ should be the answer for all questions in life',
295        'main.metaKeywords'                       => '',
296        'main.metaPublisher'                      => '__PHPMYFAQ_PUBLISHER__',
297        'main.send2friendText'                    => '',
298        'main.titleFAQ'                           => 'phpMyFAQ Codename Poseidon',
299        'main.urlValidateInterval'                => '86400',
300        'main.enableWysiwygEditor'                => 'true',
301        'main.enableWysiwygEditorFrontend'        => 'false',
302        'main.templateSet'                        => 'default',
303        'main.optionalMailAddress'                => 'false',
304        'main.dateFormat'                         => 'Y-m-d H:i',
305        'main.maintenanceMode'                    => 'false',
306        'main.enableGravatarSupport'              => 'false',
307        'main.enableRssFeeds'                     => 'true',
308
309        'records.numberOfRecordsPerPage'          => '10',
310        'records.numberOfShownNewsEntries'        => '3',
311        'records.defaultActivation'               => 'false',
312        'records.defaultAllowComments'            => 'false',
313        'records.enableVisibilityQuestions'       => 'false',
314        'records.numberOfRelatedArticles'         => '5',
315        'records.orderby'                         => 'id',
316        'records.sortby'                          => 'DESC',
317        'records.orderingPopularFaqs'             => 'visits',
318        'records.disableAttachments'              => 'true',
319        'records.maxAttachmentSize'               => '100000',
320        'records.attachmentsPath'                 => 'attachments',
321        'records.attachmentsStorageType'          => '0',
322        'records.enableAttachmentEncryption'      => 'false',
323        'records.defaultAttachmentEncKey'         => '',
324        'records.enableCloseQuestion'             => 'false',
325        'records.enableDeleteQuestion'            => 'false',
326        'records.autosaveActive'                  => 'false',
327        'records.autosaveSecs'                    => '180',
328        'records.randomSort'                      => 'false',
329        'records.allowCommentsForGuests'          => 'true',
330        'records.allowQuestionsForGuests'         => 'true',
331        'records.allowNewFaqsForGuests'           => 'true',
332        'records.hideEmptyCategories'             => 'false',
333
334        'search.useAjaxSearchOnStartpage'         => 'false',
335        'search.numberSearchTerms'                => '10',
336        'search.relevance'                        => 'thema,content,keywords',
337        'search.enableRelevance'                  => 'false',
338        'search.enableHighlighting'               => 'true',
339        'search.searchForSolutionId'              => 'true',
340
341        'security.permLevel'                      => 'basic',
342        'security.ipCheck'                        => 'false',
343        'security.enableLoginOnly'                => 'false',
344        'security.ldapSupport'                    => 'false',
345        'security.bannedIPs'                      => '',
346        'security.ssoSupport'                     => 'false',
347        'security.ssoLogoutRedirect'              => '',
348        'security.useSslForLogins'                => 'false',
349        'security.useSslOnly'                     => 'false',
350        'security.forcePasswordUpdate'            => 'false',
351
352        'spam.checkBannedWords'                   => 'true',
353        'spam.enableCaptchaCode'                  => null,
354        'spam.enableSafeEmail'                    => 'true',
355
356        'socialnetworks.enableTwitterSupport'     => 'false',
357        'socialnetworks.twitterConsumerKey'       => '',
358        'socialnetworks.twitterConsumerSecret'    => '',
359        'socialnetworks.twitterAccessTokenKey'    => '',
360        'socialnetworks.twitterAccessTokenSecret' => '',
361        'socialnetworks.enableFacebookSupport'    => 'false',
362        'socialnetworks.disableAll'               => 'false'
363    );
364
365    /**
366     * Constructor
367     *
368     * @return PMF_Installer
369     */
370    public function __construct()
371    {
372        $this->_system = new PMF_System();
373        $dynMainConfig = array(
374            'main.currentVersion'    => PMF_System::getVersion(),
375            'main.currentApiVersion' => PMF_System::getApiVersion(),
376            'main.phpMyFAQToken'     => md5(uniqid(rand())),
377            'spam.enableCaptchaCode' => (extension_loaded('gd') ? 'true' : 'false'),
378        );
379        $this->_mainConfig = array_merge($this->_mainConfig, $dynMainConfig);
380    }
381
382    /**
383     * Check absolutely necessary stuff and die
384     *
385     * @return array
386     */
387    public function checkBasicStuff()
388    {
389        $errors = array();
390
391        if (!$this->checkMinimumPhpVersion()) {
392            $errors[] = sprintf(
393                'Sorry, but you need PHP %s or later!',
394                PMF_System::VERSION_MINIMUM_PHP
395            );
396        }
397
398        if (! function_exists('date_default_timezone_set')) {
399            $errors[] = 'Sorry, but setting a default timezone doesn\'t work in your environment!';
400        }
401
402        if (! $this->_system->checkDatabase()) {
403            $dbError = "No supported database detected! Please install one of the following database systems and " .
404                        "enable the corresponding PHP extension in php.ini:";
405            $dbError .= "<ul>";
406            foreach ($this->_system->getSupportedDatabases() as $database) {
407                $dbError .= sprintf("    <li>%s</li>\n", $database[1]);
408            }
409            $dbError .= "</ul>";
410            $errors[] = $dbError;
411        }
412
413        if (! $this->_system->checkRequiredExtensions()) {
414            $extError  = "The following extensions are missing! Please enable the PHP extension(s) in php.ini.";
415            $extError .= "<ul>";
416            foreach ($this->_system->getMissingExtensions() as $extension) {
417                $extError .= sprintf("    <li>ext/%s</li>\n", $extension);
418            }
419            $extError .= "</ul>";
420            $errors[] = $extError;
421        }
422
423        if (! $this->_system->checkRegisterGlobals()) {
424            $errors[] = "Please disable register_globals!";
425        }
426
427        if (! $this->_system->checkMagicQuotesGpc()) {
428            $errors[] = "Please disable magic_quotes_gpc!";
429        }
430
431        if (! $this->_system->checkphpMyFAQInstallation()) {
432            $errors[] = "It seems you're already running a version of phpMyFAQ. Please use the " .
433                        "<a href=\"update.php\">update script</a>.";
434        }
435
436        return $errors;
437    }
438
439    /**
440     * Checks for the minimum PHP requirement and if the database credentials file is readable
441     *
442     * @return void
443     */
444    public function checkPreUpgrade()
445    {
446        if (! $this->checkMinimumPhpVersion()) {
447            printf(
448                '<p class="alert alert-danger">Sorry, but you need PHP %s or later!</p>',
449                PMF_System::VERSION_MINIMUM_PHP
450            );
451            PMF_System::renderFooter();
452        }
453
454        if (! is_readable(PMF_ROOT_DIR . '/config/database.php')) {
455            echo '<p class="alert alert-error">It seems you never run a version of phpMyFAQ.<br />' .
456                'Please use the <a href="setup.php">install script</a>.</p>';
457            PMF_System::renderFooter();
458        }
459
460        if (! $this->_system->checkRegisterGlobals()) {
461            echo '<p class="alert alert-danger">Please disable register_globals!</p>';
462            PMF_System::renderFooter();
463        }
464
465        if (! $this->_system->checkMagicQuotesGpc()) {
466            echo '<p class="alert alert-danger">Please disable magic_quotes_gpc!</p>';
467            PMF_System::renderFooter();
468        }
469    }
470
471    /**
472     * Checks the minimum required PHP version, defined in PMF_System
473     *
474     * @return bool
475     */
476    public function checkMinimumPhpVersion()
477    {
478        if (version_compare(PHP_VERSION, PMF_System::VERSION_MINIMUM_PHP, '<')) {
479            return false;
480        }
481        return true;
482    }
483
484    /**
485     * Checks if the file permissions are okay
486     *
487     * @return string
488     */
489    public function checkFilesystemPermissions()
490    {
491        $instanceSetup = new PMF_Instance_Setup();
492        $instanceSetup->setRootDir(PMF_ROOT_DIR);
493
494        $permError  = '';
495        $dirs       = array('/attachments', '/config', '/data', '/images');
496        $failedDirs = $instanceSetup->checkDirs($dirs);
497        $numDirs    = sizeof($failedDirs);
498
499        if (1 <= $numDirs) {
500            $permError = sprintf(
501                'The following %s could not be created or %s not writable:<ul>',
502                (1 < $numDirs) ? 'directories' : 'directory',
503                (1 < $numDirs) ? 'are' : 'is'
504            );
505            foreach ($failedDirs as $dir) {
506                $permError .= sprintf("<li>%s</li>\n", $dir);
507            }
508            $permError .= sprintf(
509                "</ul>Please create %s manually and/or change access to chmod 755 (or greater if necessary).",
510                (1 < $numDirs) ? 'them' : 'it'
511            );
512        }
513
514        return $permError;
515    }
516
517    /**
518     * Checks some non critical settings and print some hints
519     *
520     * @return array
521     */
522    public function checkNoncriticalSettings()
523    {
524        $errors = array();
525
526        if ((@ini_get('safe_mode') == 'On' || @ini_get('safe_mode') === 1)) {
527            $errors[] = "The PHP safe mode is enabled. You may have problems when phpMyFAQ tries to write in some " .
528                        "directories.";
529        }
530        if (! extension_loaded('gd')) {
531            $errors[] = "You don't have GD support enabled in your PHP installation. Please enable GD support in " .
532                        "your php.ini file otherwise you can't use Captchas for spam protection.";
533        }
534        if (! function_exists('imagettftext')) {
535            $errors[] = "You don't have Freetype support enabled in the GD extension of your PHP installation. " .
536                        "Please enable Freetype support in GD extension otherwise the Captchas for spam protection " .
537                        "will be quite easy to break.";
538        }
539        if (! extension_loaded('curl') || ! extension_loaded('openssl')) {
540            $errors[] = "You don't have cURL and/or OpenSSL support enabled in your PHP installation. Please enable " .
541                        "cURL and/or OpenSSL support in your php.ini file otherwise you can't use the Twitter support.";
542        }
543        if (! extension_loaded('fileinfo')) {
544            $errors[] = "You don't have Fileinfo support enabled in your PHP installation. Please enable Fileinfo " .
545                        "support in your php.ini file otherwise you can't use our backup/restore functionality.";
546        }
547        return $errors;
548    }
549
550    /**
551     * Checks if we can store data via sessions. If not, e.g. an user can't
552     * login into the admin section
553     *
554     * @return bool
555     */
556    public function checkSessionSettings()
557    {
558        return true;
559    }
560
561    /**
562     * Starts the installation
563     *
564     * @param array $DB
565     */
566    public function startInstall(Array $DB = null)
567    {
568        $query = $uninst = $dbSetup = [];
569
570        // Check table prefix
571        $dbSetup['dbPrefix'] = $sqltblpre = PMF_Filter::filterInput(INPUT_POST, 'sqltblpre', FILTER_SANITIZE_STRING, '');
572        if ('' !== $dbSetup['dbPrefix']) {
573            PMF_Db::setTablePrefix($dbSetup['dbPrefix']);
574        }
575
576        // Check database entries
577        $dbSetup['dbType'] = PMF_Filter::filterInput(INPUT_POST, 'sql_type', FILTER_SANITIZE_STRING);
578        if (!is_null($dbSetup['dbType'])) {
579            $dbSetup['dbType'] = trim($dbSetup['dbType']);
580            if (! file_exists(PMF_ROOT_DIR . '/setup/assets/sql/' . $dbSetup['dbType'] . '.sql.php')) {
581                printf(
582                    '<p class="alert alert-danger"><strong>Error:</strong> Invalid server type: %s</p>',
583                    $dbSetup['dbType']
584                );
585                PMF_System::renderFooter(true);
586            }
587        } else {
588            echo "<p class=\"alert alert-danger\"><strong>Error:</strong> Please select a database type.</p>\n";
589            PMF_System::renderFooter(true);
590        }
591
592        $dbSetup['dbServer'] = PMF_Filter::filterInput(INPUT_POST, 'sql_server', FILTER_SANITIZE_STRING);
593        if (is_null($dbSetup['dbServer']) && ! PMF_System::isSqlite($dbSetup['dbType'])) {
594            echo "<p class=\"alert alert-danger\"><strong>Error:</strong> Please add a database server.</p>\n";
595            PMF_System::renderFooter(true);
596        }
597
598        $dbSetup['dbPort'] = PMF_Filter::filterInput(INPUT_POST, 'sql_port', FILTER_VALIDATE_INT);
599        if (is_null($dbSetup['dbPort']) && ! PMF_System::isSqlite($dbSetup['dbType'])) {
600            echo "<p class=\"alert alert-error\"><strong>Error:</strong> Please add a valid database port.</p>\n";
601            PMF_System::renderFooter(true);
602        }
603
604        $dbSetup['dbUser'] = PMF_Filter::filterInput(INPUT_POST, 'sql_user', FILTER_SANITIZE_STRING);
605        if (is_null($dbSetup['dbUser']) && ! PMF_System::isSqlite($dbSetup['dbType'])) {
606            echo "<p class=\"alert alert-danger\"><strong>Error:</strong> Please add a database username.</p>\n";
607            PMF_System::renderFooter(true);
608        }
609
610        $dbSetup['dbPassword'] = PMF_Filter::filterInput(INPUT_POST, 'sql_passwort', FILTER_UNSAFE_RAW);
611        if (is_null($dbSetup['dbPassword']) && ! PMF_System::isSqlite($dbSetup['dbType'])) {
612            // Password can be empty...
613            $dbSetup['dbPassword'] = '';
614        }
615
616        $dbSetup['dbDatabaseName'] = PMF_Filter::filterInput(INPUT_POST, 'sql_db', FILTER_SANITIZE_STRING);
617        if (is_null($dbSetup['dbDatabaseName']) && ! PMF_System::isSqlite($dbSetup['dbType'])) {
618            echo "<p class=\"alert alert-danger\"><strong>Error:</strong> Please add a database name.</p>\n";
619            PMF_System::renderFooter(true);
620        }
621
622        if (PMF_System::isSqlite($dbSetup['dbType'])) {
623            $dbSetup['dbServer'] = PMF_Filter::filterInput(INPUT_POST, 'sql_sqlitefile', FILTER_SANITIZE_STRING);
624            if (is_null($dbSetup['dbServer'])) {
625                echo "<p class=\"alert alert-danger\"><strong>Error:</strong> Please add a SQLite database filename.</p>\n";
626                PMF_System::renderFooter(true);
627            }
628        }
629
630        // check database connection
631        PMF_Db::setTablePrefix($dbSetup['dbPrefix']);
632        $db = PMF_Db::factory($dbSetup['dbType']);
633        $db->connect($dbSetup['dbServer'], $dbSetup['dbUser'], $dbSetup['dbPassword'], $dbSetup['dbDatabaseName']);
634        if (!$db) {
635            printf("<p class=\"alert alert-danger\"><strong>DB Error:</strong> %s</p>\n", $db->error());
636            PMF_System::renderFooter(true);
637        }
638
639        $configuration = new PMF_Configuration($db);
640
641        // check LDAP if available
642        $ldapEnabled = PMF_Filter::filterInput(INPUT_POST, 'ldap_enabled', FILTER_SANITIZE_STRING);
643        if (extension_loaded('ldap') && !is_null($ldapEnabled)) {
644
645            $ldapSetup = [];
646
647            // check LDAP entries
648            $ldapSetup['ldapServer'] = PMF_Filter::filterInput(INPUT_POST, 'ldap_server', FILTER_SANITIZE_STRING);
649            if (is_null($ldapSetup['ldapServer'])) {
650                echo "<p class=\"alert alert-danger\"><strong>Error:</strong> Please add a LDAP server.</p>\n";
651                PMF_System::renderFooter(true);
652            }
653
654            $ldapSetup['ldapPort'] = PMF_Filter::filterInput(INPUT_POST, 'ldap_port', FILTER_VALIDATE_INT);
655            if (is_null($ldapSetup['ldapPort'])) {
656                echo "<p class=\"alert alert-danger\"><strong>Error:</strong> Please add a LDAP port.</p>\n";
657                PMF_System::renderFooter(true);
658            }
659
660            $ldapSetup['ldapBase'] = PMF_Filter::filterInput(INPUT_POST, 'ldap_base', FILTER_SANITIZE_STRING);
661            if (is_null($ldapSetup['ldapBase'])) {
662                echo "<p class=\"alert alert-danger\"><strong>Error:</strong> Please add a LDAP base search DN.</p>\n";
663                PMF_System::renderFooter(true);
664            }
665
666            // LDAP User and LDAP password are optional
667            $ldapSetup['ldapUser']     = PMF_Filter::filterInput(INPUT_POST, 'ldap_user', FILTER_SANITIZE_STRING, '');
668            $ldapSetup['ldapPassword'] = PMF_Filter::filterInput(INPUT_POST, 'ldap_password', FILTER_SANITIZE_STRING, '');
669
670            // check LDAP connection
671            require PMF_ROOT_DIR . "/inc/PMF/Ldap.php";
672            $ldap = new PMF_Ldap($configuration);
673            $ldap->connect(
674                $ldapSetup['ldapServer'],
675                $ldapSetup['ldapPort'],
676                $ldapSetup['ldapBase'],
677                $ldapSetup['ldapUser'],
678                $ldapSetup['ldapPassword']
679            );
680            if (!$ldap) {
681                echo "<p class=\"alert alert-danger\"><strong>LDAP Error:</strong> " . $ldap->error() . "</p>\n";
682                PMF_System::renderFooter(true);
683            }
684        }
685
686        // check loginname
687        $loginname = PMF_Filter::filterInput(INPUT_POST, 'loginname', FILTER_SANITIZE_STRING);
688        if (is_null($loginname)) {
689            echo '<p class="alert alert-danger"><strong>Error:</strong> Please add a loginname for your account.</p>';
690            PMF_System::renderFooter(true);
691        }
692
693        // check user entries
694        $password = PMF_Filter::filterInput(INPUT_POST, 'password', FILTER_SANITIZE_STRING);
695        if (is_null($password)) {
696            echo '<p class="alert alert-danger"><strong>Error:</strong> Please add a password for the your account.</p>';
697            PMF_System::renderFooter(true);
698        }
699
700        $password_retyped = PMF_Filter::filterInput(INPUT_POST, 'password_retyped', FILTER_SANITIZE_STRING);
701        if (is_null($password_retyped)) {
702            echo '<p class="alert alert-danger"><strong>Error:</strong> Please add a retyped password.</p>';
703            PMF_System::renderFooter(true);
704        }
705
706        if (strlen($password) <= 5 || strlen($password_retyped) <= 5) {
707            echo '<p class="alert alert-danger"><strong>Error:</strong> Your password and retyped password are too short.' .
708                ' Please set your password and your retyped password with a minimum of 6 characters.</p>';
709            PMF_System::renderFooter(true);
710        }
711        if ($password != $password_retyped) {
712            echo '<p class="alert alert-danger"><strong>Error:</strong> Your password and retyped password are not equal.' .
713                ' Please check your password and your retyped password.</p>';
714            PMF_System::renderFooter(true);
715        }
716
717        $language  = PMF_Filter::filterInput(INPUT_POST, 'language', FILTER_SANITIZE_STRING, 'en');
718        $realname  = PMF_Filter::filterInput(INPUT_POST, 'realname', FILTER_SANITIZE_STRING, '');
719        $email     = PMF_Filter::filterInput(INPUT_POST, 'email', FILTER_SANITIZE_EMAIL, '');
720        $permLevel = PMF_Filter::filterInput(INPUT_POST, 'permLevel', FILTER_SANITIZE_STRING, 'basic');
721
722        $instanceSetup = new PMF_Instance_Setup();
723        $instanceSetup->setRootDir(PMF_ROOT_DIR);
724
725        // Write the DB variables in database.php
726        if (! $instanceSetup->createDatabaseFile($dbSetup)) {
727            echo "<p class=\"alert alert-danger\"><strong>Error:</strong> Setup cannot write to ./config/database.php.</p>";
728            $this->_system->cleanInstallation();
729            PMF_System::renderFooter(true);
730        }
731
732        // check LDAP if available
733        if (extension_loaded('ldap') && !is_null($ldapEnabled)) {
734            if (! $instanceSetup->createLdapFile($ldapSetup, '')) {
735                echo "<p class=\"alert alert-danger\"><strong>Error:</strong> Setup cannot write to ./config/ldap.php.</p>";
736                $this->_system->cleanInstallation();
737                PMF_System::renderFooter(true);
738            }
739        }
740
741        // connect to the database using config/database.php
742        require PMF_ROOT_DIR . '/config/database.php';
743        $db = PMF_Db::factory($dbSetup['dbType']);
744        $db->connect($DB['server'], $DB['user'], $DB['password'], $DB['db']);
745        if (!$db) {
746            echo "<p class=\"alert alert-danger\"><strong>DB Error:</strong> ".$db->error()."</p>\n";
747            $this->_system->cleanInstallation();
748            PMF_System::renderFooter(true);
749        }
750
751        require PMF_ROOT_DIR . '/setup/assets/sql/' . $dbSetup['dbType'] . '.sql.php'; // CREATE TABLES
752        require PMF_ROOT_DIR . '/setup/assets/sql/stopwords.sql.php';  // INSERTs for stopwords
753
754        $this->_system->setDatabase($db);
755
756        echo '<p>';
757
758        // Erase any table before starting creating the required ones
759        if (! PMF_System::isSqlite($dbSetup['dbType'])) {
760            $this->_system->dropTables($uninst);
761        }
762
763        // Start creating the required tables
764        $count = 0;
765        foreach ($query as $executeQuery) {
766            $result = @$db->query($executeQuery);
767            if (!$result) {
768                echo '<p class="alert alert-danger"><strong>Error:</strong> Please install your version of phpMyFAQ once again or send
769            us a <a href=\"http://www.phpmyfaq.de\" target=\"_blank\">bug report</a>.</p>';
770                printf('<p class="alert alert-danger"><strong>DB error:</strong> %s</p>', $db->error());
771                printf('<code>%s</code>', htmlentities($executeQuery));
772                $this->_system->dropTables($uninst);
773                $this->_system->cleanInstallation();
774                PMF_System::renderFooter(true);
775            }
776            usleep(2500);
777            $count++;
778            if (!($count % 10)) {
779                echo '| ';
780            }
781        }
782
783        $link = new PMF_Link(null, $configuration);
784
785        // add main configuration, add personal settings
786        $this->_mainConfig['main.metaPublisher']      = $realname;
787        $this->_mainConfig['main.administrationMail'] = $email;
788        $this->_mainConfig['main.language']           = $language;
789        $this->_mainConfig['security.permLevel']      = $permLevel;
790
791        foreach ($this->_mainConfig as $name => $value) {
792            $configuration->add($name, $value);
793        }
794
795        $configuration->update(array('main.referenceURL' => $link->getSystemUri('/setup/index.php')));
796        $configuration->add('security.salt', md5($configuration->get('main.referenceURL')));
797
798        // add admin account and rights
799        $admin = new PMF_User($configuration);
800        if (! $admin->createUser($loginname, $password, 1)) {
801            printf(
802                "<p class=\"alert alert-danger\"><strong>Fatal installation error:</strong><br>" .
803                "Couldn't create the admin user: %s</p>\n",
804                $admin->error()
805            );
806            $this->_system->cleanInstallation();
807            PMF_System::renderFooter(true);
808        }
809        $admin->setStatus('protected');
810        $adminData = array(
811            'display_name' => $realname,
812            'email'        => $email
813        );
814        $admin->setUserData($adminData);
815
816        // add default rights
817        foreach ($this->_mainRights as $right) {
818            $admin->perm->grantUserRight(1, $admin->perm->addRight($right));
819        }
820
821        // Add anonymous user account
822        $instanceSetup->createAnonymousUser($configuration);
823
824        // Add master instance
825        $instanceData = array(
826            'url'      => $link->getSystemUri($_SERVER['SCRIPT_NAME']),
827            'instance' => $link->getSystemRelativeUri('setup/index.php'),
828            'comment'  => 'phpMyFAQ ' . PMF_System::getVersion()
829        );
830        $faqInstance = new PMF_Instance($configuration);
831        $faqInstance->addInstance($instanceData);
832
833        $faqInstanceMaster = new PMF_Instance_Master($configuration);
834        $faqInstanceMaster->createMaster($faqInstance);
835
836        echo '</p>';
837    }
838
839    /**
840     * Cleanup all files after an installation
841     *
842     * @return void
843     */
844    public function cleanUpFiles()
845    {
846        // Remove 'setup.php' file
847        if (@unlink(basename($_SERVER['SCRIPT_NAME']))) {
848            echo "<p class=\"alert alert-success\">The file <em>./setup/index.php</em> was deleted automatically.</p>\n";
849        } else {
850            echo "<p class=\"alert alert-danger\">Please delete the file <em>./setup/index.php</em> manually.</p>\n";
851        }
852        // Remove 'update.php' file
853        if (@unlink(dirname($_SERVER['PATH_TRANSLATED']) . '/update.php')) {
854            echo "<p class=\"alert alert-success\">The file <em>./setup/update.php</em> was deleted automatically.</p>\n";
855        } else {
856            echo "<p class=\"alert alert-danger\">Please delete the file <em>./setup/update.php</em> manually.</p>\n";
857        }
858    }
859
860    /**
861     * Renders the <option> list with supported languages
862     *
863     * @param array $languageCodes
864     *
865     * @return string
866     */
867    public function renderLanguageOptions(Array $languageCodes)
868    {
869        $options = '';
870        if ($dir = @opendir(PMF_ROOT_DIR . '/lang')) {
871            while ($dat = @readdir($dir)) {
872                if (substr($dat, -4) == '.php') {
873                    $options .= sprintf('<option value="%s"', $dat);
874                    if ($dat == "language_en.php") {
875                        $options .= ' selected';
876                    }
877                    $options .= sprintf(
878                        '>%s</option>',
879                        $languageCodes[substr(strtoupper($dat), 9, 2)]
880                    );
881                }
882            }
883        } else {
884            $options = '<option>English</option>';
885        }
886
887        return $options;
888    }
889
890    /**
891     * Echos the questionnaire data
892     *
893     * @return string
894     */
895    public function renderDataList()
896    {
897        $questionnaire = new PMF_Questionnaire_Data($this->_mainConfig);
898        $options       = $questionnaire->get();
899        $dataList      = '<dl>' . PHP_EOL;
900        array_walk($options, 'data_printer');
901        $dataList .= sprintf(
902            '</dl><input type="hidden" name="systemdata" value="%s" />',
903            PMF_String::htmlspecialchars(serialize($questionnaire->get()), ENT_QUOTES)
904        );
905        return $dataList;
906    }
907}