PageRenderTime 2ms CodeModel.GetById 120ms app.highlight 6ms RepoModel.GetById 1ms app.codeStats 0ms

/src/Racecore/GATracking/GATracking.php

https://github.com/michanismus/google-measurement-php-client
PHP | 409 lines | 162 code | 59 blank | 188 comment | 13 complexity | 8a894588277f8d0f606c5f12bb4bff49 MD5 | raw file
  1<?php
  2namespace Racecore\GATracking;
  3
  4use Racecore\GATracking\Exception\EndpointServerException;
  5use Racecore\GATracking\Exception\MissingConfigurationException;
  6use Racecore\GATracking\Tracking\AbstractTracking;
  7
  8/**
  9 * Google Analytics Measurement PHP Class
 10 * Licensed under the 3-clause BSD License.
 11 * This source file is subject to the 3-clause BSD License that is
 12 * bundled with this package in the LICENSE file.  It is also available at
 13 * the following URL: http://www.opensource.org/licenses/BSD-3-Clause
 14 *
 15 * Google Documentation
 16 * https://developers.google.com/analytics/devguides/collection/protocol/v1/
 17 *
 18 * @author  Marco Rieger
 19 * @email   Rieger(at)racecore.de
 20 * @git     https://github.com/ins0
 21 * @url     http://www.racecore.de
 22 * @package Racecore\GATracking\Tracking
 23 */
 24class GATracking
 25{
 26    /**
 27     * Google Analytics Account ID UA-...
 28     *
 29     * @var
 30     */
 31    private $accountID;
 32
 33    /**
 34     * Current User Client ID
 35     *
 36     * @var string
 37     */
 38    private $clientID;
 39
 40    /**
 41     * Protocol Version
 42     *
 43     * @var string
 44     */
 45    private $protocol = '1';
 46
 47    /**
 48     * Analytics Endpoint URL
 49     *
 50     * @var string
 51     */
 52    private $analytics_endpoint = 'http://www.google-analytics.com/collect';
 53
 54    /**
 55     * Tacking Holder
 56     *
 57     * @var array
 58     */
 59    private $tracking_holder = array();
 60
 61    /**
 62     * Holds the last Response from Google Analytics Server
 63     *
 64     * @var string
 65     */
 66    private $last_response = null;
 67
 68    /**
 69     * Holds all Responses from GA Server
 70     *
 71     * @var array
 72     */
 73    private $last_response_stack = array();
 74
 75    /**
 76     * Sets the Analytics Account ID
 77     *
 78     * @param $account
 79     */
 80    public function setAccountID($account)
 81    {
 82
 83        $this->accountID = $account;
 84    }
 85
 86    /**
 87     * Set the current Client ID
 88     *
 89     * @param $clientID
 90     * @return $this
 91     */
 92    public function setClientID($clientID)
 93    {
 94        $this->clientID = $clientID;
 95        return $this;
 96    }
 97
 98    /**
 99     * Returns the current Client ID
100     *
101     * @return string
102     */
103    public function getClientID()
104    {
105        if (!$this->clientID) {
106            $this->clientID = $this->createClientID();
107        }
108
109        return $this->clientID;
110    }
111
112    /**
113     * Return all registered Events
114     *
115     * @return array
116     */
117    public function getEvents()
118    {
119        return $this->tracking_holder;
120    }
121
122    /**
123     * Returns current Google Account ID
124     *
125     * @return mixed
126     */
127    public function getAccountID()
128    {
129        return $this->accountID;
130    }
131
132    /**
133     * Constructor
134     *
135     * @param string $accountID
136     */
137    public function __construct( $accountID = null )
138    {
139        $this->setAccountID( $accountID );
140
141        return $this;
142    }
143
144    /**
145     * Create a GUID on Client specific values
146     *
147     * @return string
148     */
149    private function createClientID()
150    {
151        // collect user specific data
152        if (isset($_COOKIE['_ga'])) {
153
154            $gaCookie = explode('.', $_COOKIE['_ga']);
155            if( isset($gaCookie[2] ) )
156            {
157                // check if uuid
158                if( $this->checkUUID( $gaCookie[2] ) )
159                {
160                    // uuid set in cookie
161                    return $gaCookie[2];
162                }
163                elseif( isset($gaCookie[2]) && isset($gaCookie[3]) )
164                {
165                    // google default client id
166                    return $gaCookie[2] . '.' . $gaCookie[3];
167                }
168            }
169        }
170
171        // nothing found - return random uuid client id
172        return $this->generateUUID();
173    }
174
175    /**
176     * Check if is a valid UUID v4
177     *
178     * @param $uuid
179     * @return int
180     */
181    private function checkUUID( $uuid )
182    {
183        return preg_match('#^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$#i', $uuid );
184    }
185
186    /**
187     * Generate UUID v4 function - needed to generate a CID when one isn't available
188     *
189     * @author Andrew Moore http://www.php.net/manual/en/function.uniqid.php#94959
190     * @return string
191     */
192    private function generateUUID() {
193        return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
194            // 32 bits for "time_low"
195            mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
196
197            // 16 bits for "time_mid"
198            mt_rand( 0, 0xffff ),
199
200            // 16 bits for "time_hi_and_version",
201            // four most significant bits holds version number 4
202            mt_rand( 0, 0x0fff ) | 0x4000,
203
204            // 16 bits, 8 bits for "clk_seq_hi_res",
205            // 8 bits for "clk_seq_low",
206            // two most significant bits holds zero and one for variant DCE1.1
207            mt_rand( 0, 0x3fff ) | 0x8000,
208
209            // 48 bits for "node"
210            mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff )
211        );
212    }
213
214    /**
215     * Send all captured Trackings to Analytics Server
216     * Flush all prev. captured tracking responses
217     *
218     * @return bool
219     */
220    public function send()
221    {
222        // clear response logs
223        $this->last_response_stack = array();
224        $this->last_response = null;
225
226        /** @var AbstractTracking $event */
227        foreach ($this->tracking_holder as $tracking) {
228            $this->sendTracking($tracking);
229        }
230
231        return true;
232    }
233
234    /**
235     * Returns the Client IP
236     * The last octect of the IP address is removed to anonymize the user
237     *
238     * @param string $address
239     * @return string
240     */
241    function getClientIP($address = '')
242    {
243
244        if (!$address) {
245            $address = $_SERVER['REMOTE_ADDR'];
246        }
247
248        if (!$address) {
249            return '';
250        }
251
252        // Capture the first three octects of the IP address and replace the forth
253        // with 0, e.g. 124.455.3.123 becomes 124.455.3.0
254        $regex = "/^([^.]+\.[^.]+\.[^.]+\.).*/";
255        if (preg_match($regex, $address, $matches)) {
256            return $matches[1] . '0';
257        }
258
259        return '';
260    }
261
262    /**
263     * Build the POST Packet
264     *
265     * @param AbstractTracking $event
266     * @return string
267     * @throws Exception\MissingConfigurationException
268     */
269    private function buildPacket( AbstractTracking $event )
270    {
271        // get packet
272        $eventPacket = $event->getPaket();
273
274        if( ! $this->getAccountID() )
275        {
276            throw new MissingConfigurationException('Google Account ID is missing');
277        }
278
279        // Add Protocol
280        $eventPacket['v'] = $this->protocol; // protocol version
281        $eventPacket['tid'] = $this->getAccountID(); // account id
282        $eventPacket['cid'] = $this->getClientID(); // client id
283
284        $eventPacket = array_reverse($eventPacket);
285
286        // build query
287        return http_build_query($eventPacket);
288    }
289
290    /**
291     * Send an Event to Google Analytics
292     * Will be removed
293     *
294     * @param AbstractTracking $tracking
295     * @return bool
296     * @throws Exception\EndpointServerException
297     * @deprecated Use sendTracking
298     */
299    public function sendEvent(AbstractTracking $tracking)
300    {
301        return $this->sendTracking($tracking);
302    }
303
304    /**
305     * Send an Event to Google Analytics
306     *
307     * @param AbstractTracking $event
308     * @return bool
309     * @throws Exception\EndpointServerException
310     */
311    public function sendTracking(AbstractTracking $event)
312    {
313        // get packet
314        $eventPacket = $this->buildPacket( $event );
315
316        // get endpoint
317        $endpoint = parse_url($this->analytics_endpoint);
318
319        // port
320        $port = ($endpoint['scheme'] == 'https' ? 443 : 80);
321
322        // connect
323        $connection = @fsockopen($endpoint['scheme'] == 'https' ? 'ssl://' : $endpoint['host'], $port, $error, $errorstr, 10);
324
325        if (!$connection) {
326            throw new EndpointServerException('Analytics Host not reachable!');
327        }
328
329        $header =   'POST ' . $endpoint['path'] . ' HTTP/1.1' . "\r\n" .
330                    'Host: ' . $endpoint['host'] . "\r\n" .
331                    'User-Agent: Google-Measurement-PHP-Client' . "\r\n" .
332                    'Content-Type: application/x-www-form-urlencoded' . "\r\n" .
333                    'Content-Length: ' . strlen($eventPacket) . "\r\n" .
334                    'Connection: Close' . "\r\n\r\n";
335
336        $this->last_response = '';
337
338        // frwite data
339        fwrite($connection, $header);
340        fwrite($connection, $eventPacket);
341
342        // response
343        $response = '';
344
345        // receive response
346        while (!feof($connection)) {
347            $response .= fgets($connection, 1024);
348        }
349
350        // response
351        $responseContainer = explode("\r\n\r\n", $response, 2);
352        $responseContainer[0] = explode("\r\n", $responseContainer[0]);
353
354        // save last response
355        $this->addResponse( $responseContainer );
356
357        // connection close
358        fclose($connection);
359
360        return true;
361    }
362
363    /**
364     * Add a Response to the Stack
365     *
366     * @param $response
367     * @return bool
368     */
369    public function addResponse( $response )
370    {
371        $this->last_response_stack[] = $response;
372        $this->last_response = $response;
373        return true;
374    }
375
376    /**
377     * Returns the last Response from Google Analytics Server
378     *
379     * @author  Marco Rieger
380     * @return string
381     */
382    public function getLastResponse()
383    {
384        return $this->last_response;
385    }
386
387    /**
388     * Returns all Responses since the last Send Method Call
389     *
390     * @return array
391     */
392    public function getLastResponseStack()
393    {
394        return $this->last_response_stack;
395    }
396
397    /**
398     * Add Tracking Event
399     *
400     * @param AbstractTracking $tracking
401     * @return $this
402     */
403    public function addTracking(AbstractTracking $tracking)
404    {
405        $this->tracking_holder[] = $tracking;
406
407        return $this;
408    }
409}