PageRenderTime 36ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/plugins/Installation/Controller.php

https://github.com/quarkness/piwik
PHP | 893 lines | 659 code | 119 blank | 115 comment | 72 complexity | 1037986f80cf56a8a3ef16a463c91493 MD5 | raw file
  1. <?php
  2. /**
  3. * Piwik - Open source web analytics
  4. *
  5. * @link http://piwik.org
  6. * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
  7. * @version $Id$
  8. *
  9. * @category Piwik_Plugins
  10. * @package Piwik_Installation
  11. */
  12. /**
  13. * Installation controller
  14. *
  15. * @package Piwik_Installation
  16. */
  17. class Piwik_Installation_Controller extends Piwik_Controller
  18. {
  19. // public so plugins can add/delete installation steps
  20. public $steps = array(
  21. 'welcome' => 'Installation_Welcome',
  22. 'systemCheck' => 'Installation_SystemCheck',
  23. 'databaseSetup' => 'Installation_DatabaseSetup',
  24. 'databaseCheck' => 'Installation_DatabaseCheck',
  25. 'tablesCreation' => 'Installation_Tables',
  26. 'generalSetup' => 'Installation_SuperUser',
  27. 'firstWebsiteSetup' => 'Installation_SetupWebsite',
  28. 'displayJavascriptCode' => 'Installation_JsTag',
  29. 'finished' => 'Installation_Congratulations',
  30. );
  31. protected $pathView = 'Installation/templates/';
  32. protected $session;
  33. public function __construct()
  34. {
  35. $this->session = new Piwik_Session_Namespace('Piwik_Installation');
  36. if(!isset($this->session->currentStepDone))
  37. {
  38. $this->session->currentStepDone = '';
  39. $this->session->skipThisStep = array();
  40. }
  41. Piwik_PostEvent('InstallationController.construct', $this);
  42. }
  43. /**
  44. * Get installation steps
  45. *
  46. * @return array installation steps
  47. */
  48. public function getInstallationSteps()
  49. {
  50. return $this->steps;
  51. }
  52. /**
  53. * Get default action (first installation step)
  54. *
  55. * @return string function name
  56. */
  57. function getDefaultAction()
  58. {
  59. $steps = array_keys($this->steps);
  60. return $steps[0];
  61. }
  62. /**
  63. * Installation Step 1: Welcome
  64. */
  65. function welcome($message = false)
  66. {
  67. // Delete merged js/css files to force regenerations based on updated activated plugin list
  68. Piwik::deleteAllCacheOnUpdate();
  69. $view = new Piwik_Installation_View(
  70. $this->pathView . 'welcome.tpl',
  71. $this->getInstallationSteps(),
  72. __FUNCTION__
  73. );
  74. $view->newInstall = !file_exists(Piwik_Config::getDefaultUserConfigPath());
  75. $view->errorMessage = $message;
  76. $this->skipThisStep( __FUNCTION__ );
  77. $view->showNextStep = $view->newInstall;
  78. $this->session->currentStepDone = __FUNCTION__;
  79. echo $view->render();
  80. }
  81. /**
  82. * Installation Step 2: System Check
  83. */
  84. function systemCheck()
  85. {
  86. $this->checkPreviousStepIsValid( __FUNCTION__ );
  87. $view = new Piwik_Installation_View(
  88. $this->pathView . 'systemCheck.tpl',
  89. $this->getInstallationSteps(),
  90. __FUNCTION__
  91. );
  92. $this->skipThisStep( __FUNCTION__ );
  93. $view->infos = self::getSystemInformation();
  94. $this->session->general_infos = $view->infos['general_infos'];
  95. $view->helpMessages = array(
  96. 'zlib' => 'Installation_SystemCheckZlibHelp',
  97. 'SPL' => 'Installation_SystemCheckSplHelp',
  98. 'iconv' => 'Installation_SystemCheckIconvHelp',
  99. 'json' => 'Installation_SystemCheckWarnJsonHelp',
  100. 'libxml' => 'Installation_SystemCheckWarnLibXmlHelp',
  101. 'dom' => 'Installation_SystemCheckWarnDomHelp',
  102. 'SimpleXML' => 'Installation_SystemCheckWarnSimpleXMLHelp',
  103. 'set_time_limit' => 'Installation_SystemCheckTimeLimitHelp',
  104. 'mail' => 'Installation_SystemCheckMailHelp',
  105. 'parse_ini_file' => 'Installation_SystemCheckParseIniFileHelp',
  106. 'glob' => 'Installation_SystemCheckGlobHelp',
  107. 'debug_backtrace' => 'Installation_SystemCheckDebugBacktraceHelp',
  108. 'create_function' => 'Installation_SystemCheckCreateFunctionHelp',
  109. 'eval' => 'Installation_SystemCheckEvalHelp',
  110. 'gzcompress' => 'Installation_SystemCheckGzcompressHelp',
  111. 'gzuncompress' => 'Installation_SystemCheckGzuncompressHelp',
  112. 'pack' => 'Installation_SystemCheckPackHelp',
  113. );
  114. $view->problemWithSomeDirectories = (false !== array_search(false, $view->infos['directories']));
  115. $view->showNextStep = !$view->problemWithSomeDirectories
  116. && $view->infos['phpVersion_ok']
  117. && count($view->infos['adapters'])
  118. && !count($view->infos['missing_extensions'])
  119. && !count($view->infos['missing_functions'])
  120. ;
  121. $this->session->currentStepDone = __FUNCTION__;
  122. echo $view->render();
  123. }
  124. /**
  125. * Installation Step 3: Database Set-up
  126. */
  127. function databaseSetup()
  128. {
  129. $this->checkPreviousStepIsValid( __FUNCTION__ );
  130. // case the user hits the back button
  131. $this->session->skipThisStep = array(
  132. 'firstWebsiteSetup' => false,
  133. 'displayJavascriptCode' => false,
  134. );
  135. $view = new Piwik_Installation_View(
  136. $this->pathView . 'databaseSetup.tpl',
  137. $this->getInstallationSteps(),
  138. __FUNCTION__
  139. );
  140. $this->skipThisStep( __FUNCTION__ );
  141. $view->showNextStep = false;
  142. $form = new Piwik_Installation_FormDatabaseSetup();
  143. if($form->validate())
  144. {
  145. $adapter = $form->getSubmitValue('adapter');
  146. $port = Piwik_Db_Adapter::getDefaultPortForAdapter($adapter);
  147. $dbInfos = array(
  148. 'host' => $form->getSubmitValue('host'),
  149. 'username' => $form->getSubmitValue('username'),
  150. 'password' => $form->getSubmitValue('password'),
  151. 'dbname' => $form->getSubmitValue('dbname'),
  152. 'tables_prefix' => $form->getSubmitValue('tables_prefix'),
  153. 'adapter' => $adapter,
  154. 'port' => $port,
  155. );
  156. if(($portIndex = strpos($dbInfos['host'], '/')) !== false)
  157. {
  158. // unix_socket=/path/sock.n
  159. $dbInfos['port'] = substr($dbInfos['host'], $portIndex);
  160. $dbInfos['host'] = '';
  161. }
  162. else if(($portIndex = strpos($dbInfos['host'], ':')) !== false)
  163. {
  164. // host:port
  165. $dbInfos['port'] = substr($dbInfos['host'], $portIndex + 1 );
  166. $dbInfos['host'] = substr($dbInfos['host'], 0, $portIndex);
  167. }
  168. try{
  169. try {
  170. @Piwik::createDatabaseObject($dbInfos);
  171. $this->session->databaseCreated = true;
  172. } catch (Zend_Db_Adapter_Exception $e) {
  173. $db = Piwik_Db_Adapter::factory($adapter, $dbInfos, $connect = false);
  174. // database not found, we try to create it
  175. if($db->isErrNo($e, '1049'))
  176. {
  177. $dbInfosConnectOnly = $dbInfos;
  178. $dbInfosConnectOnly['dbname'] = null;
  179. @Piwik::createDatabaseObject($dbInfosConnectOnly);
  180. @Piwik::createDatabase($dbInfos['dbname']);
  181. $this->session->databaseCreated = true;
  182. }
  183. else
  184. {
  185. throw $e;
  186. }
  187. }
  188. Piwik::checkDatabaseVersion();
  189. $this->session->databaseVersionOk = true;
  190. $this->session->db_infos = $dbInfos;
  191. $this->redirectToNextStep( __FUNCTION__ );
  192. } catch(Exception $e) {
  193. $view->errorMessage = $e->getMessage();
  194. }
  195. }
  196. $view->addForm($form);
  197. echo $view->render();
  198. }
  199. /**
  200. * Installation Step 4: Database Check
  201. */
  202. function databaseCheck()
  203. {
  204. $this->checkPreviousStepIsValid( __FUNCTION__ );
  205. $view = new Piwik_Installation_View(
  206. $this->pathView . 'databaseCheck.tpl',
  207. $this->getInstallationSteps(),
  208. __FUNCTION__
  209. );
  210. $error = false;
  211. $this->skipThisStep( __FUNCTION__ );
  212. if(isset($this->session->databaseVersionOk)
  213. && $this->session->databaseVersionOk === true)
  214. {
  215. $view->databaseVersionOk = true;
  216. }
  217. else
  218. {
  219. $error = true;
  220. }
  221. if(isset($this->session->databaseCreated)
  222. && $this->session->databaseCreated === true)
  223. {
  224. $dbInfos = $this->session->db_infos;
  225. $view->databaseName = $dbInfos['dbname'];
  226. $view->databaseCreated = true;
  227. }
  228. else
  229. {
  230. $error = true;
  231. }
  232. $this->createDbFromSessionInformation();
  233. $db = Zend_Registry::get('db');
  234. try {
  235. $db->checkClientVersion();
  236. } catch(Exception $e) {
  237. $view->clientVersionWarning = $e->getMessage();
  238. $error = true;
  239. }
  240. if(!Piwik::isDatabaseConnectionUTF8())
  241. {
  242. $dbInfos = $this->session->db_infos;
  243. $dbInfos['charset'] = 'utf8';
  244. $this->session->db_infos = $dbInfos;
  245. }
  246. $view->showNextStep = true;
  247. $this->session->currentStepDone = __FUNCTION__;
  248. if($error === false)
  249. {
  250. $this->redirectToNextStep(__FUNCTION__);
  251. }
  252. echo $view->render();
  253. }
  254. /**
  255. * Installation Step 5: Table Creation
  256. */
  257. function tablesCreation()
  258. {
  259. $this->checkPreviousStepIsValid( __FUNCTION__ );
  260. $view = new Piwik_Installation_View(
  261. $this->pathView . 'tablesCreation.tpl',
  262. $this->getInstallationSteps(),
  263. __FUNCTION__
  264. );
  265. $this->skipThisStep( __FUNCTION__ );
  266. $this->createDbFromSessionInformation();
  267. if(Piwik_Common::getRequestVar('deleteTables', 0, 'int') == 1)
  268. {
  269. Piwik::dropTables();
  270. $view->existingTablesDeleted = true;
  271. // when the user decides to drop the tables then we dont skip the next steps anymore
  272. // workaround ZF-1743
  273. $tmp = $this->session->skipThisStep;
  274. $tmp['firstWebsiteSetup'] = false;
  275. $tmp['displayJavascriptCode'] = false;
  276. $this->session->skipThisStep = $tmp;
  277. }
  278. $tablesInstalled = Piwik::getTablesInstalled();
  279. $tablesToInstall = Piwik::getTablesNames();
  280. $view->tablesInstalled = '';
  281. if(count($tablesInstalled) > 0)
  282. {
  283. // we have existing tables
  284. $view->tablesInstalled = implode(', ', $tablesInstalled);
  285. $view->someTablesInstalled = true;
  286. $minimumCountPiwikTables = 17;
  287. $baseTablesInstalled = preg_grep('/archive_numeric|archive_blob/', $tablesInstalled, PREG_GREP_INVERT);
  288. Piwik::createAccessObject();
  289. Piwik::setUserIsSuperUser();
  290. if(count($baseTablesInstalled) >= $minimumCountPiwikTables &&
  291. count(Piwik_SitesManager_API::getInstance()->getAllSitesId()) > 0 &&
  292. count(Piwik_UsersManager_API::getInstance()->getUsers()) > 0)
  293. {
  294. $view->showReuseExistingTables = true;
  295. // when the user reuses the same tables we skip the website creation step
  296. // workaround ZF-1743
  297. $tmp = $this->session->skipThisStep;
  298. $tmp['firstWebsiteSetup'] = true;
  299. $tmp['displayJavascriptCode'] = true;
  300. $this->session->skipThisStep = $tmp;
  301. }
  302. }
  303. else
  304. {
  305. Piwik::createTables();
  306. Piwik::createAnonymousUser();
  307. $updater = new Piwik_Updater();
  308. $updater->recordComponentSuccessfullyUpdated('core', Piwik_Version::VERSION);
  309. $view->tablesCreated = true;
  310. $view->showNextStep = true;
  311. }
  312. $this->session->currentStepDone = __FUNCTION__;
  313. echo $view->render();
  314. }
  315. /**
  316. * Installation Step 6: General Set-up (superuser login/password/email and subscriptions)
  317. */
  318. function generalSetup()
  319. {
  320. $this->checkPreviousStepIsValid( __FUNCTION__ );
  321. $view = new Piwik_Installation_View(
  322. $this->pathView . 'generalSetup.tpl',
  323. $this->getInstallationSteps(),
  324. __FUNCTION__
  325. );
  326. $this->skipThisStep( __FUNCTION__ );
  327. $form = new Piwik_Installation_FormGeneralSetup();
  328. if($form->validate())
  329. {
  330. $superUserInfos = array(
  331. 'login' => $form->getSubmitValue('login'),
  332. 'password' => md5( $form->getSubmitValue('password') ),
  333. 'email' => $form->getSubmitValue('email'),
  334. 'salt' => Piwik_Common::generateUniqId(),
  335. );
  336. $this->session->superuser_infos = $superUserInfos;
  337. $url = Zend_Registry::get('config')->General->api_service_url;
  338. $url .= '/1.0/subscribeNewsletter/';
  339. $params = array(
  340. 'email' => $form->getSubmitValue('email'),
  341. 'security' => $form->getSubmitValue('subscribe_newsletter_security'),
  342. 'community' => $form->getSubmitValue('subscribe_newsletter_community'),
  343. 'url' => Piwik_Url::getCurrentUrlWithoutQueryString(),
  344. );
  345. if($params['security'] == '1'
  346. || $params['community'] == '1')
  347. {
  348. if( !isset($params['security'])) { $params['security'] = '0'; }
  349. if( !isset($params['community'])) { $params['community'] = '0'; }
  350. $url .= '?' . http_build_query($params, '', '&');
  351. try {
  352. Piwik_Http::sendHttpRequest($url, $timeout = 2);
  353. } catch(Exception $e) {
  354. // e.g., disable_functions = fsockopen; allow_url_open = Off
  355. }
  356. }
  357. $this->redirectToNextStep( __FUNCTION__ );
  358. }
  359. $view->addForm($form);
  360. echo $view->render();
  361. }
  362. /**
  363. * Installation Step 7: Configure first web-site
  364. */
  365. public function firstWebsiteSetup()
  366. {
  367. $this->checkPreviousStepIsValid( __FUNCTION__ );
  368. $view = new Piwik_Installation_View(
  369. $this->pathView . 'firstWebsiteSetup.tpl',
  370. $this->getInstallationSteps(),
  371. __FUNCTION__
  372. );
  373. $this->skipThisStep( __FUNCTION__ );
  374. $form = new Piwik_Installation_FormFirstWebsiteSetup();
  375. if( !isset($this->session->generalSetupSuccessMessage))
  376. {
  377. $view->displayGeneralSetupSuccess = true;
  378. $this->session->generalSetupSuccessMessage = true;
  379. }
  380. $this->initObjectsToCallAPI();
  381. if($form->validate())
  382. {
  383. $name = urlencode($form->getSubmitValue('siteName'));
  384. $url = urlencode($form->getSubmitValue('url'));
  385. $ecommerce = (int)$form->getSubmitValue('ecommerce');
  386. $request = new Piwik_API_Request("
  387. method=SitesManager.addSite
  388. &siteName=$name
  389. &urls=$url
  390. &ecommerce=$ecommerce
  391. &format=original
  392. ");
  393. try {
  394. $result = $request->process();
  395. $this->session->site_idSite = $result;
  396. $this->session->site_name = $name;
  397. $this->session->site_url = $url;
  398. $this->redirectToNextStep( __FUNCTION__ );
  399. } catch(Exception $e) {
  400. $view->errorMessage = $e->getMessage();
  401. }
  402. }
  403. $view->addForm($form);
  404. echo $view->render();
  405. }
  406. /**
  407. * Installation Step 8: Display JavaScript tracking code
  408. */
  409. public function displayJavascriptCode()
  410. {
  411. $this->checkPreviousStepIsValid( __FUNCTION__ );
  412. $view = new Piwik_Installation_View(
  413. $this->pathView . 'displayJavascriptCode.tpl',
  414. $this->getInstallationSteps(),
  415. __FUNCTION__
  416. );
  417. $this->skipThisStep( __FUNCTION__ );
  418. if( !isset($this->session->firstWebsiteSetupSuccessMessage))
  419. {
  420. $view->displayfirstWebsiteSetupSuccess = true;
  421. $this->session->firstWebsiteSetupSuccessMessage = true;
  422. }
  423. $siteName = $this->session->site_name;
  424. $idSite = $this->session->site_idSite;
  425. // Load the Tracking code and help text from the SitesManager
  426. $viewTrackingHelp = new Piwik_View('SitesManager/templates/DisplayJavascriptCode.tpl');
  427. $viewTrackingHelp->displaySiteName = $siteName;
  428. $viewTrackingHelp->jsTag = Piwik::getJavascriptCode($idSite, Piwik_Url::getCurrentUrlWithoutFileName());
  429. $viewTrackingHelp->idSite = $idSite;
  430. $viewTrackingHelp->piwikUrl = Piwik_Url::getCurrentUrlWithoutFileName();
  431. // Assign the html output to a smarty variable
  432. $view->trackingHelp = $viewTrackingHelp->render();
  433. $view->displaySiteName = urldecode($siteName);
  434. $view->showNextStep = true;
  435. $this->session->currentStepDone = __FUNCTION__;
  436. echo $view->render();
  437. }
  438. /**
  439. * Installation Step 9: Finished!
  440. */
  441. public function finished()
  442. {
  443. $this->checkPreviousStepIsValid( __FUNCTION__ );
  444. $view = new Piwik_Installation_View(
  445. $this->pathView . 'finished.tpl',
  446. $this->getInstallationSteps(),
  447. __FUNCTION__
  448. );
  449. $this->skipThisStep( __FUNCTION__ );
  450. if(!file_exists(Piwik_Config::getDefaultUserConfigPath()))
  451. {
  452. $this->writeConfigFileFromSession();
  453. }
  454. $view->showNextStep = false;
  455. $this->session->currentStepDone = __FUNCTION__;
  456. echo $view->render();
  457. $this->session->unsetAll();
  458. }
  459. /**
  460. * Instantiate access and log objects
  461. */
  462. protected function initObjectsToCallAPI()
  463. {
  464. // connect to the database using the DB infos currently in the session
  465. $this->createDbFromSessionInformation();
  466. Piwik::createAccessObject();
  467. Piwik::setUserIsSuperUser();
  468. Piwik::createLogObject();
  469. }
  470. /**
  471. * Create database connection from session-store
  472. */
  473. protected function createDbFromSessionInformation()
  474. {
  475. $dbInfos = $this->session->db_infos;
  476. Zend_Registry::get('config')->disableSavingConfigurationFileUpdates();
  477. Zend_Registry::get('config')->database = $dbInfos;
  478. Piwik::createDatabaseObject($dbInfos);
  479. }
  480. /**
  481. * Write configuration file from session-store
  482. */
  483. protected function writeConfigFileFromSession()
  484. {
  485. if(!isset($this->session->superuser_infos)
  486. || !isset($this->session->db_infos))
  487. {
  488. return;
  489. }
  490. $config = Zend_Registry::get('config');
  491. $config->superuser = $this->session->superuser_infos;
  492. $dbInfos = $this->session->db_infos;
  493. $config->database = $dbInfos;
  494. if(!empty($this->session->general_infos))
  495. {
  496. $config->General = $this->session->general_infos;
  497. }
  498. unset($this->session->superuser_infos);
  499. unset($this->session->db_infos);
  500. unset($this->session->general_infos);
  501. }
  502. /**
  503. * Save language selection in session-store
  504. */
  505. public function saveLanguage()
  506. {
  507. $language = Piwik_Common::getRequestVar('language');
  508. Piwik_LanguagesManager::setLanguageForSession($language);
  509. Piwik_Url::redirectToReferer();
  510. }
  511. /**
  512. * The previous step is valid if it is either
  513. * - any step before (OK to go back)
  514. * - the current step (case when validating a form)
  515. * If step is invalid, then exit.
  516. *
  517. * @param string $currentStep Current step
  518. */
  519. protected function checkPreviousStepIsValid( $currentStep )
  520. {
  521. $error = false;
  522. if(empty($this->session->currentStepDone))
  523. {
  524. $error = true;
  525. }
  526. else if($currentStep == 'finished' && $this->session->currentStepDone == 'finished')
  527. {
  528. // ok to refresh this page or use language selector
  529. }
  530. else
  531. {
  532. if(file_exists(Piwik_Config::getDefaultUserConfigPath()))
  533. {
  534. $error = true;
  535. }
  536. $steps = array_keys($this->steps);
  537. // the currentStep
  538. $currentStepId = array_search($currentStep, $steps);
  539. // the step before
  540. $previousStepId = array_search($this->session->currentStepDone, $steps);
  541. // not OK if currentStepId > previous+1
  542. if( $currentStepId > $previousStepId + 1 )
  543. {
  544. $error = true;
  545. }
  546. }
  547. if($error)
  548. {
  549. Piwik_Login_Controller::clearSession();
  550. $message = Piwik_Translate('Installation_ErrorInvalidState',
  551. array( '<br /><b>',
  552. '</b>',
  553. '<a href=\''.Piwik_Common::sanitizeInputValue(Piwik_Url::getCurrentUrlWithoutFileName()).'\'>',
  554. '</a>')
  555. );
  556. Piwik::exitWithErrorMessage( $message );
  557. }
  558. }
  559. /**
  560. * Redirect to next step
  561. *
  562. * @param string Current step
  563. * @return none
  564. */
  565. protected function redirectToNextStep($currentStep)
  566. {
  567. $steps = array_keys($this->steps);
  568. $this->session->currentStepDone = $currentStep;
  569. $nextStep = $steps[1 + array_search($currentStep, $steps)];
  570. Piwik::redirectToModule('Installation' , $nextStep);
  571. }
  572. /**
  573. * Skip this step (typically to mark the current function as completed)
  574. *
  575. * @param string function name
  576. */
  577. protected function skipThisStep( $step )
  578. {
  579. $skipThisStep = $this->session->skipThisStep;
  580. if(isset($skipThisStep[$step]) && $skipThisStep[$step])
  581. {
  582. $this->redirectToNextStep($step);
  583. }
  584. }
  585. /**
  586. * Get system information
  587. */
  588. public static function getSystemInformation()
  589. {
  590. global $piwik_minimumPHPVersion;
  591. $minimumMemoryLimit = Zend_Registry::get('config')->General->minimum_memory_limit;
  592. $infos = array();
  593. $infos['general_infos'] = array();
  594. $infos['directories'] = Piwik::checkDirectoriesWritable();
  595. $infos['can_auto_update'] = Piwik::canAutoUpdate();
  596. if(Piwik_Common::isIIS())
  597. {
  598. Piwik::createWebConfigFiles();
  599. }
  600. else
  601. {
  602. Piwik::createHtAccessFiles();
  603. }
  604. Piwik::createWebRootFiles();
  605. $infos['phpVersion_minimum'] = $piwik_minimumPHPVersion;
  606. $infos['phpVersion'] = PHP_VERSION;
  607. $infos['phpVersion_ok'] = version_compare( $piwik_minimumPHPVersion, $infos['phpVersion']) === -1;
  608. // critical errors
  609. $extensions = @get_loaded_extensions();
  610. $needed_extensions = array(
  611. 'zlib',
  612. 'SPL',
  613. 'iconv',
  614. 'Reflection',
  615. );
  616. $infos['needed_extensions'] = $needed_extensions;
  617. $infos['missing_extensions'] = array();
  618. foreach($needed_extensions as $needed_extension)
  619. {
  620. if(!in_array($needed_extension, $extensions))
  621. {
  622. $infos['missing_extensions'][] = $needed_extension;
  623. }
  624. }
  625. $infos['pdo_ok'] = false;
  626. if(in_array('PDO', $extensions))
  627. {
  628. $infos['pdo_ok'] = true;
  629. }
  630. $infos['adapters'] = Piwik_Db_Adapter::getAdapters();
  631. $needed_functions = array(
  632. 'debug_backtrace',
  633. 'create_function',
  634. 'eval',
  635. 'gzcompress',
  636. 'gzuncompress',
  637. 'pack',
  638. );
  639. $infos['needed_functions'] = $needed_functions;
  640. $infos['missing_functions'] = array();
  641. foreach($needed_functions as $needed_function)
  642. {
  643. if(!self::functionExists($needed_function))
  644. {
  645. $infos['missing_functions'][] = $needed_function;
  646. }
  647. }
  648. // warnings
  649. $desired_extensions = array(
  650. 'json',
  651. 'libxml',
  652. 'dom',
  653. 'SimpleXML',
  654. );
  655. $infos['desired_extensions'] = $desired_extensions;
  656. $infos['missing_desired_extensions'] = array();
  657. foreach($desired_extensions as $desired_extension)
  658. {
  659. if(!in_array($desired_extension, $extensions))
  660. {
  661. $infos['missing_desired_extensions'][] = $desired_extension;
  662. }
  663. }
  664. $desired_functions = array(
  665. 'set_time_limit',
  666. 'mail',
  667. 'parse_ini_file',
  668. 'glob',
  669. );
  670. $infos['desired_functions'] = $desired_functions;
  671. $infos['missing_desired_functions'] = array();
  672. foreach($desired_functions as $desired_function)
  673. {
  674. if(!self::functionExists($desired_function))
  675. {
  676. $infos['missing_desired_functions'][] = $desired_function;
  677. }
  678. }
  679. $infos['openurl'] = Piwik_Http::getTransportMethod();
  680. $infos['gd_ok'] = false;
  681. if (in_array('gd', $extensions))
  682. {
  683. $gdInfo = gd_info();
  684. $infos['gd_version'] = $gdInfo['GD Version'];
  685. preg_match('/([0-9]{1})/', $gdInfo['GD Version'], $gdVersion);
  686. if($gdVersion[0] >= 2)
  687. {
  688. $infos['gd_ok'] = true;
  689. }
  690. }
  691. $infos['hasMbstring'] = false;
  692. $infos['multibyte_ok'] = true;
  693. if(function_exists('mb_internal_encoding'))
  694. {
  695. $infos['hasMbstring'] = true;
  696. if (((int) ini_get('mbstring.func_overload')) != 0)
  697. {
  698. $infos['multibyte_ok'] = false;
  699. }
  700. }
  701. $serverSoftware = isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : '';
  702. $infos['serverVersion'] = addslashes($serverSoftware);
  703. $infos['serverOs'] = @php_uname();
  704. $infos['serverTime'] = date('H:i:s');
  705. $infos['registerGlobals_ok'] = ini_get('register_globals') == 0;
  706. $infos['memoryMinimum'] = $minimumMemoryLimit;
  707. $infos['memory_ok'] = true;
  708. $infos['memoryCurrent'] = '';
  709. $raised = Piwik::raiseMemoryLimitIfNecessary();
  710. if(($memoryValue = Piwik::getMemoryLimitValue()) > 0)
  711. {
  712. $infos['memoryCurrent'] = $memoryValue.'M';
  713. $infos['memory_ok'] = $memoryValue >= $minimumMemoryLimit;
  714. }
  715. $infos['isWindows'] = Piwik_Common::isWindows();
  716. $integrityInfo = Piwik::getFileIntegrityInformation();
  717. $infos['integrity'] = $integrityInfo[0];
  718. $infos['integrityErrorMessages'] = array();
  719. if(isset($integrityInfo[1]))
  720. {
  721. if($infos['integrity'] == false)
  722. {
  723. $infos['integrityErrorMessages'][] = '<b>'.Piwik_Translate('General_FileIntegrityWarningExplanation').'</b>';
  724. }
  725. $infos['integrityErrorMessages'] = array_merge($infos['integrityErrorMessages'], array_slice($integrityInfo, 1));
  726. }
  727. $infos['timezone'] = Piwik::isTimezoneSupportEnabled();
  728. $infos['tracker_status'] = Piwik_Common::getRequestVar('trackerStatus', 0, 'int');
  729. $infos['protocol'] = Piwik_ProxyHeaders::getProtocolInformation();
  730. if(!Piwik::isHttps() && $infos['protocol'] !== null)
  731. {
  732. $infos['general_infos']['secure_protocol'] = '1';
  733. }
  734. if(count($headers = Piwik_ProxyHeaders::getProxyClientHeaders()) > 0)
  735. {
  736. $infos['general_infos']['proxy_client_headers'] = $headers;
  737. }
  738. if(count($headers = Piwik_ProxyHeaders::getProxyHostHeaders()) > 0)
  739. {
  740. $infos['general_infos']['proxy_host_headers'] = $headers;
  741. }
  742. return $infos;
  743. }
  744. /**
  745. * Test if function exists. Also handles case where function is disabled via Suhosin.
  746. *
  747. * @param string $functionName Function name
  748. * @return bool True if function exists (not disabled); False otherwise.
  749. */
  750. public static function functionExists($functionName)
  751. {
  752. // eval() is a language construct
  753. if($functionName == 'eval')
  754. {
  755. // does not check suhosin.executor.eval.whitelist (or blacklist)
  756. if(extension_loaded('suhosin'))
  757. {
  758. return @ini_get("suhosin.executor.disable_eval") != "1";
  759. }
  760. return true;
  761. }
  762. $exists = function_exists($functionName);
  763. if(extension_loaded('suhosin'))
  764. {
  765. $blacklist = @ini_get("suhosin.executor.func.blacklist");
  766. if(!empty($blacklist))
  767. {
  768. $blacklistFunctions = array_map('strtolower', array_map('trim', explode(',', $blacklist)));
  769. return $exists && !in_array($functionName, $blacklistFunctions);
  770. }
  771. }
  772. return $exists;
  773. }
  774. }