├── .gitignore ├── LICENSE ├── README.md ├── composer.json └── woopra_tracker.php /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Woopra, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Track customers directly in PHP using Woopra's PHP SDK 2 | 3 | The purpose of this SDK is to allow our customers who have servers running PHP to track their users by writing only PHP code. Tracking directly in PHP will allow you to decide whether you want to track your users: 4 | - through the front-end: after configuring the tracker, identifying the user, and tracking page views and events in PHP, the SDK will generate the corresponding JavaScript code, and you will be able to print that code in your pages' headers. 5 | - through the back-end: after configuring the tracker & identifying the user, add the optional parameter TRUE to the methods track or push, and the PHP tracker will handle sending the data to Woopra by making HTTP Requests. By doing that, the client is never involved in the tracking process. 6 | 7 | The best way to install Woopra/Woopra-php-sdk is using [Composer](https://getcomposer.org/) 8 | 9 | ``` sh 10 | $ composer require woopra/woopra:dev-master 11 | ``` 12 | 13 | The first step is to setup the tracker SDK. To do so, import the woopra_tracker.php file then configure the tracker instance as follows (replace mybusiness.com with your website as registered on Woopra): 14 | ``` php 15 | require_once('woopra_tracker.php'); 16 | // require_once('vendor/autoload.php'); // for composer installation 17 | $woopra = new WoopraTracker(array("domain" => "mybusiness.com")); 18 | ``` 19 | You can update your idle timeout (default: 30 seconds) by updating the timeout property in your WoopraTracker instance (NB: this could also have been done in the step above, by adding all the properties you wish to configure to the array): 20 | ``` php 21 | $woopra->config(array("idle_timeout" => 15000)); // in milliseconds 22 | ``` 23 | If you don't want to keep the user online on Woopra when they don't commit any event between the last event and the idle_timeout, you can disable auto pings (auto ping only matters for front-end tracking). 24 | ``` php 25 | $woopra->config(array("ping" => false)); // default is true 26 | ``` 27 | To add custom visitor properties, you should use the identify($user) function: 28 | ``` php 29 | $woopra->identify(array( 30 | "name" => "User Name", 31 | "email" => "user@company.com", 32 | "company" => "User Business" 33 | )); 34 | ``` 35 | If you wish to track page views, first call track(), and finally calling js_code() in your page header will insert the woopra javascript tracker: 36 | ``` php 37 | 38 | ... 39 | track()->js_code(); ?> 40 | 41 | 42 | ``` 43 | You can always track events through front-end later in the page. With all the previous steps done at once, it should look like: 44 | ``` php 45 | 46 | 47 | ... 48 | identify($user)->track()->js_code(); 51 | ?> 52 | 53 | 54 | ... 55 | track("play", array( 57 | "artist" => "Dave Brubeck", 58 | "song" => "Take Five", 59 | "genre" => "Jazz" 60 | )); 61 | ?> 62 | ... 63 | 64 | 65 | 66 | ``` 67 | To track a custom event through back-end, just specify the additional parameter TRUE in the track() functions. 68 | ``` php 69 | $woopra->track($event_name, $event_properties, TRUE); 70 | ``` 71 | If you identify the user after the last tracking event, don't forget to push() the update to Woopra: 72 | ``` php 73 | $woopra->identify($user)->push(); 74 | //or, to push through back-end: 75 | $woopra->identify($user)->push(TRUE); 76 | ``` 77 | If you're only going to be tracking through the back-end, set the cookie (before the headers are sent): 78 | ``` php 79 | $woopra->set_woopra_cookie(); 80 | ``` 81 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "woopra/woopra", 3 | "type": "library", 4 | "description": "Woopra.com PHP Library", 5 | "keywords": ["woopra", "analytics"], 6 | "homepage": "https://github.com/Woopra/woopra-php-sdk", 7 | "authors": [ 8 | { 9 | "name": "Antoine Chkaiban", 10 | "email": "antoine.chkaiban@student.ecp.fr" 11 | }, 12 | { 13 | "name": "Billy Vong", 14 | "email": "billy@woopra.com" 15 | } 16 | ], 17 | "autoload": { 18 | "classmap": ["woopra_tracker.php"] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /woopra_tracker.php: -------------------------------------------------------------------------------- 1 | "", 35 | "cookie_name" => "wooTracker", 36 | "cookie_domain" => "", 37 | "cookie_path" => "/", 38 | "ping" => true, 39 | "ping_interval" => 12000, 40 | "idle_timeout" => 300000, 41 | "download_tracking" => true, 42 | "outgoing_tracking" => true, 43 | "download_pause" => 200, 44 | "outgoing_pause" => 400, 45 | "ignore_query_url" => true, 46 | "hide_campaign" => false, 47 | "ip_address" => "", 48 | "cookie_value" => "", 49 | "app" => "" 50 | ); 51 | 52 | /** 53 | * Custom configuration stack. 54 | * If the user has set up custom configuration, store it in this array. It will be sent when the tracker is ready. 55 | * @var array 56 | */ 57 | private $custom_config; 58 | 59 | /** 60 | * Current configuration 61 | * Default configuration array, updated by Manual configurations. 62 | * @var array 63 | */ 64 | public $current_config; 65 | 66 | /** 67 | * User array. 68 | * If the user has been identified, store his information in this array 69 | * KEYS: 70 | * email (string) – Which displays the visitor’s email address and it will be used as a unique identifier instead of cookies. 71 | * name (string) – Which displays the visitor’s full name 72 | * company (string) – Which displays the company name or account of your customer 73 | * avatar (string) – Which is a URL link to a visitor avatar 74 | * other (string) - You can define any attribute you like and have that detail passed from within the visitor live stream data when viewing Woopra 75 | * @var array 76 | */ 77 | private $user; 78 | 79 | /** 80 | * Has the latest information on the user been sent to woopra? 81 | * @var boolean 82 | */ 83 | private $user_up_to_date; 84 | 85 | /** 86 | * Events array stack 87 | * Each item of the stack is either: 88 | * - an empty array (if pv event) 89 | * - an array(2) (if custom event) 90 | * O (string) - the name of the event 91 | * 1 (array) - properties associated with that action 92 | * @var array 93 | */ 94 | private $events; 95 | 96 | /** 97 | * Is JavaScript Tracker Ready? 98 | * @var boolean 99 | */ 100 | private $tracker_ready; 101 | 102 | /** 103 | * Woopra Analytics 104 | * @param none 105 | * @return none 106 | * @constructor 107 | */ 108 | function __construct($config_params = null) { 109 | 110 | //Tracker is not ready yet 111 | $this->tracker_ready = false; 112 | 113 | //Current configuration is Default 114 | $this->current_config = WoopraTracker::$default_config; 115 | 116 | //Set the default IP 117 | $this->current_config["ip_address"] = $this->get_client_ip(); 118 | 119 | //Set the domain name and the cookie_domain 120 | $this->current_config["domain"] = $_SERVER["HTTP_HOST"]; 121 | $this->current_config["cookie_domain"] = $_SERVER["HTTP_HOST"]; 122 | 123 | //configure app ID 124 | $this->current_config["app"] = WoopraTracker::$SDK_ID; 125 | $this->custom_config = array("app" => WoopraTracker::$SDK_ID); 126 | 127 | //If configuration array was passed, configure Woopra 128 | if (isset($config_params)) { 129 | $this->config($config_params); 130 | } 131 | 132 | //Get cookie or generate a random one 133 | $this->current_config["cookie_value"] = isset($_COOKIE[$this->current_config["cookie_name"]]) ? $_COOKIE[$this->current_config["cookie_name"]] : WoopraTracker::RandomString(); 134 | 135 | //We don't have any info on the user yet, so he is up to date by default. 136 | $this->user_up_to_date = true; 137 | 138 | } 139 | 140 | /** 141 | * Echoes JS code to configure the tracker 142 | * @return none 143 | */ 144 | private function print_javascript_configuration() { 145 | if (isset($this->custom_config)) { 146 | 147 | ?> 148 | woopra.config(custom_config); ?>); 149 | custom_config ); 152 | } 153 | } 154 | 155 | /** 156 | * Echoes JS code to identify the user with the tracker 157 | * @return none 158 | */ 159 | private function print_javascript_identification() { 160 | 161 | if ( ! $this->user_up_to_date ) { 162 | ?> 163 | woopra.identify(user); ?>); 164 | user_up_to_date = true; 166 | } 167 | } 168 | 169 | /** 170 | * Echoes JS code to track custom events 171 | * @param none 172 | * @return none 173 | */ 174 | private function print_javascript_events() { 175 | 176 | if (isset($this->events)) { 177 | 178 | foreach ($this->events as $event) { 179 | if(empty($event)) { 180 | ?> 181 | woopra.track(); 182 | 185 | woopra.track(, ); 186 | events ); 191 | } 192 | } 193 | 194 | /** 195 | * Random Cookie generator in case the user doesn't have a cookie yet. Better to use a hash of the email. 196 | * @param none 197 | * @return string 198 | */ 199 | private static function RandomString() { 200 | $characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 201 | $randstring = ""; 202 | for ($i = 0; $i < 12; $i++) { 203 | $randstring .= $characters[rand(0, strlen($characters)-1)]; 204 | } 205 | return $randstring; 206 | } 207 | 208 | 209 | 210 | /** 211 | * Prepares the http request and sends it. 212 | * @param boolean Is this a tracking event or are we just identifying a user? 213 | * @param (optional) array 214 | * @return none 215 | */ 216 | private function woopra_http_request($is_tracking, $event = null) { 217 | 218 | $base_url = "http://www.woopra.com/track/"; 219 | 220 | //Config params 221 | $config_params = "?host=" . urlencode($this->current_config["domain"]); 222 | $config_params .= "&cookie=" . urlencode($this->current_config["cookie_value"]); 223 | $config_params .= "&ip=" . urlencode($this->current_config["ip_address"]); 224 | $config_params .= "&timeout=" . urlencode($this->current_config["idle_timeout"]); 225 | 226 | //User params 227 | $user_params = ""; 228 | if ( isset($this->user) ) { 229 | foreach($this->user as $option => $value) { 230 | if (! (empty($option) || empty($value))) { 231 | $user_params .= "&cv_" . urlencode($option) . "=" . urlencode($value); 232 | } 233 | } 234 | } 235 | 236 | //Just identifying 237 | if ( ! $is_tracking ) { 238 | $url = $base_url . "identify/" . $config_params . $user_params . "&app=" . $this->current_config["app"]; 239 | 240 | //Tracking 241 | } else { 242 | 243 | //Event params 244 | $event_params = ""; 245 | if ( $event != null ) { 246 | $event_params .= "&event=" . urlencode($event[0]); 247 | foreach($event[1] as $option => $value) { 248 | if (! (empty($option) || empty($value))) { 249 | $event_params .= "&ce_" . urlencode($option) . "=" . urlencode($value); 250 | //also add referrer without prefix for woopra to pick up 251 | if ($option == "referer" || $option == "referrer") { 252 | $event_params .= "&referer=" . urlencode($value); 253 | } 254 | } 255 | } 256 | } else { 257 | $event_params .= "&event=pv&ce_url=" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; 258 | } 259 | $url = $base_url . "ce/" . $config_params . $user_params . $event_params . "&app=" . $this->current_config["app"]; 260 | } 261 | 262 | //Send the request 263 | if (function_exists('curl_version')) { 264 | $this->get_data($url); 265 | } else { 266 | $opts = array( 267 | 'http'=>array( 268 | 'method'=>"GET", 269 | 'header'=>"User-Agent: ".$_SERVER['HTTP_USER_AGENT'] 270 | ) 271 | ); 272 | $context = stream_context_create($opts); 273 | file_get_contents( $url, false, $context); 274 | } 275 | 276 | } 277 | 278 | /** 279 | * Echoes Woopra Widget JS code, and checks if there is any stored Configuration, Identification, or Custom events awaiting process and echoes it too. 280 | * @param none 281 | * @return Woopra object 282 | */ 283 | public function js_code() { 284 | 285 | ?> 286 | 287 | 288 | 308 | 309 | 310 | custom_config)) { 323 | $this->custom_config = array(); 324 | } 325 | foreach( $args as $option => $value) { 326 | 327 | if ( array_key_exists($option, WoopraTracker::$default_config) ) { 328 | 329 | if ( gettype($value) == gettype( WoopraTracker::$default_config[$option] ) ) { 330 | if ($option != "ip_address" && $option != "cookie_value") { 331 | $this->custom_config[$option] = $value; 332 | } 333 | $this->current_config[$option] = $value; 334 | //If the user is customizing the name of the cookie, check again if the user already has one. 335 | if ($option == "cookie_name") { 336 | $this->current_config["cookie_value"] = isset($_COOKIE[$this->current_config["cookie_name"]]) ? $_COOKIE[$this->current_config["cookie_name"]] : $this->current_config["cookie_value"]; 337 | } 338 | } 339 | else { 340 | trigger_error("Wrong value type in configuration array for parameter ".$option.". Recieved ".gettype($value).", expected ".gettype( WoopraTracker::$default_config[$option] )."."); 341 | } 342 | } 343 | else { 344 | trigger_error("Unexpected parameter in configuration array: ".$option."."); 345 | } 346 | } 347 | return $this; 348 | } 349 | 350 | /** 351 | * Identifies User 352 | * @param array 353 | * @return Woopra object 354 | */ 355 | public function identify($identified_user, $override = false) { 356 | if (!empty($identified_user)) { 357 | $this->user = $identified_user; 358 | $this->user_up_to_date = false; 359 | 360 | if(isset($identified_user["email"]) && ! empty($identified_user["email"])) { 361 | if ($override || !isset($_COOKIE[$this->current_config["cookie_name"]])) { 362 | $this->current_config["cookie_value"] = crc32($identified_user["email"]); 363 | } 364 | } 365 | return $this; 366 | } 367 | } 368 | 369 | /** 370 | * Tracks Custom Event. If no parameters are specified, will simply track pageview. 371 | * @param string 372 | * @param array 373 | * @param (optional) boolean 374 | * @return Woopra object 375 | */ 376 | public function track($event = null, $args = array(), $back_end_processing = false) { 377 | 378 | if ( $back_end_processing ) { 379 | $http_event = null; 380 | if ( $event != null ) { 381 | $http_event = array($event, $args); 382 | } 383 | $this->woopra_http_request(true, $http_event); 384 | return $this; 385 | } 386 | 387 | if ($event == null) { 388 | if ( $this->tracker_ready ) { 389 | ?> 390 | 397 | events) ) { 400 | $this->events = array(); 401 | } 402 | array_push( $this->events, array()); 403 | } 404 | return $this; 405 | } 406 | 407 | if (! isset($this->events) ) { 408 | $this->events = array(); 409 | } 410 | array_push( $this->events, array($event, $args) ); 411 | 412 | if ( $this->tracker_ready ) { 413 | ?> 414 | 421 | woopra_http_request(false); 436 | $this->user_up_to_date = true; 437 | } elseif($this->tracker_ready) { 438 | 439 | ?> 440 | 447 | current_config["cookie_name"], $this->current_config["cookie_value"], time()+(60*60*24*365*2), $this->current_config["cookie_path"], $this->current_config["cookie_domain"] ); 458 | } 459 | 460 | /** 461 | * Retrieves the user's IP address 462 | * @param none 463 | * @return String 464 | */ 465 | private function get_client_ip() { 466 | if (isset($_SERVER["HTTP_X_FORWARDED_FOR"])) { 467 | $ips = explode(",", $_SERVER["HTTP_X_FORWARDED_FOR"]); 468 | return trim($ips[0]); 469 | } else { 470 | return $_SERVER["REMOTE_ADDR"]; 471 | } 472 | } 473 | 474 | /** 475 | * Gets the data from a URL using CURL 476 | * @param String 477 | * @return String 478 | */ 479 | private function get_data($url) { 480 | $ch = curl_init(); 481 | $timeout = 5; 482 | curl_setopt($ch, CURLOPT_URL, $url); 483 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 484 | curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); 485 | curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); 486 | $data = curl_exec($ch); 487 | curl_close($ch); 488 | return $data; 489 | } 490 | } 491 | 492 | ?> 493 | --------------------------------------------------------------------------------