PageRenderTime 1201ms CodeModel.GetById 26ms RepoModel.GetById 2ms app.codeStats 0ms

/core/SettingsPiwik.php

https://github.com/CodeYellowBV/piwik
PHP | 416 lines | 199 code | 44 blank | 173 comment | 37 complexity | 5d5c06bd6c0de14c3df730bc1004b1a6 MD5 | raw file
Possible License(s): LGPL-3.0, JSON, MIT, GPL-3.0, LGPL-2.1, GPL-2.0, AGPL-1.0, BSD-2-Clause, BSD-3-Clause
  1. <?php
  2. /**
  3. * Piwik - free/libre analytics platform
  4. *
  5. * @link http://piwik.org
  6. * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
  7. *
  8. */
  9. namespace Piwik;
  10. use Exception;
  11. /**
  12. * Contains helper methods that can be used to get common Piwik settings.
  13. *
  14. */
  15. class SettingsPiwik
  16. {
  17. const OPTION_PIWIK_URL = 'piwikUrl';
  18. /**
  19. * Get salt from [General] section
  20. *
  21. * @return string
  22. */
  23. public static function getSalt()
  24. {
  25. static $salt = null;
  26. if (is_null($salt)) {
  27. $salt = @Config::getInstance()->General['salt'];
  28. }
  29. return $salt;
  30. }
  31. /**
  32. * Should Piwik check that the login & password have minimum length and valid characters?
  33. *
  34. * @return bool True if checks enabled; false otherwise
  35. */
  36. public static function isUserCredentialsSanityCheckEnabled()
  37. {
  38. return Config::getInstance()->General['disable_checks_usernames_attributes'] == 0;
  39. }
  40. /**
  41. * @see getKnownSegmentsToArchive
  42. *
  43. * @var array
  44. */
  45. public static $cachedKnownSegmentsToArchive = null;
  46. /**
  47. * Returns every stored segment to pre-process for each site during cron archiving.
  48. *
  49. * @return array The list of stored segments that apply to all sites.
  50. */
  51. public static function getKnownSegmentsToArchive()
  52. {
  53. if (self::$cachedKnownSegmentsToArchive === null) {
  54. $segments = Config::getInstance()->Segments;
  55. $segmentsToProcess = isset($segments['Segments']) ? $segments['Segments'] : array();
  56. /**
  57. * Triggered during the cron archiving process to collect segments that
  58. * should be pre-processed for all websites. The archiving process will be launched
  59. * for each of these segments when archiving data.
  60. *
  61. * This event can be used to add segments to be pre-processed. If your plugin depends
  62. * on data from a specific segment, this event could be used to provide enhanced
  63. * performance.
  64. *
  65. * _Note: If you just want to add a segment that is managed by the user, use the
  66. * SegmentEditor API._
  67. *
  68. * **Example**
  69. *
  70. * Piwik::addAction('Segments.getKnownSegmentsToArchiveAllSites', function (&$segments) {
  71. * $segments[] = 'country=jp;city=Tokyo';
  72. * });
  73. *
  74. * @param array &$segmentsToProcess List of segment definitions, eg,
  75. *
  76. * array(
  77. * 'browserCode=ff;resolution=800x600',
  78. * 'country=jp;city=Tokyo'
  79. * )
  80. *
  81. * Add segments to this array in your event handler.
  82. */
  83. Piwik::postEvent('Segments.getKnownSegmentsToArchiveAllSites', array(&$segmentsToProcess));
  84. self::$cachedKnownSegmentsToArchive = array_unique($segmentsToProcess);
  85. }
  86. return self::$cachedKnownSegmentsToArchive;
  87. }
  88. /**
  89. * Returns the list of stored segments to pre-process for an individual site when executing
  90. * cron archiving.
  91. *
  92. * @param int $idSite The ID of the site to get stored segments for.
  93. * @return string The list of stored segments that apply to the requested site.
  94. */
  95. public static function getKnownSegmentsToArchiveForSite($idSite)
  96. {
  97. $segments = array();
  98. /**
  99. * Triggered during the cron archiving process to collect segments that
  100. * should be pre-processed for one specific site. The archiving process will be launched
  101. * for each of these segments when archiving data for that one site.
  102. *
  103. * This event can be used to add segments to be pre-processed for one site.
  104. *
  105. * _Note: If you just want to add a segment that is managed by the user, you should use the
  106. * SegmentEditor API._
  107. *
  108. * **Example**
  109. *
  110. * Piwik::addAction('Segments.getKnownSegmentsToArchiveForSite', function (&$segments, $idSite) {
  111. * $segments[] = 'country=jp;city=Tokyo';
  112. * });
  113. *
  114. * @param array &$segmentsToProcess List of segment definitions, eg,
  115. *
  116. * array(
  117. * 'browserCode=ff;resolution=800x600',
  118. * 'country=JP;city=Tokyo'
  119. * )
  120. *
  121. * Add segments to this array in your event handler.
  122. * @param int $idSite The ID of the site to get segments for.
  123. */
  124. Piwik::postEvent('Segments.getKnownSegmentsToArchiveForSite', array(&$segments, $idSite));
  125. return $segments;
  126. }
  127. /**
  128. * Number of websites to show in the Website selector
  129. *
  130. * @return int
  131. */
  132. public static function getWebsitesCountToDisplay()
  133. {
  134. $count = max(Config::getInstance()->General['site_selector_max_sites'],
  135. Config::getInstance()->General['autocomplete_min_sites']);
  136. return (int)$count;
  137. }
  138. /**
  139. * Returns the URL to this Piwik instance, eg. **http://demo.piwik.org/** or **http://example.org/piwik/**.
  140. *
  141. * @return string
  142. * @api
  143. */
  144. public static function getPiwikUrl()
  145. {
  146. $url = Option::get(self::OPTION_PIWIK_URL);
  147. $isPiwikCoreDispatching = defined('PIWIK_ENABLE_DISPATCH') && PIWIK_ENABLE_DISPATCH;
  148. if (Common::isPhpCliMode()
  149. // in case core:archive command is triggered (often with localhost domain)
  150. || SettingsServer::isArchivePhpTriggered()
  151. // When someone else than core is dispatching this request then we return the URL as it is read only
  152. || !$isPiwikCoreDispatching
  153. ) {
  154. return $url;
  155. }
  156. $currentUrl = Common::sanitizeInputValue(Url::getCurrentUrlWithoutFileName());
  157. if (empty($url)
  158. // if URL changes, always update the cache
  159. || $currentUrl != $url
  160. ) {
  161. if (strlen($currentUrl) >= strlen('http://a/')) {
  162. self::overwritePiwikUrl($currentUrl);
  163. }
  164. $url = $currentUrl;
  165. }
  166. if(ProxyHttp::isHttps()) {
  167. $url = str_replace("http://", "https://", $url);
  168. }
  169. return $url;
  170. }
  171. /**
  172. * Return true if Piwik is installed (installation is done).
  173. * @return bool
  174. */
  175. public static function isPiwikInstalled()
  176. {
  177. $config = Config::getInstance()->getLocalConfigPath();
  178. $exists = file_exists($config);
  179. // Piwik is installed if the config file is found
  180. if(!$exists) {
  181. return false;
  182. }
  183. $general = Config::getInstance()->General;
  184. $isInstallationInProgress = false;
  185. if (array_key_exists('installation_in_progress', $general)) {
  186. $isInstallationInProgress = (bool) $general['installation_in_progress'];
  187. }
  188. if($isInstallationInProgress) {
  189. return false;
  190. }
  191. // Check that the database section is really set, ie. file is not empty
  192. if(empty(Config::getInstance()->database['username'])) {
  193. return false;
  194. }
  195. return true;
  196. }
  197. /**
  198. * Returns `true` if segmentation is allowed for this user, `false` if otherwise.
  199. *
  200. * @return bool
  201. * @api
  202. */
  203. public static function isSegmentationEnabled()
  204. {
  205. return !Piwik::isUserIsAnonymous()
  206. || Config::getInstance()->General['anonymous_user_enable_use_segments_API'];
  207. }
  208. /**
  209. * Returns true if unique visitors should be processed for the given period type.
  210. *
  211. * Unique visitor processing is controlled by the `[General] enable_processing_unique_visitors_...`
  212. * INI config options. By default, unique visitors are processed only for day/week/month periods.
  213. *
  214. * @param string $periodLabel `"day"`, `"week"`, `"month"`, `"year"` or `"range"`
  215. * @return bool
  216. * @api
  217. */
  218. public static function isUniqueVisitorsEnabled($periodLabel)
  219. {
  220. $generalSettings = Config::getInstance()->General;
  221. $settingName = "enable_processing_unique_visitors_$periodLabel";
  222. $result = !empty($generalSettings[$settingName]) && $generalSettings[$settingName] == 1;
  223. // check enable_processing_unique_visitors_year_and_range for backwards compatibility
  224. if (($periodLabel == 'year' || $periodLabel == 'range')
  225. && isset($generalSettings['enable_processing_unique_visitors_year_and_range'])
  226. ) {
  227. $result |= $generalSettings['enable_processing_unique_visitors_year_and_range'] == 1;
  228. }
  229. return $result;
  230. }
  231. /**
  232. * @deprecated Use SettingsPiwik::rewriteTmpPathWithInstanceId instead
  233. */
  234. public static function rewriteTmpPathWithHostname($path)
  235. {
  236. return self::rewriteTmpPathWithInstanceId($path);
  237. }
  238. /**
  239. * If Piwik uses per-domain config file, also make tmp/ folder per-domain
  240. * @param $path
  241. * @return string
  242. * @throws \Exception
  243. */
  244. public static function rewriteTmpPathWithInstanceId($path)
  245. {
  246. $tmp = '/tmp/';
  247. $path = self::rewritePathAppendPiwikInstanceId($path, $tmp);
  248. return $path;
  249. }
  250. /**
  251. * If Piwik uses per-domain config file, make sure CustomLogo is unique
  252. * @param $path
  253. * @return mixed
  254. */
  255. public static function rewriteMiscUserPathWithInstanceId($path)
  256. {
  257. $tmp = 'misc/user/';
  258. $path = self::rewritePathAppendPiwikInstanceId($path, $tmp);
  259. return $path;
  260. }
  261. /**
  262. * Returns true if the Piwik server appears to be working.
  263. *
  264. * @param $piwikServerUrl
  265. * @return bool
  266. */
  267. static public function checkPiwikServerWorking($piwikServerUrl, $acceptInvalidSSLCertificates = false)
  268. {
  269. // Now testing if the webserver is running
  270. try {
  271. $fetched = Http::sendHttpRequestBy('curl',
  272. $piwikServerUrl,
  273. $timeout = 45,
  274. $userAgent = null,
  275. $destinationPath = null,
  276. $file = null,
  277. $followDepth = 0,
  278. $acceptLanguage = false,
  279. $acceptInvalidSSLCertificates
  280. );
  281. } catch (Exception $e) {
  282. $fetched = "ERROR fetching: " . $e->getMessage();
  283. }
  284. // this will match when Piwik not installed yet, or favicon not customised
  285. $expectedStringAlt = 'plugins/CoreHome/images/favicon.ico';
  286. // this will match when Piwik is installed and favicon has been customised
  287. $expectedString = 'misc/user/';
  288. $expectedStringNotFound = strpos($fetched, $expectedString) === false && strpos($fetched, $expectedStringAlt) === false;
  289. if ($expectedStringNotFound) {
  290. throw new Exception("\nPiwik should be running at: "
  291. . $piwikServerUrl
  292. . " but this URL returned an unexpected response: '"
  293. . $fetched . "'\n\n");
  294. }
  295. }
  296. public static function getCurrentGitBranch()
  297. {
  298. $file = PIWIK_INCLUDE_PATH . '/.git/HEAD';
  299. if(!file_exists($file)) {
  300. return '';
  301. }
  302. $firstLineOfGitHead = file($file);
  303. if (empty($firstLineOfGitHead)) {
  304. return '';
  305. }
  306. $firstLineOfGitHead = $firstLineOfGitHead[0];
  307. $parts = explode('/', $firstLineOfGitHead);
  308. if (empty($parts[2])) {
  309. return '';
  310. }
  311. $currentGitBranch = trim($parts[2]);
  312. return $currentGitBranch;
  313. }
  314. /**
  315. * @param $pathToRewrite
  316. * @param $leadingPathToAppendHostnameTo
  317. * @param $hostname
  318. * @return mixed
  319. * @throws \Exception
  320. */
  321. protected static function rewritePathAppendPiwikInstanceId($pathToRewrite, $leadingPathToAppendHostnameTo)
  322. {
  323. $instanceId = self::getPiwikInstanceId();
  324. if (empty($instanceId)) {
  325. return $pathToRewrite;
  326. }
  327. if (($posTmp = strrpos($pathToRewrite, $leadingPathToAppendHostnameTo)) === false) {
  328. throw new Exception("The path $pathToRewrite was expected to contain the string $leadingPathToAppendHostnameTo");
  329. }
  330. $tmpToReplace = $leadingPathToAppendHostnameTo . $instanceId . '/';
  331. // replace only the latest occurrence (in case path contains twice /tmp)
  332. $pathToRewrite = substr_replace($pathToRewrite, $tmpToReplace, $posTmp, strlen($leadingPathToAppendHostnameTo));
  333. return $pathToRewrite;
  334. }
  335. /**
  336. * @throws \Exception
  337. * @return string or False if not set
  338. */
  339. protected static function getPiwikInstanceId()
  340. {
  341. // until Piwik is installed, we use hostname as instance_id
  342. if(!self::isPiwikInstalled()
  343. && Common::isPhpCliMode()) {
  344. // enterprise:install use case
  345. return Config::getHostname();
  346. }
  347. // config.ini.php not ready yet, instance_id will not be set
  348. if(!Config::getInstance()->existsLocalConfig()) {
  349. return false;
  350. }
  351. $instanceId = @Config::getInstance()->General['instance_id'];
  352. if(!empty($instanceId)) {
  353. return $instanceId;
  354. }
  355. // do not rewrite the path as Piwik uses the standard config.ini.php file
  356. return false;
  357. }
  358. /**
  359. * @param $currentUrl
  360. */
  361. public static function overwritePiwikUrl($currentUrl)
  362. {
  363. Option::set(self::OPTION_PIWIK_URL, $currentUrl, $autoLoad = true);
  364. }
  365. /**
  366. * @return bool
  367. */
  368. public static function isHttpsForced()
  369. {
  370. return Config::getInstance()->General['force_ssl'] == 1;
  371. }
  372. }