+ {postEvent name="template_topBar"} +
+
+
diff --git a/oss/piwik/trunk/plugins/Installation/Controller.php b/oss/piwik/trunk/plugins/Installation/Controller.php
new file mode 100644
index 00000000..e2f4e4ec
--- /dev/null
+++ b/oss/piwik/trunk/plugins/Installation/Controller.php
@@ -0,0 +1,889 @@
+ 'Installation_Welcome',
+ 'systemCheck' => 'Installation_SystemCheck',
+ 'databaseSetup' => 'Installation_DatabaseSetup',
+ 'databaseCheck' => 'Installation_DatabaseCheck',
+ 'tablesCreation' => 'Installation_Tables',
+ 'generalSetup' => 'Installation_GeneralSetup',
+ 'firstWebsiteSetup' => 'Installation_SetupWebsite',
+ 'displayJavascriptCode' => 'Installation_JsTag',
+ 'finished' => 'Installation_Congratulations',
+ );
+
+ protected $pathView = 'Installation/templates/';
+
+ protected $session;
+
+ public function __construct()
+ {
+ $this->session = new Zend_Session_Namespace('Piwik_Installation');
+ 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];
+ }
+
+ /**
+ * 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 = $view->newInstall;
+ $this->session->currentStepDone = __FUNCTION__;
+ echo $view->render();
+ }
+
+ /**
+ * Installation Step 2: System Check
+ */
+ function systemCheck()
+ {
+ $this->checkPreviousStepIsValid( __FUNCTION__ );
+
+ $view = new Piwik_Installation_View(
+ $this->pathView . 'systemCheck.tpl',
+ $this->getInstallationSteps(),
+ __FUNCTION__
+ );
+ $this->skipThisStep( __FUNCTION__ );
+
+ $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',
+ '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']));
+
+ $view->showNextStep = !$view->problemWithSomeDirectories
+ && $view->infos['phpVersion_ok']
+ && count($view->infos['adapters'])
+ && !count($view->infos['missing_extensions'])
+ && !count($view->infos['missing_functions'])
+ ;
+
+ $this->session->currentStepDone = __FUNCTION__;
+
+ echo $view->render();
+ }
+
+ /**
+ * Installation Step 3: Database Set-up
+ */
+ function databaseSetup()
+ {
+ $this->checkPreviousStepIsValid( __FUNCTION__ );
+
+ // case the user hits the back button
+ $this->session->skipThisStep = array(
+ 'firstWebsiteSetup' => false,
+ 'displayJavascriptCode' => false,
+ );
+
+ $view = new Piwik_Installation_View(
+ $this->pathView . 'databaseSetup.tpl',
+ $this->getInstallationSteps(),
+ __FUNCTION__
+ );
+ $this->skipThisStep( __FUNCTION__ );
+
+ $view->showNextStep = false;
+
+ $form = new Piwik_Installation_FormDatabaseSetup();
+
+ if($form->validate())
+ {
+ $adapter = $form->getSubmitValue('adapter');
+ $port = Piwik_Db_Adapter::getDefaultPortForAdapter($adapter);
+
+ $dbInfos = array(
+ 'host' => $form->getSubmitValue('host'),
+ 'username' => $form->getSubmitValue('username'),
+ 'password' => $form->getSubmitValue('password'),
+ 'dbname' => $form->getSubmitValue('dbname'),
+ 'tables_prefix' => $form->getSubmitValue('tables_prefix'),
+ 'adapter' => $adapter,
+ 'port' => $port,
+ );
+
+ if(($portIndex = strpos($dbInfos['host'], '/')) !== false)
+ {
+ // unix_socket=/path/sock.n
+ $dbInfos['port'] = substr($dbInfos['host'], $portIndex);
+ $dbInfos['host'] = '';
+ }
+ else if(($portIndex = strpos($dbInfos['host'], ':')) !== false)
+ {
+ // host:port
+ $dbInfos['port'] = substr($dbInfos['host'], $portIndex + 1 );
+ $dbInfos['host'] = substr($dbInfos['host'], 0, $portIndex);
+ }
+
+ 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($db->isErrNo($e, '1049'))
+ {
+ $dbInfosConnectOnly = $dbInfos;
+ $dbInfosConnectOnly['dbname'] = null;
+ Piwik::createDatabaseObject($dbInfosConnectOnly);
+ Piwik::createDatabase($dbInfos['dbname']);
+ $this->session->databaseCreated = true;
+ }
+ else
+ {
+ throw $e;
+ }
+ }
+
+ Piwik::checkDatabaseVersion();
+ $this->session->databaseVersionOk = true;
+
+ $this->session->db_infos = $dbInfos;
+ $this->redirectToNextStep( __FUNCTION__ );
+ } catch(Exception $e) {
+ $view->errorMessage = $e->getMessage();
+ }
+ }
+ $view->addForm($form);
+
+ 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__ );
+
+ $view = new Piwik_Installation_View(
+ $this->pathView . 'tablesCreation.tpl',
+ $this->getInstallationSteps(),
+ __FUNCTION__
+ );
+ $this->skipThisStep( __FUNCTION__ );
+ $this->createDbFromSessionInformation();
+
+ if(Piwik_Common::getRequestVar('deleteTables', 0, 'int') == 1)
+ {
+ Piwik::dropTables();
+ $view->existingTablesDeleted = true;
+
+ // when the user decides to drop the tables then we dont skip the next steps anymore
+ // workaround ZF-1743
+ $tmp = $this->session->skipThisStep;
+ $tmp['firstWebsiteSetup'] = false;
+ $tmp['displayJavascriptCode'] = false;
+ $this->session->skipThisStep = $tmp;
+ }
+
+ $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);
+
+ 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;
+ $this->session->skipThisStep = $tmp;
+ }
+ }
+ else
+ {
+ Piwik::createTables();
+ Piwik::createAnonymousUser();
+
+ $updater = new Piwik_Updater();
+ $updater->recordComponentSuccessfullyUpdated('core', Piwik_Version::VERSION);
+ $view->tablesCreated = true;
+ $view->showNextStep = true;
+ }
+
+ $this->session->currentStepDone = __FUNCTION__;
+ echo $view->render();
+ }
+
+ /**
+ * Installation Step 6: General Set-up (superuser login/password/email and subscriptions)
+ */
+ function generalSetup()
+ {
+ $this->checkPreviousStepIsValid( __FUNCTION__ );
+
+ $view = new Piwik_Installation_View(
+ $this->pathView . 'generalSetup.tpl',
+ $this->getInstallationSteps(),
+ __FUNCTION__
+ );
+ $this->skipThisStep( __FUNCTION__ );
+
+ $form = new Piwik_Installation_FormGeneralSetup();
+
+ if($form->validate())
+ {
+ $superUserInfos = array(
+ 'login' => $form->getSubmitValue('login'),
+ 'password' => md5( $form->getSubmitValue('password') ),
+ 'email' => $form->getSubmitValue('email'),
+ 'salt' => Piwik_Common::generateUniqId(),
+ );
+
+ $this->session->superuser_infos = $superUserInfos;
+
+ $host = 'http://api.piwik.org/1.0/';
+ $host .= 'subscribeNewsletter/';
+ $params = array(
+ 'email' => $form->getSubmitValue('email'),
+ 'security' => $form->getSubmitValue('subscribe_newsletter_security'),
+ 'community' => $form->getSubmitValue('subscribe_newsletter_community'),
+ 'url' => Piwik_Url::getCurrentUrlWithoutQueryString(),
+ );
+ if($params['security'] == '1'
+ || $params['community'] == '1')
+ {
+ if( !isset($params['security'])) { $params['security'] = '0'; }
+ if( !isset($params['community'])) { $params['community'] = '0'; }
+ $url = $host . '?' . http_build_query($params, '', '&');
+ try {
+ Piwik_Http::sendHttpRequest($url, $timeout = 2);
+ } catch(Exception $e) {
+ // e.g., disable_functions = fsockopen; allow_url_open = Off
+ }
+ }
+ $this->redirectToNextStep( __FUNCTION__ );
+ }
+ $view->addForm($form);
+
+ echo $view->render();
+ }
+
+ /**
+ * Installation Step 7: Configure first web-site
+ */
+ public function firstWebsiteSetup()
+ {
+ $this->checkPreviousStepIsValid( __FUNCTION__ );
+
+ $view = new Piwik_Installation_View(
+ $this->pathView . 'firstWebsiteSetup.tpl',
+ $this->getInstallationSteps(),
+ __FUNCTION__
+ );
+ $this->skipThisStep( __FUNCTION__ );
+
+ $form = new Piwik_Installation_FormFirstWebsiteSetup();
+ if( !isset($this->session->generalSetupSuccessMessage))
+ {
+ $view->displayGeneralSetupSuccess = true;
+ $this->session->generalSetupSuccessMessage = true;
+ }
+
+ $this->initObjectsToCallAPI();
+ if($form->validate())
+ {
+ $name = urlencode($form->getSubmitValue('siteName'));
+ $url = urlencode($form->getSubmitValue('url'));
+
+
+ $request = new Piwik_API_Request("
+ method=SitesManager.addSite
+ &siteName=$name
+ &urls=$url
+ &format=original
+ ");
+
+ try {
+ $result = $request->process();
+ $this->session->site_idSite = $result;
+ $this->session->site_name = $name;
+ $this->session->site_url = $url;
+
+ $this->redirectToNextStep( __FUNCTION__ );
+ } catch(Exception $e) {
+ $view->errorMessage = $e->getMessage();
+ }
+
+ }
+ $view->addForm($form);
+ echo $view->render();
+ }
+
+ /**
+ * Installation Step 8: Display JavaScript tracking code
+ */
+ public function displayJavascriptCode()
+ {
+ $this->checkPreviousStepIsValid( __FUNCTION__ );
+
+ $view = new Piwik_Installation_View(
+ $this->pathView . 'displayJavascriptCode.tpl',
+ $this->getInstallationSteps(),
+ __FUNCTION__
+ );
+ $this->skipThisStep( __FUNCTION__ );
+
+ if( !isset($this->session->firstWebsiteSetupSuccessMessage))
+ {
+ $view->displayfirstWebsiteSetupSuccess = true;
+ $this->session->firstWebsiteSetupSuccessMessage = true;
+ }
+
+ $view->websiteName = urldecode($this->session->site_name);
+
+ $jsTag = Piwik::getJavascriptCode($this->session->site_idSite, Piwik_Url::getCurrentUrlWithoutFileName());
+
+ $view->javascriptTag = $jsTag;
+ $view->showNextStep = true;
+
+ $this->session->currentStepDone = __FUNCTION__;
+ echo $view->render();
+ }
+
+ /**
+ * Installation Step 9: Finished!
+ */
+ public function finished()
+ {
+ $this->checkPreviousStepIsValid( __FUNCTION__ );
+
+ $view = new Piwik_Installation_View(
+ $this->pathView . 'finished.tpl',
+ $this->getInstallationSteps(),
+ __FUNCTION__
+ );
+ $this->skipThisStep( __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
+ $this->createDbFromSessionInformation();
+
+ Piwik::createAccessObject();
+ Piwik::setUserIsSuperUser();
+ 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)
+ || !isset($this->session->db_infos))
+ {
+ return;
+ }
+ $config = Zend_Registry::get('config');
+ $config->superuser = $this->session->superuser_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;
+
+ 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
+ $currentStepId = array_search($currentStep, $steps);
+
+ // the step before
+ $previousStepId = array_search($this->session->currentStepDone, $steps);
+
+ // not OK if currentStepId > previous+1
+ if( $currentStepId > $previousStepId + 1 )
+ {
+ $error = true;
+ }
+ }
+ if($error)
+ {
+ Piwik_Login_Controller::clearSession();
+ $message = Piwik_Translate('Installation_ErrorInvalidState',
+ array( '
',
+ '',
+ '',
+ '')
+ );
+ Piwik::exitWithErrorMessage( $message );
+ }
+ }
+
+ /**
+ * Redirect to next step
+ *
+ * @param string Current step
+ * @return none
+ */
+ protected function redirectToNextStep($currentStep)
+ {
+ $steps = array_keys($this->steps);
+ $this->session->currentStepDone = $currentStep;
+ $nextStep = $steps[1 + array_search($currentStep, $steps)];
+ Piwik::redirectToModule('Installation' , $nextStep);
+ }
+
+ /**
+ * Skip this step (typically to mark the current function as completed)
+ *
+ * @param string function name
+ */
+ protected function skipThisStep( $step )
+ {
+ $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;
+ $minimumMemoryLimit = Zend_Registry::get('config')->General->minimum_memory_limit;
+
+ $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;
+
+ // critical errors
+ $extensions = @get_loaded_extensions();
+ $needed_extensions = array(
+ 'zlib',
+ 'SPL',
+ 'iconv',
+ 'Reflection',
+ );
+ $infos['needed_extensions'] = $needed_extensions;
+ $infos['missing_extensions'] = array();
+ foreach($needed_extensions as $needed_extension)
+ {
+ if(!in_array($needed_extension, $extensions))
+ {
+ $infos['missing_extensions'][] = $needed_extension;
+ }
+ }
+
+ $infos['pdo_ok'] = false;
+ if(in_array('PDO', $extensions))
+ {
+ $infos['pdo_ok'] = true;
+ }
+
+ $infos['adapters'] = Piwik_Db_Adapter::getAdapters();
+
+ $infos['json'] = false;
+ if(in_array('json', $extensions))
+ {
+ $infos['json'] = true;
+ }
+
+ $infos['xml'] = false;
+ if(in_array('xml', $extensions))
+ {
+ $infos['xml'] = true;
+ }
+
+ $needed_functions = array(
+ 'debug_backtrace',
+ 'create_function',
+ 'eval',
+ );
+ $infos['needed_functions'] = $needed_functions;
+ $infos['missing_functions'] = array();
+ foreach($needed_functions as $needed_function)
+ {
+ if(!self::functionExists($needed_function))
+ {
+ $infos['missing_functions'][] = $needed_function;
+ }
+ }
+
+ // 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();
+ $infos['gd_version'] = $gdInfo['GD Version'];
+ preg_match('/([0-9]{1})/', $gdInfo['GD Version'], $gdVersion);
+ if($gdVersion[0] >= 2)
+ {
+ $infos['gd_ok'] = true;
+ }
+ }
+
+ $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');
+
+ $infos['registerGlobals_ok'] = ini_get('register_globals') == 0;
+ $infos['memoryMinimum'] = $minimumMemoryLimit;
+
+ $infos['memory_ok'] = true;
+ $infos['memoryCurrent'] = '-1';
+
+ $raised = Piwik::raiseMemoryLimitIfNecessary();
+ if( $memoryValue = Piwik::getMemoryLimitValue() )
+ {
+ $infos['memoryCurrent'] = $memoryValue.'M';
+ $infos['memory_ok'] = $memoryValue >= $minimumMemoryLimit;
+ }
+
+ $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'][] = ''.Piwik_Translate('General_FileIntegrityWarningExplanation').'';
+ }
+ $infos['integrityErrorMessages'] = array_merge($infos['integrityErrorMessages'], array_slice($integrityInfo, 1));
+ }
+
+ $infos['timezone'] = Piwik::isTimezoneSupportEnabled();
+ return $infos;
+ }
+
+ /**
+ * Get protocol information, with the exception of HTTPS
+ *
+ * @return string protocol information
+ */
+ public static function getProtocolInformation()
+ {
+ if(Piwik_Common::getRequestVar('clientProtocol', 'http', 'string') == 'https')
+ {
+ 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;
+ }
+
+ /**
+ * 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)
+ {
+ // 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;
+ }
+}
diff --git a/oss/piwik/trunk/plugins/Installation/FormDatabaseSetup.php b/oss/piwik/trunk/plugins/Installation/FormDatabaseSetup.php
new file mode 100644
index 00000000..687883d0
--- /dev/null
+++ b/oss/piwik/trunk/plugins/Installation/FormDatabaseSetup.php
@@ -0,0 +1,54 @@
+ $port)
+ {
+ $adapters[$adapter] = $adapter;
+ }
+
+ $formElements = array(
+ array('text', 'host', Piwik_Translate('Installation_DatabaseSetupServer'), 'value='.'localhost'),
+ array('text', 'username', Piwik_Translate('Installation_DatabaseSetupLogin')),
+ array('password', 'password', Piwik_Translate('Installation_DatabaseSetupPassword')),
+ array('text', 'dbname', Piwik_Translate('Installation_DatabaseSetupDatabaseName')),
+ array('text', 'tables_prefix', Piwik_Translate('Installation_DatabaseSetupTablePrefix'), 'value='.'piwik_'),
+ array('select', 'adapter', Piwik_Translate('Installation_DatabaseSetupAdapter'), $adapters),
+ );
+ $this->addElements( $formElements );
+
+ $formRules = array();
+ foreach($formElements as $row)
+ {
+ if($row[1] != 'password' && $row[1] != 'tables_prefix')
+ {
+ $formRules[] = array($row[1], Piwik_Translate('General_Required', $row[2]), 'required');
+ }
+ }
+ $this->addRules( $formRules );
+
+ $this->addElement('submit', 'submit', Piwik_Translate('Installation_SubmitGo'));
+ }
+}
diff --git a/oss/piwik/trunk/plugins/Installation/FormFirstWebsiteSetup.php b/oss/piwik/trunk/plugins/Installation/FormFirstWebsiteSetup.php
new file mode 100644
index 00000000..efda7c7a
--- /dev/null
+++ b/oss/piwik/trunk/plugins/Installation/FormFirstWebsiteSetup.php
@@ -0,0 +1,68 @@
+getSubmitValue('timezone');
+ if(!empty($timezone))
+ {
+ Piwik_SitesManager_API::getInstance()->setDefaultTimezone($timezone);
+ }
+ } catch(Exception $e) {
+ $this->_errors['timezone'] = Piwik_Translate('General_NotValid', Piwik_Translate('Installation_Timezone'));
+ }
+ return parent::validate();
+ }
+
+ function init()
+ {
+ $urlToGoAfter = 'index.php' . Piwik_Url::getCurrentQueryString();
+
+ $urlExample = 'http://example.org';
+ $javascriptOnClickUrlExample = "\"javascript:if(this.value=='$urlExample'){this.value='http://';} this.style.color='black';\"";
+
+ $timezones = Piwik_SitesManager_API::getInstance()->getTimezonesList();
+ $timezones = array_merge(array('No timezone' => Piwik_Translate('SitesManager_SelectACity')), $timezones);
+
+ $formElements = array(
+ array('text', 'siteName', Piwik_Translate('Installation_SetupWebSiteName')),
+ array('text', 'url', Piwik_Translate('Installation_SetupWebSiteURL'), "style='color:rgb(153, 153, 153);' value=$urlExample onfocus=".$javascriptOnClickUrlExample." onclick=".$javascriptOnClickUrlExample),
+ array('select', 'timezone', Piwik_Translate('Installation_Timezone'), $timezones),
+
+ );
+ $this->addElements( $formElements );
+
+ $formRules = array();
+ foreach($formElements as $row)
+ {
+ $formRules[] = array($row[1], Piwik_Translate('General_Required', $row[2]), 'required');
+ }
+
+
+ $submitTimezone = $this->getSubmitValue('timezone');
+ if(!$this->isSubmitted()
+ || !empty($submitTimezone))
+ {
+ $this->setSelected('timezone', $submitTimezone);
+ }
+ $this->addRules( $formRules );
+
+ $this->addElement('submit', 'submit', Piwik_Translate('Installation_SubmitGo'));
+ }
+}
diff --git a/oss/piwik/trunk/plugins/Installation/FormGeneralSetup.php b/oss/piwik/trunk/plugins/Installation/FormGeneralSetup.php
new file mode 100644
index 00000000..08892db2
--- /dev/null
+++ b/oss/piwik/trunk/plugins/Installation/FormGeneralSetup.php
@@ -0,0 +1,87 @@
+getSubmitValue('login');
+ if(!empty($login))
+ {
+ Piwik::checkValidLoginString($login);
+ }
+ } catch(Exception $e) {
+ $this->_errors['login'] = $e->getMessage();
+ }
+ return parent::validate();
+ }
+
+ function init()
+ {
+ $urlToGoAfter = 'index.php' . Piwik_Url::getCurrentQueryString();
+
+ $formElements = array(
+ array('text', 'login', Piwik_Translate('Installation_SuperUserLogin')),
+ array('password', 'password', Piwik_Translate('Installation_Password')),
+ array('password', 'password_bis', Piwik_Translate('Installation_PasswordRepeat')),
+ array('text', 'email', Piwik_Translate('Installation_Email')),
+ array('checkbox', 'subscribe_newsletter_security', '', ' ' . Piwik_Translate('Installation_SecurityNewsletter')),
+ array('checkbox', 'subscribe_newsletter_community', '', ' '. Piwik_Translate('Installation_CommunityNewsletter')),
+ );
+ $this->addElements( $formElements );
+
+ if(!$this->isSubmitted()
+ || $this->getSubmitValue('subscribe_newsletter_community') == '1')
+ {
+ $this->setChecked('subscribe_newsletter_community');
+ }
+ if(!$this->isSubmitted()
+ || $this->getSubmitValue('subscribe_newsletter_security') == '1')
+ {
+ $this->setChecked('subscribe_newsletter_security');
+ }
+
+ $formRules = array();
+ foreach($formElements as $row)
+ {
+ // checkboxes are not required (form should validate when unchecked)
+ if(in_array($row[1],array('subscribe_newsletter_security','subscribe_newsletter_community')))
+ {
+ continue;
+ }
+ $formRules[] = array($row[1], Piwik_Translate('General_Required', $row[2]), 'required');
+ }
+
+ $formRules[] = array( 'email',
+ Piwik_Translate( 'UsersManager_ExceptionInvalidEmail'),
+ 'checkEmail'
+ );
+ $formRules[] = array( 'password',
+ Piwik_Translate( 'Installation_PasswordDoNotMatch'),
+ 'fieldHaveSameValue',
+ 'password_bis'
+ );
+
+ $this->addRules( $formRules );
+ $this->addElement('submit', 'submit', Piwik_Translate('Installation_SubmitGo'));
+ }
+}
diff --git a/oss/piwik/trunk/plugins/Installation/Installation.php b/oss/piwik/trunk/plugins/Installation/Installation.php
new file mode 100644
index 00000000..d4a41caf
--- /dev/null
+++ b/oss/piwik/trunk/plugins/Installation/Installation.php
@@ -0,0 +1,81 @@
+ Piwik_Translate('Installation_PluginDescription'),
+ 'author' => 'Piwik',
+ 'author_homepage' => 'http://piwik.org/',
+ 'version' => Piwik_Version::VERSION,
+ );
+
+ return $info;
+ }
+
+ function getListHooksRegistered()
+ {
+ $hooks = array(
+ 'FrontController.NoConfigurationFile' => 'dispatch',
+ 'FrontController.badConfigurationFile' => 'dispatch',
+ );
+ return $hooks;
+ }
+
+ public function setControllerToLoad( $newControllerName )
+ {
+ $this->installationControllerName = $newControllerName;
+ }
+
+ protected function getInstallationController()
+ {
+ return new $this->installationControllerName();
+ }
+
+ function dispatch($notification = null)
+ {
+ if($notification)
+ {
+ $exception = $notification->getNotificationObject();
+ $message = $exception->getMessage();
+ }
+ else
+ {
+ $message = '';
+ }
+
+ Piwik_Translate::getInstance()->loadUserTranslation();
+
+ Piwik_PostEvent('Installation.startInstallation', $this);
+
+ $step = Piwik_Common::getRequestVar('action', 'welcome', 'string');
+ $controller = $this->getInstallationController();
+ if(in_array($step, array_keys($controller->getInstallationSteps())) || $step == 'saveLanguage')
+ {
+ $controller->$step($message);
+ }
+ else
+ {
+ Piwik::exitWithErrorMessage(Piwik_Translate('Installation_NoConfigFound'));
+ }
+
+ exit;
+ }
+}
diff --git a/oss/piwik/trunk/plugins/Installation/View.php b/oss/piwik/trunk/plugins/Installation/View.php
new file mode 100644
index 00000000..10cddf51
--- /dev/null
+++ b/oss/piwik/trunk/plugins/Installation/View.php
@@ -0,0 +1,59 @@
+mainTemplate);
+
+ $this->subTemplateToLoad = $subtemplatePath;
+ $this->steps = array_keys($installationSteps);
+ $this->allStepsTitle = array_values($installationSteps);
+ $this->currentStepName = $currentStepName;
+ $this->showNextStep = false;
+ }
+
+ function render()
+ {
+ // prepare the all steps templates
+ $this->currentStepId = array_search($this->currentStepName, $this->steps);
+ $this->totalNumberOfSteps = count($this->steps);
+
+ $this->percentDone = round(($this->currentStepId) * 100 / ($this->totalNumberOfSteps-1));
+ $this->percentToDo = 100 - $this->percentDone;
+
+ $this->nextModuleName = '';
+ if(isset($this->steps[$this->currentStepId + 1]))
+ {
+ $this->nextModuleName = $this->steps[$this->currentStepId + 1];
+ }
+ $this->previousModuleName = '';
+ if(isset($this->steps[$this->currentStepId - 1]))
+ {
+ $this->previousModuleName = $this->steps[$this->currentStepId - 1];
+ }
+ $this->previousPreviousModuleName = '';
+ if(isset($this->steps[$this->currentStepId - 2]))
+ {
+ $this->previousPreviousModuleName = $this->steps[$this->currentStepId - 2];
+ }
+
+ return parent::render();
+ }
+}
diff --git a/oss/piwik/trunk/plugins/Installation/templates/allSteps.tpl b/oss/piwik/trunk/plugins/Installation/templates/allSteps.tpl
new file mode 100644
index 00000000..5cba61e4
--- /dev/null
+++ b/oss/piwik/trunk/plugins/Installation/templates/allSteps.tpl
@@ -0,0 +1,11 @@
+
"}
+{assign var=error value="
"}
+{assign var=warning value="
"}
+{assign var=link value="
"}
+
+| {'Installation_DatabaseServerVersion'|translate} | +{if isset($databaseVersionOk)}{$ok}{else}{$error}{/if} | +
| {'Installation_DatabaseClientVersion'|translate} | +{if isset($clientVersionWarning)}{$warning}{else}{$ok}{/if} | +
| + + {$clientVersionWarning} + + | +|
| {'Installation_DatabaseCreation'|translate} | +{if isset($databaseCreated)}{$ok}{else}{$error}{/if} | +
+{$link} {'Installation_Requirements'|translate} +
diff --git a/oss/piwik/trunk/plugins/Installation/templates/databaseSetup.tpl b/oss/piwik/trunk/plugins/Installation/templates/databaseSetup.tpl new file mode 100644 index 00000000..ff60befc --- /dev/null +++ b/oss/piwik/trunk/plugins/Installation/templates/databaseSetup.tpl @@ -0,0 +1,14 @@ +
+ {'Installation_DatabaseErrorConnect'|translate}:
+
+
+{/if}
+
+{$javascriptTag}
+
+
++ {'Installation_ContinueToPiwik'|translate} » +
diff --git a/oss/piwik/trunk/plugins/Installation/templates/firstWebsiteSetup.tpl b/oss/piwik/trunk/plugins/Installation/templates/firstWebsiteSetup.tpl new file mode 100644 index 00000000..f8d19f70 --- /dev/null +++ b/oss/piwik/trunk/plugins/Installation/templates/firstWebsiteSetup.tpl @@ -0,0 +1,23 @@ + + +{if isset($displayGeneralSetupSuccess)} + + {'Installation_GeneralSetupSuccess'|translate} +
+
+{/if}
+
+
+ {'Installation_SetupWebsiteError'|translate}:
+
"}
+{assign var=error value="
"}
+{assign var=warning value="
"}
+{assign var=link value="
"}
+
+| {'Installation_SystemCheckPhp'|translate} > {$infos.phpVersion_minimum} | +{if $infos.phpVersion_ok}{$ok}{else}{$error}{/if} | +
| PDO {'Installation_Extension'|translate} | +{if $infos.pdo_ok}{$ok} + {else}-{/if} + | +
| {$adapter} {'Installation_Extension'|translate} | +{$ok} | +
|
+
+ {'Installation_SystemCheckDatabaseHelp'|translate}
+
+ {if $infos.isWindows}
+ {'Installation_SystemCheckWinPdoAndMysqliHelp'|translate:" |
+ |
| + {'Installation_SystemCheckJson'|translate} + | +{if $infos.json || $infos.xml}{$ok} + {else}{$error}{/if} + | +
|
+
+ {'Installation_SystemCheckJsonHelp'|translate}
+ + {if version_compare($infos.phpVersion, '5.2.0') >= 0} + {'Installation_SystemCheckJsonSite'|translate} + {else} + {'Installation_SystemCheckXmlSite'|translate} + {/if} + + |
+ |
| {'Installation_SystemCheckExtensions'|translate} | +{foreach from=$infos.needed_extensions item=needed_extension}
+ {$needed_extension}
+ {if in_array($needed_extension, $infos.missing_extensions)}
+ {$error}
+ {else}
+ {$ok}
+ {/if}
+ + {/foreach} + |
+
|
+
+ {foreach from=$infos.missing_extensions item=missing_extension}
+ + {$helpMessages[$missing_extension]|translate} + + {/foreach} + + |
+ |
| {'Installation_SystemCheckFunctions'|translate} | +{foreach from=$infos.needed_functions item=needed_function}
+ {$needed_function}
+ {if in_array($needed_function, $infos.missing_functions)}
+ {$error}
+ + {$helpMessages[$needed_function]|translate} + + {else} + {$ok}+ {/if} + {/foreach} + |
+
| + {'Installation_SystemCheckWriteDirs'|translate} + | +
+
+ {foreach from=$infos.directories key=dir item=bool}
+ {if $bool}{$ok}{else}
+ {$error}{/if}
+ {$dir}
+ + {/foreach} + + |
+
chmod a+w {$dir}| {'Installation_SystemCheckFileIntegrity'|translate} | ++ {if empty($infos.integrityErrorMessages)} + {$ok} + {else} + {if $infos.integrity} + {$warning} {$infos.integrityErrorMessages[0]} + {else} + {$error} {$infos.integrityErrorMessages[0]} + {/if} + {if count($infos.integrityErrorMessages) > 1} + + {/if} + {/if} + | +
| {'Installation_SystemCheckMemoryLimit'|translate} | +
+ {$infos.memoryCurrent}
+ {if $infos.memory_ok}{$ok}{else}{$warning}
+ {'Installation_SystemCheckMemoryLimitHelp'|translate}{/if} + |
+
| {'SitesManager_Timezone'|translate} | +
+ {if $infos.timezone}{$ok}{else}{$warning}
+ {'SitesManager_AdvancedTimezoneSupportNotFound'|translate}{/if} + |
+
| {'Installation_SystemCheckOpenURL'|translate} | +
+ {if $infos.openurl}{$infos.openurl} {$ok}{else}{$warning} {'Installation_SystemCheckOpenURLHelp'|translate}{/if} + |
+
| {'Installation_SystemCheckXml'|translate} | +
+ {if $infos.xml}{$ok}{else}{$warning} {'Installation_SystemCheckXmlHelp'|translate}{/if} + |
+
| {'Installation_SystemCheckGD'|translate} | +
+ {if $infos.gd_ok}{$ok}{else}{$warning} {'Installation_SystemCheckGDHelp'|translate}{/if} + |
+
| {'Installation_SystemCheckMbstring'|translate} | +
+ {if $infos.multibyte_ok}{$ok}{else}{$warning} {'Installation_SystemCheckMbstringHelp'|translate}{/if} + |
+
| {'Installation_SystemCheckFunctions'|translate} | +{foreach from=$infos.desired_functions item=desired_function}
+ {$desired_function}
+ {if in_array($desired_function, $infos.missing_desired_functions)}
+ {$warning}
+ + {$helpMessages[$desired_function]|translate} + + {else} + {$ok}+ {/if} + {/foreach} + |
+
| {'Installation_SystemCheckProtocol'|translate} | +
+ {if $infos.protocol_ok}{$ok}{else}{$warning} {$infos.protocol} {'Installation_SystemCheckProtocolHelp'|translate} [General]reverse_proxy = 1{/if} + |
+
| {'Installation_SystemCheckIpv4'|translate} | +
+ {if $infos.isIpv4}{$ok}{else}{$warning} {'Installation_SystemCheckIpv4Help'|translate}{/if} + |
+
+{$link} {'Installation_Requirements'|translate} +
+ +{if !$showNextStep} +{literal} + +{/literal} ++ {'General_Refresh'|translate} » +
+{/if} diff --git a/oss/piwik/trunk/plugins/Installation/templates/tablesCreation.tpl b/oss/piwik/trunk/plugins/Installation/templates/tablesCreation.tpl new file mode 100644 index 00000000..028799e9 --- /dev/null +++ b/oss/piwik/trunk/plugins/Installation/templates/tablesCreation.tpl @@ -0,0 +1,63 @@ +
+ {'Installation_TablesWarningHelp'|translate}
+{'Installation_TablesReuse'|translate} »
+ {else} +« {'Installation_GoBackAndDefinePrefix'|translate}
+ {/if} + +{'Installation_TablesDelete'|translate} »
+{/if} + +{if isset($existingTablesDeleted)} +

{'Installation_ConfigurationHelp'|translate}
++ {'General_Refresh'|translate} » +
+{/if} diff --git a/oss/piwik/trunk/plugins/LanguagesManager/API.php b/oss/piwik/trunk/plugins/LanguagesManager/API.php new file mode 100644 index 00000000..05910ede --- /dev/null +++ b/oss/piwik/trunk/plugins/LanguagesManager/API.php @@ -0,0 +1,197 @@ +getAvailableLanguages()); + } + + /** + * Return array of available languages + * + * @return array Arry of strings, each containing its ISO language code + */ + public function getAvailableLanguages() + { + if(!is_null($this->languageNames)) + { + return $this->languageNames; + } + $path = PIWIK_INCLUDE_PATH . "/lang/"; + $languages = glob($path . "*.php"); + $pathLength = strlen($path); + $languageNames = array(); + foreach($languages as $language) + { + $languageNames[] = substr($language, $pathLength, -strlen('.php')); + } + $this->languageNames = $languageNames; + return $languageNames; + } + + /** + * Return information on translations (code, language, % translated, etc) + * + * @return array Array of arrays + */ + public function getAvailableLanguagesInfo() + { + require PIWIK_INCLUDE_PATH . '/lang/en.php'; + $englishTranslation = $translations; + $filenames = $this->getAvailableLanguages(); + $languagesInfo = array(); + foreach($filenames as $filename) + { + require PIWIK_INCLUDE_PATH . "/lang/$filename.php"; + $translationStringsDone = array_intersect_key($englishTranslation, array_filter($translations, 'strlen')); + $percentageComplete = count($translationStringsDone) / count($englishTranslation); + $percentageComplete = round(100 * $percentageComplete, 0); + $languageInfo = array( 'code' => $filename, + 'name' => $translations['General_OriginalLanguageName'], + 'english_name' => $translations['General_EnglishLanguageName'], + 'translators' => $translations['General_TranslatorName'], + 'translators_email' => $translations['General_TranslatorEmail'], + 'percentage_complete' => $percentageComplete . '%', + ); + $languagesInfo[] = $languageInfo; + } + return $languagesInfo; + } + + /** + * Return array of available languages + * + * @return array Arry of array, each containing its ISO language code and name of the language + */ + public function getAvailableLanguageNames() + { + if(!is_null($this->availableLanguageNames)) + { + return $this->availableLanguageNames; + } + + $filenames = $this->getAvailableLanguages(); + $languagesInfo = array(); + foreach($filenames as $filename) + { + require PIWIK_INCLUDE_PATH . "/lang/$filename.php"; + $languagesInfo[] = array( 'code' => $filename, 'name' => $translations['General_OriginalLanguageName']); + } + $this->availableLanguageNames = $languagesInfo; + return $this->availableLanguageNames; + } + + /** + * Returns translation strings by language + * + * @param string $languageCode ISO language code + * @return array|false Array of arrays, each containing 'label' (translation index) and 'value' (translated string); false if language unavailable + */ + public function getTranslationsForLanguage($languageCode) + { + if(!$this->isLanguageAvailable($languageCode)) + { + return false; + } + require PIWIK_INCLUDE_PATH . "/lang/$languageCode.php"; + $languageInfo = array(); + foreach($translations as $key => $value) + { + $languageInfo[] = array('label' => $key, 'value' => $value); + } + return $languageInfo; + } + + /** + * Returns the language for the user + * + * @param string $login + * @param string|false $layout + */ + public function getLanguageForUser( $login ) + { + Piwik::checkUserIsSuperUserOrTheUser($login); + return Piwik_FetchOne('SELECT language FROM '.Piwik_Common::prefixTable('user_language') . + ' WHERE login = ? ', array($login )); + } + + /** + * Sets the language for the user + * + * @param string $login + * @param string $languageCode + */ + public function setLanguageForUser($login, $languageCode) + { + Piwik::checkUserIsSuperUserOrTheUser($login); + $paramsBind = array($login, $languageCode, $languageCode); + Piwik_Query('INSERT INTO '.Piwik_Common::prefixTable('user_language') . + ' (login, language) + VALUES (?,?) + ON DUPLICATE KEY UPDATE language=?', + $paramsBind); + } + + /** + * Returns the langage for the session + * + * @return string|null + */ + public function getLanguageForSession() + { + $session = new Zend_Session_Namespace("Piwik_LanguagesManager"); + if(isset($session->language)) + { + return $session->language; + } + return null; + } + + /** + * Set the language for the session + * + * @param string $languageCode ISO language code + */ + public function setLanguageForSession($languageCode) + { + $session = new Zend_Session_Namespace("Piwik_LanguagesManager"); + $session->language = $languageCode; + } +} diff --git a/oss/piwik/trunk/plugins/LanguagesManager/Controller.php b/oss/piwik/trunk/plugins/LanguagesManager/Controller.php new file mode 100644 index 00000000..b7cb43c8 --- /dev/null +++ b/oss/piwik/trunk/plugins/LanguagesManager/Controller.php @@ -0,0 +1,36 @@ +setLanguageForSession($language); + if(Zend_Registry::isRegistered('access')) { + $currentUser = Piwik::getCurrentUserLogin(); + if($currentUser && $currentUser !== 'anonymous') + { + Piwik_LanguagesManager_API::getInstance()->setLanguageForUser($currentUser, $language); + } + } + Piwik_Url::redirectToReferer(); + } +} diff --git a/oss/piwik/trunk/plugins/LanguagesManager/LanguagesManager.php b/oss/piwik/trunk/plugins/LanguagesManager/LanguagesManager.php new file mode 100644 index 00000000..39fe26ab --- /dev/null +++ b/oss/piwik/trunk/plugins/LanguagesManager/LanguagesManager.php @@ -0,0 +1,154 @@ + Piwik_Translate('LanguagesManager_PluginDescription'), + 'author' => 'Piwik', + 'author_homepage' => 'http://piwik.org/', + 'version' => Piwik_Version::VERSION, + ); + } + + public function getListHooksRegistered() + { + return array( + 'template_css_import' => 'css', + 'template_topBar' => 'showLanguagesSelector', + 'Translate.getLanguageToLoad' => 'getLanguageToLoad', + 'UsersManager.deleteUser' => 'deleteUserLanguage', + ); + } + + function css() + { + echo "\n"; + } + + /** + * Show styled language selection drop-down list + * + * @param string $url The form action. Default is to save language. + */ + function showLanguagesSelector() + { + // don't use Piwik_View::factory() here + $view = new Piwik_View("LanguagesManager/templates/languages.tpl"); + $view->languages = Piwik_LanguagesManager_API::getInstance()->getAvailableLanguageNames(); + $view->currentLanguageCode = self::getLanguageCodeForCurrentUser(); + $view->currentLanguageName = self::getLanguageNameForCurrentUser(); + echo $view->render(); + } + + function getLanguageToLoad($notification) + { + $language =& $notification->getNotificationObject(); + $language = self::getLanguageCodeForCurrentUser(); + } + + function deleteUserLanguage($notification) + { + $userLogin = $notification->getNotificationObject(); + Piwik_Query('DELETE FROM ' . Piwik_Common::prefixTable('user_language') . ' WHERE login = ?', $userLogin); + } + + /** + * @throws Exception if non-recoverable error + */ + public function install() + { + // we catch the exception + try{ + $sql = "CREATE TABLE ". Piwik_Common::prefixTable('user_language')." ( + login VARCHAR( 100 ) NOT NULL , + language VARCHAR( 10 ) NOT NULL , + PRIMARY KEY ( login ) + ) DEFAULT CHARSET=utf8 " ; + Piwik_Exec($sql); + } catch(Exception $e){ + // mysql code error 1050:table already exists + // see bug #153 http://dev.piwik.org/trac/ticket/153 + if(!Zend_Registry::get('db')->isErrNo($e, '1050')) + { + throw $e; + } + } + } + + /** + * @throws Exception if non-recoverable error + */ + public function uninstall() + { + $sql = "DROP TABLE ". Piwik_Common::prefixTable('user_language') ; + Piwik_Exec($sql); + } + + /** + * @return string Two letters language code, eg. "fr" + */ + static public function getLanguageCodeForCurrentUser() + { + $languageCode = self::getLanguageFromPreferences(); + if(!Piwik_LanguagesManager_API::getInstance()->isLanguageAvailable($languageCode)) + { + $languageCode = Piwik_Common::extractLanguageCodeFromBrowserLanguage(Piwik_Common::getBrowserLanguage(), Piwik_LanguagesManager_API::getInstance()->getAvailableLanguages()); + } + if(!Piwik_LanguagesManager_API::getInstance()->isLanguageAvailable($languageCode)) + { + $languageCode = 'en'; + } + return $languageCode; + } + + /** + * @return string Full english language string, eg. "French" + */ + static public function getLanguageNameForCurrentUser() + { + $languageCode = self::getLanguageCodeForCurrentUser(); + $languages = Piwik_LanguagesManager_API::getInstance()->getAvailableLanguageNames(); + foreach($languages as $language) + { + if($language['code'] === $languageCode) + { + return $language['name']; + } + } + } + + /** + * @return string|false if language preference could not be loaded + */ + static protected function getLanguageFromPreferences() + { + if ($language = Piwik_LanguagesManager_API::getInstance()->getLanguageForSession()) + { + return $language; + } + + try { + $currentUser = Piwik::getCurrentUserLogin(); + return Piwik_LanguagesManager_API::getInstance()->getLanguageForUser($currentUser); + } catch(Exception $e) { + return false; + } + } +} diff --git a/oss/piwik/trunk/plugins/LanguagesManager/templates/languages.tpl b/oss/piwik/trunk/plugins/LanguagesManager/templates/languages.tpl new file mode 100644 index 00000000..444caf72 --- /dev/null +++ b/oss/piwik/trunk/plugins/LanguagesManager/templates/languages.tpl @@ -0,0 +1,22 @@ + + + + {literal} + {/literal} +