OsmAnd/config/site/GoogleAnalytics/Visitor.php

463 lines
11 KiB
PHP
Raw Normal View History

2012-01-14 00:17:28 +01:00
<?php
/**
* Generic Server-Side Google Analytics PHP Client
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License (LGPL) as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* Google Analytics is a registered trademark of Google Inc.
*
* @link http://code.google.com/p/php-ga
*
* @license http://www.gnu.org/licenses/lgpl.html
* @author Thomas Bachem <tb@unitedprototype.com>
* @copyright Copyright (c) 2010 United Prototype GmbH (http://unitedprototype.com)
*/
namespace UnitedPrototype\GoogleAnalytics;
use UnitedPrototype\GoogleAnalytics\Internals\Util;
use DateTime;
/**
* You should serialize this object and store it in the user database to keep it
* persistent for the same user permanently (similar to the "__umta" cookie of
* the GA Javascript client).
*/
class Visitor {
/**
* Unique user ID, will be part of the "__utma" cookie parameter
*
* @see Internals\ParameterHolder::$__utma
* @var int
*/
protected $uniqueId;
/**
* Time of the very first visit of this user, will be part of the "__utma"
* cookie parameter
*
* @see Internals\ParameterHolder::$__utma
* @var DateTime
*/
protected $firstVisitTime;
/**
* Time of the previous visit of this user, will be part of the "__utma"
* cookie parameter
*
* @see Internals\ParameterHolder::$__utma
* @see addSession
* @var DateTime
*/
protected $previousVisitTime;
/**
* Time of the current visit of this user, will be part of the "__utma"
* cookie parameter
*
* @see Internals\ParameterHolder::$__utma
* @see addSession
* @var DateTime
*/
protected $currentVisitTime;
/**
* Amount of total visits by this user, will be part of the "__utma"
* cookie parameter
*
* @see Internals\ParameterHolder::$__utma
* @var int
*/
protected $visitCount;
/**
* IP Address of the end user, e.g. "123.123.123.123", will be mapped to "utmip" parameter
* and "X-Forwarded-For" request header
*
* @see Internals\ParameterHolder::$utmip
* @see Internals\Request\HttpRequest::$xForwardedFor
* @var string
*/
protected $ipAddress;
/**
* User agent string of the end user, will be mapped to "User-Agent" request header
*
* @see Internals\Request\HttpRequest::$userAgent
* @var string
*/
protected $userAgent;
/**
* Locale string (country part optional), e.g. "de-DE", will be mapped to "utmul" parameter
*
* @see Internals\ParameterHolder::$utmul
* @var string
*/
protected $locale;
/**
* Visitor's Flash version, e.g. "9.0 r28", will be maped to "utmfl" parameter
*
* @see Internals\ParameterHolder::$utmfl
* @var string
*/
protected $flashVersion;
/**
* Visitor's Java support, will be mapped to "utmje" parameter
*
* @see Internals\ParameterHolder::$utmje
* @var bool
*/
protected $javaEnabled;
/**
* Visitor's screen color depth, e.g. 32, will be mapped to "utmsc" parameter
*
* @see Internals\ParameterHolder::$utmsc
* @var string
*/
protected $screenColorDepth;
/**
* Visitor's screen resolution, e.g. "1024x768", will be mapped to "utmsr" parameter
*
* @see Internals\ParameterHolder::$utmsr
* @var string
*/
protected $screenResolution;
/**
* Creates a new visitor without any previous visit information.
*/
public function __construct() {
// ga.js sets all three timestamps to now for new visitors, so we do the same
$now = new DateTime();
$this->setFirstVisitTime($now);
$this->setPreviousVisitTime($now);
$this->setCurrentVisitTime($now);
$this->setVisitCount(1);
}
/**
* Will extract information for the "uniqueId", "firstVisitTime", "previousVisitTime",
* "currentVisitTime" and "visitCount" properties from the given "__utma" cookie
* value.
*
* @see Internals\ParameterHolder::$__utma
* @see Internals\Request\Request::buildCookieParameters()
* @param string $value
* @return $this
*/
public function fromUtma($value) {
$parts = explode('.', $value);
if(count($parts) != 6) {
Tracker::_raiseError('The given "__utma" cookie value is invalid.', __METHOD__);
return $this;
}
$this->setUniqueId($parts[1]);
$this->setFirstVisitTime(new DateTime('@' . $parts[2]));
$this->setPreviousVisitTime(new DateTime('@' . $parts[3]));
$this->setCurrentVisitTime(new DateTime('@' . $parts[4]));
$this->setVisitCount($parts[5]);
// Allow chaining
return $this;
}
/**
* Will extract information for the "ipAddress", "userAgent" and "locale" properties
* from the given $_SERVER variable.
*
* @param array $value
* @return $this
*/
public function fromServerVar(array $value) {
if(!empty($value['REMOTE_ADDR'])) {
$ip = null;
foreach(array('X_FORWARDED_FOR', 'REMOTE_ADDR') as $key) {
if(!empty($value[$key]) && !$ip) {
$ips = explode(',', $value[$key]);
$ip = trim($ips[(count($ips) - 1)]);
// Double-check if the address has a valid format
if(!preg_match('/^[\d+]{1,3}\.[\d+]{1,3}\.[\d+]{1,3}\.[\d+]{1,3}$/i', $ip)) {
$ip = null;
}
// Exclude private IP address ranges
if(preg_match('#^(?:127\.0\.0\.1|10\.|192\.168\.|172\.(?:1[6-9]|2[0-9]|3[0-1])\.)#', $ip)) {
$ip = null;
}
}
}
if($ip) {
$this->setIpAddress($ip);
}
}
if(!empty($value['HTTP_USER_AGENT'])) {
$this->setUserAgent($value['HTTP_USER_AGENT']);
}
if(!empty($value['HTTP_ACCEPT_LANGUAGE'])) {
$parsedLocales = array();
if(preg_match_all('/(^|\s*,\s*)([a-zA-Z]{1,8}(-[a-zA-Z]{1,8})*)\s*(;\s*q\s*=\s*(1(\.0{0,3})?|0(\.[0-9]{0,3})))?/i', $value['HTTP_ACCEPT_LANGUAGE'], $matches)) {
$matches[2] = array_map(function($part) { return str_replace('-', '_', $part); }, $matches[2]);
$matches[5] = array_map(function($part) { return $part === '' ? 1 : $part; }, $matches[5]);
$parsedLocales = array_combine($matches[2], $matches[5]);
arsort($parsedLocales, SORT_NUMERIC);
$parsedLocales = array_keys($parsedLocales);
}
if($parsedLocales) {
$this->setLocale($parsedLocales[0]);
}
}
// Allow chaining
return $this;
}
/**
* Generates a hashed value from user-specific properties.
*
* @link http://code.google.com/p/gaforflash/source/browse/trunk/src/com/google/analytics/v4/Tracker.as#542
* @return int
*/
protected function generateHash() {
// TODO: Emulate orginal Google Analytics client library generation more closely
$string = $this->userAgent;
$string .= $this->screenResolution . $this->screenColorDepth;
return Util::generateHash($string);
}
/**
* Generates a unique user ID from the current user-specific properties.
*
* @link http://code.google.com/p/gaforflash/source/browse/trunk/src/com/google/analytics/v4/Tracker.as#563
* @return int
*/
protected function generateUniqueId() {
// There seems to be an error in the gaforflash code, so we take the formula
// from http://xahlee.org/js/google_analytics_tracker_2010-07-01_expanded.js line 711
// instead ("&" instead of "*")
return ((Util::generate32bitRandom() ^ $this->generateHash()) & 0x7fffffff);
}
/**
* @see generateUniqueId
* @param int $value
*/
public function setUniqueId($value) {
if($value < 0 || $value > 0x7fffffff) {
Tracker::_raiseError('Visitor unique ID has to be a 32-bit integer between 0 and ' . 0x7fffffff . '.', __METHOD__);
}
$this->uniqueId = (int)$value;
}
/**
* Will be generated on first call (if not set already) to include as much
* user-specific information as possible.
*
* @return int
*/
public function getUniqueId() {
if($this->uniqueId === null) {
$this->uniqueId = $this->generateUniqueId();
}
return $this->uniqueId;
}
/**
* Updates the "previousVisitTime", "currentVisitTime" and "visitCount"
* fields based on the given session object.
*
* @param Session $session
*/
public function addSession(Session $session) {
$startTime = $session->getStartTime();
if($startTime != $this->currentVisitTime) {
$this->previousVisitTime = $this->currentVisitTime;
$this->currentVisitTime = $startTime;
++$this->visitCount;
}
}
/**
* @param DateTime $value
*/
public function setFirstVisitTime(DateTime $value) {
$this->firstVisitTime = $value;
}
/**
* @return DateTime
*/
public function getFirstVisitTime() {
return $this->firstVisitTime;
}
/**
* @param DateTime $value
*/
public function setPreviousVisitTime(DateTime $value) {
$this->previousVisitTime = $value;
}
/**
* @return DateTime
*/
public function getPreviousVisitTime() {
return $this->previousVisitTime;
}
/**
* @param DateTime $value
*/
public function setCurrentVisitTime(DateTime $value) {
$this->currentVisitTime = $value;
}
/**
* @return DateTime
*/
public function getCurrentVisitTime() {
return $this->currentVisitTime;
}
/**
* @param int $value
*/
public function setVisitCount($value) {
$this->visitCount = (int)$value;
}
/**
* @return int
*/
public function getVisitCount() {
return $this->visitCount;
}
/**
* @param string $value
*/
public function setIpAddress($value) {
$this->ipAddress = $value;
}
/**
* @return string
*/
public function getIpAddress() {
return $this->ipAddress;
}
/**
* @param string $value
*/
public function setUserAgent($value) {
$this->userAgent = $value;
}
/**
* @return string
*/
public function getUserAgent() {
return $this->userAgent;
}
/**
* @param string $value
*/
public function setLocale($value) {
$this->locale = $value;
}
/**
* @return string
*/
public function getLocale() {
return $this->locale;
}
/**
* @param string $value
*/
public function setFlashVersion($value) {
$this->flashVersion = $value;
}
/**
* @return string
*/
public function getFlashVersion() {
return $this->flashVersion;
}
/**
* @param bool $value
*/
public function setJavaEnabled($value) {
$this->javaEnabled = (bool)$value;
}
/**
* @return bool
*/
public function getJavaEnabled() {
return $this->javaEnabled;
}
/**
* @param int $value
*/
public function setScreenColorDepth($value) {
$this->screenColorDepth = (int)$value;
}
/**
* @return string
*/
public function getScreenColorDepth() {
return $this->screenColorDepth;
}
/**
* @param string $value
*/
public function setScreenResolution($value) {
$this->screenResolution = $value;
}
/**
* @return string
*/
public function getScreenResolution() {
return $this->screenResolution;
}
}
?>