xref: /plugin/statistics/admin.php (revision 2998b1f6cbd57e9dd6b6614b5d932281bcf317c4)
11878f16fSAndreas Gohr<?php
21878f16fSAndreas Gohr/**
31878f16fSAndreas Gohr * statistics plugin
41878f16fSAndreas Gohr *
51878f16fSAndreas Gohr * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
61878f16fSAndreas Gohr * @author     Andreas Gohr <gohr@cosmocode.de>
71878f16fSAndreas Gohr */
81878f16fSAndreas Gohr
91878f16fSAndreas Gohr// must be run within Dokuwiki
101878f16fSAndreas Gohrif(!defined('DOKU_INC')) die();
111878f16fSAndreas Gohr
121878f16fSAndreas Gohrif(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
131878f16fSAndreas Gohrrequire_once(DOKU_PLUGIN.'admin.php');
141878f16fSAndreas Gohr
15*2998b1f6SAndreas Gohrrequire_once(DOKU_PLUGIN.'statistics/inc/DokuBrowscap.php');
16*2998b1f6SAndreas Gohr
171878f16fSAndreas Gohr/**
181878f16fSAndreas Gohr * All DokuWiki plugins to extend the admin function
191878f16fSAndreas Gohr * need to inherit from this class
201878f16fSAndreas Gohr */
211878f16fSAndreas Gohrclass admin_plugin_statistics extends DokuWiki_Admin_Plugin {
22a901d721SAndreas Gohr    public    $dblink = null;
23a901d721SAndreas Gohr    protected $opt    = '';
24a901d721SAndreas Gohr    protected $from   = '';
25a901d721SAndreas Gohr    protected $to     = '';
26a901d721SAndreas Gohr    protected $start  = '';
27a901d721SAndreas Gohr    protected $tlimit = '';
28a901d721SAndreas Gohr
29a901d721SAndreas Gohr    /**
30a901d721SAndreas Gohr     * Available statistic pages
31a901d721SAndreas Gohr     */
32a901d721SAndreas Gohr    protected $pages  = array('dashboard','page','referer','newreferer',
33a901d721SAndreas Gohr                              'outlinks','searchphrases','searchwords',
34a901d721SAndreas Gohr                              'searchengines','browser','os','country',
35a901d721SAndreas Gohr                              'resolution');
361878f16fSAndreas Gohr
371878f16fSAndreas Gohr    /**
381878f16fSAndreas Gohr     * Access for managers allowed
391878f16fSAndreas Gohr     */
401878f16fSAndreas Gohr    function forAdminOnly(){
411878f16fSAndreas Gohr        return false;
421878f16fSAndreas Gohr    }
431878f16fSAndreas Gohr
441878f16fSAndreas Gohr    /**
451878f16fSAndreas Gohr     * return sort order for position in admin menu
461878f16fSAndreas Gohr     */
471878f16fSAndreas Gohr    function getMenuSort() {
4814d99ec0SAndreas Gohr        return 150;
491878f16fSAndreas Gohr    }
501878f16fSAndreas Gohr
511878f16fSAndreas Gohr    /**
521878f16fSAndreas Gohr     * handle user request
531878f16fSAndreas Gohr     */
541878f16fSAndreas Gohr    function handle() {
55264f1744SAndreas Gohr        $this->opt = preg_replace('/[^a-z]+/','',$_REQUEST['opt']);
56a901d721SAndreas Gohr        if(!in_array($this->opt,$this->pages)) $this->opt = 'dashboard';
57a901d721SAndreas Gohr
5895eb68e6SAndreas Gohr        $this->start = (int) $_REQUEST['s'];
59e8699bceSAndreas Gohr        $this->setTimeframe($_REQUEST['f'],$_REQUEST['t']);
60e8699bceSAndreas Gohr    }
6195eb68e6SAndreas Gohr
62e8699bceSAndreas Gohr    /**
63e8699bceSAndreas Gohr     * set limit clause
64e8699bceSAndreas Gohr     */
65e8699bceSAndreas Gohr    function setTimeframe($from,$to){
66264f1744SAndreas Gohr        // fixme add better sanity checking here:
67e8699bceSAndreas Gohr        $from = preg_replace('/[^\d\-]+/','',$from);
68e8699bceSAndreas Gohr        $to   = preg_replace('/[^\d\-]+/','',$to);
69e8699bceSAndreas Gohr        if(!$from) $from = date('Y-m-d');
70e8699bceSAndreas Gohr        if(!$to)   $to   = date('Y-m-d');
71264f1744SAndreas Gohr
72264f1744SAndreas Gohr        //setup limit clause
732ee939eeSAndreas Gohr        $tlimit = "A.dt >= '$from 00:00:00' AND A.dt <= '$to 23:59:59'";
74e8699bceSAndreas Gohr        $this->tlimit = $tlimit;
75e8699bceSAndreas Gohr        $this->from   = $from;
76e8699bceSAndreas Gohr        $this->to     = $to;
771878f16fSAndreas Gohr    }
781878f16fSAndreas Gohr
791878f16fSAndreas Gohr    /**
8079b4a855SAndreas Gohr     * Output the Statistics
811878f16fSAndreas Gohr     */
821878f16fSAndreas Gohr    function html() {
83264f1744SAndreas Gohr        echo '<h1>Access Statistics</h1>';
84264f1744SAndreas Gohr        $this->html_timeselect();
85264f1744SAndreas Gohr
8679b4a855SAndreas Gohr        $method = 'html_'.$this->opt;
8779b4a855SAndreas Gohr        if(method_exists($this,$method)){
88a901d721SAndreas Gohr            echo '<div class="plg_stats_'.$this->opt.'">';
89a901d721SAndreas Gohr            echo '<h2>'.$this->getLang($this->opt).'</h2>';
9079b4a855SAndreas Gohr            $this->$method();
91a901d721SAndreas Gohr            echo '</div>';
9214d99ec0SAndreas Gohr        }
9314d99ec0SAndreas Gohr    }
9414d99ec0SAndreas Gohr
9547ffcf7dSAndreas Gohr    function getTOC(){
9647ffcf7dSAndreas Gohr        $toc = array();
97a901d721SAndreas Gohr        foreach($this->pages as $page){
9847ffcf7dSAndreas Gohr            $toc[] = array(
9947ffcf7dSAndreas Gohr                    'link'  => '?do=admin&amp;page=statistics&amp;opt='.$page.'&amp;f='.$this->from.'&amp;t='.$this->to,
10047ffcf7dSAndreas Gohr                    'title' => $this->getLang($page),
10147ffcf7dSAndreas Gohr                    'level' => 1,
10247ffcf7dSAndreas Gohr                    'type'  => 'ul'
10347ffcf7dSAndreas Gohr            );
10447ffcf7dSAndreas Gohr        }
10547ffcf7dSAndreas Gohr        return $toc;
1069da6395dSAndreas Gohr    }
1079da6395dSAndreas Gohr
1082507f8e0SAndreas Gohr    function html_pager($limit,$next){
1092507f8e0SAndreas Gohr        echo '<div class="plg_stats_pager">';
1102507f8e0SAndreas Gohr
1112507f8e0SAndreas Gohr        if($this->start > 0){
1122507f8e0SAndreas Gohr            $go = max($this->start - $limit, 0);
1132507f8e0SAndreas Gohr            echo '<a href="?do=admin&amp;page=statistics&amp;opt='.$this->opt.'&amp;f='.$this->from.'&amp;t='.$this->to.'&amp;s='.$go.'" class="prev">previous page</a>';
1142507f8e0SAndreas Gohr        }
1152507f8e0SAndreas Gohr
1162507f8e0SAndreas Gohr        if($next){
1172507f8e0SAndreas Gohr            $go = $this->start + $limit;
1182507f8e0SAndreas Gohr            echo '<a href="?do=admin&amp;page=statistics&amp;opt='.$this->opt.'&amp;f='.$this->from.'&amp;t='.$this->to.'&amp;s='.$go.'" class="next">next page</a>';
1192507f8e0SAndreas Gohr        }
1202507f8e0SAndreas Gohr        echo '</div>';
1212507f8e0SAndreas Gohr    }
1222507f8e0SAndreas Gohr
123264f1744SAndreas Gohr    /**
124264f1744SAndreas Gohr     * Print the time selection menu
125264f1744SAndreas Gohr     */
12614d99ec0SAndreas Gohr    function html_timeselect(){
127264f1744SAndreas Gohr        $now   = date('Y-m-d');
128264f1744SAndreas Gohr        $yday  = date('Y-m-d',time()-(60*60*24));
129264f1744SAndreas Gohr        $week  = date('Y-m-d',time()-(60*60*24*7));
130264f1744SAndreas Gohr        $month = date('Y-m-d',time()-(60*60*24*30));
13114d99ec0SAndreas Gohr
132264f1744SAndreas Gohr        echo '<div class="plg_stats_timeselect">';
133264f1744SAndreas Gohr        echo '<span>Select the timeframe:</span>';
134264f1744SAndreas Gohr        echo '<ul>';
135264f1744SAndreas Gohr
136264f1744SAndreas Gohr        echo '<li>';
1372507f8e0SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt='.$this->opt.'&amp;f='.$now.'&amp;t='.$now.'">';
138264f1744SAndreas Gohr        echo 'today';
139264f1744SAndreas Gohr        echo '</a>';
140264f1744SAndreas Gohr        echo '</li>';
141264f1744SAndreas Gohr
142264f1744SAndreas Gohr        echo '<li>';
1432507f8e0SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt='.$this->opt.'&amp;f='.$yday.'&amp;t='.$yday.'">';
144264f1744SAndreas Gohr        echo 'yesterday';
145264f1744SAndreas Gohr        echo '</a>';
146264f1744SAndreas Gohr        echo '</li>';
147264f1744SAndreas Gohr
148264f1744SAndreas Gohr        echo '<li>';
1492507f8e0SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt='.$this->opt.'&amp;f='.$week.'&amp;t='.$now.'">';
150264f1744SAndreas Gohr        echo 'last 7 days';
151264f1744SAndreas Gohr        echo '</a>';
152264f1744SAndreas Gohr        echo '</li>';
153264f1744SAndreas Gohr
154264f1744SAndreas Gohr        echo '<li>';
1552507f8e0SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt='.$this->opt.'&amp;f='.$month.'&amp;t='.$now.'">';
156264f1744SAndreas Gohr        echo 'last 30 days';
157264f1744SAndreas Gohr        echo '</a>';
158264f1744SAndreas Gohr        echo '</li>';
159264f1744SAndreas Gohr
160264f1744SAndreas Gohr        echo '</ul>';
161264f1744SAndreas Gohr
162264f1744SAndreas Gohr
163264f1744SAndreas Gohr        echo '<form action="" method="get">';
164264f1744SAndreas Gohr        echo '<input type="hidden" name="do" value="admin" />';
165264f1744SAndreas Gohr        echo '<input type="hidden" name="page" value="statistics" />';
166264f1744SAndreas Gohr        echo '<input type="hidden" name="opt" value="'.$this->opt.'" />';
167264f1744SAndreas Gohr        echo '<input type="text" name="f" value="'.$this->from.'" class="edit" />';
168264f1744SAndreas Gohr        echo '<input type="text" name="t" value="'.$this->to.'" class="edit" />';
169264f1744SAndreas Gohr        echo '<input type="submit" value="go" class="button" />';
17014d99ec0SAndreas Gohr        echo '</form>';
171264f1744SAndreas Gohr
172264f1744SAndreas Gohr        echo '</div>';
17314d99ec0SAndreas Gohr    }
17414d99ec0SAndreas Gohr
17514d99ec0SAndreas Gohr
176f5f32cbfSAndreas Gohr    /**
177f5f32cbfSAndreas Gohr     * Print an introductionary screen
178f5f32cbfSAndreas Gohr     */
17914d99ec0SAndreas Gohr    function html_dashboard(){
1802812a751SAndreas Gohr        echo '<p>This page gives you a quick overview on what is happening in your Wiki. For detailed lists
1812812a751SAndreas Gohr              choose a topic from the list.</p>';
1822812a751SAndreas Gohr
1832812a751SAndreas Gohr        // general info
1842812a751SAndreas Gohr        echo '<div class="plg_stats_top">';
1852812a751SAndreas Gohr        $result = $this->sql_aggregate($this->tlimit);
1862812a751SAndreas Gohr        echo '<ul>';
1872812a751SAndreas Gohr        echo '<li><span>'.$result['pageviews'].'</span> page views </li>';
1883c0acc14SAndreas Gohr        echo '<li><span>'.$result['sessions'].'</span> visits (sessions) </li>';
1893c0acc14SAndreas Gohr        echo '<li><span>'.$result['visitors'].'</span> unique visitors </li>';
1902812a751SAndreas Gohr        echo '<li><span>'.$result['users'].'</span> logged in users</li>';
1912812a751SAndreas Gohr
1922812a751SAndreas Gohr        echo '</ul>';
1932812a751SAndreas Gohr        echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/img.php?img=trend&amp;f='.$this->from.'&amp;t='.$this->to.'" />';
1942812a751SAndreas Gohr        echo '</div>';
1952812a751SAndreas Gohr
19614d99ec0SAndreas Gohr
19787d5e44bSAndreas Gohr        // top pages today
198264f1744SAndreas Gohr        echo '<div>';
199264f1744SAndreas Gohr        echo '<h2>Most popular pages</h2>';
20095eb68e6SAndreas Gohr        $result = $this->sql_pages($this->tlimit,$this->start,15);
2012812a751SAndreas Gohr        $this->html_resulttable($result);
2022507f8e0SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt=page&amp;f='.$this->from.'&amp;t='.$this->to.'" class="more">more</a>';
203264f1744SAndreas Gohr        echo '</div>';
20487d5e44bSAndreas Gohr
20587d5e44bSAndreas Gohr        // top referer today
206264f1744SAndreas Gohr        echo '<div>';
207e7a2f1e0SAndreas Gohr        echo '<h2>Newest incoming links</h2>';
208e7a2f1e0SAndreas Gohr        $result = $this->sql_newreferer($this->tlimit,$this->start,15);
2092812a751SAndreas Gohr        $this->html_resulttable($result);
2102507f8e0SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt=newreferer&amp;f='.$this->from.'&amp;t='.$this->to.'" class="more">more</a>';
211264f1744SAndreas Gohr        echo '</div>';
21254f6c432SAndreas Gohr
21329dea504SAndreas Gohr        // top searches today
214264f1744SAndreas Gohr        echo '<div>';
21529dea504SAndreas Gohr        echo '<h2>Top search phrases</h2>';
21629dea504SAndreas Gohr        $result = $this->sql_searchphrases($this->tlimit,$this->start,15);
21729dea504SAndreas Gohr        $this->html_resulttable($result);
21829dea504SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt=searchphrases&amp;f='.$this->from.'&amp;t='.$this->to.'" class="more">more</a>';
219264f1744SAndreas Gohr        echo '</div>';
22014d99ec0SAndreas Gohr    }
22114d99ec0SAndreas Gohr
2229da6395dSAndreas Gohr    function html_country(){
223bd4217d3SAndreas Gohr        echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/img.php?img=country&amp;f='.$this->from.'&amp;t='.$this->to.'" />';
2249da6395dSAndreas Gohr        $result = $this->sql_countries($this->tlimit,$this->start,150);
2252507f8e0SAndreas Gohr        $this->html_resulttable($result,'',150);
2269da6395dSAndreas Gohr    }
2279da6395dSAndreas Gohr
2289da6395dSAndreas Gohr    function html_page(){
2299da6395dSAndreas Gohr        $result = $this->sql_pages($this->tlimit,$this->start,150);
2302507f8e0SAndreas Gohr        $this->html_resulttable($result,'',150);
2319da6395dSAndreas Gohr    }
2329da6395dSAndreas Gohr
23375fa767dSAndreas Gohr    function html_browser(){
23475fa767dSAndreas Gohr        echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/img.php?img=browser&amp;f='.$this->from.'&amp;t='.$this->to.'" />';
23575fa767dSAndreas Gohr        $result = $this->sql_browsers($this->tlimit,$this->start,150,true);
2362507f8e0SAndreas Gohr        $this->html_resulttable($result,'',150);
23775fa767dSAndreas Gohr    }
23875fa767dSAndreas Gohr
239bd4217d3SAndreas Gohr    function html_os(){
240bd4217d3SAndreas Gohr        $result = $this->sql_os($this->tlimit,$this->start,150,true);
2412507f8e0SAndreas Gohr        $this->html_resulttable($result,'',150);
242bd4217d3SAndreas Gohr    }
243bd4217d3SAndreas Gohr
2449da6395dSAndreas Gohr    function html_referer(){
2452812a751SAndreas Gohr        $result = $this->sql_aggregate($this->tlimit);
2462812a751SAndreas Gohr
2472812a751SAndreas Gohr        $all    = $result['search']+$result['external']+$result['direct'];
2482812a751SAndreas Gohr
24994023548SAndreas Gohr        if($all){
2502812a751SAndreas Gohr            printf("<p>Of all %d external visits, %d (%.1f%%) were bookmarked (direct) accesses,
2512812a751SAndreas Gohr                    %d (%.1f%%) came from search engines and %d (%.1f%%) were referred through
2522812a751SAndreas Gohr                    links from other pages.</p>",$all,$result['direct'],(100*$result['direct']/$all),
2532812a751SAndreas Gohr                    $result['search'],(100*$result['search']/$all),$result['external'],
2542812a751SAndreas Gohr                    (100*$result['external']/$all));
25594023548SAndreas Gohr        }
2562812a751SAndreas Gohr
2579da6395dSAndreas Gohr        $result = $this->sql_referer($this->tlimit,$this->start,150);
2582507f8e0SAndreas Gohr        $this->html_resulttable($result,'',150);
2599da6395dSAndreas Gohr    }
2609da6395dSAndreas Gohr
261e7a2f1e0SAndreas Gohr    function html_newreferer(){
262e7a2f1e0SAndreas Gohr        echo '<p>The following incoming links where first logged in the selected time frame,
263e7a2f1e0SAndreas Gohr              and have never been seen before.</p>';
264e7a2f1e0SAndreas Gohr
265e7a2f1e0SAndreas Gohr        $result = $this->sql_newreferer($this->tlimit,$this->start,150);
2662507f8e0SAndreas Gohr        $this->html_resulttable($result,'',150);
267e7a2f1e0SAndreas Gohr    }
268e7a2f1e0SAndreas Gohr
269e25286daSAndreas Gohr    function html_outlinks(){
270e25286daSAndreas Gohr        $result = $this->sql_outlinks($this->tlimit,$this->start,150);
271e25286daSAndreas Gohr        $this->html_resulttable($result,'',150);
272e25286daSAndreas Gohr    }
273e25286daSAndreas Gohr
27412dcdeccSAndreas Gohr    function html_searchphrases(){
27512dcdeccSAndreas Gohr        $result = $this->sql_searchphrases($this->tlimit,$this->start,150);
27612dcdeccSAndreas Gohr        $this->html_resulttable($result,'',150);
27712dcdeccSAndreas Gohr    }
27812dcdeccSAndreas Gohr
27912dcdeccSAndreas Gohr    function html_searchwords(){
28012dcdeccSAndreas Gohr        $result = $this->sql_searchwords($this->tlimit,$this->start,150);
28112dcdeccSAndreas Gohr        $this->html_resulttable($result,'',150);
28212dcdeccSAndreas Gohr    }
28312dcdeccSAndreas Gohr
28412dcdeccSAndreas Gohr    function html_searchengines(){
28512dcdeccSAndreas Gohr        $result = $this->sql_searchengines($this->tlimit,$this->start,150);
28612dcdeccSAndreas Gohr        $this->html_resulttable($result,'',150);
28712dcdeccSAndreas Gohr    }
28812dcdeccSAndreas Gohr
289e25286daSAndreas Gohr
290c73e16f1SAndreas Gohr    function html_resolution(){
291c73e16f1SAndreas Gohr        $result = $this->sql_resolution($this->tlimit,$this->start,150);
292c73e16f1SAndreas Gohr        $this->html_resulttable($result,'',150);
293c73e16f1SAndreas Gohr
294c73e16f1SAndreas Gohr        echo '<p>While the data above gives you some info about the resolution your visitors use, it does not tell you
295c73e16f1SAndreas Gohr              much about about the real size of their browser windows. The graphic below shows the size distribution of
296c73e16f1SAndreas Gohr              the view port (document area) of your visitor\'s browsers. Please note that this data can not be logged
297c73e16f1SAndreas Gohr              in all browsers. Because users may resize their browser window while browsing your site the statistics may
298c73e16f1SAndreas Gohr              be flawed. Take it with a grain of salt.</p>';
299c73e16f1SAndreas Gohr
300c73e16f1SAndreas Gohr        echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/img.php?img=view&amp;f='.$this->from.'&amp;t='.$this->to.'" />';
301c73e16f1SAndreas Gohr    }
3029da6395dSAndreas Gohr
3039da6395dSAndreas Gohr
30414d99ec0SAndreas Gohr    /**
30514d99ec0SAndreas Gohr     * Display a result in a HTML table
30614d99ec0SAndreas Gohr     */
3072507f8e0SAndreas Gohr    function html_resulttable($result,$header='',$pager=0){
30814d99ec0SAndreas Gohr        echo '<table>';
3092812a751SAndreas Gohr        if(is_array($header)){
31014d99ec0SAndreas Gohr            echo '<tr>';
31114d99ec0SAndreas Gohr            foreach($header as $h){
31214d99ec0SAndreas Gohr                echo '<th>'.hsc($h).'</th>';
31314d99ec0SAndreas Gohr            }
31414d99ec0SAndreas Gohr            echo '</tr>';
3152812a751SAndreas Gohr        }
31614d99ec0SAndreas Gohr
3172507f8e0SAndreas Gohr        $count = 0;
3182ee939eeSAndreas Gohr        if(is_array($result)) foreach($result as $row){
31914d99ec0SAndreas Gohr            echo '<tr>';
32014d99ec0SAndreas Gohr            foreach($row as $k => $v){
3212812a751SAndreas Gohr                echo '<td class="plg_stats_X'.$k.'">';
32214d99ec0SAndreas Gohr                if($k == 'page'){
32314d99ec0SAndreas Gohr                    echo '<a href="'.wl($v).'" class="wikilink1">';
32414d99ec0SAndreas Gohr                    echo hsc($v);
32514d99ec0SAndreas Gohr                    echo '</a>';
32614d99ec0SAndreas Gohr                }elseif($k == 'url'){
32754f6c432SAndreas Gohr                    $url = hsc($v);
32883b63546SAndreas Gohr                    $url = preg_replace('/^https?:\/\/(www\.)?/','',$url);
3292812a751SAndreas Gohr                    if(strlen($url) > 45){
3302812a751SAndreas Gohr                        $url = substr($url,0,30).' &hellip; '.substr($url,-15);
33154f6c432SAndreas Gohr                    }
33214d99ec0SAndreas Gohr                    echo '<a href="'.$v.'" class="urlextern">';
33354f6c432SAndreas Gohr                    echo $url;
33414d99ec0SAndreas Gohr                    echo '</a>';
33529dea504SAndreas Gohr                }elseif($k == 'lookup'){
33629dea504SAndreas Gohr                    echo '<a href="http://www.google.com/search?q='.rawurlencode($v).'">';
33729dea504SAndreas Gohr                    echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/ico/search/google.png" alt="lookup in Google" border="0" />';
33829dea504SAndreas Gohr                    echo '</a> ';
33929dea504SAndreas Gohr
34029dea504SAndreas Gohr                    echo '<a href="http://search.yahoo.com/search?p='.rawurlencode($v).'">';
34129dea504SAndreas Gohr                    echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/ico/search/yahoo.png" alt="lookup in Yahoo" border="0" />';
34229dea504SAndreas Gohr                    echo '</a> ';
34329dea504SAndreas Gohr
34429dea504SAndreas Gohr                    echo '<a href="http://search.msn.com/results.aspx?q='.rawurlencode($v).'">';
34529dea504SAndreas Gohr                    echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/ico/search/msn.png" alt="lookup in MSN Live" border="0" />';
34629dea504SAndreas Gohr                    echo '</a> ';
34729dea504SAndreas Gohr
34812dcdeccSAndreas Gohr                }elseif($k == 'engine'){
34912dcdeccSAndreas Gohr                    include_once(dirname(__FILE__).'/inc/search_engines.php');
35012dcdeccSAndreas Gohr                    echo $SearchEnginesHashLib[$v];
35175fa767dSAndreas Gohr                }elseif($k == 'bflag'){
352*2998b1f6SAndreas Gohr                    echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/ico/browser/'.strtolower(preg_replace('/[^\w]+/','',$v)).'.png" alt="'.hsc($v).'" />';
353bd4217d3SAndreas Gohr                }elseif($k == 'osflag'){
354*2998b1f6SAndreas Gohr                    echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/ico/os/'.strtolower(preg_replace('/[^\w]+/','',$v)).'.png" alt="'.hsc($v).'" />';
35575fa767dSAndreas Gohr                }elseif($k == 'cflag'){
35675fa767dSAndreas Gohr                    echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/ico/flags/'.hsc($v).'.png" alt="'.hsc($v).'" width="18" height="12" />';
35714d99ec0SAndreas Gohr                }elseif($k == 'html'){
35814d99ec0SAndreas Gohr                    echo $v;
35914d99ec0SAndreas Gohr                }else{
36014d99ec0SAndreas Gohr                    echo hsc($v);
36114d99ec0SAndreas Gohr                }
36214d99ec0SAndreas Gohr                echo '</td>';
36314d99ec0SAndreas Gohr            }
36414d99ec0SAndreas Gohr            echo '</tr>';
3652507f8e0SAndreas Gohr
3662507f8e0SAndreas Gohr            if($pager && ($count == $pager)) break;
3672507f8e0SAndreas Gohr            $count++;
36814d99ec0SAndreas Gohr        }
36914d99ec0SAndreas Gohr        echo '</table>';
3702507f8e0SAndreas Gohr
3712507f8e0SAndreas Gohr        if($pager) $this->html_pager($pager,count($result) > $pager);
3721878f16fSAndreas Gohr    }
3731878f16fSAndreas Gohr
37495eb68e6SAndreas Gohr    /**
37595eb68e6SAndreas Gohr     * Create an image
37695eb68e6SAndreas Gohr     */
37795eb68e6SAndreas Gohr    function img_build($img){
37895eb68e6SAndreas Gohr        include(dirname(__FILE__).'/inc/AGC.class.php');
37995eb68e6SAndreas Gohr
38095eb68e6SAndreas Gohr        switch($img){
38195eb68e6SAndreas Gohr            case 'country':
38295eb68e6SAndreas Gohr                // build top countries + other
38395eb68e6SAndreas Gohr                $result = $this->sql_countries($this->tlimit,$this->start,0);
38495eb68e6SAndreas Gohr                $data = array();
38595eb68e6SAndreas Gohr                $top = 0;
38695eb68e6SAndreas Gohr                foreach($result as $row){
38795eb68e6SAndreas Gohr                    if($top < 7){
38895eb68e6SAndreas Gohr                        $data[$row['country']] = $row['cnt'];
38995eb68e6SAndreas Gohr                    }else{
39095eb68e6SAndreas Gohr                        $data['other'] += $row['cnt'];
39195eb68e6SAndreas Gohr                    }
39295eb68e6SAndreas Gohr                    $top++;
39395eb68e6SAndreas Gohr                }
39495eb68e6SAndreas Gohr                $pie = new AGC(300, 200);
39595eb68e6SAndreas Gohr                $pie->setProp("showkey",true);
39695eb68e6SAndreas Gohr                $pie->setProp("showval",false);
39795eb68e6SAndreas Gohr                $pie->setProp("showgrid",false);
39895eb68e6SAndreas Gohr                $pie->setProp("type","pie");
39995eb68e6SAndreas Gohr                $pie->setProp("keyinfo",1);
40095eb68e6SAndreas Gohr                $pie->setProp("keysize",8);
40195eb68e6SAndreas Gohr                $pie->setProp("keywidspc",-50);
40295eb68e6SAndreas Gohr                $pie->setProp("key",array_keys($data));
40395eb68e6SAndreas Gohr                $pie->addBulkPoints(array_values($data));
40495eb68e6SAndreas Gohr                @$pie->graph();
40595eb68e6SAndreas Gohr                $pie->showGraph();
40695eb68e6SAndreas Gohr                break;
40775fa767dSAndreas Gohr            case 'browser':
40875fa767dSAndreas Gohr                // build top browsers + other
40975fa767dSAndreas Gohr                include_once(dirname(__FILE__).'/inc/browsers.php');
41075fa767dSAndreas Gohr
41175fa767dSAndreas Gohr                $result = $this->sql_browsers($this->tlimit,$this->start,0,false);
41275fa767dSAndreas Gohr                $data = array();
41375fa767dSAndreas Gohr                $top = 0;
41475fa767dSAndreas Gohr                foreach($result as $row){
41575fa767dSAndreas Gohr                    if($top < 5){
41675fa767dSAndreas Gohr                        $data[strip_tags($BrowsersHashIDLib[$row['ua_info']])] = $row['cnt'];
41775fa767dSAndreas Gohr                    }else{
41875fa767dSAndreas Gohr                        $data['other'] += $row['cnt'];
41975fa767dSAndreas Gohr                    }
42075fa767dSAndreas Gohr                    $top++;
42175fa767dSAndreas Gohr                }
42275fa767dSAndreas Gohr                $pie = new AGC(300, 200);
42375fa767dSAndreas Gohr                $pie->setProp("showkey",true);
42475fa767dSAndreas Gohr                $pie->setProp("showval",false);
42575fa767dSAndreas Gohr                $pie->setProp("showgrid",false);
42675fa767dSAndreas Gohr                $pie->setProp("type","pie");
42775fa767dSAndreas Gohr                $pie->setProp("keyinfo",1);
42875fa767dSAndreas Gohr                $pie->setProp("keysize",8);
42975fa767dSAndreas Gohr                $pie->setProp("keywidspc",-50);
43075fa767dSAndreas Gohr                $pie->setProp("key",array_keys($data));
43175fa767dSAndreas Gohr                $pie->addBulkPoints(array_values($data));
43275fa767dSAndreas Gohr                @$pie->graph();
43375fa767dSAndreas Gohr                $pie->showGraph();
43475fa767dSAndreas Gohr                break;
435c73e16f1SAndreas Gohr            case 'view':
436c73e16f1SAndreas Gohr
437c73e16f1SAndreas Gohr                $graph = new AGC(400, 200);
438c73e16f1SAndreas Gohr                $graph->setColor('color',0,'blue');
439c73e16f1SAndreas Gohr                $graph->setColor('color',1,'red');
440c73e16f1SAndreas Gohr                $graph->setProp("showkey",true);
441c73e16f1SAndreas Gohr                $graph->setProp("key",'view port width',0);
442c73e16f1SAndreas Gohr                $graph->setProp("key",'view port height',1);
443c73e16f1SAndreas Gohr
444c73e16f1SAndreas Gohr                $result = $this->sql_viewport($this->tlimit,0,0,true);
445c73e16f1SAndreas Gohr                foreach($result as $row){
446c73e16f1SAndreas Gohr                    $graph->addPoint($row['cnt'],$row['res_x'],0);
447c73e16f1SAndreas Gohr                }
448c73e16f1SAndreas Gohr
449c73e16f1SAndreas Gohr                $result = $this->sql_viewport($this->tlimit,0,0,false);
450c73e16f1SAndreas Gohr                foreach($result as $row){
451c73e16f1SAndreas Gohr                    $graph->addPoint($row['cnt'],$row['res_y'],1);
452c73e16f1SAndreas Gohr                }
453c73e16f1SAndreas Gohr
454c73e16f1SAndreas Gohr                @$graph->graph();
455c73e16f1SAndreas Gohr                $graph->showGraph();
456c73e16f1SAndreas Gohr
457c73e16f1SAndreas Gohr                break;
4582812a751SAndreas Gohr            case 'trend':
4592812a751SAndreas Gohr                $hours  = ($this->from == $this->to);
4602812a751SAndreas Gohr                $result = $this->sql_trend($this->tlimit,$hours);
4612812a751SAndreas Gohr                $data1   = array();
4622812a751SAndreas Gohr                $data2   = array();
4632812a751SAndreas Gohr
4642812a751SAndreas Gohr                $graph = new AGC(400, 150);
4652812a751SAndreas Gohr                $graph->setProp("type","bar");
4662812a751SAndreas Gohr                $graph->setProp("showgrid",false);
4672812a751SAndreas Gohr                $graph->setProp("barwidth",.8);
46875fa767dSAndreas Gohr
4692812a751SAndreas Gohr                $graph->setColor('color',0,'blue');
4702812a751SAndreas Gohr                $graph->setColor('color',1,'red');
4713c0acc14SAndreas Gohr                $graph->setColor('color',2,'yellow');
4722812a751SAndreas Gohr
4732812a751SAndreas Gohr                if($hours){
4742812a751SAndreas Gohr                    //preset $hours
4752812a751SAndreas Gohr                    for($i=0;$i<24;$i++){
4762812a751SAndreas Gohr                        $data1[$i] = 0;
4772812a751SAndreas Gohr                        $data2[$i] = 0;
4783c0acc14SAndreas Gohr                        $data3[$i] = 0;
4792812a751SAndreas Gohr                        $graph->setProp("scale",array(' 0h','   4h','   8h','    12h','    16h','    20h','    24h'));
4802812a751SAndreas Gohr                    }
4812812a751SAndreas Gohr                }else{
4822812a751SAndreas Gohr                    $graph->setProp("scale",array(next(array_keys($data1)),$this->to));
4832812a751SAndreas Gohr                }
4842812a751SAndreas Gohr
4852812a751SAndreas Gohr                foreach($result as $row){
4862812a751SAndreas Gohr                    $data1[$row['time']] = $row['pageviews'];
4872812a751SAndreas Gohr                    $data2[$row['time']] = $row['sessions'];
4883c0acc14SAndreas Gohr                    $data3[$row['time']] = $row['visitors'];
4892812a751SAndreas Gohr                }
4902812a751SAndreas Gohr
4912812a751SAndreas Gohr                foreach($data1 as $key => $val){
4922812a751SAndreas Gohr                    $graph->addPoint($val,$key,0);
4932812a751SAndreas Gohr                }
4942812a751SAndreas Gohr                foreach($data2 as $key => $val){
4952812a751SAndreas Gohr                    $graph->addPoint($val,$key,1);
4962812a751SAndreas Gohr                }
4973c0acc14SAndreas Gohr                foreach($data3 as $key => $val){
4983c0acc14SAndreas Gohr                    $graph->addPoint($val,$key,2);
4993c0acc14SAndreas Gohr                }
5002812a751SAndreas Gohr
5012812a751SAndreas Gohr                @$graph->graph();
5022812a751SAndreas Gohr                $graph->showGraph();
5032812a751SAndreas Gohr
50495eb68e6SAndreas Gohr            default:
50595eb68e6SAndreas Gohr                $this->sendGIF();
50695eb68e6SAndreas Gohr        }
50795eb68e6SAndreas Gohr    }
50895eb68e6SAndreas Gohr
50995eb68e6SAndreas Gohr
5102812a751SAndreas Gohr    /**
5112812a751SAndreas Gohr     * Return some aggregated statistics
5122812a751SAndreas Gohr     */
5132812a751SAndreas Gohr    function sql_aggregate($tlimit){
5142812a751SAndreas Gohr        $data = array();
5152812a751SAndreas Gohr
5162812a751SAndreas Gohr        $sql = "SELECT ref_type, COUNT(*) as cnt
5172812a751SAndreas Gohr                  FROM ".$this->getConf('db_prefix')."access as A
5182812a751SAndreas Gohr                 WHERE $tlimit
5192812a751SAndreas Gohr                   AND ua_type = 'browser'
5202812a751SAndreas Gohr              GROUP BY ref_type";
5212812a751SAndreas Gohr        $result = $this->runSQL($sql);
5222812a751SAndreas Gohr
5232ee939eeSAndreas Gohr        if(is_array($result)) foreach($result as $row){
5242812a751SAndreas Gohr            if($row['ref_type'] == 'search')   $data['search']   = $row['cnt'];
5252812a751SAndreas Gohr            if($row['ref_type'] == 'external') $data['external'] = $row['cnt'];
5262812a751SAndreas Gohr            if($row['ref_type'] == 'internal') $data['internal'] = $row['cnt'];
5272812a751SAndreas Gohr            if($row['ref_type'] == '')         $data['direct']   = $row['cnt'];
5282812a751SAndreas Gohr        }
5292812a751SAndreas Gohr
5302812a751SAndreas Gohr        $sql = "SELECT COUNT(DISTINCT session) as sessions,
5312812a751SAndreas Gohr                       COUNT(session) as views,
5323c0acc14SAndreas Gohr                       COUNT(DISTINCT user) as users,
5333c0acc14SAndreas Gohr                       COUNT(DISTINCT uid) as visitors
5342812a751SAndreas Gohr                  FROM ".$this->getConf('db_prefix')."access as A
5352812a751SAndreas Gohr                 WHERE $tlimit
5362812a751SAndreas Gohr                   AND ua_type = 'browser'";
5372812a751SAndreas Gohr        $result = $this->runSQL($sql);
5382812a751SAndreas Gohr
53975fa767dSAndreas Gohr        $data['users']     = max($result[0]['users'] - 1,0); // subtract empty user
5402812a751SAndreas Gohr        $data['sessions']  = $result[0]['sessions'];
5412812a751SAndreas Gohr        $data['pageviews'] = $result[0]['views'];
5423c0acc14SAndreas Gohr        $data['visitors']  = $result[0]['visitors'];
5432812a751SAndreas Gohr
5442812a751SAndreas Gohr        $sql = "SELECT COUNT(id) as robots
5452812a751SAndreas Gohr                  FROM ".$this->getConf('db_prefix')."access as A
5462812a751SAndreas Gohr                 WHERE $tlimit
5472812a751SAndreas Gohr                   AND ua_type = 'robot'";
5482812a751SAndreas Gohr        $result = $this->runSQL($sql);
5492812a751SAndreas Gohr        $data['robots'] = $result[0]['robots'];
5502812a751SAndreas Gohr
5512812a751SAndreas Gohr        return $data;
5522812a751SAndreas Gohr    }
5532812a751SAndreas Gohr
554bd4217d3SAndreas Gohr    /**
555bd4217d3SAndreas Gohr     * standard statistics follow, only accesses made by browsers are counted
556bd4217d3SAndreas Gohr     * for general stats like browser or OS only visitors not pageviews are counted
557bd4217d3SAndreas Gohr     */
5582812a751SAndreas Gohr    function sql_trend($tlimit,$hours=false){
5592812a751SAndreas Gohr        if($hours){
5602812a751SAndreas Gohr            $sql = "SELECT HOUR(dt) as time,
5612812a751SAndreas Gohr                           COUNT(DISTINCT session) as sessions,
5623c0acc14SAndreas Gohr                           COUNT(session) as pageviews,
5633c0acc14SAndreas Gohr                           COUNT(DISTINCT uid) as visitors
5642812a751SAndreas Gohr                      FROM ".$this->getConf('db_prefix')."access as A
5652812a751SAndreas Gohr                     WHERE $tlimit
5662812a751SAndreas Gohr                       AND ua_type = 'browser'
5672812a751SAndreas Gohr                  GROUP BY HOUR(dt)
5682812a751SAndreas Gohr                  ORDER BY time";
5692812a751SAndreas Gohr        }else{
5702812a751SAndreas Gohr            $sql = "SELECT DATE(dt) as time,
5712812a751SAndreas Gohr                           COUNT(DISTINCT session) as sessions,
5723c0acc14SAndreas Gohr                           COUNT(session) as pageviews,
5733c0acc14SAndreas Gohr                            COUNT(DISTINCT uid) as visitors
5742812a751SAndreas Gohr                      FROM ".$this->getConf('db_prefix')."access as A
5752812a751SAndreas Gohr                     WHERE $tlimit
5762812a751SAndreas Gohr                       AND ua_type = 'browser'
5772812a751SAndreas Gohr                  GROUP BY DATE(dt)
5782812a751SAndreas Gohr                  ORDER BY time";
5792812a751SAndreas Gohr        }
5802812a751SAndreas Gohr        return $this->runSQL($sql);
5812812a751SAndreas Gohr    }
5822812a751SAndreas Gohr
58312dcdeccSAndreas Gohr    function sql_searchengines($tlimit,$start=0,$limit=20){
58412dcdeccSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, engine
58512dcdeccSAndreas Gohr                  FROM ".$this->getConf('db_prefix')."search as A
58612dcdeccSAndreas Gohr                 WHERE $tlimit
58712dcdeccSAndreas Gohr              GROUP BY engine
58812dcdeccSAndreas Gohr              ORDER BY cnt DESC, engine".
58912dcdeccSAndreas Gohr              $this->sql_limit($start,$limit);
59012dcdeccSAndreas Gohr        return $this->runSQL($sql);
59112dcdeccSAndreas Gohr    }
59212dcdeccSAndreas Gohr
59312dcdeccSAndreas Gohr    function sql_searchphrases($tlimit,$start=0,$limit=20){
59429dea504SAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, query, query as lookup
59512dcdeccSAndreas Gohr                  FROM ".$this->getConf('db_prefix')."search as A
59612dcdeccSAndreas Gohr                 WHERE $tlimit
59712dcdeccSAndreas Gohr              GROUP BY query
59812dcdeccSAndreas Gohr              ORDER BY cnt DESC, query".
59912dcdeccSAndreas Gohr              $this->sql_limit($start,$limit);
60012dcdeccSAndreas Gohr        return $this->runSQL($sql);
60112dcdeccSAndreas Gohr    }
60212dcdeccSAndreas Gohr
60312dcdeccSAndreas Gohr    function sql_searchwords($tlimit,$start=0,$limit=20){
60429dea504SAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, word, word as lookup
60512dcdeccSAndreas Gohr                  FROM ".$this->getConf('db_prefix')."search as A,
60612dcdeccSAndreas Gohr                       ".$this->getConf('db_prefix')."searchwords as B
60712dcdeccSAndreas Gohr                 WHERE $tlimit
60812dcdeccSAndreas Gohr                   AND A.id = B.sid
60912dcdeccSAndreas Gohr              GROUP BY word
61012dcdeccSAndreas Gohr              ORDER BY cnt DESC, word".
61112dcdeccSAndreas Gohr              $this->sql_limit($start,$limit);
61212dcdeccSAndreas Gohr        return $this->runSQL($sql);
61312dcdeccSAndreas Gohr    }
61412dcdeccSAndreas Gohr
615e25286daSAndreas Gohr    function sql_outlinks($tlimit,$start=0,$limit=20){
616e25286daSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, link as url
617e25286daSAndreas Gohr                  FROM ".$this->getConf('db_prefix')."outlinks as A
618e25286daSAndreas Gohr                 WHERE $tlimit
619e25286daSAndreas Gohr              GROUP BY link
620e25286daSAndreas Gohr              ORDER BY cnt DESC, link".
621e25286daSAndreas Gohr              $this->sql_limit($start,$limit);
622e25286daSAndreas Gohr        return $this->runSQL($sql);
623e25286daSAndreas Gohr    }
624e25286daSAndreas Gohr
62595eb68e6SAndreas Gohr    function sql_pages($tlimit,$start=0,$limit=20){
6262812a751SAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, page
62795eb68e6SAndreas Gohr                  FROM ".$this->getConf('db_prefix')."access as A
62895eb68e6SAndreas Gohr                 WHERE $tlimit
62995eb68e6SAndreas Gohr                   AND ua_type = 'browser'
63095eb68e6SAndreas Gohr              GROUP BY page
63195eb68e6SAndreas Gohr              ORDER BY cnt DESC, page".
63295eb68e6SAndreas Gohr              $this->sql_limit($start,$limit);
63395eb68e6SAndreas Gohr        return $this->runSQL($sql);
63495eb68e6SAndreas Gohr    }
63595eb68e6SAndreas Gohr
63695eb68e6SAndreas Gohr    function sql_referer($tlimit,$start=0,$limit=20){
6372812a751SAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, ref as url
63895eb68e6SAndreas Gohr                  FROM ".$this->getConf('db_prefix')."access as A
63995eb68e6SAndreas Gohr                 WHERE $tlimit
64095eb68e6SAndreas Gohr                   AND ua_type = 'browser'
64195eb68e6SAndreas Gohr                   AND ref_type = 'external'
64295eb68e6SAndreas Gohr              GROUP BY ref_md5
64395eb68e6SAndreas Gohr              ORDER BY cnt DESC, url".
64495eb68e6SAndreas Gohr              $this->sql_limit($start,$limit);
64595eb68e6SAndreas Gohr        return $this->runSQL($sql);
64695eb68e6SAndreas Gohr    }
64795eb68e6SAndreas Gohr
648e7a2f1e0SAndreas Gohr    function sql_newreferer($tlimit,$start=0,$limit=20){
649e7a2f1e0SAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, ref as url
6502ee939eeSAndreas Gohr                  FROM ".$this->getConf('db_prefix')."access as B,
6512ee939eeSAndreas Gohr                       ".$this->getConf('db_prefix')."refseen as A
6522ee939eeSAndreas Gohr                 WHERE $tlimit
6532ee939eeSAndreas Gohr                   AND ua_type = 'browser'
654e7a2f1e0SAndreas Gohr                   AND ref_type = 'external'
6552ee939eeSAndreas Gohr                   AND A.ref_md5 = B.ref_md5
6562ee939eeSAndreas Gohr              GROUP BY A.ref_md5
657e7a2f1e0SAndreas Gohr              ORDER BY cnt DESC, url".
658e7a2f1e0SAndreas Gohr              $this->sql_limit($start,$limit);
659e7a2f1e0SAndreas Gohr        return $this->runSQL($sql);
660e7a2f1e0SAndreas Gohr    }
661e7a2f1e0SAndreas Gohr
66295eb68e6SAndreas Gohr    function sql_countries($tlimit,$start=0,$limit=20){
663bd4217d3SAndreas Gohr        $sql = "SELECT COUNT(DISTINCT session) as cnt, B.code AS cflag, B.country
66495eb68e6SAndreas Gohr                  FROM ".$this->getConf('db_prefix')."access as A,
66595eb68e6SAndreas Gohr                       ".$this->getConf('db_prefix')."iplocation as B
66695eb68e6SAndreas Gohr                 WHERE $tlimit
66795eb68e6SAndreas Gohr                   AND A.ip = B.ip
66895eb68e6SAndreas Gohr              GROUP BY B.country
66995eb68e6SAndreas Gohr              ORDER BY cnt DESC, B.country".
67095eb68e6SAndreas Gohr              $this->sql_limit($start,$limit);
67195eb68e6SAndreas Gohr        return $this->runSQL($sql);
67295eb68e6SAndreas Gohr    }
67395eb68e6SAndreas Gohr
67475fa767dSAndreas Gohr    function sql_browsers($tlimit,$start=0,$limit=20,$ext=true){
67575fa767dSAndreas Gohr        if($ext){
67675fa767dSAndreas Gohr            $sel = 'ua_info as bflag, ua_info as browser, ua_ver';
67775fa767dSAndreas Gohr            $grp = 'ua_info, ua_ver';
67875fa767dSAndreas Gohr        }else{
67975fa767dSAndreas Gohr            $grp = 'ua_info';
68075fa767dSAndreas Gohr            $sel = 'ua_info';
68175fa767dSAndreas Gohr        }
68275fa767dSAndreas Gohr
683bd4217d3SAndreas Gohr        $sql = "SELECT COUNT(DISTINCT session) as cnt, $sel
68475fa767dSAndreas Gohr                  FROM ".$this->getConf('db_prefix')."access as A
68575fa767dSAndreas Gohr                 WHERE $tlimit
68675fa767dSAndreas Gohr                   AND ua_type = 'browser'
68775fa767dSAndreas Gohr              GROUP BY $grp
68875fa767dSAndreas Gohr              ORDER BY cnt DESC, ua_info".
68975fa767dSAndreas Gohr              $this->sql_limit($start,$limit);
69075fa767dSAndreas Gohr        return $this->runSQL($sql);
69175fa767dSAndreas Gohr    }
69275fa767dSAndreas Gohr
693bd4217d3SAndreas Gohr    function sql_os($tlimit,$start=0,$limit=20){
694bd4217d3SAndreas Gohr        $sql = "SELECT COUNT(DISTINCT session) as cnt, os as osflag, os
695bd4217d3SAndreas Gohr                  FROM ".$this->getConf('db_prefix')."access as A
696bd4217d3SAndreas Gohr                 WHERE $tlimit
697bd4217d3SAndreas Gohr                   AND ua_type = 'browser'
698bd4217d3SAndreas Gohr              GROUP BY os
699bd4217d3SAndreas Gohr              ORDER BY cnt DESC, os".
700bd4217d3SAndreas Gohr              $this->sql_limit($start,$limit);
701bd4217d3SAndreas Gohr        return $this->runSQL($sql);
702bd4217d3SAndreas Gohr    }
703bd4217d3SAndreas Gohr
704c73e16f1SAndreas Gohr    function sql_resolution($tlimit,$start=0,$limit=20){
705c73e16f1SAndreas Gohr        $sql = "SELECT COUNT(DISTINCT session) as cnt, CONCAT(screen_x,'x',screen_y) as res
706c73e16f1SAndreas Gohr                  FROM ".$this->getConf('db_prefix')."access as A
707c73e16f1SAndreas Gohr                 WHERE $tlimit
708c73e16f1SAndreas Gohr                   AND ua_type  = 'browser'
709c73e16f1SAndreas Gohr                   AND screen_x != 0
710c73e16f1SAndreas Gohr              GROUP BY screen_x, screen_y
711c73e16f1SAndreas Gohr              ORDER BY cnt DESC, screen_x".
712c73e16f1SAndreas Gohr              $this->sql_limit($start,$limit);
713c73e16f1SAndreas Gohr        return $this->runSQL($sql);
714c73e16f1SAndreas Gohr    }
715c73e16f1SAndreas Gohr
716c73e16f1SAndreas Gohr    function sql_viewport($tlimit,$start=0,$limit=20,$x=true){
717c73e16f1SAndreas Gohr        if($x){
718c73e16f1SAndreas Gohr            $col = 'view_x';
719c73e16f1SAndreas Gohr            $res = 'res_x';
720c73e16f1SAndreas Gohr        }else{
721c73e16f1SAndreas Gohr            $col = 'view_y';
722c73e16f1SAndreas Gohr            $res = 'res_y';
723c73e16f1SAndreas Gohr        }
724c73e16f1SAndreas Gohr
725c73e16f1SAndreas Gohr        $sql = "SELECT COUNT(*) as cnt,
726c73e16f1SAndreas Gohr                       ROUND($col/10)*10 as $res
727c73e16f1SAndreas Gohr                  FROM ".$this->getConf('db_prefix')."access as A
728c73e16f1SAndreas Gohr                 WHERE $tlimit
729c73e16f1SAndreas Gohr                   AND ua_type  = 'browser'
730c73e16f1SAndreas Gohr                   AND $col != 0
731c73e16f1SAndreas Gohr              GROUP BY $res
732c73e16f1SAndreas Gohr              ORDER BY cnt DESC, $res".
733c73e16f1SAndreas Gohr              $this->sql_limit($start,$limit);
734c73e16f1SAndreas Gohr        return $this->runSQL($sql);
735c73e16f1SAndreas Gohr    }
736c73e16f1SAndreas Gohr
73775fa767dSAndreas Gohr
73895eb68e6SAndreas Gohr    /**
73995eb68e6SAndreas Gohr     * Builds a limit clause
74095eb68e6SAndreas Gohr     */
74195eb68e6SAndreas Gohr    function sql_limit($start,$limit){
74295eb68e6SAndreas Gohr        $start = (int) $start;
74395eb68e6SAndreas Gohr        $limit = (int) $limit;
74495eb68e6SAndreas Gohr        if($limit){
7452507f8e0SAndreas Gohr            $limit += 1;
74695eb68e6SAndreas Gohr            return " LIMIT $start,$limit";
74795eb68e6SAndreas Gohr        }elseif($start){
74895eb68e6SAndreas Gohr            return " OFFSET $start";
74995eb68e6SAndreas Gohr        }
75095eb68e6SAndreas Gohr        return '';
75195eb68e6SAndreas Gohr    }
7521878f16fSAndreas Gohr
7531878f16fSAndreas Gohr    /**
75414d99ec0SAndreas Gohr     * Return a link to the DB, opening the connection if needed
7551878f16fSAndreas Gohr     */
75614d99ec0SAndreas Gohr    function dbLink(){
7571878f16fSAndreas Gohr        // connect to DB if needed
7581878f16fSAndreas Gohr        if(!$this->dblink){
7591878f16fSAndreas Gohr            $this->dblink = mysql_connect($this->getConf('db_server'),
7601878f16fSAndreas Gohr                                          $this->getConf('db_user'),
7611878f16fSAndreas Gohr                                          $this->getConf('db_password'));
7621878f16fSAndreas Gohr            if(!$this->dblink){
7631878f16fSAndreas Gohr                msg('DB Error: connection failed',-1);
7641878f16fSAndreas Gohr                return null;
7651878f16fSAndreas Gohr            }
7661878f16fSAndreas Gohr            // set utf-8
7671878f16fSAndreas Gohr            if(!mysql_db_query($this->getConf('db_database'),'set names utf8',$this->dblink)){
7681878f16fSAndreas Gohr                msg('DB Error: could not set UTF-8 ('.mysql_error($this->dblink).')',-1);
7691878f16fSAndreas Gohr                return null;
7701878f16fSAndreas Gohr            }
7711878f16fSAndreas Gohr        }
77214d99ec0SAndreas Gohr        return $this->dblink;
77314d99ec0SAndreas Gohr    }
7741878f16fSAndreas Gohr
77514d99ec0SAndreas Gohr    /**
77614d99ec0SAndreas Gohr     * Simple function to run a DB query
77714d99ec0SAndreas Gohr     */
77814d99ec0SAndreas Gohr    function runSQL($sql_string) {
77914d99ec0SAndreas Gohr        $link = $this->dbLink();
78014d99ec0SAndreas Gohr
78114d99ec0SAndreas Gohr        $result = mysql_db_query($this->conf['db_database'],$sql_string,$link);
78294171ff3SAndreas Gohr        if(!$result){
7832812a751SAndreas Gohr            msg('DB Error: '.mysql_error($link).' '.hsc($sql_string),-1);
7841878f16fSAndreas Gohr            return null;
7851878f16fSAndreas Gohr        }
7861878f16fSAndreas Gohr
7871878f16fSAndreas Gohr        $resultarray = array();
7881878f16fSAndreas Gohr
7891878f16fSAndreas Gohr        //mysql_db_query returns 1 on a insert statement -> no need to ask for results
7901878f16fSAndreas Gohr        if ($result != 1) {
7911878f16fSAndreas Gohr            for($i=0; $i< mysql_num_rows($result); $i++) {
7921878f16fSAndreas Gohr                $temparray = mysql_fetch_assoc($result);
7931878f16fSAndreas Gohr                $resultarray[]=$temparray;
7941878f16fSAndreas Gohr            }
7951878f16fSAndreas Gohr            mysql_free_result($result);
7961878f16fSAndreas Gohr        }
7971878f16fSAndreas Gohr
79814d99ec0SAndreas Gohr        if (mysql_insert_id($link)) {
79914d99ec0SAndreas Gohr            $resultarray = mysql_insert_id($link); //give back ID on insert
8001878f16fSAndreas Gohr        }
8011878f16fSAndreas Gohr
8021878f16fSAndreas Gohr        return $resultarray;
8031878f16fSAndreas Gohr    }
8041878f16fSAndreas Gohr
8051878f16fSAndreas Gohr    /**
80614d99ec0SAndreas Gohr     * Returns a short name for a User Agent and sets type, version and os info
8071878f16fSAndreas Gohr     */
808*2998b1f6SAndreas Gohr    function ua_info($agent,&$type,&$version,&$os){
809*2998b1f6SAndreas Gohr        global $conf;
810*2998b1f6SAndreas Gohr        $bc = new DokuBrowscap($conf['cachedir']);
811*2998b1f6SAndreas Gohr        $ua = $bc->getBrowser($agent);
81214d99ec0SAndreas Gohr
81314d99ec0SAndreas Gohr        $type = 'browser';
814*2998b1f6SAndreas Gohr        if($ua->Crawler) $type = 'robot';
815*2998b1f6SAndreas Gohr        if($ua->isSyndicationReader) $type = 'feedreader';
81614d99ec0SAndreas Gohr
817*2998b1f6SAndreas Gohr        $version = $ua->Version;
818*2998b1f6SAndreas Gohr        $os      = $ua->Platform;
819*2998b1f6SAndreas Gohr        return $ua->Browser;
8201878f16fSAndreas Gohr    }
8211878f16fSAndreas Gohr
8221878f16fSAndreas Gohr    /**
823322de360SAndreas Gohr     * Log search queries
82414d99ec0SAndreas Gohr     */
82514d99ec0SAndreas Gohr    function log_search($referer,&$type){
82614d99ec0SAndreas Gohr        $referer = strtolower($referer);
827673875b1SAndreas Gohr        $ref     = strtr($referer,' +','__');
82814d99ec0SAndreas Gohr
82914d99ec0SAndreas Gohr        include(dirname(__FILE__).'/inc/search_engines.php');
83014d99ec0SAndreas Gohr
83114d99ec0SAndreas Gohr        foreach($SearchEnginesSearchIDOrder as $regex){
832673875b1SAndreas Gohr            if(preg_match('/'.$regex.'/',$ref)){
83314d99ec0SAndreas Gohr                if(!$NotSearchEnginesKeys[$regex] ||
834673875b1SAndreas Gohr                   !preg_match('/'.$NotSearchEnginesKeys[$regex].'/',$ref)){
83514d99ec0SAndreas Gohr                    // it's a search engine!
83614d99ec0SAndreas Gohr                    $type = 'search';
83714d99ec0SAndreas Gohr                    break;
83814d99ec0SAndreas Gohr                }
83914d99ec0SAndreas Gohr            }
84014d99ec0SAndreas Gohr        }
84114d99ec0SAndreas Gohr        if($type != 'search') return; // we're done here
84214d99ec0SAndreas Gohr
843322de360SAndreas Gohr        // extract query
844322de360SAndreas Gohr        $engine = $SearchEnginesHashID[$regex];
845322de360SAndreas Gohr        $param = $SearchEnginesKnownUrl[$engine];
846322de360SAndreas Gohr        if($param && preg_match('/'.$param.'(.*?)[&$]/',$referer,$match)){
847322de360SAndreas Gohr            $query = array_pop($match);
848322de360SAndreas Gohr        }elseif(preg_match('/'.$WordsToExtractSearchUrl.'(.*?)[&$]/',$referer,$match)){
849322de360SAndreas Gohr            $query = array_pop($match);
850322de360SAndreas Gohr        }
851322de360SAndreas Gohr        if(!$query) return; // we failed
852322de360SAndreas Gohr
853322de360SAndreas Gohr        // clean the query
854322de360SAndreas Gohr        $query = preg_replace('/^(cache|related):[^\+]+/','',$query);  // non-search queries
855322de360SAndreas Gohr        $query = preg_replace('/%0[ad]/',' ',$query);                  // LF CR
856322de360SAndreas Gohr        $query = preg_replace('/%2[02789abc]/',' ',$query);            // space " ' ( ) * + ,
857322de360SAndreas Gohr        $query = preg_replace('/%3a/',' ',$query);                     // :
858673875b1SAndreas Gohr        $query = strtr($query,'+\'()"*,:','        ');                 // badly encoded
859322de360SAndreas Gohr        $query = preg_replace('/ +/',' ',$query);                      // ws compact
860322de360SAndreas Gohr        $query = trim($query);
861322de360SAndreas Gohr        $query = urldecode($query);
862322de360SAndreas Gohr        if(!utf8_check($query)) $query = utf8_encode($query);          // assume latin1 if not utf8
863322de360SAndreas Gohr        $query = utf8_strtolower($query);
864322de360SAndreas Gohr
865322de360SAndreas Gohr        // log it!
866322de360SAndreas Gohr        $page  = addslashes($_REQUEST['p']);
867322de360SAndreas Gohr        $query = addslashes($query);
868673875b1SAndreas Gohr        $sql  = "INSERT INTO ".$this->getConf('db_prefix')."search
869322de360SAndreas Gohr                    SET dt       = NOW(),
870322de360SAndreas Gohr                        page     = '$page',
871322de360SAndreas Gohr                        query    = '$query',
872322de360SAndreas Gohr                        engine   = '$engine'";
873322de360SAndreas Gohr        $id = $this->runSQL($sql);
874322de360SAndreas Gohr        if(is_null($id)){
875322de360SAndreas Gohr            global $MSG;
876322de360SAndreas Gohr            print_r($MSG);
877322de360SAndreas Gohr            return;
878322de360SAndreas Gohr        }
879322de360SAndreas Gohr
880322de360SAndreas Gohr        // log single keywords
881322de360SAndreas Gohr        $words = explode(' ',utf8_stripspecials($query,' ','\._\-:\*'));
882322de360SAndreas Gohr        foreach($words as $word){
883673875b1SAndreas Gohr            if(!$word) continue;
884322de360SAndreas Gohr            $word = addslashes($word);
885322de360SAndreas Gohr            $sql = "INSERT DELAYED INTO ".$this->getConf('db_prefix')."searchwords
886322de360SAndreas Gohr                       SET sid  = $id,
887322de360SAndreas Gohr                           word = '$word'";
888322de360SAndreas Gohr            $ok = $this->runSQL($sql);
889322de360SAndreas Gohr            if(is_null($ok)){
890322de360SAndreas Gohr                global $MSG;
891322de360SAndreas Gohr                print_r($MSG);
892322de360SAndreas Gohr            }
893322de360SAndreas Gohr        }
89414d99ec0SAndreas Gohr    }
89514d99ec0SAndreas Gohr
89614d99ec0SAndreas Gohr    /**
89714d99ec0SAndreas Gohr     * Resolve IP to country/city
89814d99ec0SAndreas Gohr     */
89914d99ec0SAndreas Gohr    function log_ip($ip){
90014d99ec0SAndreas Gohr        // check if IP already known and up-to-date
90114d99ec0SAndreas Gohr        $sql = "SELECT ip
90214d99ec0SAndreas Gohr                  FROM ".$this->getConf('db_prefix')."iplocation
90314d99ec0SAndreas Gohr                 WHERE ip ='".addslashes($ip)."'
90414d99ec0SAndreas Gohr                   AND lastupd > DATE_SUB(CURDATE(),INTERVAL 30 DAY)";
90514d99ec0SAndreas Gohr        $result = $this->runSQL($sql);
90614d99ec0SAndreas Gohr        if($result[0]['ip']) return;
90714d99ec0SAndreas Gohr
90814d99ec0SAndreas Gohr        $http = new DokuHTTPClient();
90914d99ec0SAndreas Gohr        $http->timeout = 10;
91014d99ec0SAndreas Gohr        $data = $http->get('http://api.hostip.info/get_html.php?ip='.$ip);
91114d99ec0SAndreas Gohr
91214d99ec0SAndreas Gohr        if(preg_match('/^Country: (.*?) \((.*?)\)\nCity: (.*?)$/s',$data,$match)){
91314d99ec0SAndreas Gohr            $country = addslashes(trim($match[1]));
91414d99ec0SAndreas Gohr            $code    = addslashes(strtolower(trim($match[2])));
91514d99ec0SAndreas Gohr            $city    = addslashes(trim($match[3]));
91614d99ec0SAndreas Gohr            $host    = addslashes(gethostbyaddr($ip));
91714d99ec0SAndreas Gohr            $ip      = addslashes($ip);
91814d99ec0SAndreas Gohr
91914d99ec0SAndreas Gohr            $sql = "REPLACE INTO ".$this->getConf('db_prefix')."iplocation
92014d99ec0SAndreas Gohr                        SET ip = '$ip',
92114d99ec0SAndreas Gohr                            country = '$country',
92214d99ec0SAndreas Gohr                            code    = '$code',
92314d99ec0SAndreas Gohr                            city    = '$city',
92414d99ec0SAndreas Gohr                            host    = '$host'";
92514d99ec0SAndreas Gohr            $this->runSQL($sql);
92614d99ec0SAndreas Gohr        }
92714d99ec0SAndreas Gohr    }
92814d99ec0SAndreas Gohr
92914d99ec0SAndreas Gohr    /**
930e25286daSAndreas Gohr     * log a click on an external link
931e25286daSAndreas Gohr     *
932e25286daSAndreas Gohr     * called from log.php
933e25286daSAndreas Gohr     */
934e25286daSAndreas Gohr    function log_outgoing(){
935e25286daSAndreas Gohr        if(!$_REQUEST['ol']) return;
936e25286daSAndreas Gohr
937e25286daSAndreas Gohr        $link_md5 = md5($link);
938e25286daSAndreas Gohr        $link     = addslashes($_REQUEST['ol']);
939e25286daSAndreas Gohr        $session  = addslashes(session_id());
940d8c4d85eSAndreas Gohr        $page     = addslashes($_REQUEST['p']);
941e25286daSAndreas Gohr
942e25286daSAndreas Gohr        $sql  = "INSERT DELAYED INTO ".$this->getConf('db_prefix')."outlinks
943e25286daSAndreas Gohr                    SET dt       = NOW(),
944e25286daSAndreas Gohr                        session  = '$session',
945d8c4d85eSAndreas Gohr                        page     = '$page',
946e25286daSAndreas Gohr                        link_md5 = '$link_md5',
947e25286daSAndreas Gohr                        link     = '$link'";
948e25286daSAndreas Gohr        $ok = $this->runSQL($sql);
949e25286daSAndreas Gohr        if(is_null($ok)){
950e25286daSAndreas Gohr            global $MSG;
951e25286daSAndreas Gohr            print_r($MSG);
952e25286daSAndreas Gohr        }
953e25286daSAndreas Gohr    }
954e25286daSAndreas Gohr
955e25286daSAndreas Gohr    /**
9561878f16fSAndreas Gohr     * log a page access
9571878f16fSAndreas Gohr     *
9581878f16fSAndreas Gohr     * called from log.php
9591878f16fSAndreas Gohr     */
9601878f16fSAndreas Gohr    function log_access(){
96194171ff3SAndreas Gohr        if(!$_REQUEST['p']) return;
96294171ff3SAndreas Gohr
96314d99ec0SAndreas Gohr        # FIXME check referer against blacklist and drop logging for bad boys
96414d99ec0SAndreas Gohr
96514d99ec0SAndreas Gohr        // handle referer
96614d99ec0SAndreas Gohr        $referer = trim($_REQUEST['r']);
96714d99ec0SAndreas Gohr        if($referer){
96814d99ec0SAndreas Gohr            $ref     = addslashes($referer);
96914d99ec0SAndreas Gohr            $ref_md5 = ($ref) ? md5($referer) : '';
97014d99ec0SAndreas Gohr            if(strpos($referer,DOKU_URL) === 0){
97114d99ec0SAndreas Gohr                $ref_type = 'internal';
97214d99ec0SAndreas Gohr            }else{
97314d99ec0SAndreas Gohr                $ref_type = 'external';
97414d99ec0SAndreas Gohr                $this->log_search($referer,$ref_type);
97514d99ec0SAndreas Gohr            }
97614d99ec0SAndreas Gohr        }else{
97714d99ec0SAndreas Gohr            $ref      = '';
97814d99ec0SAndreas Gohr            $ref_md5  = '';
97914d99ec0SAndreas Gohr            $ref_type = '';
98014d99ec0SAndreas Gohr        }
98114d99ec0SAndreas Gohr
98214d99ec0SAndreas Gohr        // handle user agent
98314d99ec0SAndreas Gohr        $agent   = trim($_SERVER['HTTP_USER_AGENT']);
98414d99ec0SAndreas Gohr
98514d99ec0SAndreas Gohr        $ua      = addslashes($agent);
98614d99ec0SAndreas Gohr        $ua_type = '';
98714d99ec0SAndreas Gohr        $ua_ver  = '';
98814d99ec0SAndreas Gohr        $os      = '';
98914d99ec0SAndreas Gohr        $ua_info = addslashes($this->ua_info($agent,$ua_type,$ua_ver,$os));
99014d99ec0SAndreas Gohr
9911878f16fSAndreas Gohr        $page    = addslashes($_REQUEST['p']);
9921878f16fSAndreas Gohr        $ip      = addslashes($_SERVER['REMOTE_ADDR']);
9931878f16fSAndreas Gohr        $sx      = (int) $_REQUEST['sx'];
9941878f16fSAndreas Gohr        $sy      = (int) $_REQUEST['sy'];
9951878f16fSAndreas Gohr        $vx      = (int) $_REQUEST['vx'];
9961878f16fSAndreas Gohr        $vy      = (int) $_REQUEST['vy'];
99775fa767dSAndreas Gohr        $js      = (int) $_REQUEST['js'];
9983c0acc14SAndreas Gohr        $uid     = addslashes($_REQUEST['uid']);
9991878f16fSAndreas Gohr        $user    = addslashes($_SERVER['REMOTE_USER']);
10001878f16fSAndreas Gohr        $session = addslashes(session_id());
10013c0acc14SAndreas Gohr        if(!$uid) $uid = $session;
10021878f16fSAndreas Gohr
100394171ff3SAndreas Gohr        $sql  = "INSERT DELAYED INTO ".$this->getConf('db_prefix')."access
100475fa767dSAndreas Gohr                    SET dt       = NOW(),
100575fa767dSAndreas Gohr                        page     = '$page',
10061878f16fSAndreas Gohr                        ip       = '$ip',
10071878f16fSAndreas Gohr                        ua       = '$ua',
10081878f16fSAndreas Gohr                        ua_info  = '$ua_info',
100914d99ec0SAndreas Gohr                        ua_type  = '$ua_type',
101014d99ec0SAndreas Gohr                        ua_ver   = '$ua_ver',
101114d99ec0SAndreas Gohr                        os       = '$os',
10121878f16fSAndreas Gohr                        ref      = '$ref',
101394171ff3SAndreas Gohr                        ref_md5  = '$ref_md5',
101414d99ec0SAndreas Gohr                        ref_type = '$ref_type',
10151878f16fSAndreas Gohr                        screen_x = '$sx',
10161878f16fSAndreas Gohr                        screen_y = '$sy',
10171878f16fSAndreas Gohr                        view_x   = '$vx',
10181878f16fSAndreas Gohr                        view_y   = '$vy',
101975fa767dSAndreas Gohr                        js       = '$js',
10201878f16fSAndreas Gohr                        user     = '$user',
10213c0acc14SAndreas Gohr                        session  = '$session',
10223c0acc14SAndreas Gohr                        uid      = '$uid'";
10231878f16fSAndreas Gohr        $ok = $this->runSQL($sql);
10241878f16fSAndreas Gohr        if(is_null($ok)){
10251878f16fSAndreas Gohr            global $MSG;
10261878f16fSAndreas Gohr            print_r($MSG);
10271878f16fSAndreas Gohr        }
102814d99ec0SAndreas Gohr
10292ee939eeSAndreas Gohr        $sql = "INSERT DELAYED IGNORE INTO ".$this->getConf('db_prefix')."refseen
10302ee939eeSAndreas Gohr                   SET ref_md5  = '$ref_md5',
10312ee939eeSAndreas Gohr                       dt       = NOW()";
10322ee939eeSAndreas Gohr        $ok = $this->runSQL($sql);
10332ee939eeSAndreas Gohr        if(is_null($ok)){
10342ee939eeSAndreas Gohr            global $MSG;
10352ee939eeSAndreas Gohr            print_r($MSG);
10362ee939eeSAndreas Gohr        }
10372ee939eeSAndreas Gohr
103814d99ec0SAndreas Gohr        // resolve the IP
103914d99ec0SAndreas Gohr        $this->log_ip($_SERVER['REMOTE_ADDR']);
10401878f16fSAndreas Gohr    }
10411878f16fSAndreas Gohr
10421878f16fSAndreas Gohr    /**
10431878f16fSAndreas Gohr     * Just send a 1x1 pixel blank gif to the browser
10441878f16fSAndreas Gohr     *
10451878f16fSAndreas Gohr     * @called from log.php
10461878f16fSAndreas Gohr     *
10471878f16fSAndreas Gohr     * @author Andreas Gohr <andi@splitbrain.org>
10481878f16fSAndreas Gohr     * @author Harry Fuecks <fuecks@gmail.com>
10491878f16fSAndreas Gohr     */
10501878f16fSAndreas Gohr    function sendGIF(){
10511878f16fSAndreas Gohr        $img = base64_decode('R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAEALAAAAAABAAEAAAIBTAA7');
10521878f16fSAndreas Gohr        header('Content-Type: image/gif');
10531878f16fSAndreas Gohr        header('Content-Length: '.strlen($img));
10541878f16fSAndreas Gohr        header('Connection: Close');
10551878f16fSAndreas Gohr        print $img;
10561878f16fSAndreas Gohr        flush();
10571878f16fSAndreas Gohr        // Browser should drop connection after this
10581878f16fSAndreas Gohr        // Thinks it's got the whole image
10591878f16fSAndreas Gohr    }
10601878f16fSAndreas Gohr
10611878f16fSAndreas Gohr}
1062