Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
PHP Helper für serverseitiges und / oder cookieloses Tracking mit Google Analytics
//Einfaches Beispiel der Nutzung des serverseitigen Loggers im Client - also der entsprechende "Trackingcode":
function doLog(tp, pr) {
tp = tp.toLowerCase();
if (!pr) pr = "";
var params = "?ht=" + tp + "&rf=" + encodeURI(document.referrer);
params += "&in=" + encodeURI(pr);
var img = new Image();
img.src = '/logger.php'+params;
document.querySelector('body').appendChild(img);
}
/*Hinweis: Als Parameter nimmt diese Funktion nur zwei Parameter entgegen: Den "HitTyp" und die "Nutzlast".
Der Typ wird passend zum obigen Beispiel-Logger mit "p" für Seitenaufrufe und "e>" für Events aufgerufen.
Als Nutzlast verwendet dieses Beispiel nur Kategorie, Aktion und Label eines Ereignisses, die durch "|"
getrennt übergeben und im Logger wieder in die Einzelteile zerlegt werden. Zum Abruf wird "ganz
klassisch" ein Pixel verwendet, das vom Logger zurückgeliefert wird (ja genau: drängt sich für eigene
GTM Templates geradezu auf ;)).
** Nutzung als Ersatz zum normalen Trackingcode **
Im einfachsten Fall reicht eine bedingte Initialisierung entweder des vollwertigen Trackers oder
einer "Dummy-Funktion", die alle Aufrufe an die o. a. Funktion weiterleitet. Dieser Ersatz ist
kompatibel zu den typischen Aufrufen der ga()-Funktion, so dass man alles "wie sonst auch" an
Trackingaufrufen nutzen kann. Durch die Reduktion auf Seitenaufrufe und Events mit maximal drei
Eigenschaften geht das ziemlich einfach. Beispiel:
*/
function initGaDummy() {
ga = new Function("p1", "p2", "p3", "p4", "p5", "p6", "p7", "p8",
"if ((p1.toLowerCase() == 'send') && (p2.toLowerCase() == 'pageview')) "+
"doLog(p3); else "+
"if ((p1.toLowerCase() == 'send') && (p2.toLowerCase() == 'event')) "+
"doLog(p3+'||'+p4+'||'+p5); "+
"return true;");
doLog();
}
</pre>
//Zur Erklärung: Durch die Deklaration einer eigenen ga()-Funktion werden alle Aufrufe inkl. der Parameter
//an doLog() weitergegeben und gelangen von dort zum serverseitigen Logger, der dann tut, was auch immer er
//tun soll. In unserem Fall das Weitergeben der Hits an Google Analytics. Wird diese Funktion als Ersatz
//des normalen Trackingcodes aufgerufen, dient die letzte Zeile dazu, den Messpunkt für den aktuellen
//Seitenaufruf auszulösen (der keine Parameter benötigt).
<?php
const USE_FINGERPRINT = 1;
const USE_COOKIE = 2;
const USE_SESSION = 3;
/*************************** SETUP ********************************************************************/
//Google Analytics Property Id
$ua = "UA-12345678-1";
//Parameterstring mit beliebigen Konstanten oder variablen Werten definieren, der an ausgehende Hits
//angehaengt wird. Dabei koennen folgende Platzhalter verwendet werden:
//%%SESSION_ID%% : Die Session- bzw. ClientId, die auch als Parameter cid uebergeben wird
//%%HIT_TIMESTAMP%% : Zeitstempel des Servers zum Zeitpunkt des Absendens des Hits
//%%USER_AGENT%% : Der User Agent String des aufrufenden Browsers
//%%RANDOM_UUID%% : Eine UUID als Zufalls-String, die z. B. als Sitzuingskennung im Session Scope dienen kann
//Hinweis: Kein "&" am Anfang des Strings erforderlich, wenn er definiert werden sollte.
$customParameters = "";
//Verfahren der ClientId Generierung
$clientDetectionMethod = USE_SESSION;
//Optionen:
//USE_FINGERPRINT : Es wird eine ClientId als Hash aus der anonymisierten IP, dem User Agent und
// der Sprache gebildet. Verfahren im Ergebnis vergleichbar mit Matomo, siehe
// https://matomo.org/faq/general/faq_21418/
// Wie die Session kann auch dieser Wert per Parameter abgerufen werden, um ihn
// z. B. in den dataLayer zu schreiben (sehe USE_SESSION)
//USE_COOKIE : Es wird ein Cookiewert ausgelesen und als ClientId verwendet. Dazu muss unten
// ein Cookiename definiert werden. Das Handling des Cookies kann optional auch
// von diesem Logger uebernommen werden (siehe Optionen zu Cookies unten). Solange
// Cookies nicht geloescht werden, bleibt der User erkennbar
//USE_SESSION : Die PHP Session-ID wird als ClientId genutzt. Im einfachsten Fall existiert
// diese bereits durch das System und es gibt ein PHPSESSID Cookie. Anderenfalls
// kann eine Session auch durch Aufruf des Loggers mit dem Parameter ht=sid gestartet
// und abgerufen werden. In diesem Fall ist der Besucher nach der Sitzung nicht mehr
// wiedererkennbar und gilt bei jedem neuen Besuch als neuer Benutzer
//Als Alternative kann die Session- bzw. Client Id auch als Parameter "si" uebergeben werden. Ist der
//Parameter vorhanden, ueberschreibt er die Session aus der o. a. Methode.
//Wenn deaktiviert, wird die Session Id genutzt, um den User - dann nur fuer diese eine Session - zu
//identifizieren. Bei Aktivierung ist der User wiedererkennbar, solange die IP bestehen bleibt und der
//gleiche Browser genutzt wird. Auf diese Weise sind allerdings auch mehrere User im gleichen Netztwerk
//in einem Topf zu finden, wenn die User Agents und Sprachen ebenso gleich gestaltet sind.
//Optionen bei Verwendung von USE_COOKIE:
//Kennung eines Cookies eintragen, wenn dieses verwendet werden soll. Beispiel: _ga zur Verwendung der
//ClientId aus dem Analytics Cookie. Leer lassen = kein Zugriff auf Cookies und auch kein Setzen
//die folgende Option ist in diesem Fall irrelevant
$ClientCookieValue = "_UID";
//Wenn o. Cookie nicht vom Browser oder System erzeugt und verwaltet wird, kann der Logger dies selbst
//uebernehmen, wenn oben eine Kennung angegeben ist. Es wird ein Cookie mit 2 Jahren Laufzeit verwendet.
$setCookieIfNotPresent = false;
//Wenn ein Cookie gesetzt werden soll, kann dieses hiermit wahlweise als Secure und httpOnly gesetzt
//werden, so dass es im Browser von Scripts nicht gelesen werden kann.
$setSecureCookie = true;
/*************************** ENDE SETUP ***************************************************************/
if ($clientDetectionMethod === USE_SESSION)
session_start(['cookie_secure' => true,
'cookie_httponly' => true,
'cookie_samesite' => true]);
function gen_uuid() {
return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
mt_rand( 0, 0xffff ),
mt_rand( 0, 0x0fff ) | 0x4000,
mt_rand( 0, 0x3fff ) | 0x8000,
mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff )
);
}
function get_domain_from_host($h) {
$hst = explode(".", $h);
return $hst[count($hst)-2] . "." . $hst[count($hst)-1];
}
function anonymizeIp($ip) {
//IPV4/IPV6
return preg_replace(['/\.\d*$/','/[\da-f]*:[\da-f]*$/'],['.0','0000:0000'],$ip);
}
function get_fingerprint($i, $l, $a) {
//nicht nachvollziehbarer Hash aus anonymer IP, Sprache und User Agent
$in = $i . 'k1|' . $l . 'k2|' . $a . 's|';
$salt = 'S&6!l%aV<*MFy;~Uy9)t#^ygl';
return hash('md5', $in.$salt);
}
function send_ga_hit($url) {
$ch = cURL_init($url);
cURL_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
cURL_setopt($ch, CURLOPT_FRESH_CONNECT, true);
cURL_setopt($ch, CURLOPT_TIMEOUT_MS, 50);
curl_exec($ch);
cURL_close($ch);
return true ;
}
//Parameter auslesen
$htype = strtolower($_GET['ht']); //"p" f. Seitenaufruf, "e" f. Event, "sid" zum Abruf der Session- / Client Id
$pageref = $_GET['rf']; //Referrer der aufrufenden Seite
$input = $_GET['in']; //Seite als Parameter oder Angaben f. Event im Format Kategorie||Aktion||Label
$set_sid = $_GET['si']; //Session- Client Id als Parameter. Ueberschreibt Session- o. Cookie-Wert
$pgurl = urlencode($_SERVER['HTTP_REFERER']);
$call_from = strtolower(get_domain_from_host(parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST)));
$this_domain = strtolower(get_domain_from_host($_SERVER['SERVER_NAME']));
//Browser und Merkmale lesen
$lng = strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE']);
if ($lng != "") $lng = explode(',', $lng)[0];
$agent = urlencode($_SERVER['HTTP_USER_AGENT']);
if ($set_sid != "") {
$session = $set_sid;
} else if ($clientDetectionMethod === USE_COOKIE) {
$session = $_COOKIE[$ClientCookieValue];
if (($session == "") && ($setCookieIfNotPresent === true)) {
//Session ID Cookie erzeugen
$session = rand(10000, 99999).rand(20000, 99999).".".time();
//Set secure http cookie with 2 years lifetime
setcookie($ClientCookieValue, $session, time()+60*60*24*365*2, "/",
$this_domain, $secure = $setSecureCookie, $httponly = $setSecureCookie);
}
} else if ($clientDetectionMethod === USE_SESSION) {
$session = session_id();
} else if ($clientDetectionMethod === USE_FINGERPRINT) {
if (! isset($_SERVER['HTTP_X_FORWARDED_FOR']))
$clientIp = anonymizeIp($_SERVER['REMOTE_ADDR']);
else
$clientIp = anonymizeIp($_SERVER['HTTP_X_FORWARDED_FOR']);
//Client Id als Fingerprintberechnen
$session = urlencode(get_fingerprint($clientIp, $lng, $agent));
}
//Hits validieren
if (($htype != 'sid') && ($htype != 'p') && ($htype != 'e')) $session = "";
if ($call_from != $this_domain) $session = "";
//Alles da? Dann Trackinghit bauen und senden
if (($session != "") && ($agent != "")) {
$cid = urlencode($session);
//Hinweis: Es kann, sollte aber nicht die IP des Clients verwendet werden. Wir gehen vom nicht
//Consent-Fall aus und nutzen daher keine IP jenseits des Fingerprints. Ansonsten kann auch die
//IP wie oben im Fall von USE_FINGERPRINT ermittelt und anonymisiert werden.
$uip = "0.0.0.0";
if ($htype === 'sid') {
//Session- / ClientId wurde angefordert
echo $cid;
} else {
//Hit zusammenbauen und senden
$collect_url = "https://www.google-analytics.com/collect?v=1&ul=$lng&ua=$agent&tid=$ua&cid=$cid&aip=1";
$collect_url .= "&uip=$uip";
if ($htype === 'p') {
$collect_url .= "&t=pageview";
if ($input != "") $collect_url .= "&dp=$input";
} else {
$prs = explode('||', $input.'|| || ');
$ec = urlencode($prs[0]);
$ea = urlencode($prs[1]);
$el = urlencode($prs[2]);
$collect_url .= "&t=event&ec=$ec&ea=$ea&el=$el";
}
$collect_url .= "&dl=$pgurl&dh=$this_domain&dr=$pageref";
//Custom Dimensions anhaengen, wenn definiert
if ($customParameters != "") {
$cd = str_replace("%%USER_AGENT%%", $agent, $customParameters);
$cd = str_replace("%%SESSION_ID%%", $cid, $cd);
$cd = str_replace("%%HIT_TIMESTAMP%%", date(DATE_ATOM, time()), $cd);
if (strpos($customParameters, "%%RANDOM_UUID%%"))
$cd = str_replace("%%RANDOM_UUID%%", gen_uuid(), $cd);
$collect_url .= "&".$cd;
}
send_ga_hit($collect_url);
//Geschafft. Wir liefern ein Pixel aus, weil wir ein Tracker sind!
header('Content-Type: image/gif');
echo(hex2bin('47494638396101000100900000ff000000000021f90405100000002c00000000010001000002020401003b'));
}
//setrawcookie("_dbg", $collect_url);
} else echo "No!";
?>
@mbaersch

This comment has been minimized.

Copy link
Owner Author

mbaersch commented Oct 13, 2019

Hinweise zum Einsatz siehe Blogbeitrag zum serverseitigen Tracking

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.