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