Teknik is a suite of services with attractive and functional interfaces. https://www.teknik.io/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SettingsPiwik.php 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  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()->getLocalPath();
  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. * If the Piwik server is in an error state (eg. some directories are not writable and Piwik displays error message),
  265. * or if the Piwik server is "offline",
  266. * this will return false..
  267. *
  268. * @param $piwikServerUrl
  269. * @return bool
  270. */
  271. public static function checkPiwikServerWorking($piwikServerUrl, $acceptInvalidSSLCertificates = false)
  272. {
  273. // Now testing if the webserver is running
  274. try {
  275. $fetched = Http::sendHttpRequestBy('curl',
  276. $piwikServerUrl,
  277. $timeout = 45,
  278. $userAgent = null,
  279. $destinationPath = null,
  280. $file = null,
  281. $followDepth = 0,
  282. $acceptLanguage = false,
  283. $acceptInvalidSSLCertificates
  284. );
  285. } catch (Exception $e) {
  286. $fetched = "ERROR fetching: " . $e->getMessage();
  287. }
  288. // this will match when Piwik not installed yet, or favicon not customised
  289. $expectedStringAlt = 'plugins/CoreHome/images/favicon.ico';
  290. // this will match when Piwik is installed and favicon has been customised
  291. $expectedString = 'misc/user/';
  292. $expectedStringNotFound = strpos($fetched, $expectedString) === false && strpos($fetched, $expectedStringAlt) === false;
  293. $hasError = false !== strpos($fetched, PAGE_TITLE_WHEN_ERROR);
  294. if ($hasError || $expectedStringNotFound) {
  295. throw new Exception("\nPiwik should be running at: "
  296. . $piwikServerUrl
  297. . " but this URL returned an unexpected response: '"
  298. . $fetched . "'\n\n");
  299. }
  300. }
  301. public static function getCurrentGitBranch()
  302. {
  303. $file = PIWIK_INCLUDE_PATH . '/.git/HEAD';
  304. if(!file_exists($file)) {
  305. return '';
  306. }
  307. $firstLineOfGitHead = file($file);
  308. if (empty($firstLineOfGitHead)) {
  309. return '';
  310. }
  311. $firstLineOfGitHead = $firstLineOfGitHead[0];
  312. $parts = explode('/', $firstLineOfGitHead);
  313. if (empty($parts[2])) {
  314. return '';
  315. }
  316. $currentGitBranch = trim($parts[2]);
  317. return $currentGitBranch;
  318. }
  319. /**
  320. * @param $pathToRewrite
  321. * @param $leadingPathToAppendHostnameTo
  322. * @param $hostname
  323. * @return mixed
  324. * @throws \Exception
  325. */
  326. protected static function rewritePathAppendPiwikInstanceId($pathToRewrite, $leadingPathToAppendHostnameTo)
  327. {
  328. $instanceId = self::getPiwikInstanceId();
  329. if (empty($instanceId)) {
  330. return $pathToRewrite;
  331. }
  332. if (($posTmp = strrpos($pathToRewrite, $leadingPathToAppendHostnameTo)) === false) {
  333. throw new Exception("The path $pathToRewrite was expected to contain the string $leadingPathToAppendHostnameTo");
  334. }
  335. $tmpToReplace = $leadingPathToAppendHostnameTo . $instanceId . '/';
  336. // replace only the latest occurrence (in case path contains twice /tmp)
  337. $pathToRewrite = substr_replace($pathToRewrite, $tmpToReplace, $posTmp, strlen($leadingPathToAppendHostnameTo));
  338. return $pathToRewrite;
  339. }
  340. /**
  341. * @throws \Exception
  342. * @return string or False if not set
  343. */
  344. protected static function getPiwikInstanceId()
  345. {
  346. // until Piwik is installed, we use hostname as instance_id
  347. if(!self::isPiwikInstalled()
  348. && Common::isPhpCliMode()) {
  349. // enterprise:install use case
  350. return Config::getHostname();
  351. }
  352. // config.ini.php not ready yet, instance_id will not be set
  353. if(!Config::getInstance()->existsLocalConfig()) {
  354. return false;
  355. }
  356. $instanceId = @Config::getInstance()->General['instance_id'];
  357. if(!empty($instanceId)) {
  358. return $instanceId;
  359. }
  360. // do not rewrite the path as Piwik uses the standard config.ini.php file
  361. return false;
  362. }
  363. /**
  364. * @param $currentUrl
  365. */
  366. public static function overwritePiwikUrl($currentUrl)
  367. {
  368. Option::set(self::OPTION_PIWIK_URL, $currentUrl, $autoLoad = true);
  369. }
  370. /**
  371. * @return bool
  372. */
  373. public static function isHttpsForced()
  374. {
  375. return Config::getInstance()->General['force_ssl'] == 1;
  376. }
  377. }