diff options
Diffstat (limited to 'plugins/Installation/Controller.php')
-rw-r--r-- | plugins/Installation/Controller.php | 417 |
1 files changed, 348 insertions, 69 deletions
diff --git a/plugins/Installation/Controller.php b/plugins/Installation/Controller.php index 022c1e4911..ef0929899e 100644 --- a/plugins/Installation/Controller.php +++ b/plugins/Installation/Controller.php @@ -11,6 +11,7 @@ */ /** + * Installation controller * * @package Piwik_Installation */ @@ -21,6 +22,7 @@ class Piwik_Installation_Controller extends Piwik_Controller 'welcome' => 'Installation_Welcome', 'systemCheck' => 'Installation_SystemCheck', 'databaseSetup' => 'Installation_DatabaseSetup', + 'databaseCheck' => 'Installation_DatabaseCheck', 'tablesCreation' => 'Installation_Tables', 'generalSetup' => 'Installation_GeneralSetup', 'firstWebsiteSetup' => 'Installation_SetupWebsite', @@ -38,35 +40,54 @@ class Piwik_Installation_Controller extends Piwik_Controller if(!isset($this->session->currentStepDone)) { $this->session->currentStepDone = ''; + $this->session->skipThisStep = array(); } Piwik_PostEvent('InstallationController.construct', $this); } + /** + * Get installation steps + * + * @return array installation steps + */ public function getInstallationSteps() { return $this->steps; } + /** + * Get default action (first installation step) + * + * @return string function name + */ function getDefaultAction() { $steps = array_keys($this->steps); return $steps[0]; } - function welcome() + /** + * Installation Step 1: Welcome + */ + function welcome($message) { $view = new Piwik_Installation_View( $this->pathView . 'welcome.tpl', $this->getInstallationSteps(), __FUNCTION__ ); + $view->newInstall = !file_exists(Piwik_Config::getDefaultUserConfigPath()); + $view->errorMessage = $message; $this->skipThisStep( __FUNCTION__ ); - $view->showNextStep = true; + $view->showNextStep = $view->newInstall; $this->session->currentStepDone = __FUNCTION__; echo $view->render(); } + /** + * Installation Step 2: System Check + */ function systemCheck() { $this->checkPreviousStepIsValid( __FUNCTION__ ); @@ -80,12 +101,16 @@ class Piwik_Installation_Controller extends Piwik_Controller $view->infos = self::getSystemInformation(); $view->helpMessages = array( - 'zlib' => 'Installation_SystemCheckZlibHelp', - 'SPL' => 'Installation_SystemCheckSplHelp', - 'iconv' => 'Installation_SystemCheckIconvHelp', - 'dom' => 'Installation_SystemCheckDomHelp', - 'set_time_limit' => 'Installation_SystemCheckTimeLimitHelp', - 'mail' => 'Installation_SystemCheckMailHelp', + 'zlib' => 'Installation_SystemCheckZlibHelp', + 'SPL' => 'Installation_SystemCheckSplHelp', + 'iconv' => 'Installation_SystemCheckIconvHelp', + 'dom' => 'Installation_SystemCheckDomHelp', + 'set_time_limit' => 'Installation_SystemCheckTimeLimitHelp', + 'mail' => 'Installation_SystemCheckMailHelp', + 'parse_ini_file' => 'Installation_SystemCheckParseIniFileHelp', + 'debug_backtrace' => 'Installation_SystemCheckDebugBacktraceHelp', + 'create_function' => 'Installation_SystemCheckCreateFunctionHelp', + 'eval' => 'Installation_SystemCheckEvalHelp', ); $view->problemWithSomeDirectories = (false !== array_search(false, $view->infos['directories'])); @@ -94,6 +119,7 @@ class Piwik_Installation_Controller extends Piwik_Controller && $view->infos['phpVersion_ok'] && count($view->infos['adapters']) && !count($view->infos['missing_extensions']) + && !count($view->infos['missing_functions']) ; $this->session->currentStepDone = __FUNCTION__; @@ -101,6 +127,9 @@ class Piwik_Installation_Controller extends Piwik_Controller echo $view->render(); } + /** + * Installation Step 3: Database Set-up + */ function databaseSetup() { $this->checkPreviousStepIsValid( __FUNCTION__ ); @@ -125,7 +154,7 @@ class Piwik_Installation_Controller extends Piwik_Controller if($form->validate()) { $adapter = $form->getSubmitValue('adapter'); - $port = Piwik_Db::getDefaultPortForAdapter($adapter); + $port = Piwik_Db_Adapter::getDefaultPortForAdapter($adapter); $dbInfos = array( 'host' => $form->getSubmitValue('host'), @@ -153,9 +182,12 @@ class Piwik_Installation_Controller extends Piwik_Controller try{ try { Piwik::createDatabaseObject($dbInfos); + $this->session->databaseCreated = true; } catch (Zend_Db_Adapter_Exception $e) { + $db = Piwik_Db_Adapter::factory($adapter, $dbInfos); + // database not found, we try to create it - if(Zend_Registry::isRegistered('db') && Zend_Registry::get('db')->isErrNo($e, '1049')) + if($db->isErrNo($e, '1049')) { $dbInfosConnectOnly = $dbInfos; $dbInfosConnectOnly['dbname'] = null; @@ -165,11 +197,12 @@ class Piwik_Installation_Controller extends Piwik_Controller } else { - throw $e; + throw $e; } } Piwik::checkDatabaseVersion(); + $this->session->databaseVersionOk = true; $this->session->db_infos = $dbInfos; $this->redirectToNextStep( __FUNCTION__ ); @@ -179,11 +212,76 @@ class Piwik_Installation_Controller extends Piwik_Controller } $view->addForm($form); - $view->infos = self::getSystemInformation(); + echo $view->render(); + } + + /** + * Installation Step 4: Database Check + */ + function databaseCheck() + { + $this->checkPreviousStepIsValid( __FUNCTION__ ); + $view = new Piwik_Installation_View( + $this->pathView . 'databaseCheck.tpl', + $this->getInstallationSteps(), + __FUNCTION__ + ); + + $error = false; + $this->skipThisStep( __FUNCTION__ ); + + if(isset($this->session->databaseVersionOk) + && $this->session->databaseVersionOk === true) + { + $view->databaseVersionOk = true; + } + else + { + $error = true; + } + + if(isset($this->session->databaseCreated) + && $this->session->databaseCreated === true) + { + $dbInfos = $this->session->db_infos; + $view->databaseName = $dbInfos['dbname']; + $view->databaseCreated = true; + } + else + { + $error = true; + } + + $this->createDbFromSessionInformation(); + $db = Zend_Registry::get('db'); + + try { + $db->checkClientVersion(); + } catch(Exception $e) { + $view->clientVersionWarning = $e->getMessage(); + $error = true; + } + + if(!Piwik::isDatabaseConnectionUTF8()) + { + $dbInfos = $this->session->db_infos; + $dbInfos['charset'] = 'utf8'; + $this->session->db_infos = $dbInfos; + } + $view->showNextStep = true; + $this->session->currentStepDone = __FUNCTION__; + + if($error === false) + { + $this->redirectToNextStep(__FUNCTION__); + } echo $view->render(); } + /** + * Installation Step 5: Table Creation + */ function tablesCreation() { $this->checkPreviousStepIsValid( __FUNCTION__ ); @@ -209,29 +307,31 @@ class Piwik_Installation_Controller extends Piwik_Controller $this->session->skipThisStep = $tmp; } - if(!Piwik::isDatabaseConnectionUTF8()) - { -// $view->charsetWarning = true; - } - $tablesInstalled = Piwik::getTablesInstalled(); $tablesToInstall = Piwik::getTablesNames(); $view->tablesInstalled = ''; if(count($tablesInstalled) > 0) { + // we have existing tables $view->tablesInstalled = implode(', ', $tablesInstalled); $view->someTablesInstalled = true; $minimumCountPiwikTables = 12; $baseTablesInstalled = preg_grep('/archive_numeric|archive_blob/', $tablesInstalled, PREG_GREP_INVERT); - if(count($baseTablesInstalled) >= $minimumCountPiwikTables ) + + Piwik::createAccessObject(); + Piwik::setUserIsSuperUser(); + + if(count($baseTablesInstalled) >= $minimumCountPiwikTables && + count(Piwik_SitesManager_API::getInstance()->getAllSitesId()) > 0 && + count(Piwik_UsersManager_API::getInstance()->getUsers()) > 0) { $view->showReuseExistingTables = true; // when the user reuses the same tables we skip the website creation step // workaround ZF-1743 $tmp = $this->session->skipThisStep; $tmp['firstWebsiteSetup'] = true; - $tmp['displayJavascriptCode'] = true; + $tmp['displayJavascriptCode'] = true; $this->session->skipThisStep = $tmp; } } @@ -246,18 +346,13 @@ class Piwik_Installation_Controller extends Piwik_Controller $view->showNextStep = true; } - if(isset($this->session->databaseCreated) - && $this->session->databaseCreated === true) - { - $view->databaseName = $this->session->db_infos['dbname']; - $view->databaseCreated = true; - unset($this->session->databaseCreated); - } - $this->session->currentStepDone = __FUNCTION__; echo $view->render(); } + /** + * Installation Step 6: General Set-up (superuser login/password/email and subscriptions) + */ function generalSetup() { $this->checkPreviousStepIsValid( __FUNCTION__ ); @@ -277,6 +372,7 @@ class Piwik_Installation_Controller extends Piwik_Controller 'login' => $form->getSubmitValue('login'), 'password' => md5( $form->getSubmitValue('password') ), 'email' => $form->getSubmitValue('email'), + 'salt' => Piwik_Common::generateUniqId(), ); $this->session->superuser_infos = $superUserInfos; @@ -296,7 +392,7 @@ class Piwik_Installation_Controller extends Piwik_Controller if( !isset($params['community'])) { $params['community'] = '0'; } $url = $host . '?' . http_build_query($params, '', '&'); try { - Piwik::sendHttpRequest($url, $timeout = 2); + Piwik_Http::sendHttpRequest($url, $timeout = 2); } catch(Exception $e) { // e.g., disable_functions = fsockopen; allow_url_open = Off } @@ -308,6 +404,9 @@ class Piwik_Installation_Controller extends Piwik_Controller echo $view->render(); } + /** + * Installation Step 7: Configure first web-site + */ public function firstWebsiteSetup() { $this->checkPreviousStepIsValid( __FUNCTION__ ); @@ -326,12 +425,12 @@ class Piwik_Installation_Controller extends Piwik_Controller $this->session->generalSetupSuccessMessage = true; } + $this->initObjectsToCallAPI(); if($form->validate()) { $name = urlencode($form->getSubmitValue('siteName')); $url = urlencode($form->getSubmitValue('url')); - $this->initObjectsToCallAPI(); $request = new Piwik_API_Request(" method=SitesManager.addSite @@ -356,6 +455,9 @@ class Piwik_Installation_Controller extends Piwik_Controller echo $view->render(); } + /** + * Installation Step 8: Display JavaScript tracking code + */ public function displayJavascriptCode() { $this->checkPreviousStepIsValid( __FUNCTION__ ); @@ -373,7 +475,6 @@ class Piwik_Installation_Controller extends Piwik_Controller $this->session->firstWebsiteSetupSuccessMessage = true; } - $view->websiteName = urldecode($this->session->site_name); $jsTag = Piwik::getJavascriptCode($this->session->site_idSite, Piwik_Url::getCurrentUrlWithoutFileName()); @@ -385,6 +486,9 @@ class Piwik_Installation_Controller extends Piwik_Controller echo $view->render(); } + /** + * Installation Step 9: Finished! + */ public function finished() { $this->checkPreviousStepIsValid( __FUNCTION__ ); @@ -395,14 +499,21 @@ class Piwik_Installation_Controller extends Piwik_Controller __FUNCTION__ ); $this->skipThisStep( __FUNCTION__ ); - $this->writeConfigFileFromSession(); - $this->session->currentStepDone = __FUNCTION__; + if(!file_exists(Piwik_Config::getDefaultUserConfigPath())) + { + $this->writeConfigFileFromSession(); + } + $view->showNextStep = false; + $this->session->currentStepDone = __FUNCTION__; echo $view->render(); } + /** + * Instantiate access and log objects + */ protected function initObjectsToCallAPI() { // connect to the database using the DB infos currently in the session @@ -413,6 +524,20 @@ class Piwik_Installation_Controller extends Piwik_Controller Piwik::createLogObject(); } + /** + * Create database connection from session-store + */ + protected function createDbFromSessionInformation() + { + $dbInfos = $this->session->db_infos; + Zend_Registry::get('config')->disableSavingConfigurationFileUpdates(); + Zend_Registry::get('config')->database = $dbInfos; + Piwik::createDatabaseObject($dbInfos); + } + + /** + * Write configuration file from session-store + */ protected function writeConfigFileFromSession() { if(!isset($this->session->superuser_infos) @@ -422,32 +547,50 @@ class Piwik_Installation_Controller extends Piwik_Controller } $config = Zend_Registry::get('config'); $config->superuser = $this->session->superuser_infos; - $config->database = $this->session->db_infos; + $dbInfos = $this->session->db_infos; + $config->database = $dbInfos; + + unset($this->session->superuser_infos); + unset($this->session->db_infos); + } + + /** + * Save language selection in session-store + */ + public function saveLanguage() + { + $language = Piwik_Common::getRequestVar('language'); + Piwik_LanguagesManager_API::getInstance()->setLanguageForSession($language); + Piwik_Url::redirectToReferer(); } /** * The previous step is valid if it is either * - any step before (OK to go back) * - the current step (case when validating a form) + * If step is invalid, then exit. + * + * @param string $currentStep Current step */ protected function checkPreviousStepIsValid( $currentStep ) { $error = false; - // first we make sure that the config file is not present, ie. Installation state is expected - try { - $config = new Piwik_Config(); - $config->init(); - $error = true; - } catch(Exception $e) { - } - if(empty($this->session->currentStepDone)) { $error = true; } + else if($currentStep == 'finished' && $this->session->currentStepDone == 'finished') + { + // ok to refresh this page or use language selector + } else { + if(file_exists(Piwik_Config::getDefaultUserConfigPath())) + { + $error = true; + } + $steps = array_keys($this->steps); // the currentStep @@ -475,6 +618,12 @@ class Piwik_Installation_Controller extends Piwik_Controller } } + /** + * Redirect to next step + * + * @param string Current step + * @return none + */ protected function redirectToNextStep($currentStep) { $steps = array_keys($this->steps); @@ -483,14 +632,23 @@ class Piwik_Installation_Controller extends Piwik_Controller Piwik::redirectToModule('Installation' , $nextStep); } - protected function createDbFromSessionInformation() + /** + * Skip this step (typically to mark the current function as completed) + * + * @param string function name + */ + protected function skipThisStep( $step ) { - $dbInfos = $this->session->db_infos; - Zend_Registry::get('config')->disableSavingConfigurationFileUpdates(); - Zend_Registry::get('config')->database = $dbInfos; - Piwik::createDatabaseObject($dbInfos); + $skipThisStep = $this->session->skipThisStep; + if(isset($skipThisStep[$step]) && $skipThisStep[$step]) + { + $this->redirectToNextStep($step); + } } + /** + * Get system information + */ public static function getSystemInformation() { $minimumPhpVersion = Zend_Registry::get('config')->General->minimum_php_version; @@ -499,6 +657,17 @@ class Piwik_Installation_Controller extends Piwik_Controller $infos = array(); $infos['directories'] = Piwik::checkDirectoriesWritable(); + + $serverSoftware = $_SERVER['SERVER_SOFTWARE']; + if(preg_match('/^Microsoft-IIS\/(.+)/', $serverSoftware, $matches) && version_compare($matches[1], '7') >= 0) + { + Piwik::createWebConfigFiles(); + } + else if(strpos($serverSoftware, 'Apache/') === 0) + { + Piwik::createHtAccessFiles(); + } + $infos['phpVersion_minimum'] = $minimumPhpVersion; $infos['phpVersion'] = phpversion(); $infos['phpVersion_ok'] = version_compare( $minimumPhpVersion, $infos['phpVersion']) === -1; @@ -509,6 +678,7 @@ class Piwik_Installation_Controller extends Piwik_Controller 'zlib', 'SPL', 'iconv', + 'Reflection', ); $infos['needed_extensions'] = $needed_extensions; $infos['missing_extensions'] = array(); @@ -526,7 +696,7 @@ class Piwik_Installation_Controller extends Piwik_Controller $infos['pdo_ok'] = true; } - $infos['adapters'] = Piwik_Db::getAdapters(); + $infos['adapters'] = Piwik_Db_Adapter::getAdapters(); $infos['json'] = false; if(in_array('json', $extensions)) @@ -540,36 +710,72 @@ class Piwik_Installation_Controller extends Piwik_Controller $infos['xml'] = true; } - // warnings $needed_functions = array( - 'set_time_limit', - 'mail', + 'debug_backtrace', + 'create_function', + 'eval', ); $infos['needed_functions'] = $needed_functions; $infos['missing_functions'] = array(); foreach($needed_functions as $needed_function) { - if(!function_exists($needed_function)) + if(!self::functionExists($needed_function)) { $infos['missing_functions'][] = $needed_function; } } - $infos['openurl'] = Piwik::getTransportMethod(); + // warnings + $desired_functions = array( + 'set_time_limit', + 'mail', + 'parse_ini_file', + ); + $infos['desired_functions'] = $desired_functions; + $infos['missing_desired_functions'] = array(); + foreach($desired_functions as $desired_function) + { + if(!self::functionExists($desired_function)) + { + $infos['missing_desired_functions'][] = $desired_function; + } + } + + $infos['openurl'] = Piwik_Http::getTransportMethod(); $infos['gd_ok'] = false; if (in_array('gd', $extensions)) { - $gdInfo = gd_info(); + $gdInfo = gd_info(); $infos['gd_version'] = $gdInfo['GD Version']; - preg_match('/([0-9]{1})/', $gdInfo['GD Version'], $gdVersion); - if($gdVersion[0] >= 2) - { + preg_match('/([0-9]{1})/', $gdInfo['GD Version'], $gdVersion); + if($gdVersion[0] >= 2) + { $infos['gd_ok'] = true; - } + } } - $infos['serverVersion'] = addslashes($_SERVER['SERVER_SOFTWARE']); + $infos['hasMbstring'] = false; + $infos['multibyte_ok'] = true; + if(function_exists('mb_internal_encoding')) + { + $infos['hasMbstring'] = true; + if (((int) ini_get('mbstring.func_overload')) != 0) + { + $infos['multibyte_ok'] = false; + } + } + + /** + * @see http://php.net/ip2long + */ + $infos['isIpv4'] = true; + if(strpos($_SERVER['REMOTE_ADDR'], ':') !== false) + { + $infos['isIpv4'] = false; + } + + $infos['serverVersion'] = addslashes($serverSoftware); $infos['serverOs'] = @php_uname(); $infos['serverTime'] = date('H:i:s'); @@ -577,8 +783,7 @@ class Piwik_Installation_Controller extends Piwik_Controller $infos['memoryMinimum'] = $minimumMemoryLimit; $infos['memory_ok'] = true; - // on windows the ini_get is not working? - $infos['memoryCurrent'] = '?M'; + $infos['memoryCurrent'] = '-1'; $raised = Piwik::raiseMemoryLimitIfNecessary(); if( $memoryValue = Piwik::getMemoryLimitValue() ) @@ -587,24 +792,98 @@ class Piwik_Installation_Controller extends Piwik_Controller $infos['memory_ok'] = $memoryValue >= $minimumMemoryLimit; } - $infos['isWindows'] = substr(PHP_OS, 0, 3) == 'WIN'; + $infos['isWindows'] = strtoupper(substr(PHP_OS, 0, 3)) == 'WIN'; + + $infos['protocol_ok'] = true; + $infos['protocol'] = self::getProtocolInformation(); + if(Piwik_Url::getCurrentScheme() == 'http' && + $infos['protocol'] !== null) + { + $infos['protocol_ok'] = false; + } + + $integrityInfo = Piwik::getFileIntegrityInformation(); + $infos['integrity'] = $integrityInfo[0]; + + $infos['integrityErrorMessages'] = array(); + if(isset($integrityInfo[1])) + { + if($infos['integrity'] == false) + { + $infos['integrityErrorMessages'][] = '<b>'.Piwik_Translate('General_FileIntegrityWarningExplanation').'</b>'; + } + $infos['integrityErrorMessages'] = array_merge($infos['integrityErrorMessages'], array_slice($integrityInfo, 1)); + } + $infos['timezone'] = Piwik::isTimezoneSupportEnabled(); return $infos; } - protected function skipThisStep( $step ) + /** + * Get protocol information, with the exception of HTTPS + * + * @return string protocol information + */ + public static function getProtocolInformation() { - if(isset($this->session->skipThisStep[$step]) - && $this->session->skipThisStep[$step]) + if(Piwik_Common::getRequestVar('clientProtocol', 'http', 'string') == 'https') { - $this->redirectToNextStep($step); + return 'https'; + } + + if(isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443) + { + return 'SERVER_PORT=443'; } + + if(isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https') + { + return 'X-Forwarded-Proto'; + } + + if(isset($_SERVER['HTTP_X_FORWARDED_SCHEME']) && strtolower($_SERVER['HTTP_X_FORWARDED_SCHEME']) == 'https') + { + return 'X-Forwarded-Scheme'; + } + + if(isset($_SERVER['HTTP_X_URL_SCHEME']) && strtolower($_SERVER['HTTP_X_URL_SCHEME']) == 'https') + { + return 'X-Url-Scheme'; + } + + return null; } - public function saveLanguage() + /** + * Test if function exists. Also handles case where function is disabled via Suhosin. + * + * @param string $functionName Function name + * @return bool True if function exists (not disabled); False otherwise. + */ + public static function functionExists($functionName) { - $language = Piwik_Common::getRequestVar('language'); - Piwik_LanguagesManager_API::setLanguageForSession($language); - Piwik_Url::redirectToReferer(); + // eval() is a language construct + if($functionName == 'eval') + { + // does not check suhosin.executor.eval.whitelist (or blacklist) + if(extension_loaded('suhosin')) + { + return @ini_get("suhosin.executor.disable_eval") != "1"; + } + return true; + } + + $exists = function_exists($functionName); + if(extension_loaded('suhosin')) + { + $blacklist = @ini_get("suhosin.executor.func.blacklist"); + if(!empty($blacklist)) + { + $blacklistFunctions = array_map('strtolower', array_map('trim', explode(',', $blacklist))); + return $exists && !in_array($functionName, $blacklistFunctions); + } + + } + return $exists; } } |