PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/core/Piwik.php

https://github.com/CodeYellowBV/piwik
PHP | 846 lines | 476 code | 66 blank | 304 comment | 42 complexity | 29d71cb74d8be123f621b487ed5e862c 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. use Piwik\Db\Adapter;
  12. use Piwik\Db\Schema;
  13. use Piwik\Db;
  14. use Piwik\Plugin;
  15. use Piwik\Plugins\SitesManager\API as APISitesManager;
  16. use Piwik\Plugins\UsersManager\API as APIUsersManager;
  17. use Piwik\Session;
  18. use Piwik\Tracker;
  19. use Piwik\View;
  20. /**
  21. * @see core/Translate.php
  22. */
  23. require_once PIWIK_INCLUDE_PATH . '/core/Translate.php';
  24. /**
  25. * Main piwik helper class.
  26. *
  27. * Contains helper methods for a variety of common tasks. Plugin developers are
  28. * encouraged to reuse these methods as much as possible.
  29. */
  30. class Piwik
  31. {
  32. /**
  33. * Piwik periods
  34. * @var array
  35. */
  36. public static $idPeriods = array(
  37. 'day' => 1,
  38. 'week' => 2,
  39. 'month' => 3,
  40. 'year' => 4,
  41. 'range' => 5,
  42. );
  43. /**
  44. * The idGoal query parameter value for the special 'abandoned carts' goal.
  45. *
  46. * @api
  47. */
  48. const LABEL_ID_GOAL_IS_ECOMMERCE_CART = 'ecommerceAbandonedCart';
  49. /**
  50. * The idGoal query parameter value for the special 'ecommerce' goal.
  51. *
  52. * @api
  53. */
  54. const LABEL_ID_GOAL_IS_ECOMMERCE_ORDER = 'ecommerceOrder';
  55. /**
  56. * Trigger E_USER_ERROR with optional message
  57. *
  58. * @param string $message
  59. */
  60. static public function error($message = '')
  61. {
  62. trigger_error($message, E_USER_ERROR);
  63. }
  64. /**
  65. * Display the message in a nice red font with a nice icon
  66. * ... and dies
  67. *
  68. * @param string $message
  69. */
  70. static public function exitWithErrorMessage($message)
  71. {
  72. if (!Common::isPhpCliMode()) {
  73. @header('Content-Type: text/html; charset=utf-8');
  74. }
  75. $output = "<style>a{color:red;}</style>\n" .
  76. "<div style='color:red;font-family:Georgia;font-size:120%'>" .
  77. "<p><img src='plugins/Morpheus/images/error_medium.png' style='vertical-align:middle; float:left;padding:20 20 20 20' />" .
  78. $message .
  79. "</p></div>";
  80. print($output);
  81. exit;
  82. }
  83. /**
  84. * Computes the division of i1 by i2. If either i1 or i2 are not number, or if i2 has a value of zero
  85. * we return 0 to avoid the division by zero.
  86. *
  87. * @param number $i1
  88. * @param number $i2
  89. * @return number The result of the division or zero
  90. */
  91. static public function secureDiv($i1, $i2)
  92. {
  93. if (is_numeric($i1) && is_numeric($i2) && floatval($i2) != 0) {
  94. return $i1 / $i2;
  95. }
  96. return 0;
  97. }
  98. /**
  99. * Safely compute a percentage. Return 0 to avoid division by zero.
  100. *
  101. * @param number $dividend
  102. * @param number $divisor
  103. * @param int $precision
  104. * @return number
  105. */
  106. static public function getPercentageSafe($dividend, $divisor, $precision = 0)
  107. {
  108. if ($divisor == 0) {
  109. return 0;
  110. }
  111. return round(100 * $dividend / $divisor, $precision);
  112. }
  113. /**
  114. * Returns the Javascript code to be inserted on every page to track
  115. *
  116. * @param int $idSite
  117. * @param string $piwikUrl http://path/to/piwik/directory/
  118. * @return string
  119. */
  120. static public function getJavascriptCode($idSite, $piwikUrl, $mergeSubdomains = false, $groupPageTitlesByDomain = false,
  121. $mergeAliasUrls = false, $visitorCustomVariables = false, $pageCustomVariables = false,
  122. $customCampaignNameQueryParam = false, $customCampaignKeywordParam = false,
  123. $doNotTrack = false)
  124. {
  125. // changes made to this code should be mirrored in plugins/CoreAdminHome/javascripts/jsTrackingGenerator.js var generateJsCode
  126. $jsCode = file_get_contents(PIWIK_INCLUDE_PATH . "/plugins/Morpheus/templates/javascriptCode.tpl");
  127. $jsCode = htmlentities($jsCode);
  128. if(substr($piwikUrl, 0, 4) !== 'http') {
  129. $piwikUrl = 'http://' . $piwikUrl;
  130. }
  131. preg_match('~^(http|https)://(.*)$~D', $piwikUrl, $matches);
  132. $piwikUrl = rtrim(@$matches[2], "/");
  133. // Build optional parameters to be added to text
  134. $options = '';
  135. if ($groupPageTitlesByDomain) {
  136. $options .= ' _paq.push(["setDocumentTitle", document.domain + "/" + document.title]);' . PHP_EOL;
  137. }
  138. if ($mergeSubdomains || $mergeAliasUrls) {
  139. $options .= self::getJavascriptTagOptions($idSite, $mergeSubdomains, $mergeAliasUrls);
  140. }
  141. $maxCustomVars = Plugins\CustomVariables\CustomVariables::getMaxCustomVariables();
  142. if ($visitorCustomVariables) {
  143. $options .= ' // you can set up to ' . $maxCustomVars . ' custom variables for each visitor' . PHP_EOL;
  144. $index = 1;
  145. foreach ($visitorCustomVariables as $visitorCustomVariable) {
  146. $options .= ' _paq.push(["setCustomVariable", '.$index++.', "'.$visitorCustomVariable[0].'", "'.$visitorCustomVariable[1].'", "visit"]);' . PHP_EOL;
  147. }
  148. }
  149. if ($pageCustomVariables) {
  150. $options .= ' // you can set up to ' . $maxCustomVars . ' custom variables for each action (page view, download, click, site search)' . PHP_EOL;
  151. $index = 1;
  152. foreach ($pageCustomVariables as $pageCustomVariable) {
  153. $options .= ' _paq.push(["setCustomVariable", '.$index++.', "'.$pageCustomVariable[0].'", "'.$pageCustomVariable[1].'", "page"]);' . PHP_EOL;
  154. }
  155. }
  156. if ($customCampaignNameQueryParam) {
  157. $options .= ' _paq.push(["setCampaignNameKey", "'.$customCampaignNameQueryParam.'"]);' . PHP_EOL;
  158. }
  159. if ($customCampaignKeywordParam) {
  160. $options .= ' _paq.push(["setCampaignKeywordKey", "'.$customCampaignKeywordParam.'"]);' . PHP_EOL;
  161. }
  162. if ($doNotTrack) {
  163. $options .= ' _paq.push(["setDoNotTrack", true]);' . PHP_EOL;
  164. }
  165. $codeImpl = array(
  166. 'idSite' => $idSite,
  167. 'piwikUrl' => Common::sanitizeInputValue($piwikUrl),
  168. 'options' => $options
  169. );
  170. $parameters = compact('mergeSubdomains', 'groupPageTitlesByDomain', 'mergeAliasUrls', 'visitorCustomVariables',
  171. 'pageCustomVariables', 'customCampaignNameQueryParam', 'customCampaignKeywordParam',
  172. 'doNotTrack');
  173. /**
  174. * Triggered when generating JavaScript tracking code server side. Plugins can use
  175. * this event to customise the JavaScript tracking code that is displayed to the
  176. * user.
  177. *
  178. * @param array &$codeImpl An array containing snippets of code that the event handler
  179. * can modify. Will contain the following elements:
  180. *
  181. * - **idSite**: The ID of the site being tracked.
  182. * - **piwikUrl**: The tracker URL to use.
  183. * - **options**: A string of JavaScript code that customises
  184. * the JavaScript tracker.
  185. *
  186. * The **httpsPiwikUrl** element can be set if the HTTPS
  187. * domain is different from the normal domain.
  188. * @param array $parameters The parameters supplied to the `Piwik::getJavascriptCode()`.
  189. */
  190. self::postEvent('Piwik.getJavascriptCode', array(&$codeImpl, $parameters));
  191. if (!empty($codeImpl['httpsPiwikUrl'])) {
  192. $setTrackerUrl = 'var u=(("https:" == document.location.protocol) ? "https://{$httpsPiwikUrl}/" : '
  193. . '"http://{$piwikUrl}/");';
  194. $codeImpl['httpsPiwikUrl'] = rtrim($codeImpl['httpsPiwikUrl'], "/");
  195. } else {
  196. $setTrackerUrl = 'var u=(("https:" == document.location.protocol) ? "https" : "http") + "://{$piwikUrl}/";';
  197. }
  198. $codeImpl = array('setTrackerUrl' => htmlentities($setTrackerUrl)) + $codeImpl;
  199. foreach ($codeImpl as $keyToReplace => $replaceWith) {
  200. $jsCode = str_replace('{$' . $keyToReplace . '}', $replaceWith, $jsCode);
  201. }
  202. return $jsCode;
  203. }
  204. /**
  205. * Generate a title for image tags
  206. *
  207. * @return string
  208. */
  209. static public function getRandomTitle()
  210. {
  211. static $titles = array(
  212. 'Web analytics',
  213. 'Open analytics platform',
  214. 'Real Time Web Analytics',
  215. 'Analytics',
  216. 'Real Time Analytics',
  217. 'Analytics in Real time',
  218. 'Free/Libre Web Analytics',
  219. 'Free Website Analytics',
  220. 'Free Web Analytics',
  221. 'Analytics Platform',
  222. 'Data Platform',
  223. );
  224. $id = abs(intval(md5(Url::getCurrentHost())));
  225. $title = $titles[$id % count($titles)];
  226. return $title;
  227. }
  228. /*
  229. * Access
  230. */
  231. /**
  232. * Returns the current user's email address.
  233. *
  234. * @return string
  235. * @api
  236. */
  237. static public function getCurrentUserEmail()
  238. {
  239. $user = APIUsersManager::getInstance()->getUser(Piwik::getCurrentUserLogin());
  240. return $user['email'];
  241. }
  242. /**
  243. * Get a list of all email addresses having Super User access.
  244. *
  245. * @return array
  246. */
  247. static public function getAllSuperUserAccessEmailAddresses()
  248. {
  249. $emails = array();
  250. try {
  251. $superUsers = APIUsersManager::getInstance()->getUsersHavingSuperUserAccess();
  252. } catch (\Exception $e) {
  253. return $emails;
  254. }
  255. foreach ($superUsers as $superUser) {
  256. $emails[$superUser['login']] = $superUser['email'];
  257. }
  258. return $emails;
  259. }
  260. /**
  261. * Returns the current user's username.
  262. *
  263. * @return string
  264. * @api
  265. */
  266. static public function getCurrentUserLogin()
  267. {
  268. return Access::getInstance()->getLogin();
  269. }
  270. /**
  271. * Returns the current user's token auth.
  272. *
  273. * @return string
  274. * @api
  275. */
  276. static public function getCurrentUserTokenAuth()
  277. {
  278. return Access::getInstance()->getTokenAuth();
  279. }
  280. /**
  281. * Returns `true` if the current user is either the Super User or the user specified by
  282. * `$theUser`.
  283. *
  284. * @param string $theUser A username.
  285. * @return bool
  286. * @api
  287. */
  288. static public function hasUserSuperUserAccessOrIsTheUser($theUser)
  289. {
  290. try {
  291. self::checkUserHasSuperUserAccessOrIsTheUser($theUser);
  292. return true;
  293. } catch (Exception $e) {
  294. return false;
  295. }
  296. }
  297. /**
  298. * Check that the current user is either the specified user or the superuser.
  299. *
  300. * @param string $theUser A username.
  301. * @throws NoAccessException If the user is neither the Super User nor the user `$theUser`.
  302. * @api
  303. */
  304. static public function checkUserHasSuperUserAccessOrIsTheUser($theUser)
  305. {
  306. try {
  307. if (Piwik::getCurrentUserLogin() !== $theUser) {
  308. // or to the Super User
  309. Piwik::checkUserHasSuperUserAccess();
  310. }
  311. } catch (NoAccessException $e) {
  312. throw new NoAccessException(Piwik::translate('General_ExceptionCheckUserHasSuperUserAccessOrIsTheUser', array($theUser)));
  313. }
  314. }
  315. /**
  316. * Check whether the given user has superuser access.
  317. *
  318. * @param string $theUser A username.
  319. * @return bool
  320. * @api
  321. */
  322. static public function hasTheUserSuperUserAccess($theUser)
  323. {
  324. if (empty($theUser)) {
  325. return false;
  326. }
  327. if (Piwik::getCurrentUserLogin() === $theUser && Piwik::hasUserSuperUserAccess()) {
  328. return true;
  329. }
  330. try {
  331. $superUsers = APIUsersManager::getInstance()->getUsersHavingSuperUserAccess();
  332. } catch (\Exception $e) {
  333. return false;
  334. }
  335. foreach ($superUsers as $superUser) {
  336. if ($theUser === $superUser['login']) {
  337. return true;
  338. }
  339. }
  340. return false;
  341. }
  342. /**
  343. * Returns true if the current user has Super User access.
  344. *
  345. * @return bool
  346. * @api
  347. */
  348. static public function hasUserSuperUserAccess()
  349. {
  350. try {
  351. self::checkUserHasSuperUserAccess();
  352. return true;
  353. } catch (Exception $e) {
  354. return false;
  355. }
  356. }
  357. /**
  358. * Returns true if the current user is the special **anonymous** user or not.
  359. *
  360. * @return bool
  361. * @api
  362. */
  363. static public function isUserIsAnonymous()
  364. {
  365. return Piwik::getCurrentUserLogin() == 'anonymous';
  366. }
  367. /**
  368. * Checks that the user is not the anonymous user.
  369. *
  370. * @throws NoAccessException if the current user is the anonymous user.
  371. * @api
  372. */
  373. static public function checkUserIsNotAnonymous()
  374. {
  375. if (Access::getInstance()->hasSuperUserAccess()) {
  376. return;
  377. }
  378. if (self::isUserIsAnonymous()) {
  379. throw new NoAccessException(Piwik::translate('General_YouMustBeLoggedIn'));
  380. }
  381. }
  382. /**
  383. * Helper method user to set the current as superuser.
  384. * This should be used with great care as this gives the user all permissions.
  385. *
  386. * @param bool $bool true to set current user as Super User
  387. */
  388. static public function setUserHasSuperUserAccess($bool = true)
  389. {
  390. Access::getInstance()->setSuperUserAccess($bool);
  391. }
  392. /**
  393. * Check that the current user has superuser access.
  394. *
  395. * @throws Exception if the current user is not the superuser.
  396. * @api
  397. */
  398. static public function checkUserHasSuperUserAccess()
  399. {
  400. Access::getInstance()->checkUserHasSuperUserAccess();
  401. }
  402. /**
  403. * Returns `true` if the user has admin access to the requested sites, `false` if otherwise.
  404. *
  405. * @param int|array $idSites The list of site IDs to check access for.
  406. * @return bool
  407. * @api
  408. */
  409. static public function isUserHasAdminAccess($idSites)
  410. {
  411. try {
  412. self::checkUserHasAdminAccess($idSites);
  413. return true;
  414. } catch (Exception $e) {
  415. return false;
  416. }
  417. }
  418. /**
  419. * Checks that the current user has admin access to the requested list of sites.
  420. *
  421. * @param int|array $idSites One or more site IDs to check access for.
  422. * @throws Exception If user doesn't have admin access.
  423. * @api
  424. */
  425. static public function checkUserHasAdminAccess($idSites)
  426. {
  427. Access::getInstance()->checkUserHasAdminAccess($idSites);
  428. }
  429. /**
  430. * Returns `true` if the current user has admin access to at least one site.
  431. *
  432. * @return bool
  433. * @api
  434. */
  435. static public function isUserHasSomeAdminAccess()
  436. {
  437. try {
  438. self::checkUserHasSomeAdminAccess();
  439. return true;
  440. } catch (Exception $e) {
  441. return false;
  442. }
  443. }
  444. /**
  445. * Checks that the current user has admin access to at least one site.
  446. *
  447. * @throws Exception if user doesn't have admin access to any site.
  448. * @api
  449. */
  450. static public function checkUserHasSomeAdminAccess()
  451. {
  452. Access::getInstance()->checkUserHasSomeAdminAccess();
  453. }
  454. /**
  455. * Returns `true` if the user has view access to the requested list of sites.
  456. *
  457. * @param int|array $idSites One or more site IDs to check access for.
  458. * @return bool
  459. * @api
  460. */
  461. static public function isUserHasViewAccess($idSites)
  462. {
  463. try {
  464. self::checkUserHasViewAccess($idSites);
  465. return true;
  466. } catch (Exception $e) {
  467. return false;
  468. }
  469. }
  470. /**
  471. * Checks that the current user has view access to the requested list of sites
  472. *
  473. * @param int|array $idSites The list of site IDs to check access for.
  474. * @throws Exception if the current user does not have view access to every site in the list.
  475. * @api
  476. */
  477. static public function checkUserHasViewAccess($idSites)
  478. {
  479. Access::getInstance()->checkUserHasViewAccess($idSites);
  480. }
  481. /**
  482. * Returns `true` if the current user has view access to at least one site.
  483. *
  484. * @return bool
  485. * @api
  486. */
  487. static public function isUserHasSomeViewAccess()
  488. {
  489. try {
  490. self::checkUserHasSomeViewAccess();
  491. return true;
  492. } catch (Exception $e) {
  493. return false;
  494. }
  495. }
  496. /**
  497. * Checks that the current user has view access to at least one site.
  498. *
  499. * @throws Exception if user doesn't have view access to any site.
  500. * @api
  501. */
  502. static public function checkUserHasSomeViewAccess()
  503. {
  504. Access::getInstance()->checkUserHasSomeViewAccess();
  505. }
  506. /*
  507. * Current module, action, plugin
  508. */
  509. /**
  510. * Returns the name of the Login plugin currently being used.
  511. * Must be used since it is not allowed to hardcode 'Login' in URLs
  512. * in case another Login plugin is being used.
  513. *
  514. * @return string
  515. */
  516. static public function getLoginPluginName()
  517. {
  518. return Registry::get('auth')->getName();
  519. }
  520. /**
  521. * Returns the plugin currently being used to display the page
  522. *
  523. * @return Plugin
  524. */
  525. static public function getCurrentPlugin()
  526. {
  527. return \Piwik\Plugin\Manager::getInstance()->getLoadedPlugin(Piwik::getModule());
  528. }
  529. /**
  530. * Returns the current module read from the URL (eg. 'API', 'UserSettings', etc.)
  531. *
  532. * @return string
  533. */
  534. static public function getModule()
  535. {
  536. return Common::getRequestVar('module', '', 'string');
  537. }
  538. /**
  539. * Returns the current action read from the URL
  540. *
  541. * @return string
  542. */
  543. static public function getAction()
  544. {
  545. return Common::getRequestVar('action', '', 'string');
  546. }
  547. /**
  548. * Helper method used in API function to introduce array elements in API parameters.
  549. * Array elements can be passed by comma separated values, or using the notation
  550. * array[]=value1&array[]=value2 in the URL.
  551. * This function will handle both cases and return the array.
  552. *
  553. * @param array|string $columns
  554. * @return array
  555. */
  556. static public function getArrayFromApiParameter($columns)
  557. {
  558. if (empty($columns)) {
  559. return array();
  560. }
  561. if (is_array($columns)) {
  562. return $columns;
  563. }
  564. $array = explode(',', $columns);
  565. $array = array_unique($array);
  566. return $array;
  567. }
  568. /**
  569. * Redirects the current request to a new module and action.
  570. *
  571. * @param string $newModule The target module, eg, `'UserCountry'`.
  572. * @param string $newAction The target controller action, eg, `'index'`.
  573. * @param array $parameters The query parameter values to modify before redirecting.
  574. * @api
  575. */
  576. static public function redirectToModule($newModule, $newAction = '', $parameters = array())
  577. {
  578. $newUrl = 'index.php' . Url::getCurrentQueryStringWithParametersModified(
  579. array('module' => $newModule, 'action' => $newAction)
  580. + $parameters
  581. );
  582. Url::redirectToUrl($newUrl);
  583. }
  584. /*
  585. * User input validation
  586. */
  587. /**
  588. * Returns `true` if supplied the email address is a valid.
  589. *
  590. * @param string $emailAddress
  591. * @return bool
  592. * @api
  593. */
  594. static public function isValidEmailString($emailAddress)
  595. {
  596. return (preg_match('/^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9_.-]+\.[a-zA-Z]{2,7}$/D', $emailAddress) > 0);
  597. }
  598. /**
  599. * Returns `true` if the login is valid.
  600. *
  601. * _Warning: does not check if the login already exists! You must use UsersManager_API->userExists as well._
  602. *
  603. * @param string $userLogin
  604. * @throws Exception
  605. * @return bool
  606. */
  607. static public function checkValidLoginString($userLogin)
  608. {
  609. if (!SettingsPiwik::isUserCredentialsSanityCheckEnabled()
  610. && !empty($userLogin)
  611. ) {
  612. return;
  613. }
  614. $loginMinimumLength = 3;
  615. $loginMaximumLength = 100;
  616. $l = strlen($userLogin);
  617. if (!($l >= $loginMinimumLength
  618. && $l <= $loginMaximumLength
  619. && (preg_match('/^[A-Za-z0-9_.@+-]*$/D', $userLogin) > 0))
  620. ) {
  621. throw new Exception(Piwik::translate('UsersManager_ExceptionInvalidLoginFormat', array($loginMinimumLength, $loginMaximumLength)));
  622. }
  623. }
  624. /**
  625. * Utility function that checks if an object type is in a set of types.
  626. *
  627. * @param mixed $o
  628. * @param array $types List of class names that $o is expected to be one of.
  629. * @throws Exception if $o is not an instance of the types contained in $types.
  630. */
  631. static public function checkObjectTypeIs($o, $types)
  632. {
  633. foreach ($types as $type) {
  634. if ($o instanceof $type) {
  635. return;
  636. }
  637. }
  638. $oType = is_object($o) ? get_class($o) : gettype($o);
  639. throw new Exception("Invalid variable type '$oType', expected one of following: " . implode(', ', $types));
  640. }
  641. /**
  642. * Returns true if an array is an associative array, false if otherwise.
  643. *
  644. * This method determines if an array is associative by checking that the
  645. * first element's key is 0, and that each successive element's key is
  646. * one greater than the last.
  647. *
  648. * @param array $array
  649. * @return bool
  650. */
  651. static public function isAssociativeArray($array)
  652. {
  653. reset($array);
  654. if (!is_numeric(key($array))
  655. || key($array) != 0
  656. ) // first key must be 0
  657. {
  658. return true;
  659. }
  660. // check that each key is == next key - 1 w/o actually indexing the array
  661. while (true) {
  662. $current = key($array);
  663. next($array);
  664. $next = key($array);
  665. if ($next === null) {
  666. break;
  667. } else if ($current + 1 != $next) {
  668. return true;
  669. }
  670. }
  671. return false;
  672. }
  673. /**
  674. * Returns the class name of an object without its namespace.
  675. *
  676. * @param mixed|string $object
  677. * @return string
  678. */
  679. public static function getUnnamespacedClassName($object)
  680. {
  681. $className = is_string($object) ? $object : get_class($object);
  682. $parts = explode('\\', $className);
  683. return end($parts);
  684. }
  685. /**
  686. * Post an event to Piwik's event dispatcher which will execute the event's observers.
  687. *
  688. * @param string $eventName The event name.
  689. * @param array $params The parameter array to forward to observer callbacks.
  690. * @param bool $pending If true, plugins that are loaded after this event is fired will
  691. * have their observers for this event executed.
  692. * @param array|null $plugins The list of plugins to execute observers for. If null, all
  693. * plugin observers will be executed.
  694. * @api
  695. */
  696. public static function postEvent($eventName, $params = array(), $pending = false, $plugins = null)
  697. {
  698. EventDispatcher::getInstance()->postEvent($eventName, $params, $pending, $plugins);
  699. }
  700. /**
  701. * Register an observer to an event.
  702. *
  703. * **_Note: Observers should normally be defined in plugin objects. It is unlikely that you will
  704. * need to use this function._**
  705. *
  706. * @param string $eventName The event name.
  707. * @param callable|array $function The observer.
  708. * @api
  709. */
  710. public static function addAction($eventName, $function)
  711. {
  712. EventDispatcher::getInstance()->addObserver($eventName, $function);
  713. }
  714. /**
  715. * Posts an event if we are currently running tests. Whether we are running tests is
  716. * determined by looking for the PIWIK_TEST_MODE constant.
  717. */
  718. public static function postTestEvent($eventName, $params = array(), $pending = false, $plugins = null)
  719. {
  720. if (defined('PIWIK_TEST_MODE')) {
  721. Piwik::postEvent($eventName, $params, $pending, $plugins);
  722. }
  723. }
  724. /**
  725. * Returns an internationalized string using a translation token. If a translation
  726. * cannot be found for the toke, the token is returned.
  727. *
  728. * @param string $translationId Translation ID, eg, `'General_Date'`.
  729. * @param array|string|int $args `sprintf` arguments to be applied to the internationalized
  730. * string.
  731. * @return string The translated string or `$translationId`.
  732. * @api
  733. */
  734. public static function translate($translationId, $args = array())
  735. {
  736. if (!is_array($args)) {
  737. $args = array($args);
  738. }
  739. if (strpos($translationId, "_") !== false) {
  740. list($plugin, $key) = explode("_", $translationId, 2);
  741. if (isset($GLOBALS['Piwik_translations'][$plugin]) && isset($GLOBALS['Piwik_translations'][$plugin][$key])) {
  742. $translationId = $GLOBALS['Piwik_translations'][$plugin][$key];
  743. }
  744. }
  745. if (count($args) == 0) {
  746. return $translationId;
  747. }
  748. return vsprintf($translationId, $args);
  749. }
  750. protected static function getJavascriptTagOptions($idSite, $mergeSubdomains, $mergeAliasUrls)
  751. {
  752. try {
  753. $websiteUrls = APISitesManager::getInstance()->getSiteUrlsFromId($idSite);
  754. } catch (\Exception $e) {
  755. return '';
  756. }
  757. // We need to parse_url to isolate hosts
  758. $websiteHosts = array();
  759. foreach ($websiteUrls as $site_url) {
  760. $referrerParsed = parse_url($site_url);
  761. $websiteHosts[] = $referrerParsed['host'];
  762. }
  763. $options = '';
  764. if ($mergeSubdomains && !empty($websiteHosts)) {
  765. $options .= ' _paq.push(["setCookieDomain", "*.' . $websiteHosts[0] . '"]);' . PHP_EOL;
  766. }
  767. if ($mergeAliasUrls && !empty($websiteHosts)) {
  768. $urls = '["*.' . implode('","*.', $websiteHosts) . '"]';
  769. $options .= ' _paq.push(["setDomains", ' . $urls . ']);' . PHP_EOL;
  770. }
  771. return $options;
  772. }
  773. }