Ticket #434: Visit.php

File Visit.php, 24.9 KB (added by uhaefele, 3 years ago)

visits.php with switch included

Line 
1<?php
2/**
3 * Piwik - Open source web analytics
4 *
5 * @link http://piwik.org
6 * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
7 * @version $Id: Visit.php 575 2008-07-26 23:08:32Z matt $
8 *
9 * @package Piwik_Tracker
10 */
11
12
13interface Piwik_Tracker_Visit_Interface {
14    function handle();
15    function setDb($db);
16}
17
18/**
19 * Class used to handle a Visit.
20 * A visit is either NEW or KNOWN.
21 * - If a visit is NEW then we process the visitor information (settings, referers, etc.) and save
22 * a new line in the log_visit table.
23 * - If a visit is KNOWN then we update the visit row in the log_visit table, updating the number of pages
24 * views, time spent, etc.
25 *
26 * Whether a visit is NEW or KNOWN we also save the action in the DB.
27 * One request to the piwik.php script is associated to one action.
28 *
29 * @package Piwik_Tracker
30 */
31
32class Piwik_Tracker_Visit implements Piwik_Tracker_Visit_Interface
33{
34    protected $cookieLog = null;
35    protected $visitorInfo = array();
36    protected $userSettingsInformation = null;
37    protected $db = null;
38    protected $idsite;
39
40    function __construct()
41    {
42        $idsite = Piwik_Common::getRequestVar('idsite', 0, 'int');
43        if($idsite <= 0)
44        {
45            throw new Exception("The 'idsite' in the request is invalid.");
46        }
47       
48        $this->idsite = $idsite;
49    }
50   
51    public function setDb($db)
52    {
53        $this->db = $db;
54    }
55   
56    /**
57     * Returns the current date in the "Y-m-d" PHP format
58     * @return string
59     */
60    protected function getCurrentDate( $format = "Y-m-d")
61    {
62        return date($format, $this->getCurrentTimestamp() );
63    }
64   
65    /**
66     * Returns the current Timestamp
67     * @return int
68     */
69    protected function getCurrentTimestamp()
70    {
71        return time();
72    }
73   
74    /**
75     * Returns the date in the "Y-m-d H:i:s" PHP format
76     * @return string
77     */
78    protected function getDatetimeFromTimestamp($timestamp)
79    {
80        return date("Y-m-d H:i:s", $timestamp);
81    }
82
83    /**
84     * Test if the current visitor is excluded from the statistics.
85     *
86     * Plugins can for example exclude visitors based on the
87     * - IP
88     * - If a given cookie is found
89     *
90     * @return bool True if the visit must not be saved, false otherwise
91     */
92    protected function isExcluded()
93    {
94        $excluded = 0;
95        Piwik_PostEvent('Tracker.Visit.isExcluded', $excluded);
96        if($excluded)
97        {
98            printDebug("Visitor excluded.");
99            return true;
100        }
101       
102        return false;
103    }
104   
105    /**
106     * Returns the cookie name used for the Piwik Tracker cookie
107     * @return string
108     */
109    protected function getCookieName()
110    {
111        return Piwik_Tracker_Config::getInstance()->Tracker['cookie_name'] . $this->idsite;
112    }
113   
114   
115    /**
116     * This methods tries to see if the visitor has visited the website before.
117     *
118     * We have to split the visitor into one of the category
119     * - Known visitor
120     * - New visitor
121     *
122     * A known visitor is a visitor that has already visited the website in the current month.
123     * We define a known visitor using the algorithm:
124     *
125     * 1) Checking if a cookie contains
126     *         // a unique id for the visitor
127     *         - id_visitor
128     *
129     *         // the timestamp of the last action in the most recent visit
130     *         - timestamp_last_action
131     *
132      *      // the timestamp of the first action in the most recent visit
133     *         - timestamp_first_action
134     *
135     *         // the ID of the most recent visit (which could be in the past or the current visit)
136     *         - id_visit
137     *
138     *         // the ID of the most recent action
139     *         - id_last_action
140     *
141     * 2) If the visitor doesn't have a cookie, we try to look for a similar visitor configuration.
142     *       We search for a visitor with the same plugins/OS/Browser/Resolution for today for this website.
143     */
144    protected function recognizeTheVisitor()
145    {
146        $this->visitorKnown = false;
147       
148        $this->cookieLog = new Piwik_Cookie( $this->getCookieName() );
149        /*
150         * Case the visitor has the piwik cookie.
151         * We make sure all the data that should saved in the cookie is available.
152         */
153       
154        if( false !== ($idVisitor = $this->cookieLog->get( Piwik_Tracker::COOKIE_INDEX_IDVISITOR )) )
155        {
156            $timestampLastAction = $this->cookieLog->get( Piwik_Tracker::COOKIE_INDEX_TIMESTAMP_LAST_ACTION );
157            $timestampFirstAction = $this->cookieLog->get( Piwik_Tracker::COOKIE_INDEX_TIMESTAMP_FIRST_ACTION );
158            $idVisit = $this->cookieLog->get( Piwik_Tracker::COOKIE_INDEX_ID_VISIT );
159            $idLastAction = $this->cookieLog->get( Piwik_Tracker::COOKIE_INDEX_ID_LAST_ACTION );
160           
161            if(        $timestampLastAction !== false && is_numeric($timestampLastAction)
162                &&     $timestampFirstAction !== false && is_numeric($timestampFirstAction)
163                &&     $idVisit !== false && is_numeric($idVisit)
164                &&     $idLastAction !== false && is_numeric($idLastAction)
165            )
166            {
167                $this->visitorInfo['visitor_idcookie'] = $idVisitor;
168                $this->visitorInfo['visit_last_action_time'] = $timestampLastAction;
169                $this->visitorInfo['visit_first_action_time'] = $timestampFirstAction;
170                $this->visitorInfo['idvisit'] = $idVisit;
171                $this->visitorInfo['visit_exit_idaction'] = $idLastAction;
172               
173                $this->visitorKnown = true;                               
174               
175                printDebug("The visitor is known because he has the piwik cookie (idcookie = {$this->visitorInfo['visitor_idcookie']}, idvisit = {$this->visitorInfo['idvisit']}, last action = ".date("r", $this->visitorInfo['visit_last_action_time']).") ");
176            }
177        }
178
179        /*
180         * If the visitor doesn't have the piwik cookie, we look for a visitor that has exactly the same configuration
181         * and that visited the website today.
182         * This function might be switched off using the visitor_heuristic=false setting in global.ini.php
183         */
184        //printDebug("Use heuristics ? -".Piwik_Tracker_Config::getInstance()->Tracker['visitor_heuristic']."-");
185               
186        if (( !$this->visitorKnown ) and (Piwik_Tracker_Config::getInstance()->Tracker['visitor_heuristic']))
187        {
188            $userInfo = $this->getUserSettingsInformation();
189            $md5Config = $userInfo['config_md5config'];
190
191            $visitRow = $this->db->fetch(
192                                        " SELECT      visitor_idcookie,
193                                                    UNIX_TIMESTAMP(visit_last_action_time) as visit_last_action_time,
194                                                    UNIX_TIMESTAMP(visit_first_action_time) as visit_first_action_time,
195                                                    idvisit,
196                                                    visit_exit_idaction
197                                        FROM ".$this->db->prefixTable('log_visit').
198                                        " WHERE visit_server_date = ?
199                                            AND idsite = ?
200                                            AND config_md5config = ?
201                                        ORDER BY visit_last_action_time DESC
202                                        LIMIT 1",
203                                        array( $this->getCurrentDate(), $this->idsite, $md5Config));
204            if($visitRow
205                && count($visitRow) > 0)
206            {
207                $this->visitorInfo['visitor_idcookie'] = $visitRow['visitor_idcookie'];
208                $this->visitorInfo['visit_last_action_time'] = $visitRow['visit_last_action_time'];
209                $this->visitorInfo['visit_first_action_time'] = $visitRow['visit_first_action_time'];
210                $this->visitorInfo['idvisit'] = $visitRow['idvisit'];
211                $this->visitorInfo['visit_exit_idaction'] = $visitRow['visit_exit_idaction'];
212               
213                $this->visitorKnown = true;
214               
215                printDebug("The visitor is known because of his userSettings+IP (idcookie = {$visitRow['visitor_idcookie']}, idvisit = {$this->visitorInfo['idvisit']}, last action = ".date("r", $this->visitorInfo['visit_last_action_time']).") ");
216            }
217        }
218    }
219   
220    /**
221     * Gets the UserSettings information and returns them in an array of name => value
222     *
223     * @return array
224     */
225    protected function getUserSettingsInformation()
226    {
227        // we already called this method before, simply returns the result
228        if(is_array($this->userSettingsInformation))
229        {
230            return $this->userSettingsInformation;
231        }
232       
233       
234        $plugin_Flash             = Piwik_Common::getRequestVar( 'fla', 0, 'int');
235        $plugin_Director         = Piwik_Common::getRequestVar( 'dir', 0, 'int');
236        $plugin_Quicktime        = Piwik_Common::getRequestVar( 'qt', 0, 'int');
237        $plugin_RealPlayer         = Piwik_Common::getRequestVar( 'realp', 0, 'int');
238        $plugin_Pdf             = Piwik_Common::getRequestVar( 'pdf', 0, 'int');
239        $plugin_WindowsMedia     = Piwik_Common::getRequestVar( 'wma', 0, 'int');
240        $plugin_Java             = Piwik_Common::getRequestVar( 'java', 0, 'int');
241        $plugin_Cookie             = Piwik_Common::getRequestVar( 'cookie', 0, 'int');
242       
243        $userAgent        = Piwik_Common::sanitizeInputValues(@$_SERVER['HTTP_USER_AGENT']);
244        $aBrowserInfo    = Piwik_Common::getBrowserInfo($userAgent);
245        $browserName    = $aBrowserInfo['name'];
246        $browserVersion    = $aBrowserInfo['version'];
247       
248        $os                = Piwik_Common::getOs($userAgent);
249       
250        $resolution        = Piwik_Common::getRequestVar('res', 'unknown', 'string');
251
252        $ip                = Piwik_Common::getIp();
253        $ip             = ip2long($ip);
254
255        $browserLang    = substr(Piwik_Common::getBrowserLanguage(), 0, 20);
256       
257        $configurationHash = $this->getConfigHash(
258                                                $os,
259                                                $browserName,
260                                                $browserVersion,
261                                                $resolution,
262                                                $plugin_Flash,
263                                                $plugin_Director,
264                                                $plugin_RealPlayer,
265                                                $plugin_Pdf,
266                                                $plugin_WindowsMedia,
267                                                $plugin_Java,
268                                                $plugin_Cookie,
269                                                $ip,
270                                                $browserLang);
271                                               
272        $this->userSettingsInformation = array(
273            'config_md5config' => $configurationHash,
274            'config_os'             => $os,
275            'config_browser_name'     => $browserName,
276            'config_browser_version' => $browserVersion,
277            'config_resolution'     => $resolution,
278            'config_pdf'             => $plugin_Pdf,
279            'config_flash'             => $plugin_Flash,
280            'config_java'             => $plugin_Java,
281            'config_director'         => $plugin_Director,
282            'config_quicktime'         => $plugin_Quicktime,
283            'config_realplayer'     => $plugin_RealPlayer,
284            'config_windowsmedia'     => $plugin_WindowsMedia,
285            'config_cookie'         => $plugin_Cookie,
286            'location_ip'             => $ip,
287            'location_browser_lang' => $browserLang,           
288        );
289       
290        return $this->userSettingsInformation;
291    }
292   
293    /**
294     * Returns true if the last action was done during the last 30 minutes
295     * @return bool
296     */
297    protected function isLastActionInTheSameVisit()
298    {
299        return $this->visitorInfo['visit_last_action_time']
300                    >= ($this->getCurrentTimestamp() - Piwik_Tracker_Config::getInstance()->Tracker['visit_standard_length']);
301    }
302
303    /**
304     * Returns true if the recognizeTheVisitor() method did recognize the visitor
305     */
306    protected function isVisitorKnown()
307    {
308        return $this->visitorKnown === true;
309    }
310   
311    /**
312     *    Main algorith to handle the visit.
313     *
314     *  Once we have the visitor information, we have to define if the visit is a new or a known visit.
315     *
316     * 1) When the last action was done more than 30min ago,
317     *       or if the visitor is new, then this is a new visit.
318     *   
319     * 2) If the last action is less than 30min ago, then the same visit is going on.
320     *    Because the visit goes on, we can get the time spent during the last action.
321     *
322     * NB:
323     *  - In the case of a new visit, then the time spent
324     *    during the last action of the previous visit is unknown.
325     *
326     *    - In the case of a new visit but with a known visitor,
327     *    we can set the 'returning visitor' flag.
328     *
329     * In all the cases we set a cookie to the visitor with the new information.
330     */
331    public function handle()
332    {
333        if($this->isExcluded())
334        {
335            return;
336        }
337       
338        $this->recognizeTheVisitor();
339        if( $this->isVisitorKnown()
340            && $this->isLastActionInTheSameVisit())
341        {
342            $this->handleKnownVisit();
343        }
344        else
345        {
346            $this->handleNewVisit();
347        }
348       
349        // we update the cookie with the new visit information
350        $this->updateCookie();
351    }
352
353    /**
354     * Update the cookie information.
355     */
356    protected function updateCookie()
357    {
358        printDebug("We manage the cookie...");
359       
360        // idcookie has been generated in handleNewVisit or we simply propagate the old value
361        $this->cookieLog->set(     Piwik_Tracker::COOKIE_INDEX_IDVISITOR,
362                                $this->visitorInfo['visitor_idcookie'] );
363       
364        // the last action timestamp is the current timestamp
365        $this->cookieLog->set(     Piwik_Tracker::COOKIE_INDEX_TIMESTAMP_LAST_ACTION,     
366                                $this->visitorInfo['visit_last_action_time'] );
367       
368        // the first action timestamp is the timestamp of the first action of the current visit
369        $this->cookieLog->set(     Piwik_Tracker::COOKIE_INDEX_TIMESTAMP_FIRST_ACTION,     
370                                $this->visitorInfo['visit_first_action_time'] );
371       
372        // the idvisit has been generated by mysql in handleNewVisit or simply propagated here
373        $this->cookieLog->set(     Piwik_Tracker::COOKIE_INDEX_ID_VISIT,     
374                                $this->visitorInfo['idvisit'] );
375       
376        // the last action ID is the current exit idaction
377        $this->cookieLog->set(     Piwik_Tracker::COOKIE_INDEX_ID_LAST_ACTION,     
378                                $this->visitorInfo['visit_exit_idaction'] );
379                               
380        $this->cookieLog->save();
381    }
382   
383   
384    /**
385     * In the case of a known visit, we have to do the following actions:
386     *
387     * 1) Insert the new action
388     *
389     * 2) Update the visit information
390     */
391    protected function handleKnownVisit()
392    {
393        printDebug("Visit known.");       
394       
395        /**
396         * Init the action
397         */
398        $action = $this->getActionObject();
399        $actionId = $action->getActionId();
400        printDebug("idAction = $actionId");
401               
402        $serverTime     = $this->getCurrentTimestamp();
403        $datetimeServer = $this->getDatetimeFromTimestamp($serverTime);
404   
405        $this->db->query("/* SHARDING_ID_SITE = ". $this->idsite ." */
406                            UPDATE ". $this->db->prefixTable('log_visit')."
407                            SET visit_last_action_time = ?,
408                                visit_exit_idaction = ?,
409                                visit_total_actions = visit_total_actions + 1,
410                                visit_total_time = UNIX_TIMESTAMP(visit_last_action_time) - UNIX_TIMESTAMP(visit_first_action_time)
411                            WHERE idvisit = ?
412                            LIMIT 1",
413                            array(     $datetimeServer,
414                                    $actionId,
415                                    $this->visitorInfo['idvisit'] )
416                );
417        /**
418         * Save the action
419         */
420        $timespentLastAction = $serverTime - $this->visitorInfo['visit_last_action_time'];
421       
422        $action->record(     $this->visitorInfo['idvisit'],
423                            $this->visitorInfo['visit_exit_idaction'],
424                            $timespentLastAction
425            );
426       
427       
428        /**
429         * Cookie fields to be updated
430         */
431        $this->visitorInfo['visit_last_action_time'] = $serverTime;
432        $this->visitorInfo['visit_exit_idaction'] = $actionId;
433       
434
435    }
436   
437    /**
438     * In the case of a new visit, we have to do the following actions:
439     *
440     * 1) Insert the new action
441     *
442     * 2) Insert the visit information
443     */
444    protected function handleNewVisit()
445    {
446        printDebug("New Visit.");
447       
448        /**
449         * Get the variables from the REQUEST
450         */
451        $localTime                = Piwik_Common::getRequestVar( 'h', $this->getCurrentDate("H"), 'numeric')
452                            .':'. Piwik_Common::getRequestVar( 'm', $this->getCurrentDate("i"), 'numeric')
453                            .':'. Piwik_Common::getRequestVar( 's', $this->getCurrentDate("s"), 'numeric');
454       
455        $serverTime     = $this->getCurrentTimestamp();   
456        $serverDate     = $this->getCurrentDate();   
457       
458        if($this->isVisitorKnown())
459        {
460            $idcookie = $this->visitorInfo['visitor_idcookie'];
461            $returningVisitor = 1;
462        }
463        else
464        {
465            $idcookie = $this->getVisitorUniqueId();           
466            $returningVisitor = 0;
467        }
468       
469        $defaultTimeOnePageVisit = Piwik_Tracker_Config::getInstance()->Tracker['default_time_one_page_visit'];
470       
471        $userInfo = $this->getUserSettingsInformation();
472        $country         = Piwik_Common::getCountry($userInfo['location_browser_lang']);               
473        $continent        = Piwik_Common::getContinent( $country );
474                                                       
475        $refererInfo = $this->getRefererInformation();
476       
477        /**
478         * Init the action
479         */
480        $action = $this->getActionObject();
481        $actionId = $action->getActionId();
482       
483        printDebug("idAction = $actionId");       
484       
485       
486        /**
487         * Save the visitor
488         */
489        $informationToSave = array(
490            'idsite'                 => $this->idsite,
491            'visitor_localtime'     => $localTime,
492            'visitor_idcookie'         => $idcookie,
493            'visitor_returning'     => $returningVisitor,
494            'visit_first_action_time' => $this->getDatetimeFromTimestamp($serverTime),
495            'visit_last_action_time' =>  $this->getDatetimeFromTimestamp($serverTime),
496            'visit_server_date'     => $serverDate,
497            'visit_entry_idaction'     => $actionId,
498            'visit_exit_idaction'     => $actionId,
499            'visit_total_actions'     => 1,
500            'visit_total_time'         => $defaultTimeOnePageVisit,
501            'referer_type'             => $refererInfo['referer_type'],
502            'referer_name'             => $refererInfo['referer_name'],
503            'referer_url'             => $refererInfo['referer_url'],
504            'referer_keyword'         => $refererInfo['referer_keyword'],
505            'config_md5config'         => $userInfo['config_md5config'],
506            'config_os'             => $userInfo['config_os'],
507            'config_browser_name'     => $userInfo['config_browser_name'],
508            'config_browser_version' => $userInfo['config_browser_version'],
509            'config_resolution'     => $userInfo['config_resolution'],
510            'config_pdf'             => $userInfo['config_pdf'],
511            'config_flash'             => $userInfo['config_flash'],
512            'config_java'             => $userInfo['config_java'],
513            'config_director'         => $userInfo['config_director'],
514            'config_quicktime'         => $userInfo['config_quicktime'],
515            'config_realplayer'     => $userInfo['config_realplayer'],
516            'config_windowsmedia'     => $userInfo['config_windowsmedia'],
517            'config_cookie'         => $userInfo['config_cookie'],
518            'location_ip'             => $userInfo['location_ip'],
519            'location_browser_lang' => $userInfo['location_browser_lang'],
520            'location_country'         => $country,
521            'location_continent'     => $continent,
522        );
523       
524        Piwik_PostEvent('Tracker.newVisitorInformation', $informationToSave);
525       
526        $fields = implode(", ", array_keys($informationToSave));
527        $values = substr(str_repeat( "?,",count($informationToSave)),0,-1);
528       
529        $this->db->query( "INSERT INTO ".$this->db->prefixTable('log_visit').
530                        " ($fields) VALUES ($values)", array_values($informationToSave));
531                       
532        $idVisit = $this->db->lastInsertId();
533       
534        // Update the visitor information attribute with this information array
535        $this->visitorInfo = $informationToSave;
536        $this->visitorInfo['idvisit'] = $idVisit;
537
538        // we have to save timestamp in the object properties, whereas mysql eats some other datetime format
539        $this->visitorInfo['visit_first_action_time'] = $serverTime;
540        $this->visitorInfo['visit_last_action_time'] = $serverTime;
541       
542        // saves the action
543        $action->record( $idVisit, 0, 0 );
544       
545    }
546   
547    /**
548     * Returns an object able to handle the current action
549     * Plugins can return an override Action that for example, does not record the action in the DB
550     *
551     * @return Piwik_Tracker_Action child or fake but with same public interface
552     */
553    protected function getActionObject()
554    {
555        $action = null;
556        Piwik_PostEvent('Tracker.newAction', $action);
557   
558        if(is_null($action))
559        {
560            $action = new Piwik_Tracker_Action( $this->db );
561        }
562        elseif(!($action instanceof Piwik_Tracker_Action_Interface))
563        {
564            throw new Exception("The Action object set in the plugin must implement the interface Piwik_Tracker_Action_Interface");
565        }
566        $action->setIdSite($this->idsite);
567       
568        return $action;
569    }
570   
571    /**
572     * Returns an array containing the following information:
573     * - referer_type
574     *        - direct            -- absence of referer URL OR referer URL has the same host
575     *        - site                -- based on the referer URL
576     *        - search_engine        -- based on the referer URL
577     *        - campaign            -- based on campaign URL parameter
578     *        - newsletter        -- based on newsletter URL parameter
579     *
580     * - referer_name
581     *         - ()
582     *         - piwik.net            -- site host name
583     *         - google.fr            -- search engine host name
584     *         - adwords-search    -- campaign name
585     *         - beta-release        -- newsletter name
586     *         
587     * - referer_keyword
588     *         - ()
589     *         - ()
590     *         - my keyword
591     *         - my paid keyword
592     *         - ()
593     *         - ()
594     * 
595     * - referer_url : the same for all the referer types
596     *
597     */
598    protected function getRefererInformation()
599    {   
600        // default values for the referer_* fields
601        $this->typeRefererAnalyzed = Piwik_Common::REFERER_TYPE_DIRECT_ENTRY;
602        $this->nameRefererAnalyzed = '';
603        $this->keywordRefererAnalyzed = '';
604        $this->refererHost = '';
605       
606        // get the urls and parse them
607        $refererUrl    = Piwik_Common::getRequestVar( 'urlref', '', 'string');
608        $currentUrl    = Piwik_Common::getRequestVar( 'url', '', 'string');
609
610        $this->refererUrlParse = @parse_url($refererUrl);
611        $this->currentUrlParse = @parse_url($currentUrl);
612        if(isset($this->refererUrlParse['host']))
613        {
614            $this->refererHost = $this->refererUrlParse['host'];
615        }
616
617        $refererDetected = false;
618        if( !empty($this->currentUrlParse['host']))
619        {
620            if(    $this->detectRefererNewsletter()
621                ||    $this->detectRefererCampaign() )
622            {
623                $refererDetected = true;
624            }
625        }
626       
627        if(!$refererDetected
628            && !empty($this->refererUrlParse['host']) )
629        {
630            if( $this->detectRefererSearchEngine()
631                ||    $this->detectRefererDirectEntry() )
632            {
633                $refererDetected = true;
634            }
635        }
636       
637        if(!empty($this->refererHost)
638            && !$refererDetected)
639        {
640            $this->typeRefererAnalyzed = Piwik_Common::REFERER_TYPE_WEBSITE;
641            $this->nameRefererAnalyzed = $this->refererHost;
642        }
643       
644        $refererInformation = array(
645            'referer_type'         => $this->typeRefererAnalyzed,
646            'referer_name'         => $this->nameRefererAnalyzed,
647            'referer_keyword'     => $this->keywordRefererAnalyzed,
648            'referer_url'         => $refererUrl,
649        );
650       
651        return $refererInformation;
652    }
653   
654    /*
655     * Search engine detection
656     */
657    protected function detectRefererSearchEngine()
658    {
659        /*
660         * A referer is a search engine if the URL's host is in the SearchEngines array
661         * and if we found the keyword in the URL.
662         *
663         * For example if someone comes from http://www.google.com/partners.html this will not
664         * be counted as a search engines, but as a website referer from google.com (because the
665         * keyword couldn't be found in the URL)
666         */
667        require_once "DataFiles/SearchEngines.php";
668       
669        if(array_key_exists($this->refererHost, $GLOBALS['Piwik_SearchEngines']))
670        {
671            $searchEngineName = $GLOBALS['Piwik_SearchEngines'][$this->refererHost][0];
672            $variableName = $GLOBALS['Piwik_SearchEngines'][$this->refererHost][1];
673           
674            if(isset($this->refererUrlParse['query']))
675            {
676                $query = $this->refererUrlParse['query'];
677
678                if($searchEngineName == 'Google Images')
679                {
680                    $query = urldecode(trim(strtolower(Piwik_Common::getParameterFromQueryString($query, 'prev'))));
681                    $query = str_replace('&', '&amp;', strstr($query, '?'));
682                }
683               
684                // search for keywords now &vname=keyword
685                $key = trim(strtolower(Piwik_Common::getParameterFromQueryString($query, $variableName)));
686               
687                if(!empty($key)
688                    && function_exists('iconv')
689                    && isset($GLOBALS['Piwik_SearchEngines'][$this->refererHost][2]))
690                {
691                    $charset = trim($GLOBALS['Piwik_SearchEngines'][$this->refererHost][2]);
692                   
693                    if(!empty($charset))
694                    {
695                        $key = htmlspecialchars(
696                                    @iconv(    $charset,
697                                            'utf-8//TRANSLIT',
698                                            htmlspecialchars_decode($key, Piwik_Common::HTML_ENCODING_QUOTE_STYLE))
699                                    , Piwik_Common::HTML_ENCODING_QUOTE_STYLE);
700                    }
701                }
702               
703                if(!empty($key))
704                {
705                    $this->typeRefererAnalyzed = Piwik_Common::REFERER_TYPE_SEARCH_ENGINE;
706                    $this->nameRefererAnalyzed = $searchEngineName;
707                    $this->keywordRefererAnalyzed = $key;
708                   
709                    return true;
710                }
711            }
712        }
713    }
714   
715    /*
716     * Newsletter analysis
717     */
718    protected function detectRefererNewsletter()
719    {
720        if(isset($this->currentUrlParse['query']))
721        {
722            $newsletterVariableName = Piwik_Tracker_Config::getInstance()->Tracker['newsletter_var_name'];
723            $newsletterVar = Piwik_Common::getParameterFromQueryString( $this->currentUrlParse['query'], $newsletterVariableName);
724
725            if(!empty($newsletterVar))
726            {
727                $this->typeRefererAnalyzed = Piwik_Common::REFERER_TYPE_NEWSLETTER;
728                $this->nameRefererAnalyzed = $newsletterVar;
729               
730                return true;
731            }
732        }
733    }
734   
735    /*
736     * Campaign analysis
737     */
738    protected function detectRefererCampaign()
739    {   
740        if(isset($this->currentUrlParse['query']))
741        {       
742            $campaignVariableName = Piwik_Tracker_Config::getInstance()->Tracker['campaign_var_name'];
743            $campaignName = Piwik_Common::getParameterFromQueryString($this->currentUrlParse['query'], $campaignVariableName);
744           
745            if( !empty($campaignName))
746            {
747                $campaignKeywordVariableName = Piwik_Tracker_Config::getInstance()->Tracker['campaign_keyword_var_name'];
748                $campaignKeyword = Piwik_Common::getParameterFromQueryString($this->currentUrlParse['query'], $campaignKeywordVariableName);
749
750                $this->typeRefererAnalyzed = Piwik_Common::REFERER_TYPE_CAMPAIGN;
751                $this->nameRefererAnalyzed = $campaignName;
752           
753                if(!empty($campaignKeyword))
754                {
755                    $this->keywordRefererAnalyzed = $campaignKeyword;
756                }
757               
758                return true;
759            }
760        }
761    }
762   
763   
764    /*
765     * Direct entry (referer host is similar to current host)
766     * And we have previously tried to detect the newsletter/campaign variables in the URL
767     * so it can only be a direct access
768     */
769   
770    protected function detectRefererDirectEntry()
771    {
772        if(isset($this->currentUrlParse['host']))
773        {
774            $currentHost = $this->currentUrlParse['host'];
775                   
776            if($currentHost == $this->refererHost)
777            {
778                $this->typeRefererAnalyzed = Piwik_Common::REFERER_TYPE_DIRECT_ENTRY;
779                return true;
780            }
781        }
782       
783    }
784   
785    /**
786     * Returns a MD5 of all the configuration settings
787     * @return string
788     */
789    protected function getConfigHash( $os, $browserName, $browserVersion, $resolution, $plugin_Flash, $plugin_Director, $plugin_RealPlayer, $plugin_Pdf, $plugin_WindowsMedia, $plugin_Java, $plugin_Cookie, $ip, $browserLang)
790    {
791        return md5( $os . $browserName . $browserVersion . $resolution . $plugin_Flash . $plugin_Director . $plugin_RealPlayer . $plugin_Pdf . $plugin_WindowsMedia . $plugin_Java . $plugin_Cookie . $ip . $browserLang );
792    }
793   
794    /**
795     * Returns either
796     * - "-1" for a known visitor
797     * - a unique 32 char identifier @see Piwik_Common::generateUniqId()
798     */
799    protected function getVisitorUniqueId()
800    {
801        if($this->isVisitorKnown())
802        {
803            return -1;
804        }
805        else
806        {
807            return Piwik_Common::generateUniqId();
808        }
809    }
810}