PageRenderTime 52ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/installer/wizard.php

http://github.com/ushahidi/Ushahidi_Web
PHP | 1129 lines | 680 code | 181 blank | 268 comment | 75 complexity | 774846eaf6500f8128a5ceb03b8d6ab0 MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /**
  3. * Installatation Wizard
  4. *
  5. * This class manages the installation process. It tracks the
  6. * status of the installation and allows a user to resume from
  7. * where they left off. All install stages are submitted for processing
  8. * via HTTP POST.
  9. *
  10. * The config files are created and/or modified at the end of the installation
  11. *
  12. * PHP version 5
  13. * LICENSE: This source file is subject to LGPL license
  14. * that is available through the world-wide-web at the following URI:
  15. * http://www.gnu.org/copyleft/lesser.html
  16. * @author Ushahidi Team <team@ushahidi.com>
  17. * @package Ushahidi - https://github.com/ushahidi/Ushahidi_Web
  18. * @subpackage Installer
  19. * @copyright Ushahidi - http://www.ushahidi.com
  20. * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License (LGPL)
  21. */
  22. class Installer_Wizard {
  23. /**
  24. * Configuration directory for the application
  25. */
  26. private static $_app_config_dir = '';
  27. /**
  28. * Installer data
  29. * @var array
  30. */
  31. private static $_data = array();
  32. /**
  33. * @var array
  34. */
  35. private static $_errors = array();
  36. /**
  37. * Database connection
  38. * @var mixed
  39. */
  40. private static $_connection = FALSE;
  41. /**
  42. * Required extensions
  43. * @var array
  44. */
  45. private static $_extensions = array(
  46. // Extensions required for UTF-8 functions
  47. 'pcre',
  48. 'iconv',
  49. 'mbstring',
  50. // Database access
  51. 'mysql',
  52. // cURL for remote site access
  53. 'curl',
  54. // IMAP extension
  55. //'imap',
  56. // GD library for imaging
  57. 'gd',
  58. // Encryption
  59. 'mcrypt',
  60. // Misc
  61. 'spl'
  62. );
  63. /**
  64. * Directories and files that should be writeable by the installer
  65. * and application
  66. * @var array
  67. */
  68. private static $_filesystem = array(
  69. // Cache directory
  70. 'cache' => 'application/cache',
  71. // Logs directory
  72. 'logs' => 'application/logs',
  73. // Config directory
  74. 'config' => 'application/config',
  75. // Uploads directory
  76. 'uploads' => 'media/uploads',
  77. // .htaccess file
  78. 'htaccess' => '.htaccess'
  79. );
  80. /**
  81. * Installation stages for each mode (basic & advanced)
  82. * Precedence of the stages matters
  83. * @var array
  84. */
  85. private static $_install_stages = array(
  86. // Basic install stages
  87. 'basic' => array(
  88. 'requirements',
  89. 'database',
  90. 'general',
  91. 'adminpassword',
  92. 'finish'
  93. ),
  94. // Advanced install stages
  95. 'advanced' => array(
  96. 'requirements',
  97. 'database',
  98. 'general',
  99. 'email',
  100. 'map',
  101. 'adminpassword',
  102. 'finish'
  103. )
  104. );
  105. /**
  106. * Form data for the install phases
  107. * @var array
  108. */
  109. private static $_forms = array(
  110. // Database form
  111. 'database' => array(
  112. 'base_path' => '',
  113. 'database' => '',
  114. 'username' => '',
  115. 'password' => '',
  116. 'host' => '',
  117. 'table_prefix' => ''
  118. ),
  119. // General site settings
  120. 'general' => array(
  121. 'site_name' => '',
  122. 'site_tagline' => '',
  123. 'site_language' => '',
  124. 'site_email' => '',
  125. 'enable_clean_urls' => ''
  126. ),
  127. // Email
  128. 'email' => array(
  129. 'alerts_email' => '',
  130. 'email_host' => '',
  131. 'email_username' => '',
  132. 'email_password' => '',
  133. 'email_port' => ''
  134. ),
  135. // Admin password
  136. 'adminpassword' => array(
  137. 'email' => '',
  138. 'password' => '',
  139. 'confirm_password' => ''
  140. )
  141. );
  142. /**
  143. * Bootstraps the installer
  144. */
  145. public static function init()
  146. {
  147. self::$_app_config_dir = ROOT_DIR.'application'.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR;
  148. // Initialize the session
  149. session_start();
  150. self::$_data = & $_SESSION;
  151. // Check if the application has already been installed
  152. if (self::is_installed())
  153. {
  154. session_destroy();
  155. session_unset();
  156. header("Location:../");
  157. // For security: Make sure we don't return the rest of the page
  158. exit();
  159. }
  160. //
  161. // TODO: Expire the session after 30 minutes
  162. // and implement mechanisms to prevent attacks on sessions
  163. //
  164. // Check if installation has started or if a current stage exists
  165. if ( ! isset(self::$_data['started']) OR ! isset(self::$_data['current_stage']))
  166. {
  167. self::$_data['started'] = TRUE;
  168. // Get the site protocol
  169. $protocol = (isset($_SERVER['HTTPS']) OR (isset($_SERVER['HTTPS']) AND $_SERVER['HTTPS'] === 'on'))
  170. ? 'https'
  171. : 'http';
  172. // Site protocol
  173. self::$_data['site_protocol'] = $protocol;
  174. // Build the full URI
  175. $request_uri = $_SERVER['REQUEST_URI'];
  176. // Get the installation directory
  177. $site_domain = substr(substr($request_uri, 0, stripos($request_uri, '/installer/')) ,1);
  178. if (strpos($site_domain, "/") !== 0)
  179. {
  180. $site_domain = "/" . $site_domain;
  181. }
  182. // Server port
  183. $port = ! in_array($_SERVER['SERVER_PORT'], array("80", "443"))
  184. ? ':'.$_SERVER['SERVER_PORT']
  185. : '';
  186. // Build out the base URL
  187. $base_url = $protocol.'://'.$_SERVER['SERVER_NAME'].$port.$site_domain;
  188. // Add a trailing slash to the base URL
  189. if (substr($base_url, -1) !== "/")
  190. {
  191. $base_url .= "/";
  192. }
  193. self::$_data['site_domain'] = $site_domain;
  194. self::$_data['base_url'] = $base_url;
  195. if (isset(self::$_data['current_stage']))
  196. {
  197. unset(self::$_data['current_stage']);
  198. }
  199. // Show the welcome page
  200. self::render_install_page('main');
  201. }
  202. else
  203. {
  204. self::render_install_page(self::$_data['current_stage']);
  205. }
  206. }
  207. /**
  208. * Executes the callback function of the current step of the installtion
  209. * process and loads the page for the next stage. The callback function
  210. * for the current step should halt script execution if the validation
  211. * checks fail
  212. */
  213. public static function next()
  214. {
  215. // Check for the install mode
  216. if (isset($_POST['install_mode_basic']))
  217. {
  218. self::$_data['install_mode'] = 'basic';
  219. }
  220. elseif (isset($_POST['install_mode_advanced']))
  221. {
  222. self::$_data['install_mode'] = 'advanced';
  223. }
  224. // Get the installer mode
  225. $install_mode = self::$_data['install_mode'];
  226. // Get the current stage name
  227. $stage_name = array_key_exists('current_stage', self::$_data)
  228. ? self::$_data['current_stage']
  229. : NULL;
  230. if (empty($stage_name))
  231. {
  232. // We're in the first stage
  233. $stage_name = self::$_install_stages[$install_mode][0];
  234. self::$_data['current_stage'] = $stage_name;
  235. }
  236. else
  237. {
  238. // Run the current stage before advancing to the next one
  239. $callback_func = sprintf("install_%s", $stage_name);
  240. if ( ! self::$callback_func())
  241. {
  242. self::render_install_page($stage_name);
  243. exit;
  244. }
  245. // Set the next stage to be executed
  246. $stage_position = self::_get_install_position($install_mode, $stage_name) + 1;
  247. self::$_data['current_stage'] = self::$_install_stages[$install_mode][$stage_position];
  248. }
  249. // If we're in the last stage, create/modify all the configuration files
  250. if (self::_is_last_stage())
  251. {
  252. // Create database.php
  253. self::_create_database_config();
  254. // Modify the .htaccess and config.php
  255. self::_set_base_path();
  256. // Modify encrypt.php and auth.php
  257. self::_set_security_params();
  258. // Check for errors
  259. if (count(self::$_errors) > 0)
  260. {
  261. // Go the the previous
  262. self::previous(FALSE);
  263. }
  264. }
  265. // Show the page for the next stage
  266. self::render_install_page(self::$_data['current_stage']);
  267. }
  268. /**
  269. * Loads the page for the previous installation step.
  270. */
  271. public static function previous($render = TRUE)
  272. {
  273. if ( ! array_key_exists('current_stage', self::$_data))
  274. {
  275. self::render_install_page('main');
  276. return;
  277. }
  278. $install_mode = self::$_data['install_mode'];
  279. $current_position = self::_get_install_position($install_mode, self::$_data['current_stage']);
  280. $page = 'main';
  281. if ($current_position > 0)
  282. {
  283. $current_position -= 1;
  284. $page = self::$_install_stages[$install_mode][$current_position];
  285. self::$_data['current_stage'] = $page;
  286. }
  287. else
  288. {
  289. unset(self::$_data['current_stage']);
  290. }
  291. // Render?
  292. if ($render)
  293. {
  294. self::render_install_page($page);
  295. }
  296. }
  297. /**
  298. * Given the installation mode and stage name, gets the index
  299. * of the install stage
  300. *
  301. * @param string $mode
  302. * @param string $stage_name
  303. * @return int
  304. */
  305. private static function _get_install_position($mode, $stage_name)
  306. {
  307. $stages = self::$_install_stages[$mode];
  308. $stage_pos = 0;
  309. for ($i = 0; $i < count($stages); $i++)
  310. {
  311. if ($stages[$i] === $stage_name)
  312. {
  313. $stage_pos = $i;
  314. break;
  315. }
  316. }
  317. return $stage_pos;
  318. }
  319. /**
  320. * Checks if the installer is in the last installation stage
  321. * @return bool
  322. */
  323. private static function _is_last_stage()
  324. {
  325. if ( ! array_key_exists('current_stage', self::$_data))
  326. return FALSE;
  327. $current = self::$_data['current_stage'];
  328. $mode = self::$_data['install_mode'];
  329. $position = self::_get_install_position($mode, $current);
  330. return count(self::$_install_stages[$mode]) === ($position + 1);
  331. }
  332. /**
  333. * Verifies whether all the extensions in $_extensions
  334. * have been loaded.
  335. *
  336. * @return bool
  337. */
  338. private static function _verify_extensions()
  339. {
  340. foreach (self::$_extensions as $extension)
  341. {
  342. if ( ! extension_loaded($extension))
  343. {
  344. self::$_errors[] = sprintf("The <code>%s</code> extension is disabled", $extension);
  345. }
  346. }
  347. return count(self::$_errors) == 0;
  348. }
  349. /**
  350. * Verifies that the entries in $_filesystem are writeable
  351. * by the installer and the application
  352. *
  353. * @return bool
  354. */
  355. private static function _verify_permissions()
  356. {
  357. // Check if the filesytem object are writeable
  358. foreach (self::$_filesystem as $key => $item)
  359. {
  360. $item = preg_replace("/\//", DIRECTORY_SEPARATOR, $item);
  361. $full_path = ROOT_DIR.$item;
  362. if ( ! is_writable($full_path))
  363. {
  364. $type = is_dir($full_path) ? 'directory' : 'file';
  365. self::$_errors[] = sprintf("<code>%s</code> %s is not writable", $item, $type);
  366. }
  367. }
  368. return count(self::$_errors) == 0;
  369. }
  370. /**
  371. * Checks whether the application has already been installed
  372. * The presence of database.php in application/config halts the
  373. * installation process and redirects to the landing page
  374. *
  375. * @return bool
  376. */
  377. public static function is_installed()
  378. {
  379. // Absolute file name of the DB config file
  380. $db_config_file = self::$_app_config_dir.'database.php';
  381. return file_exists($db_config_file);
  382. }
  383. /**
  384. * Helper function for display the page for the various
  385. * installation phases. The name of the page must be of a file
  386. * that exists in the {installer}/pages directory
  387. *
  388. * @param $page_name string Name of the page to be displayed
  389. */
  390. public static function render_install_page($page_name)
  391. {
  392. // Clear buffer
  393. if (ob_get_length() > 0)
  394. {
  395. ob_end_clean();
  396. }
  397. ob_start();
  398. // Full path of the page to be rendered
  399. $page_path = INSTALLER_PAGES . $page_name . '.php';
  400. include INSTALLER_PAGES . 'header.php';
  401. // If the page doesn't exist, show the main page
  402. if (file_exists($page_path))
  403. {
  404. $install_data = self::$_data;
  405. // Remove database info
  406. if (array_key_exists('database', $install_data))
  407. {
  408. unset($install_data['database']);
  409. }
  410. // Check for errors
  411. if (count(self::$_errors) > 0)
  412. {
  413. $install_data['errors'] = self::$_errors;
  414. }
  415. // Check if there are any forms for the current page
  416. if (array_key_exists($page_name, self::$_forms))
  417. {
  418. $form = self::$_forms[$page_name];
  419. if ($_POST)
  420. {
  421. foreach ($_POST as $field => $value)
  422. {
  423. if (array_key_exists($field, $form))
  424. {
  425. $form[$field] = $value;
  426. }
  427. }
  428. }
  429. $install_data['form'] = $form;
  430. }
  431. extract($install_data);
  432. }
  433. else
  434. {
  435. // Restart the installation
  436. unset (self::$_data['current_stage']);
  437. $page_path = INSTALLER_PAGES . 'main.php';
  438. }
  439. include $page_path;
  440. if (self::_is_last_stage())
  441. {
  442. // Destroy session data
  443. session_destroy();
  444. // Unset $_SESSION variable for the runtime
  445. session_unset();
  446. }
  447. $content = ob_get_contents();
  448. ob_clean();
  449. print $content;
  450. }
  451. /**
  452. * Checks whether a set of parameters have values in the payload. The optional
  453. * items are skipped
  454. *
  455. * @param array $params Parameter keys to be checked for in the payload
  456. * @param array $payload Input data
  457. * @param array $optional Parameters to be exempted from the validation check
  458. *
  459. * @return bool
  460. */
  461. private static function _validate_params($params, & $payload, $optional = NULL)
  462. {
  463. foreach ($params as $param)
  464. {
  465. if ( ! empty($optional) AND in_array($param, $optional))
  466. continue;
  467. if (empty($payload[$param]))
  468. {
  469. self::$_errors[] = sprintf("The <code>%s</code> parameter has not been specified", $param);
  470. }
  471. else
  472. {
  473. // Input sanitization
  474. $payload[$param] = strip_tags($payload[$param]);
  475. }
  476. }
  477. return count(self::$_errors) === 0;
  478. }
  479. /**
  480. * Verifies whether the installation requirements
  481. * have been met
  482. *
  483. * @return bool
  484. */
  485. public static function install_requirements()
  486. {
  487. // Verify the extensions
  488. self::_verify_extensions();
  489. // Verify the permissions
  490. self::_verify_permissions();
  491. // Check for errors
  492. if (count(self::$_errors) == 0)
  493. {
  494. // Check if clean urls are enabled
  495. self::$_data['enable_clean_urls'] = self::_clean_urls_enabled();
  496. return TRUE;
  497. }
  498. return FALSE;
  499. }
  500. /**
  501. * Sets up the database and creates the database.php
  502. * config file
  503. *
  504. * @return bool
  505. */
  506. public static function install_database()
  507. {
  508. // Verify the host, username and password have been specified
  509. $params = array('host', 'username', 'password', 'database');
  510. if ( ! self::_validate_params($params, $_POST))
  511. return FALSE;
  512. // Extract the POST data
  513. extract($_POST);
  514. // Store the database info
  515. self::$_data['database'] = array(
  516. 'host' => $host,
  517. 'user' => $username,
  518. 'pass' => $password,
  519. 'database' => $database,
  520. 'table_prefix' => $table_prefix
  521. );
  522. // Set up the database schema + objects
  523. self::_database_connect();
  524. if ( ! self::$_connection)
  525. {
  526. self::$_errors[] = sprintf("Database connection error: %s", mysql_error());
  527. return FALSE;
  528. }
  529. // Get the schema DDL script
  530. $schema_ddl = file_get_contents(ROOT_DIR.'sql'.DIRECTORY_SEPARATOR.'ushahidi.sql');
  531. // Add table prefix
  532. if ( ! empty($table_prefix))
  533. {
  534. $find = array(
  535. 'CREATE TABLE IF NOT EXISTS `',
  536. 'INSERT INTO `',
  537. 'INSERT IGNORE INTO `',
  538. 'ALTER TABLE `',
  539. 'UPDATE `',
  540. 'FROM `',
  541. 'LOCK TABLES `',
  542. 'DROP TABLE IF EXISTS `',
  543. 'RENAME TABLE `',
  544. ' TO `',
  545. );
  546. $replace = array(
  547. 'CREATE TABLE IF NOT EXISTS `'.$table_prefix,
  548. 'INSERT INTO `'.$table_prefix,
  549. 'INSERT IGNORE INTO `'.$table_prefix,
  550. 'ALTER TABLE `'.$table_prefix,
  551. 'UPDATE `'.$table_prefix,
  552. 'FROM `'.$table_prefix,
  553. 'LOCK TABLES `'.$table_prefix,
  554. 'DROP TABLE IF EXISTS `'.$table_prefix,
  555. 'RENAME TABLE `'.$table_prefix,
  556. ' TO `'.$table_prefix,
  557. );
  558. $schema_ddl = str_replace($find, $replace, $schema_ddl);
  559. }
  560. // Run the script
  561. foreach (explode(";", $schema_ddl) as $query)
  562. {
  563. if ( ! self::_execute_query($query))
  564. {
  565. break;
  566. }
  567. }
  568. return count(self::$_errors) == 0;
  569. }
  570. /**
  571. * Connects to the database
  572. */
  573. private static function _database_connect()
  574. {
  575. $params = self::$_data['database'];
  576. self::$_connection = mysql_connect($params['host'], $params['user'],
  577. $params['pass'], TRUE);
  578. if ( ! self::$_connection)
  579. {
  580. self::$_errors[] = sprintf("Connection error: <strong>%s</strong>", mysql_error());
  581. return FALSE;
  582. }
  583. $database_name = $params['database'];
  584. if ( ! mysql_select_db($database_name))
  585. {
  586. if (self::_execute_query(sprintf("CREATE DATABASE %s", self::_escape_str($database_name))))
  587. {
  588. mysql_select_db($database_name, self::$_connection);
  589. }
  590. else
  591. {
  592. self::$_errors[] = sprintf("Error creating database: %s", mysql_error());
  593. }
  594. }
  595. }
  596. /**
  597. * Executes a query against the database
  598. * @param string $query
  599. */
  600. private static function _execute_query($query)
  601. {
  602. if (self::$_connection === FALSE)
  603. {
  604. self::_database_connect();
  605. }
  606. if (strlen(trim($query)) > 0)
  607. {
  608. if ( ! mysql_query($query))
  609. {
  610. self::$_errors[] = sprintf("Encountered error <strong>%s</strong> when executing query <code>%s</code>",
  611. mysql_error(), $query);
  612. return FALSE;
  613. }
  614. }
  615. return TRUE;
  616. }
  617. /**
  618. * Escape string for the database
  619. * @param string $query
  620. */
  621. private static function _escape_str($string)
  622. {
  623. if (self::$_connection === FALSE)
  624. {
  625. self::_database_connect();
  626. }
  627. return mysql_real_escape_string($string);
  628. }
  629. /**
  630. * Creates the database configuration file - database.php
  631. */
  632. private static function _create_database_config()
  633. {
  634. $template_file_name = self::$_app_config_dir.'database.template.php';
  635. $output_file_name = self::$_app_config_dir.'database.php';
  636. // Create the new config file
  637. if (($output_file = @fopen($output_file_name, 'w')) !== FALSE)
  638. {
  639. if (($template_file = file($template_file_name)) !== FALSE)
  640. {
  641. $config_params = self::$_data['database'];
  642. foreach ($template_file as $line_no => $line)
  643. {
  644. foreach ($config_params as $config => $value)
  645. {
  646. $search = sprintf("/'%s' =>.*/i", $config);
  647. if (preg_match($search, $line, $matches))
  648. {
  649. $replace = sprintf("'%s' => '%s',", $config, addslashes($value));
  650. $line = preg_replace("/".$matches[0]."/i", $replace, $line);
  651. break;
  652. }
  653. }
  654. fwrite($output_file, $line);
  655. }
  656. }
  657. fclose($output_file);
  658. }
  659. else
  660. {
  661. self::$_errors[] = "Error creating the database config file. Check permissions";
  662. }
  663. return count(self::$_errors) == 0;
  664. }
  665. /**
  666. * Updates the .htaccess and config.php files with the base path
  667. */
  668. private static function _set_base_path()
  669. {
  670. // TODO Set the site_domain, site_protocol and install_check parameters
  671. $params = array(
  672. 'site_domain' => self::$_data['site_domain'],
  673. 'site_protocol' => self::$_data['site_protocol'],
  674. 'installer_check' => FALSE
  675. );
  676. // Clean URLs enabled, set the 'index_page' config to ''
  677. // else it remains as 'index.php'
  678. if (self::$_data['enable_clean_urls'])
  679. {
  680. $params = array_merge($params, array(
  681. 'index_page' => ''
  682. ));
  683. }
  684. // .htaccess
  685. $htaccess_file = ROOT_DIR.'.htaccess';
  686. $htaccess = file($htaccess_file);
  687. if (($fp = @fopen($htaccess_file, 'w')) !== FALSE)
  688. {
  689. foreach ($htaccess as $line_no => $line)
  690. {
  691. if (preg_match("/RewriteBase.*/i", $line, $matches))
  692. {
  693. $replace = sprintf("RewriteBase %s", self::$_data['site_domain']);
  694. $line = str_replace($matches[0], $replace, $line);
  695. }
  696. fwrite($fp, $line);
  697. }
  698. fclose($fp);
  699. }
  700. else
  701. {
  702. self::$_errors[] = "Permission error. Could not open <code>.htaccess</code> for writing";
  703. }
  704. // config.php
  705. $config_file = self::$_app_config_dir.'config.php';
  706. // Load the template file
  707. $config_template = file(self::$_app_config_dir.'config.template.php');
  708. if (($fp = @fopen($config_file, 'w')) !== FALSE)
  709. {
  710. foreach ($config_template as $line_no => $line)
  711. {
  712. foreach ($params as $param => $value)
  713. {
  714. if (preg_match("/config\['".$param."'\].*/i", $line, $matches))
  715. {
  716. // Type check for the param values
  717. if (is_bool($value))
  718. {
  719. // Get the string represenation of the boolean value
  720. // without quotes
  721. $value = ($value) ? 'TRUE' : 'FALSE';
  722. }
  723. else
  724. {
  725. // Quote the value
  726. $value = "'".$value."'";
  727. }
  728. $replace = sprintf("config['%s'] = %s;", $param, $value);
  729. $line = str_replace($matches[0], $replace, $line);
  730. break;
  731. }
  732. }
  733. fwrite($fp, $line);
  734. }
  735. fclose($fp);
  736. }
  737. else
  738. {
  739. self::$_errors[] = "Permission error. Could not open <code>config.php</code> for writing";
  740. }
  741. }
  742. /**
  743. * Updates the auth.php and encrypt.php files with
  744. * the salt pattern and encryption keys
  745. */
  746. private static function _set_security_params()
  747. {
  748. // Auth.php
  749. $auth_file_name = self::$_app_config_dir.'auth.php';
  750. // Load the template
  751. $auth_template = file(self::$_app_config_dir.'auth.template.php');
  752. if (($fp = fopen($auth_file_name, 'w')) !== FALSE)
  753. {
  754. // Get the salt pattern
  755. $salt_pattern = self::$_data['salt_pattern'];
  756. foreach ($auth_template as $line_no => $line)
  757. {
  758. if (preg_match("/config\['salt_pattern'\].*/i", $line, $matches))
  759. {
  760. $replace = sprintf("config['salt_pattern'] = '%s';", implode(", ", $salt_pattern));
  761. $line = str_replace($matches[0], $replace, $line);
  762. }
  763. fwrite($fp, $line);
  764. }
  765. fclose($fp);
  766. }
  767. else
  768. {
  769. self::$_errors[] = "Permission error. Unable to write to <code>auth.php</code>";
  770. }
  771. // encryption.php
  772. $crypto_key = Installer_Utils::get_random_str(32);
  773. $encrypt_file_name = self::$_app_config_dir.'encryption.php';
  774. // Load the template file
  775. $encryption_template = file(self::$_app_config_dir.'encryption.template.php');
  776. if (($fp = @fopen($encrypt_file_name, 'w')) !== FALSE)
  777. {
  778. foreach ($encryption_template as $line_no => $line)
  779. {
  780. if (preg_match("/config\['default'\]\['key'\].*/i", $line, $matches))
  781. {
  782. $replace = sprintf("config['default']['key'] = '%s';", $crypto_key);
  783. $line = str_replace($matches[0], $replace, $line);
  784. }
  785. fwrite($fp, $line);
  786. }
  787. fclose($fp);
  788. }
  789. else
  790. {
  791. self::$_errors[] = "Permission error. Unable to write to <code>encryption.php</code>";
  792. }
  793. }
  794. /**
  795. * Setup the general site settings
  796. * @return bool
  797. */
  798. public static function install_general()
  799. {
  800. $params = array_keys(self::$_forms['general']);
  801. $optional = array('site_email', 'enable_clean_urls');
  802. if ( ! self::_validate_params($params, $_POST, $optional))
  803. return FALSE;
  804. // Clean URLs
  805. if (isset($_POST['enable_clean_urls']))
  806. {
  807. self::$_data['enable_clean_urls'] = (bool) $_POST['enable_clean_urls'];
  808. }
  809. // Validate email
  810. if ( ! empty($_POST['site_email']))
  811. {
  812. if ((filter_var($_POST['site_email'], FILTER_VALIDATE_EMAIL)) === FALSE)
  813. {
  814. self::$_errors[] = sprintf("Invalid email address: <strong>%s</strong>", $_POST['site_email']);
  815. return FALSE;
  816. }
  817. }
  818. return self::_update_settings($params);
  819. }
  820. /**
  821. * Set up the email settings
  822. * @return bool
  823. */
  824. public static function install_email()
  825. {
  826. $params= array_keys(self::$_forms['email']);
  827. if ( ! self::_validate_params($params, $_POST))
  828. return FALSE;
  829. return self::_update_settings($params);
  830. }
  831. /**
  832. * Internal utility method to update the settings table
  833. * @return bool
  834. */
  835. private static function _update_settings($params)
  836. {
  837. $query = "UPDATE `".self::$_data['database']['table_prefix']."settings` SET `value` = CASE `key` ";
  838. // Update the site settings
  839. $settings_keys = array();
  840. foreach ($params as $param)
  841. {
  842. if ( ! isset($_POST[$param]))
  843. continue;
  844. $settings_keys[] = self::_escape_str($param);
  845. $query .= sprintf("WHEN '%s' THEN '%s' ", self::_escape_str($param), self::_escape_str($_POST[$param]));
  846. }
  847. $settings_keys = "'".implode("','", $settings_keys)."'";
  848. $query .= sprintf('END WHERE `key` IN (%s)', $settings_keys);
  849. return self::_execute_query($query);
  850. }
  851. /**
  852. * Setup the map configuration
  853. */
  854. public static function install_map()
  855. {
  856. extract($_POST);
  857. $api_key_mapping = array('bing_road' => 'api_live');
  858. $exempt_providers = array(
  859. 'google_normal',
  860. 'osm_mapnik'
  861. );
  862. if (empty($default_map))
  863. {
  864. self::$_errors[] = "You have not selected a provider";
  865. return FALSE;
  866. }
  867. // Build the update query
  868. $table_prefix = self::$_data['database']['table_prefix'];
  869. // Running as 2 seperate updates because the CASE method is messy and pointless with just 2 keys anyway
  870. $query = sprintf("UPDATE `%ssettings` SET `value` = '%s' WHERE `key` = 'default_map'", $table_prefix, self::_escape_str($default_map) );
  871. $result = TRUE;
  872. // Check for BingMaps API Key
  873. if ( ! in_array($default_map, $exempt_providers))
  874. {
  875. // Check for the API key
  876. if ( ! empty($api_key))
  877. {
  878. $setting_id = $api_key_mapping[$default_map];
  879. $query = sprintf("UPDATE `%ssettings` SET `value` = '%s' WHERE `key` = '%s' ", $table_prefix, self::_escape_str($api_key), self::_escape_str($setting_id) );
  880. $result = self::_execute_query($query) AND $result;
  881. }
  882. else
  883. {
  884. self::$_errors[] = "The selected map provider requires an API key";
  885. return FALSE;
  886. }
  887. }
  888. $result = self::_execute_query($query) AND $result;
  889. return $result;
  890. }
  891. /**
  892. * Save the admin password
  893. */
  894. public static function install_adminpassword()
  895. {
  896. $params = array_keys(self::$_forms['adminpassword']);
  897. if ( ! self::_validate_params($params, $_POST))
  898. return FALSE;
  899. extract($_POST);
  900. if (filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE)
  901. {
  902. self::$_errors[] = sprintf("Invalid email address: <strong>%s</strong>", $email);
  903. return FALSE;
  904. }
  905. // Do the passwords match?
  906. if (hash("sha1", $password) !== hash("sha1", $confirm_password))
  907. {
  908. self::$_errors[] = "The passwords do not match";
  909. return FALSE;
  910. }
  911. // Get the table prefix
  912. $table_prefix = self::$_data['database']['table_prefix'];
  913. // Get the salt pattern from the auth.php
  914. $salt_pattern = Installer_Utils::get_salt_pattern();
  915. self::$_data['salt_pattern'] = $salt_pattern;
  916. // Generate the password hash
  917. $password_hash = Installer_Utils::hash_password($password, $salt_pattern);
  918. // Update the admin user password
  919. $query = sprintf("UPDATE `%susers` SET `email` = '%s', `password` = '%s' WHERE `username` = 'admin'",
  920. $table_prefix, self::_escape_str($email), self::_escape_str($password_hash));
  921. self::$_data['admin_email'] = $email;
  922. return self::_execute_query($query);
  923. }
  924. /**
  925. * Checks if clean URLS are enabled
  926. *
  927. * @return bool
  928. */
  929. private static function _clean_urls_enabled()
  930. {
  931. $url = self::$_data['base_url']."installer/mod_rewrite/";
  932. $curl_handle = curl_init();
  933. curl_setopt($curl_handle, CURLOPT_URL, $url);
  934. curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, TRUE);
  935. curl_exec($curl_handle);
  936. $return_code = curl_getinfo($curl_handle,CURLINFO_HTTP_CODE);
  937. curl_close($curl_handle);
  938. if ($return_code == 404 OR $return_code == 403)
  939. {
  940. return FALSE;
  941. }
  942. else
  943. {
  944. return TRUE;
  945. }
  946. }
  947. }
  948. ?>