diff --git a/CHANGELOG b/CHANGELOG index 5abb052..db28f43 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,9 @@ +Version 0.9.1 (2025-04-11) +-------------------------- +Add Emitter Server Anonymization support (#152) +Fix Psalm issues in Tracker (close #137) thanks to @XWB +Update PHP version in CD + Version 0.9.0 (2025-03-03) -------------------------- Bump Ubuntu Version in GH Actions diff --git a/src/Constants.php b/src/Constants.php index 8bb2e48..5741ce4 100644 --- a/src/Constants.php +++ b/src/Constants.php @@ -45,7 +45,7 @@ class Constants { * - SSL: the default for whether or not to use SSL Encryption * - Type: the default for what type of request the emitter will be making (POST or GET) */ - const TRACKER_VERSION = "php-0.9.0"; + const TRACKER_VERSION = "php-0.9.1"; const DEFAULT_BASE_64 = true; const DEBUG_LOG_FILES = true; const CONTEXT_SCHEMA = "iglu:com.snowplowanalytics.snowplow/contexts/jsonschema/1-0-1"; @@ -61,6 +61,7 @@ class Constants { const DEFAULT_SSL = false; const DEFAULT_REQ_TYPE = "POST"; const NO_RETRY_STATUS_CODES = array(400, 401, 403, 410, 422); + const SERVER_ANONYMIZATION = "SP-Anonymous"; /** * Settings for the Synchronous Emitter diff --git a/src/Emitters/CurlEmitter.php b/src/Emitters/CurlEmitter.php index aced2fe..347a3d2 100644 --- a/src/Emitters/CurlEmitter.php +++ b/src/Emitters/CurlEmitter.php @@ -31,6 +31,7 @@ class CurlEmitter extends Emitter { private $debug; private $requests_results; private $debug_payloads; + private $server_anoymization; // Curl Specific Parameters @@ -49,14 +50,17 @@ class CurlEmitter extends Emitter { * @param int|null $buffer_size - Emitter buffer size * @param bool $debug - Debug mode * @param int|null $curl_timeout - Maximum time the request is allowed to take, in seconds + * @param bool|null $server_anonymization - Whether to enable Server Anonymization and not collect the IP or Network User ID. Defaults to false. */ - public function __construct($uri, $protocol = NULL, $type = NULL, $buffer_size = NULL, $debug = false, $curl_timeout = NULL) { + public function __construct($uri, $protocol = NULL, $type = NULL, $buffer_size = NULL, $debug = false, $curl_timeout = NULL, $server_anonymization = false) { $this->type = $this->getRequestType($type); $this->url = $this->getCollectorUrl($this->type, $uri, $protocol); $this->curl_limit = $this->type == "POST" ? self::CURL_AMOUNT_POST : self::CURL_AMOUNT_GET; $this->rolling_window = $this->type == "POST" ? self::CURL_WINDOW_POST : self::CURL_WINDOW_GET; $this->curl_timeout = $curl_timeout; + $this->server_anonymization = $server_anonymization; + // If debug is on create a requests_results array if ($debug === true) { $this->debug = true; @@ -222,19 +226,22 @@ private function rollingCurl($curls, $debug) { */ private function getCurlRequest($payload, $type) { $ch = curl_init($this->url); + $header = array(); if ($type == "POST") { - $header = array( - 'Content-Type: '.self::POST_CONTENT_TYPE, - 'Accept: '.self::POST_ACCEPT, - 'Content-Length: '.strlen($payload)); + $header[] = 'Content-Type: '.self::POST_CONTENT_TYPE; + $header[] = 'Accept: '.self::POST_ACCEPT; + $header[] = 'Content-Length: '.strlen($payload); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); curl_setopt($ch, CURLOPT_POSTFIELDS, $payload); - curl_setopt($ch, CURLOPT_HTTPHEADER, $header); } else { curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET"); curl_setopt($ch, CURLOPT_URL, $this->url."?".$payload); } + + if ($this->server_anonymization) $header[] = self::SERVER_ANONYMIZATION.": *"; + + if ($header) curl_setopt($ch, CURLOPT_HTTPHEADER, $header); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); if ($this->curl_timeout != NULL) { curl_setopt($ch, CURLOPT_TIMEOUT, $this->curl_timeout); diff --git a/src/Emitters/SocketEmitter.php b/src/Emitters/SocketEmitter.php index 8753835..774abe6 100644 --- a/src/Emitters/SocketEmitter.php +++ b/src/Emitters/SocketEmitter.php @@ -36,6 +36,7 @@ class SocketEmitter extends Emitter { private $requests_results; private $max_retry_attempts; private $retry_backoff_ms; + private $server_anonymization; // Socket Parameters @@ -53,14 +54,16 @@ class SocketEmitter extends Emitter { * @param bool|null $debug - If debug is on * @param int|null $max_retry_attempts - The maximum number of times to retry a request. Defaults to 1. * @param int|null $retry_backoff_ms - The number of milliseconds to backoff before retrying a request. Defaults to 100ms. + * @param bool|null $server_anonymization - Whether to enable Server Anonymization and not collect the IP or Network User ID. Defaults to false. */ - public function __construct($uri, $ssl = NULL, $type = NULL, $timeout = NULL, $buffer_size = NULL, $debug = NULL, $max_retry_attempts = NULL, $retry_backoff_ms = NULL) { + public function __construct($uri, $ssl = NULL, $type = NULL, $timeout = NULL, $buffer_size = NULL, $debug = NULL, $max_retry_attempts = NULL, $retry_backoff_ms = NULL, $server_anonymization = false) { $this->type = $this->getRequestType($type); $this->uri = $uri; $this->ssl = $ssl == NULL ? self::DEFAULT_SSL : (bool) $ssl; $this->timeout = $timeout == NULL ? self::SOCKET_TIMEOUT : $timeout; $this->max_retry_attempts = $max_retry_attempts; $this->retry_backoff_ms = $retry_backoff_ms; + $this->server_anonymization = $server_anonymization; // If debug is on create a requests_results array if ($debug === true) { @@ -240,6 +243,7 @@ private function getRequestBody($uri, $data, $type) { $req.= "Host: ".$uri."\r\n"; $req.= "Content-Type: ".self::POST_CONTENT_TYPE."\r\n"; $req.= "Content-length: ".strlen($data)."\r\n"; + if ($this->server_anonymization) $req.= self::SERVER_ANONYMIZATION.": *\r\n"; $req.= "Accept: ".self::POST_ACCEPT."\r\n\r\n"; $req.= $data."\r\n\r\n"; } @@ -247,6 +251,7 @@ private function getRequestBody($uri, $data, $type) { $req = "GET http://".$uri.self::GET_PATH."?".$data." "; $req.= "HTTP/1.1\r\n"; $req.= "Host: ".$uri."\r\n"; + if ($this->server_anonymization) $req.= self::SERVER_ANONYMIZATION.": *\r\n"; $req.= "Query: ".$data."\r\n"; $req.= "\r\n"; } diff --git a/src/Emitters/SyncEmitter.php b/src/Emitters/SyncEmitter.php index a2b7ae7..2ac0660 100644 --- a/src/Emitters/SyncEmitter.php +++ b/src/Emitters/SyncEmitter.php @@ -35,6 +35,7 @@ class SyncEmitter extends Emitter { private $requests_results; private $max_retry_attempts; private $retry_backoff_ms; + private $server_anonymization; /** * Creates a Synchronous Emitter @@ -46,12 +47,14 @@ class SyncEmitter extends Emitter { * @param bool|null $debug - If debug is on * @param int|null $max_retry_attempts - The maximum number of times to retry a request. Defaults to 1. * @param int|null $retry_backoff_ms - The number of milliseconds to backoff before retrying a request. Defaults to 100ms. + * @param bool|null $server_anonymization - Whether to enable Server Anonymization and not collect the IP or Network User ID. Defaults to false. */ - public function __construct($uri, $protocol = NULL, $type = NULL, $buffer_size = NULL, $debug = false, $max_retry_attempts = NULL, $retry_backoff_ms = NULL) { + public function __construct($uri, $protocol = NULL, $type = NULL, $buffer_size = NULL, $debug = false, $max_retry_attempts = NULL, $retry_backoff_ms = NULL, $server_anonymization = false) { $this->type = $this->getRequestType($type); $this->url = $this->getCollectorUrl($this->type, $uri, $protocol); $this->max_retry_attempts = $max_retry_attempts; $this->retry_backoff_ms = $retry_backoff_ms; + $this->server_anonymization = $server_anonymization; // If debug is on create a requests_results array if ($debug === true) { @@ -115,20 +118,23 @@ private function curlRequest($data, $type, $retry_request_manager = NULL) { // Create a cURL handle, set transfer options and execute $ch = curl_init($this->url); + $header = array(); if ($type == 'POST') { $json_data = json_encode($data); - $header = array( - 'Content-Type: '.self::POST_CONTENT_TYPE, - 'Accept: '.self::POST_ACCEPT, - 'Content-Length: '.strlen($json_data)); + $header[] = 'Content-Type: '.self::POST_CONTENT_TYPE; + $header[] = 'Accept: '.self::POST_ACCEPT; + $header[] = 'Content-Length: '.strlen($json_data); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); curl_setopt($ch, CURLOPT_POSTFIELDS, $json_data); - curl_setopt($ch, CURLOPT_HTTPHEADER, $header); } else { curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET"); curl_setopt($ch, CURLOPT_URL, $this->url."?".http_build_query($data)); } + + if ($this->server_anonymization) $header[] = self::SERVER_ANONYMIZATION.': *'; + if ($header) curl_setopt($ch, CURLOPT_HTTPHEADER, $header); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_exec($ch); diff --git a/src/Tracker.php b/src/Tracker.php index d9ffa25..f61ab93 100644 --- a/src/Tracker.php +++ b/src/Tracker.php @@ -23,6 +23,7 @@ namespace Snowplow\Tracker; use Ramsey\Uuid\Uuid; +use Snowplow\Tracker\Emitter; class Tracker extends Constants { @@ -36,7 +37,7 @@ class Tracker extends Constants { /** * Constructs a new tracker object with emitter(s) and a subject. * - * @param emitter|array $emitter - Emitter object, used for sending event payloads to for processing + * @param Emitter|array $emitter - Emitter object, used for sending event payloads to for processing * @param subject $subject - Subject object, contains extra information which is parcelled with the event * @param string|null $namespace * @param string|null $app_id