PageRenderTime 56ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/libs/PiwikTracker/PiwikTracker.php

https://github.com/CodeYellowBV/piwik
PHP | 1580 lines | 744 code | 133 blank | 703 comment | 111 complexity | a2576800eecb2b9af73ae16d205edb62 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

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * Piwik - free/libre analytics platform
  4. *
  5. * Client to record visits, page views, Goals, Ecommerce activity (product views, add to carts, Ecommerce orders) in a Piwik server.
  6. * This is a PHP Version of the piwik.js standard Tracking API.
  7. * For more information, see http://piwik.org/docs/tracking-api/
  8. *
  9. * This class requires:
  10. * - json extension (json_decode, json_encode)
  11. * - CURL or STREAM extensions (to issue the http request to Piwik)
  12. *
  13. * @license released under BSD License http://www.opensource.org/licenses/bsd-license.php
  14. * @link http://piwik.org/docs/tracking-api/
  15. *
  16. * @category Piwik
  17. * @package PiwikTracker
  18. */
  19. /**
  20. * PiwikTracker implements the Piwik Tracking Web API.
  21. *
  22. * The PHP Tracking Client provides all features of the Javascript Tracker, such as Ecommerce Tracking, Custom Variable, Event tracking and more.
  23. * Functions are named the same as the Javascript functions.
  24. *
  25. * See introduction docs at: {@link http://piwik.org/docs/tracking-api/}
  26. *
  27. * ### Example: using the PHP PiwikTracker class
  28. *
  29. * The following code snippet is an advanced example of how to track a Page View using the Tracking API PHP client.
  30. *
  31. * $t = new PiwikTracker( $idSite = 1, 'http://example.org/piwik/');
  32. *
  33. * // Optional function calls
  34. * $t->setUserAgent( "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB) Firefox/3.6.6");
  35. * $t->setBrowserLanguage('fr');
  36. * $t->setLocalTime( '12:34:06' );
  37. * $t->setResolution( 1024, 768 );
  38. * $t->setBrowserHasCookies(true);
  39. * $t->setPlugins($flash = true, $java = true, $director = false);
  40. *
  41. * // set a Custom Variable called 'Gender'
  42. * $t->setCustomVariable( 1, 'gender', 'male' );
  43. *
  44. * // If you want to force the visitor IP, or force the server date time to a date in the past,
  45. * // it is required to authenticate the Tracking request by calling setTokenAuth
  46. * // You can pass the Super User token_auth or any user with 'admin' privilege on the website $idSite
  47. * $t->setTokenAuth( $token_auth );
  48. * $t->setIp( "134.10.22.1" );
  49. * $t->setForceVisitDateTime( '2011-04-05 23:55:02' );
  50. *
  51. * // if you wanted to force to record the page view or conversion to a specific visitorId
  52. * // $t->setVisitorId( "33c31e01394bdc63" );
  53. * // Mandatory: set the URL being tracked
  54. * $t->setUrl( $url = 'http://example.org/store/list-category-toys/' );
  55. *
  56. * // Finally, track the page view with a Custom Page Title
  57. * // In the standard JS API, the content of the <title> tag would be set as the page title
  58. * $t->doTrackPageView('This is the page title');
  59. *
  60. * ### Example: tracking Ecommerce interactions
  61. *
  62. * Here is an example showing how to track Ecommerce interactions on your website, using the PHP Tracking API.
  63. * Usually, Ecommerce tracking is done using standard Javascript code,
  64. * but it is very common to record Ecommerce interactions after the fact
  65. * (for example, when payment is done with Paypal and user doesn't come back on the website after purchase).
  66. * For more information about Ecommerce tracking in Piwik, check out the documentation: Tracking Ecommerce in Piwik.
  67. *
  68. * $t = new PiwikTracker( $idSite = 1, 'http://example.org/piwik/');
  69. *
  70. * // Force IP to the actual visitor IP
  71. * $t->setTokenAuth( $token_auth );
  72. * $t->setIp( "134.10.22.1" );
  73. *
  74. * // Example 1: on a Product page, track an "Ecommerce Product view"
  75. * $t->setUrl( $url = 'http://www.mystore.com/Endurance-Shackletons-Legendary-Antarctic-Expedition' );
  76. * $t->setEcommerceView($sku = 'SKU0011', $name = 'Endurance - Shackleton', $category = 'Books');
  77. * $t->doTrackPageView( 'Endurance Shackletons Legendary Antarctic Expedition - Mystore.com');
  78. *
  79. * // Example 2: Tracking Ecommerce Cart containing 2 products
  80. * $t->addEcommerceItem($sku = 'SKU0011', $name = 'Endurance - Shackleton' , $category = 'Books', $price = 17, $quantity = 1);
  81. * // Note that when setting a product category, you can specify an array of up to 5 categories to track for this product
  82. * $t->addEcommerceItem($sku = 'SKU0321', $name = 'AmĂŠlie' , $categories = array('DVD Foreign','Best sellers','Our pick'), $price = 25, $quantity = 1);
  83. * $t->doTrackEcommerceCartUpdate($grandTotal = 42);
  84. *
  85. * // Example 3: Tracking Ecommerce Order
  86. * $t->addEcommerceItem($sku = 'SKU0011', $name = 'Endurance - Shackleton' , $category = 'Books', $price = 17, $quantity = 1);
  87. * $t->addEcommerceItem($sku = 'SKU0321', $name = 'AmĂŠlie' , $categories = array('DVD Foreign','Best sellers','Our pick'), $price = 25, $quantity = 1);
  88. * $t->doTrackEcommerceOrder($orderId = 'B000111387', $grandTotal = 55.5, $subTotal = 42, $tax = 8, $shipping = 5.5, $discount = 10);
  89. *
  90. * ### Note: authenticating with the token_auth
  91. *
  92. * To set the visitor IP, or the date and time of the visit, or to force to record the visit (or page, or goal conversion) to a specific Visitor ID,
  93. * you must call setTokenAuth( $token_auth ). The token_auth must be either the Super User token_auth,
  94. * or the token_auth of any user with 'admin' permission for the website you are recording data against.
  95. *
  96. * @package PiwikTracker
  97. * @api
  98. */
  99. class PiwikTracker
  100. {
  101. /**
  102. * Piwik base URL, for example http://example.org/piwik/
  103. * Must be set before using the class by calling
  104. * PiwikTracker::$URL = 'http://yourwebsite.org/piwik/';
  105. *
  106. * @var string
  107. */
  108. static public $URL = '';
  109. /**
  110. * API Version
  111. *
  112. * @ignore
  113. * @var int
  114. */
  115. const VERSION = 1;
  116. /**
  117. * @ignore
  118. */
  119. public $DEBUG_APPEND_URL = '';
  120. /**
  121. * Visitor ID length
  122. *
  123. * @ignore
  124. */
  125. const LENGTH_VISITOR_ID = 16;
  126. /**
  127. * Charset
  128. * @see setPageCharset
  129. * @ignore
  130. */
  131. const DEFAULT_CHARSET_PARAMETER_VALUES = 'utf-8';
  132. /**
  133. * See piwik.js
  134. */
  135. const FIRST_PARTY_COOKIES_PREFIX = '_pk_';
  136. /**
  137. * Ecommerce item page view tracking stores item's metadata in these Custom Variables slots.
  138. */
  139. const CVAR_INDEX_ECOMMERCE_ITEM_PRICE = 2;
  140. const CVAR_INDEX_ECOMMERCE_ITEM_SKU = 3;
  141. const CVAR_INDEX_ECOMMERCE_ITEM_NAME = 4;
  142. const CVAR_INDEX_ECOMMERCE_ITEM_CATEGORY = 5;
  143. const DEFAULT_COOKIE_PATH = '/';
  144. /**
  145. * Builds a PiwikTracker object, used to track visits, pages and Goal conversions
  146. * for a specific website, by using the Piwik Tracking API.
  147. *
  148. * @param int $idSite Id site to be tracked
  149. * @param string $apiUrl "http://example.org/piwik/" or "http://piwik.example.org/"
  150. * If set, will overwrite PiwikTracker::$URL
  151. */
  152. function __construct($idSite, $apiUrl = '')
  153. {
  154. $this->userAgent = false;
  155. $this->localHour = false;
  156. $this->localMinute = false;
  157. $this->localSecond = false;
  158. $this->hasCookies = false;
  159. $this->plugins = false;
  160. $this->pageCustomVar = false;
  161. $this->eventCustomVar = false;
  162. $this->customData = false;
  163. $this->forcedDatetime = false;
  164. $this->forcedNewVisit = false;
  165. $this->token_auth = false;
  166. $this->attributionInfo = false;
  167. $this->ecommerceLastOrderTimestamp = false;
  168. $this->ecommerceItems = array();
  169. $this->generationTime = false;
  170. $this->idSite = $idSite;
  171. $this->urlReferrer = !empty($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : false;
  172. $this->pageCharset = self::DEFAULT_CHARSET_PARAMETER_VALUES;
  173. $this->pageUrl = self::getCurrentUrl();
  174. $this->ip = !empty($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : false;
  175. $this->acceptLanguage = !empty($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? $_SERVER['HTTP_ACCEPT_LANGUAGE'] : false;
  176. $this->userAgent = !empty($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : false;
  177. if (!empty($apiUrl)) {
  178. self::$URL = $apiUrl;
  179. }
  180. // Life of the visitor cookie (in sec)
  181. $this->configVisitorCookieTimeout = 63072000; // 2 years
  182. // Life of the session cookie (in sec)
  183. $this->configSessionCookieTimeout = 1800; // 30 minutes
  184. // Life of the session cookie (in sec)
  185. $this->configReferralCookieTimeout = 15768000; // 6 months
  186. // Visitor Ids in order
  187. $this->forcedVisitorId = false;
  188. $this->cookieVisitorId = false;
  189. $this->randomVisitorId = false;
  190. $this->setNewVisitorId();
  191. $this->configCookiesDisabled = false;
  192. $this->configCookiePath = self::DEFAULT_COOKIE_PATH;
  193. $this->configCookieDomain = '';
  194. $this->currentTs = time();
  195. $this->createTs = $this->currentTs;
  196. $this->visitCount = 0;
  197. $this->currentVisitTs = false;
  198. $this->lastVisitTs = false;
  199. $this->lastEcommerceOrderTs = false;
  200. // Allow debug while blocking the request
  201. $this->requestTimeout = 600;
  202. $this->doBulkRequests = false;
  203. $this->storedTrackingActions = array();
  204. $this->visitorCustomVar = $this->getCustomVariablesFromCookie();
  205. }
  206. /**
  207. * By default, Piwik expects utf-8 encoded values, for example
  208. * for the page URL parameter values, Page Title, etc.
  209. * It is recommended to only send UTF-8 data to Piwik.
  210. * If required though, you can also specify another charset using this function.
  211. *
  212. * @param string $charset
  213. */
  214. public function setPageCharset($charset = '')
  215. {
  216. $this->pageCharset = $charset;
  217. }
  218. /**
  219. * Sets the current URL being tracked
  220. *
  221. * @param string $url Raw URL (not URL encoded)
  222. */
  223. public function setUrl($url)
  224. {
  225. $this->pageUrl = $url;
  226. }
  227. /**
  228. * Sets the URL referrer used to track Referrers details for new visits.
  229. *
  230. * @param string $url Raw URL (not URL encoded)
  231. */
  232. public function setUrlReferrer($url)
  233. {
  234. $this->urlReferrer = $url;
  235. }
  236. /**
  237. * Sets the time that generating the document on the server side took.
  238. *
  239. * @param int $timeMs Generation time in ms
  240. */
  241. public function setGenerationTime($timeMs)
  242. {
  243. $this->generationTime = $timeMs;
  244. }
  245. /**
  246. * @deprecated
  247. * @ignore
  248. */
  249. public function setUrlReferer($url)
  250. {
  251. $this->setUrlReferrer($url);
  252. }
  253. /**
  254. * Sets the attribution information to the visit, so that subsequent Goal conversions are
  255. * properly attributed to the right Referrer URL, timestamp, Campaign Name & Keyword.
  256. *
  257. * This must be a JSON encoded string that would typically be fetched from the JS API:
  258. * piwikTracker.getAttributionInfo() and that you have JSON encoded via JSON2.stringify()
  259. *
  260. * If you call enableCookies() then these referral attribution values will be set
  261. * to the 'ref' first party cookie storing referral information.
  262. *
  263. * @param string $jsonEncoded JSON encoded array containing Attribution info
  264. * @throws Exception
  265. * @see function getAttributionInfo() in https://github.com/piwik/piwik/blob/master/js/piwik.js
  266. */
  267. public function setAttributionInfo($jsonEncoded)
  268. {
  269. $decoded = json_decode($jsonEncoded, $assoc = true);
  270. if (!is_array($decoded)) {
  271. throw new Exception("setAttributionInfo() is expecting a JSON encoded string, $jsonEncoded given");
  272. }
  273. $this->attributionInfo = $decoded;
  274. }
  275. /**
  276. * Sets Visit Custom Variable.
  277. * See http://piwik.org/docs/custom-variables/
  278. *
  279. * @param int $id Custom variable slot ID from 1-5
  280. * @param string $name Custom variable name
  281. * @param string $value Custom variable value
  282. * @param string $scope Custom variable scope. Possible values: visit, page, event
  283. * @throws Exception
  284. */
  285. public function setCustomVariable($id, $name, $value, $scope = 'visit')
  286. {
  287. if (!is_int($id)) {
  288. throw new Exception("Parameter id to setCustomVariable should be an integer");
  289. }
  290. if ($scope == 'page') {
  291. $this->pageCustomVar[$id] = array($name, $value);
  292. } elseif($scope == 'event') {
  293. $this->eventCustomVar[$id] = array($name, $value);
  294. } elseif ($scope == 'visit') {
  295. $this->visitorCustomVar[$id] = array($name, $value);
  296. } else {
  297. throw new Exception("Invalid 'scope' parameter value");
  298. }
  299. }
  300. /**
  301. * Returns the currently assigned Custom Variable.
  302. *
  303. * If scope is 'visit', it will attempt to read the value set in the first party cookie created by Piwik Tracker ($_COOKIE array).
  304. *
  305. * @param int $id Custom Variable integer index to fetch from cookie. Should be a value from 1 to 5
  306. * @param string $scope Custom variable scope. Possible values: visit, page, event
  307. *
  308. * @throws Exception
  309. * @return mixed An array with this format: array( 0 => CustomVariableName, 1 => CustomVariableValue ) or false
  310. * @see Piwik.js getCustomVariable()
  311. */
  312. public function getCustomVariable($id, $scope = 'visit')
  313. {
  314. if ($scope == 'page') {
  315. return isset($this->pageCustomVar[$id]) ? $this->pageCustomVar[$id] : false;
  316. } elseif ($scope == 'event') {
  317. return isset($this->eventCustomVar[$id]) ? $this->eventCustomVar[$id] : false;
  318. } else if ($scope != 'visit') {
  319. throw new Exception("Invalid 'scope' parameter value");
  320. }
  321. if (!empty($this->visitorCustomVar[$id])) {
  322. return $this->visitorCustomVar[$id];
  323. }
  324. $cookieDecoded = $this->getCustomVariablesFromCookie();
  325. if (!is_int($id)) {
  326. throw new Exception("Parameter to getCustomVariable should be an integer");
  327. }
  328. if (!is_array($cookieDecoded)
  329. || !isset($cookieDecoded[$id])
  330. || !is_array($cookieDecoded[$id])
  331. || count($cookieDecoded[$id]) != 2
  332. ) {
  333. return false;
  334. }
  335. return $cookieDecoded[$id];
  336. }
  337. /**
  338. * Clears any Custom Variable that may be have been set.
  339. *
  340. * This can be useful when you have enabled bulk requests,
  341. * and you wish to clear Custom Variables of 'visit' scope.
  342. */
  343. public function clearCustomVariables()
  344. {
  345. $this->visitorCustomVar = array();
  346. $this->pageCustomVar = array();
  347. $this->eventCustomVar = array();
  348. }
  349. /**
  350. * Sets the current visitor ID to a random new one.
  351. */
  352. public function setNewVisitorId()
  353. {
  354. $this->randomVisitorId = substr(md5(uniqid(rand(), true)), 0, self::LENGTH_VISITOR_ID);
  355. $this->forcedVisitorId = false;
  356. $this->cookieVisitorId = false;
  357. }
  358. /**
  359. * Sets the current site ID.
  360. *
  361. * @param int $idSite
  362. */
  363. public function setIdSite($idSite)
  364. {
  365. $this->idSite = $idSite;
  366. }
  367. /**
  368. * Sets the Browser language. Used to guess visitor countries when GeoIP is not enabled
  369. *
  370. * @param string $acceptLanguage For example "fr-fr"
  371. */
  372. public function setBrowserLanguage($acceptLanguage)
  373. {
  374. $this->acceptLanguage = $acceptLanguage;
  375. }
  376. /**
  377. * Sets the user agent, used to detect OS and browser.
  378. * If this function is not called, the User Agent will default to the current user agent.
  379. *
  380. * @param string $userAgent
  381. */
  382. public function setUserAgent($userAgent)
  383. {
  384. $this->userAgent = $userAgent;
  385. }
  386. /**
  387. * Sets the country of the visitor. If not used, Piwik will try to find the country
  388. * using either the visitor's IP address or language.
  389. *
  390. * Allowed only for Admin/Super User, must be used along with setTokenAuth().
  391. * @param string $country
  392. */
  393. public function setCountry($country)
  394. {
  395. $this->country = $country;
  396. }
  397. /**
  398. * Sets the region of the visitor. If not used, Piwik may try to find the region
  399. * using the visitor's IP address (if configured to do so).
  400. *
  401. * Allowed only for Admin/Super User, must be used along with setTokenAuth().
  402. * @param string $region
  403. */
  404. public function setRegion($region)
  405. {
  406. $this->region = $region;
  407. }
  408. /**
  409. * Sets the city of the visitor. If not used, Piwik may try to find the city
  410. * using the visitor's IP address (if configured to do so).
  411. *
  412. * Allowed only for Admin/Super User, must be used along with setTokenAuth().
  413. * @param string $city
  414. */
  415. public function setCity($city)
  416. {
  417. $this->city = $city;
  418. }
  419. /**
  420. * Sets the latitude of the visitor. If not used, Piwik may try to find the visitor's
  421. * latitude using the visitor's IP address (if configured to do so).
  422. *
  423. * Allowed only for Admin/Super User, must be used along with setTokenAuth().
  424. * @param float $lat
  425. */
  426. public function setLatitude($lat)
  427. {
  428. $this->lat = $lat;
  429. }
  430. /**
  431. * Sets the longitude of the visitor. If not used, Piwik may try to find the visitor's
  432. * longitude using the visitor's IP address (if configured to do so).
  433. *
  434. * Allowed only for Admin/Super User, must be used along with setTokenAuth().
  435. * @param float $long
  436. */
  437. public function setLongitude($long)
  438. {
  439. $this->long = $long;
  440. }
  441. /**
  442. * Enables the bulk request feature. When used, each tracking action is stored until the
  443. * doBulkTrack method is called. This method will send all tracking data at once.
  444. *
  445. */
  446. public function enableBulkTracking()
  447. {
  448. $this->doBulkRequests = true;
  449. }
  450. /**
  451. * Enable Cookie Creation - this will cause a first party VisitorId cookie to be set when the VisitorId is set or reset
  452. *
  453. * @param string $domain (optional) Set first-party cookie domain. Accepted values: example.com, *.example.com (same as .example.com) or subdomain.example.com
  454. * @param string $path (optional) Set first-party cookie path
  455. */
  456. public function enableCookies( $domain = '', $path = '/' )
  457. {
  458. $this->configCookiesDisabled = false;
  459. $this->configCookieDomain = self::domainFixup($domain);
  460. $this->configCookiePath = $path;
  461. }
  462. /**
  463. * Fix-up domain
  464. */
  465. static protected function domainFixup($domain)
  466. {
  467. $dl = strlen($domain) - 1;
  468. // remove trailing '.'
  469. if ($domain{$dl} === '.') {
  470. $domain = substr($domain, 0, $dl);
  471. }
  472. // remove leading '*'
  473. if (substr($domain, 0, 2) === '*.') {
  474. $domain = substr($domain, 1);
  475. }
  476. return $domain;
  477. }
  478. /**
  479. * Get cookie name with prefix and domain hash
  480. */
  481. protected function getCookieName($cookieName) {
  482. // NOTE: If the cookie name is changed, we must also update the method in piwik.js with the same name.
  483. $hash = substr( sha1( ($this->configCookieDomain == '' ? self::getCurrentHost() : $this->configCookieDomain) . $this->configCookiePath ), 0, 4);
  484. return self::FIRST_PARTY_COOKIES_PREFIX . $cookieName . '.' . $this->idSite . '.' . $hash;
  485. }
  486. /**
  487. * Tracks a page view
  488. *
  489. * @param string $documentTitle Page title as it will appear in the Actions > Page titles report
  490. * @return mixed Response string or true if using bulk requests.
  491. */
  492. public function doTrackPageView($documentTitle)
  493. {
  494. $url = $this->getUrlTrackPageView($documentTitle);
  495. return $this->sendRequest($url);
  496. }
  497. /**
  498. * Tracks an event
  499. *
  500. * @param string $category The Event Category (Videos, Music, Games...)
  501. * @param string $action The Event's Action (Play, Pause, Duration, Add Playlist, Downloaded, Clicked...)
  502. * @param string $name (optional) The Event's object Name (a particular Movie name, or Song name, or File name...)
  503. * @param float $value (optional) The Event's value
  504. * @return mixed Response string or true if using bulk requests.
  505. */
  506. public function doTrackEvent($category, $action, $name = false, $value = false)
  507. {
  508. $url = $this->getUrlTrackEvent($category, $action, $name, $value);
  509. return $this->sendRequest($url);
  510. }
  511. /**
  512. * Tracks an internal Site Search query, and optionally tracks the Search Category, and Search results Count.
  513. * These are used to populate reports in Actions > Site Search.
  514. *
  515. * @param string $keyword Searched query on the site
  516. * @param string $category (optional) Search engine category if applicable
  517. * @param bool|int $countResults (optional) results displayed on the search result page. Used to track "zero result" keywords.
  518. *
  519. * @return mixed Response or true if using bulk requests.
  520. */
  521. public function doTrackSiteSearch($keyword, $category = '', $countResults = false)
  522. {
  523. $url = $this->getUrlTrackSiteSearch($keyword, $category, $countResults);
  524. return $this->sendRequest($url);
  525. }
  526. /**
  527. * Records a Goal conversion
  528. *
  529. * @param int $idGoal Id Goal to record a conversion
  530. * @param float $revenue Revenue for this conversion
  531. * @return mixed Response or true if using bulk request
  532. */
  533. public function doTrackGoal($idGoal, $revenue = 0.0)
  534. {
  535. $url = $this->getUrlTrackGoal($idGoal, $revenue);
  536. return $this->sendRequest($url);
  537. }
  538. /**
  539. * Tracks a download or outlink
  540. *
  541. * @param string $actionUrl URL of the download or outlink
  542. * @param string $actionType Type of the action: 'download' or 'link'
  543. * @return mixed Response or true if using bulk request
  544. */
  545. public function doTrackAction($actionUrl, $actionType)
  546. {
  547. // Referrer could be udpated to be the current URL temporarily (to mimic JS behavior)
  548. $url = $this->getUrlTrackAction($actionUrl, $actionType);
  549. return $this->sendRequest($url);
  550. }
  551. /**
  552. * Adds an item in the Ecommerce order.
  553. *
  554. * This should be called before doTrackEcommerceOrder(), or before doTrackEcommerceCartUpdate().
  555. * This function can be called for all individual products in the cart (or order).
  556. * SKU parameter is mandatory. Other parameters are optional (set to false if value not known).
  557. * Ecommerce items added via this function are automatically cleared when doTrackEcommerceOrder() or getUrlTrackEcommerceOrder() is called.
  558. *
  559. * @param string $sku (required) SKU, Product identifier
  560. * @param string $name (optional) Product name
  561. * @param string|array $category (optional) Product category, or array of product categories (up to 5 categories can be specified for a given product)
  562. * @param float|int $price (optional) Individual product price (supports integer and decimal prices)
  563. * @param int $quantity (optional) Product quantity. If not specified, will default to 1 in the Reports
  564. * @throws Exception
  565. */
  566. public function addEcommerceItem($sku, $name = '', $category = '', $price = 0.0, $quantity = 1)
  567. {
  568. if (empty($sku)) {
  569. throw new Exception("You must specify a SKU for the Ecommerce item");
  570. }
  571. $this->ecommerceItems[$sku] = array($sku, $name, $category, $price, $quantity);
  572. }
  573. /**
  574. * Tracks a Cart Update (add item, remove item, update item).
  575. *
  576. * On every Cart update, you must call addEcommerceItem() for each item (product) in the cart,
  577. * including the items that haven't been updated since the last cart update.
  578. * Items which were in the previous cart and are not sent in later Cart updates will be deleted from the cart (in the database).
  579. *
  580. * @param float $grandTotal Cart grandTotal (typically the sum of all items' prices)
  581. * @return mixed Response or true if using bulk request
  582. */
  583. public function doTrackEcommerceCartUpdate($grandTotal)
  584. {
  585. $url = $this->getUrlTrackEcommerceCartUpdate($grandTotal);
  586. return $this->sendRequest($url);
  587. }
  588. /**
  589. * Sends all stored tracking actions at once. Only has an effect if bulk tracking is enabled.
  590. *
  591. * To enable bulk tracking, call enableBulkTracking().
  592. *
  593. * @throws Exception
  594. * @return string Response
  595. */
  596. public function doBulkTrack()
  597. {
  598. if (empty($this->storedTrackingActions)) {
  599. throw new Exception("Error: you must call the function doTrackPageView or doTrackGoal from this class, before calling this method doBulkTrack()");
  600. }
  601. $data = array('requests' => $this->storedTrackingActions);
  602. // token_auth is not required by default, except if bulk_requests_require_authentication=1
  603. if(!empty($this->token_auth)) {
  604. $data['token_auth'] = $this->token_auth;
  605. }
  606. $postData = json_encode($data);
  607. $response = $this->sendRequest($this->getBaseUrl(), 'POST', $postData, $force = true);
  608. $this->storedTrackingActions = array();
  609. return $response;
  610. }
  611. /**
  612. * Tracks an Ecommerce order.
  613. *
  614. * If the Ecommerce order contains items (products), you must call first the addEcommerceItem() for each item in the order.
  615. * All revenues (grandTotal, subTotal, tax, shipping, discount) will be individually summed and reported in Piwik reports.
  616. * Only the parameters $orderId and $grandTotal are required.
  617. *
  618. * @param string|int $orderId (required) Unique Order ID.
  619. * This will be used to count this order only once in the event the order page is reloaded several times.
  620. * orderId must be unique for each transaction, even on different days, or the transaction will not be recorded by Piwik.
  621. * @param float $grandTotal (required) Grand Total revenue of the transaction (including tax, shipping, etc.)
  622. * @param float $subTotal (optional) Sub total amount, typically the sum of items prices for all items in this order (before Tax and Shipping costs are applied)
  623. * @param float $tax (optional) Tax amount for this order
  624. * @param float $shipping (optional) Shipping amount for this order
  625. * @param float $discount (optional) Discounted amount in this order
  626. * @return mixed Response or true if using bulk request
  627. */
  628. public function doTrackEcommerceOrder($orderId, $grandTotal, $subTotal = 0.0, $tax = 0.0, $shipping = 0.0, $discount = 0.0)
  629. {
  630. $url = $this->getUrlTrackEcommerceOrder($orderId, $grandTotal, $subTotal, $tax, $shipping, $discount);
  631. return $this->sendRequest($url);
  632. }
  633. /**
  634. * Sets the current page view as an item (product) page view, or an Ecommerce Category page view.
  635. *
  636. * This must be called before doTrackPageView() on this product/category page.
  637. * It will set 3 custom variables of scope "page" with the SKU, Name and Category for this page view.
  638. * Note: Custom Variables of scope "page" slots 3, 4 and 5 will be used.
  639. *
  640. * On a category page, you may set the parameter $category only and set the other parameters to false.
  641. *
  642. * Tracking Product/Category page views will allow Piwik to report on Product & Categories
  643. * conversion rates (Conversion rate = Ecommerce orders containing this product or category / Visits to the product or category)
  644. *
  645. * @param string $sku Product SKU being viewed
  646. * @param string $name Product Name being viewed
  647. * @param string|array $category Category being viewed. On a Product page, this is the product's category.
  648. * You can also specify an array of up to 5 categories for a given page view.
  649. * @param float $price Specify the price at which the item was displayed
  650. */
  651. public function setEcommerceView($sku = '', $name = '', $category = '', $price = 0.0)
  652. {
  653. if (!empty($category)) {
  654. if (is_array($category)) {
  655. $category = json_encode($category);
  656. }
  657. } else {
  658. $category = "";
  659. }
  660. $this->pageCustomVar[self::CVAR_INDEX_ECOMMERCE_ITEM_CATEGORY] = array('_pkc', $category);
  661. if (!empty($price)) {
  662. $this->pageCustomVar[self::CVAR_INDEX_ECOMMERCE_ITEM_PRICE] = array('_pkp', (float)$price);
  663. }
  664. // On a category page, do not record "Product name not defined"
  665. if (empty($sku) && empty($name)) {
  666. return;
  667. }
  668. if (!empty($sku)) {
  669. $this->pageCustomVar[self::CVAR_INDEX_ECOMMERCE_ITEM_SKU] = array('_pks', $sku);
  670. }
  671. if (empty($name)) {
  672. $name = "";
  673. }
  674. $this->pageCustomVar[self::CVAR_INDEX_ECOMMERCE_ITEM_NAME] = array('_pkn', $name);
  675. }
  676. /**
  677. * Returns URL used to track Ecommerce Cart updates
  678. * Calling this function will reinitializes the property ecommerceItems to empty array
  679. * so items will have to be added again via addEcommerceItem()
  680. * @ignore
  681. */
  682. public function getUrlTrackEcommerceCartUpdate($grandTotal)
  683. {
  684. $url = $this->getUrlTrackEcommerce($grandTotal);
  685. return $url;
  686. }
  687. /**
  688. * Returns URL used to track Ecommerce Orders
  689. * Calling this function will reinitializes the property ecommerceItems to empty array
  690. * so items will have to be added again via addEcommerceItem()
  691. * @ignore
  692. */
  693. public function getUrlTrackEcommerceOrder($orderId, $grandTotal, $subTotal = 0.0, $tax = 0.0, $shipping = 0.0, $discount = 0.0)
  694. {
  695. if (empty($orderId)) {
  696. throw new Exception("You must specifiy an orderId for the Ecommerce order");
  697. }
  698. $url = $this->getUrlTrackEcommerce($grandTotal, $subTotal, $tax, $shipping, $discount);
  699. $url .= '&ec_id=' . urlencode($orderId);
  700. $this->ecommerceLastOrderTimestamp = $this->getTimestamp();
  701. return $url;
  702. }
  703. /**
  704. * Returns URL used to track Ecommerce orders
  705. * Calling this function will reinitializes the property ecommerceItems to empty array
  706. * so items will have to be added again via addEcommerceItem()
  707. * @ignore
  708. */
  709. protected function getUrlTrackEcommerce($grandTotal, $subTotal = 0.0, $tax = 0.0, $shipping = 0.0, $discount = 0.0)
  710. {
  711. if (!is_numeric($grandTotal)) {
  712. throw new Exception("You must specifiy a grandTotal for the Ecommerce order (or Cart update)");
  713. }
  714. $url = $this->getRequest($this->idSite);
  715. $url .= '&idgoal=0';
  716. if (!empty($grandTotal)) {
  717. $url .= '&revenue=' . $grandTotal;
  718. }
  719. if (!empty($subTotal)) {
  720. $url .= '&ec_st=' . $subTotal;
  721. }
  722. if (!empty($tax)) {
  723. $url .= '&ec_tx=' . $tax;
  724. }
  725. if (!empty($shipping)) {
  726. $url .= '&ec_sh=' . $shipping;
  727. }
  728. if (!empty($discount)) {
  729. $url .= '&ec_dt=' . $discount;
  730. }
  731. if (!empty($this->ecommerceItems)) {
  732. // Removing the SKU index in the array before JSON encoding
  733. $items = array();
  734. foreach ($this->ecommerceItems as $item) {
  735. $items[] = $item;
  736. }
  737. $url .= '&ec_items=' . urlencode(json_encode($items));
  738. }
  739. $this->ecommerceItems = array();
  740. return $url;
  741. }
  742. /**
  743. * Builds URL to track a page view.
  744. *
  745. * @see doTrackPageView()
  746. * @param string $documentTitle Page view name as it will appear in Piwik reports
  747. * @return string URL to piwik.php with all parameters set to track the pageview
  748. */
  749. public function getUrlTrackPageView($documentTitle = '')
  750. {
  751. $url = $this->getRequest($this->idSite);
  752. if (strlen($documentTitle) > 0) {
  753. $url .= '&action_name=' . urlencode($documentTitle);
  754. }
  755. return $url;
  756. }
  757. /**
  758. * Builds URL to track a custom event.
  759. *
  760. * @see doTrackEvent()
  761. * @param string $category The Event Category (Videos, Music, Games...)
  762. * @param string $action The Event's Action (Play, Pause, Duration, Add Playlist, Downloaded, Clicked...)
  763. * @param string $name (optional) The Event's object Name (a particular Movie name, or Song name, or File name...)
  764. * @param float $value (optional) The Event's value
  765. * @return string URL to piwik.php with all parameters set to track the pageview
  766. */
  767. public function getUrlTrackEvent($category, $action, $name = false, $value = false)
  768. {
  769. $url = $this->getRequest($this->idSite);
  770. if(strlen($category) == 0) {
  771. throw new Exception("You must specify an Event Category name (Music, Videos, Games...).");
  772. }
  773. if(strlen($action) == 0) {
  774. throw new Exception("You must specify an Event action (click, view, add...).");
  775. }
  776. $url .= '&e_c=' . urlencode($category);
  777. $url .= '&e_a=' . urlencode($action);
  778. if(strlen($name) > 0) {
  779. $url .= '&e_n=' . urlencode($name);
  780. }
  781. if(strlen($value) > 0) {
  782. $url .= '&e_v=' . $value;
  783. }
  784. return $url;
  785. }
  786. /**
  787. * Builds URL to track a site search.
  788. *
  789. * @see doTrackSiteSearch()
  790. * @param string $keyword
  791. * @param string $category
  792. * @param int $countResults
  793. * @return string
  794. */
  795. public function getUrlTrackSiteSearch($keyword, $category, $countResults)
  796. {
  797. $url = $this->getRequest($this->idSite);
  798. $url .= '&search=' . urlencode($keyword);
  799. if (strlen($category) > 0) {
  800. $url .= '&search_cat=' . urlencode($category);
  801. }
  802. if (!empty($countResults) || $countResults === 0) {
  803. $url .= '&search_count=' . (int)$countResults;
  804. }
  805. return $url;
  806. }
  807. /**
  808. * Builds URL to track a goal with idGoal and revenue.
  809. *
  810. * @see doTrackGoal()
  811. * @param int $idGoal Id Goal to record a conversion
  812. * @param float $revenue Revenue for this conversion
  813. * @return string URL to piwik.php with all parameters set to track the goal conversion
  814. */
  815. public function getUrlTrackGoal($idGoal, $revenue = 0.0)
  816. {
  817. $url = $this->getRequest($this->idSite);
  818. $url .= '&idgoal=' . $idGoal;
  819. if (!empty($revenue)) {
  820. $url .= '&revenue=' . $revenue;
  821. }
  822. return $url;
  823. }
  824. /**
  825. * Builds URL to track a new action.
  826. *
  827. * @see doTrackAction()
  828. * @param string $actionUrl URL of the download or outlink
  829. * @param string $actionType Type of the action: 'download' or 'link'
  830. * @return string URL to piwik.php with all parameters set to track an action
  831. */
  832. public function getUrlTrackAction($actionUrl, $actionType)
  833. {
  834. $url = $this->getRequest($this->idSite);
  835. $url .= '&' . $actionType . '=' . $actionUrl;
  836. return $url;
  837. }
  838. /**
  839. * Overrides server date and time for the tracking requests.
  840. * By default Piwik will track requests for the "current datetime" but this function allows you
  841. * to track visits in the past. All times are in UTC.
  842. *
  843. * Allowed only for Super User, must be used along with setTokenAuth()
  844. * @see setTokenAuth()
  845. * @param string $dateTime Date with the format 'Y-m-d H:i:s', or a UNIX timestamp
  846. */
  847. public function setForceVisitDateTime($dateTime)
  848. {
  849. $this->forcedDatetime = $dateTime;
  850. }
  851. /**
  852. * Forces Piwik to create a new visit for the tracking request.
  853. *
  854. * By default, Piwik will create a new visit if the last request by this user was more than 30 minutes ago.
  855. * If you call setForceNewVisit() before calling doTrack*, then a new visit will be created for this request.
  856. *
  857. * Allowed only for Super User, must be used along with setTokenAuth()
  858. *
  859. * @see setTokenAuth()
  860. */
  861. public function setForceNewVisit()
  862. {
  863. $this->forcedNewVisit = true;
  864. }
  865. /**
  866. * Overrides IP address
  867. *
  868. * Allowed only for Super User, must be used along with setTokenAuth()
  869. * @see setTokenAuth()
  870. * @param string $ip IP string, eg. 130.54.2.1
  871. */
  872. public function setIp($ip)
  873. {
  874. $this->ip = $ip;
  875. }
  876. /**
  877. * Forces the requests to be recorded for the specified Visitor ID
  878. * rather than using the heuristics based on IP and other attributes.
  879. *
  880. * Allowed only for Admin/Super User, must be used along with setTokenAuth().
  881. *
  882. * You may set the Visitor ID based on a user attribute, for example the user email:
  883. * $v->setVisitorId( substr(md5( $userEmail ), 0, 16));
  884. *
  885. * If not set, the visitor ID will be fetched from the 1st party cookie, or will be set to a random UUID.
  886. *
  887. * @see setTokenAuth()
  888. * @param string $visitorId 16 hexadecimal characters visitor ID, eg. "33c31e01394bdc63"
  889. * @throws Exception
  890. */
  891. public function setVisitorId($visitorId)
  892. {
  893. $hexChars = '01234567890abcdefABCDEF';
  894. if (strlen($visitorId) != self::LENGTH_VISITOR_ID
  895. || strspn($visitorId, $hexChars) !== strlen($visitorId)
  896. ) {
  897. throw new Exception("setVisitorId() expects a "
  898. . self::LENGTH_VISITOR_ID
  899. . " characters hexadecimal string (containing only the following: "
  900. . $hexChars
  901. . ")");
  902. }
  903. $this->forcedVisitorId = $visitorId;
  904. }
  905. /**
  906. * If the user initiating the request has the Piwik first party cookie,
  907. * this function will try and return the ID parsed from this first party cookie (found in $_COOKIE).
  908. *
  909. * If you call this function from a server, where the call is triggered by a cron or script
  910. * not initiated by the actual visitor being tracked, then it will return
  911. * the random Visitor ID that was assigned to this visit object.
  912. *
  913. * This can be used if you wish to record more visits, actions or goals for this visitor ID later on.
  914. *
  915. * @return string 16 hex chars visitor ID string
  916. */
  917. public function getVisitorId()
  918. {
  919. if (!empty($this->forcedVisitorId)) {
  920. return $this->forcedVisitorId;
  921. } else if ($this->loadVisitorIdCookie()) {
  922. return $this->cookieVisitorId;
  923. } else {
  924. return $this->randomVisitorId;
  925. }
  926. }
  927. /**
  928. * Loads values from the VisitorId Cookie
  929. *
  930. * @return bool True if cookie exists and is valid, False otherwise
  931. */
  932. protected function loadVisitorIdCookie()
  933. {
  934. $idCookie = $this->getCookieMatchingName('id');
  935. if ($idCookie === false) {
  936. return false;
  937. }
  938. $parts = explode('.', $idCookie);
  939. if (strlen($parts[0]) != self::LENGTH_VISITOR_ID) {
  940. return false;
  941. }
  942. $this->cookieVisitorId = $parts[0]; // provides backward compatibility since getVisitorId() didn't change any existing VisitorId value
  943. $this->createTs = $parts[1];
  944. $this->visitCount = (int)$parts[2];
  945. $this->currentVisitTs = $parts[3];
  946. $this->lastVisitTs = $parts[4];
  947. if(isset($parts[5])) {
  948. $this->lastEcommerceOrderTs = $parts[5];
  949. }
  950. return true;
  951. }
  952. /**
  953. * Deletes all first party cookies from the client
  954. */
  955. public function deleteCookies()
  956. {
  957. $expire = $this->currentTs - 86400;
  958. $cookies = array('id', 'ses', 'cvar', 'ref');
  959. foreach($cookies as $cookie) {
  960. $this->setCookie($cookie, '', $expire);
  961. }
  962. }
  963. /**
  964. * Returns the currently assigned Attribution Information stored in a first party cookie.
  965. *
  966. * This function will only work if the user is initiating the current request, and his cookies
  967. * can be read by PHP from the $_COOKIE array.
  968. *
  969. * @return string JSON Encoded string containing the Referrer information for Goal conversion attribution.
  970. * Will return false if the cookie could not be found
  971. * @see Piwik.js getAttributionInfo()
  972. */
  973. public function getAttributionInfo()
  974. {
  975. if(!empty($this->attributionInfo)) {
  976. return json_encode($this->attributionInfo);
  977. }
  978. return $this->getCookieMatchingName('ref');
  979. }
  980. /**
  981. * Some Tracking API functionnality requires express authentication, using either the
  982. * Super User token_auth, or a user with 'admin' access to the website.
  983. *
  984. * The following features require access:
  985. * - force the visitor IP
  986. * - force the date & time of the tracking requests rather than track for the current datetime
  987. * - force Piwik to track the requests to a specific VisitorId rather than use the standard visitor matching heuristic
  988. *
  989. * @param string $token_auth token_auth 32 chars token_auth string
  990. */
  991. public function setTokenAuth($token_auth)
  992. {
  993. $this->token_auth = $token_auth;
  994. }
  995. /**
  996. * Sets local visitor time
  997. *
  998. * @param string $time HH:MM:SS format
  999. */
  1000. public function setLocalTime($time)
  1001. {
  1002. list($hour, $minute, $second) = explode(':', $time);
  1003. $this->localHour = (int)$hour;
  1004. $this->localMinute = (int)$minute;
  1005. $this->localSecond = (int)$second;
  1006. }
  1007. /**
  1008. * Sets user resolution width and height.
  1009. *
  1010. * @param int $width
  1011. * @param int $height
  1012. */
  1013. public function setResolution($width, $height)
  1014. {
  1015. $this->width = $width;
  1016. $this->height = $height;
  1017. }
  1018. /**
  1019. * Sets if the browser supports cookies
  1020. * This is reported in "List of plugins" report in Piwik.
  1021. *
  1022. * @param bool $bool
  1023. */
  1024. public function setBrowserHasCookies($bool)
  1025. {
  1026. $this->hasCookies = $bool;
  1027. }
  1028. /**
  1029. * Will append a custom string at the end of the Tracking request.
  1030. * @param string $string
  1031. */
  1032. public function setDebugStringAppend($string)
  1033. {
  1034. $this->DEBUG_APPEND_URL = '&' . $string;
  1035. }
  1036. /**
  1037. * Sets visitor browser supported plugins
  1038. *
  1039. * @param bool $flash
  1040. * @param bool $java
  1041. * @param bool $director
  1042. * @param bool $quickTime
  1043. * @param bool $realPlayer
  1044. * @param bool $pdf
  1045. * @param bool $windowsMedia
  1046. * @param bool $gears
  1047. * @param bool $silverlight
  1048. */
  1049. public function setPlugins($flash = false, $java = false, $director = false, $quickTime = false, $realPlayer = false, $pdf = false, $windowsMedia = false, $gears = false, $silverlight = false)
  1050. {
  1051. $this->plugins =
  1052. '&fla=' . (int)$flash .
  1053. '&java=' . (int)$java .
  1054. '&dir=' . (int)$director .
  1055. '&qt=' . (int)$quickTime .
  1056. '&realp=' . (int)$realPlayer .
  1057. '&pdf=' . (int)$pdf .
  1058. '&wma=' . (int)$windowsMedia .
  1059. '&gears=' . (int)$gears .
  1060. '&ag=' . (int)$silverlight;
  1061. }
  1062. /**
  1063. * By default, PiwikTracker will read first party cookies
  1064. * from the request and write updated cookies in the response (using setrawcookie).
  1065. * This can be disabled by calling this function.
  1066. */
  1067. public function disableCookieSupport()
  1068. {
  1069. $this->configCookiesDisabled = true;
  1070. }
  1071. /**
  1072. * Returns the maximum number of seconds the tracker will spend waiting for a response
  1073. * from Piwik. Defaults to 600 seconds.
  1074. */
  1075. public function getRequestTimeout()
  1076. {
  1077. return $this->requestTimeout;
  1078. }
  1079. /**
  1080. * Sets the maximum number of seconds that the tracker will spend waiting for a response
  1081. * from Piwik.
  1082. *
  1083. * @param int $timeout
  1084. * @throws Exception
  1085. */
  1086. public function setRequestTimeout($timeout)
  1087. {
  1088. if (!is_int($timeout) || $timeout < 0) {
  1089. throw new Exception("Invalid value supplied for request timeout: $timeout");
  1090. }
  1091. $this->requestTimeout = $timeout;
  1092. }
  1093. /**
  1094. * Used in tests to output useful error messages.
  1095. *
  1096. * @ignore
  1097. */
  1098. static public $DEBUG_LAST_REQUESTED_URL = false;
  1099. /**
  1100. * @ignore
  1101. */
  1102. protected function sendRequest($url, $method = 'GET', $data = null, $force = false)
  1103. {
  1104. self::$DEBUG_LAST_REQUESTED_URL = $url;
  1105. // if doing a bulk request, store the url
  1106. if ($this->doBulkRequests && !$force) {
  1107. $this->storedTrackingActions[]
  1108. = $url
  1109. . (!empty($this->userAgent) ? ('&ua=' . urlencode($this->userAgent)) : '')
  1110. . (!empty($this->acceptLanguage) ? ('&lang=' . urlencode($this->acceptLanguage)) : '');
  1111. // Clear custom variables so they don't get copied over to other users in the bulk request
  1112. $this->clearCustomVariables();
  1113. $this->userAgent = false;
  1114. $this->acceptLanguage = false;
  1115. return true;
  1116. }
  1117. if (function_exists('curl_init')) {
  1118. $options = array(
  1119. CURLOPT_URL => $url,
  1120. CURLOPT_USERAGENT => $this->userAgent,
  1121. CURLOPT_HEADER => true,
  1122. CURLOPT_TIMEOUT => $this->requestTimeout,
  1123. CURLOPT_RETURNTRANSFER => true,
  1124. CURLOPT_HTTPHEADER => array(
  1125. 'Accept-Language: ' . $this->acceptLanguage
  1126. ));
  1127. switch ($method) {
  1128. case 'POST':
  1129. $options[CURLOPT_POST] = TRUE;
  1130. break;
  1131. default:
  1132. break;
  1133. }
  1134. // only supports JSON data
  1135. if (!empty($data)) {
  1136. $options[CURLOPT_HTTPHEADER][] = 'Content-Type: application/json';
  1137. $options[CURLOPT_HTTPHEADER][] = 'Expect:';
  1138. $options[CURLOPT_POSTFIELDS] = $data;
  1139. }
  1140. $ch = curl_init();
  1141. curl_setopt_array($ch, $options);
  1142. ob_start();
  1143. $response = @curl_exec($ch);
  1144. ob_end_clean();
  1145. $content = '';
  1146. if (!empty($response)) {
  1147. list($header, $content) = explode("\r\n\r\n", $response, $limitCount = 2);
  1148. }
  1149. } else if (function_exists('stream_context_create')) {
  1150. $stream_options = array(
  1151. 'http' => array(
  1152. 'method' => $method,
  1153. 'user_agent' => $this->userAgent,
  1154. 'header' => "Accept-Language: " . $this->acceptLanguage . "\r\n",
  1155. 'timeout' => $this->requestTimeout, // PHP 5.2.1
  1156. )
  1157. );
  1158. // only supports JSON data
  1159. if (!empty($data)) {
  1160. $stream_options['http']['header'] .= "Content-Type: application/json \r\n";
  1161. $stream_options['http']['content'] = $data;
  1162. }
  1163. $ctx = stream_context_create($stream_options);
  1164. $response = file_get_contents($url, 0, $ctx);
  1165. $content = $response;
  1166. }
  1167. return $content;
  1168. }
  1169. /**
  1170. * Returns current timestamp, or forced timestamp/datetime if it was set
  1171. * @return string|int
  1172. */
  1173. protected function getTimestamp()
  1174. {
  1175. return !empty($this->forcedDatetime)
  1176. ? strtotime($this->forcedDatetime)
  1177. : time();
  1178. }
  1179. /**
  1180. * Returns the base URL for the piwik server.
  1181. */
  1182. protected function getBaseUrl()
  1183. {
  1184. if (empty(self::$URL)) {
  1185. throw new Exception('You must first set the Piwik Tracker URL by calling PiwikTracker::$URL = \'http://your-website.org/piwik/\';');
  1186. }
  1187. if (strpos(self::$URL, '/piwik.php') === false
  1188. && strpos(self::$URL, '/proxy-piwik.php') === false
  1189. ) {
  1190. self::$URL .= '/piwik.php';
  1191. }
  1192. return self::$URL;
  1193. }
  1194. /**
  1195. * @ignore
  1196. */
  1197. protected function getRequest($idSite)
  1198. {
  1199. $this->setFirstPartyCookies();
  1200. $url = $this->getBaseUrl() .
  1201. '?idsite=' . $idSite .
  1202. '&rec=1' .
  1203. '&apiv=' . self::VERSION .
  1204. '&r=' . substr(strval(mt_rand()), 2, 6) .
  1205. // XDEBUG_SESSIONS_START and KEY are related to the PHP Debugger, this can be ignored in other languages
  1206. (!empty($_GET['XDEBUG_SESSION_START']) ? '&XDEBUG_SESSION_START=' . @urlencode($_GET['XDEBUG_SESSION_START']) : '') .
  1207. (!empty($_GET['KEY']) ? '&KEY=' . @urlencode($_GET['KEY']) : '') .
  1208. // Only allowed for Super User, token_auth required,
  1209. (!empty($this->ip) ? '&cip=' . $this->ip : '') .
  1210. (!empty($this->forcedVisitorId) ? '&cid=' . $this->forcedVisitorId : '&_id=' . $this->getVisitorId()) .
  1211. (!empty($this->forcedDatetime) ? '&cdt=' . urlencode($this->forcedDatetime) : '') .
  1212. (!empty($this->forcedNewVisit) ? '&new_visit=1' : '') .
  1213. ((!empty($this->token_auth) && !$this->doBulkRequests) ? '&token_auth=' . urlencode($this->token_auth) : '') .
  1214. // Values collected from cookie
  1215. '&_idts=' . $this->createTs .
  1216. '&_idvc=' . $this->visitCount .
  1217. (!empty($this->lastVisitTs) ? '&_viewts=' . $this->lastVisitTs : '' ) .
  1218. (!empty($this->lastEcommerceOrderTs) ? '&_ects=' . $this->lastEcommerceOrderTs : '' ) .
  1219. // These parameters are set by the JS, but optional when using API
  1220. (!empty($this->plugins) ? $this->plugins : '') .
  1221. (($this->localHour !== false && $this->localMinute !== false && $this->localSecond !== false) ? '&h=' . $this->localHour . '&m=' . $this->localMinute . '&s=' . $this->localSecond : '') .
  1222. (!empty($this->width) && !empty($this->height) ? '&res=' . $this->width . 'x' . $this->height : '') .
  1223. (!empty($this->hasCookies) ? '&cookie=' . $this->hasCookies : '') .
  1224. (!empty($this->ecommerceLastOrderTimestamp) ? '&_ects=' . urlencode($this->ecommerceLastOrderTimestamp) : '') .
  1225. // Various important attributes
  1226. (!empty($this->customData) ? '&data='

Large files files are truncated, but you can click here to view the full file