xref: /plugin/statistics/helper.php (revision ba6b3b10263c8439a170c848fb8e0ce174e4f468)
16b6f8822SAndreas Gohr<?php
2a8acb244SAndreas Gohr
3d5ef99ddSAndreas Gohruse dokuwiki\Extension\Plugin;
4*ba6b3b10SAndreas Gohruse dokuwiki\HTTP\DokuHTTPClient;
5d5ef99ddSAndreas Gohruse dokuwiki\plugin\sqlite\SQLiteDB;
6*ba6b3b10SAndreas Gohruse dokuwiki\plugin\statistics\IpResolverException;
7aab59130SAndreas Gohruse dokuwiki\plugin\statistics\Logger;
8b6632b6eSAndreas Gohruse dokuwiki\plugin\statistics\Query;
964ba7f66SAnna Dabrowskause dokuwiki\plugin\statistics\StatisticsGraph;
10d5ef99ddSAndreas Gohr
116b6f8822SAndreas Gohr/**
126b6f8822SAndreas Gohr * Statistics Plugin
136b6f8822SAndreas Gohr *
146b6f8822SAndreas Gohr * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
156b6f8822SAndreas Gohr * @author  Andreas Gohr <andi@splitbrain.org>
166b6f8822SAndreas Gohr */
17d5ef99ddSAndreas Gohrclass helper_plugin_statistics extends Plugin
18a8acb244SAndreas Gohr{
1941d1fffcSAndreas Gohr    protected ?Query $oQuery = null;
20c4c84f98SAndreas Gohr    protected ?StatisticsGraph $oGraph = null;
21762f4807SAndreas Gohr    protected ?SQLiteDB $db = null;
22*ba6b3b10SAndreas Gohr    public ?DokuHTTPClient $httpClient = null; // public for testing purposes
236b6f8822SAndreas Gohr
246b6f8822SAndreas Gohr    /**
25d5ef99ddSAndreas Gohr     * Get SQLiteDB instance
26d5ef99ddSAndreas Gohr     *
27d5ef99ddSAndreas Gohr     * @return SQLiteDB|null
28483101d3SAndreas Gohr     * @throws Exception when SQLite initialization failed
29d5ef99ddSAndreas Gohr     */
30483101d3SAndreas Gohr    public function getDB(): ?SQLiteDB
31d5ef99ddSAndreas Gohr    {
322adee4c6SAndreas Gohr        if (!$this->db instanceof SQLiteDB) {
33211caa5dSAndreas Gohr            if (!class_exists(SQLiteDB::class)) throw new Exception('SQLite Plugin missing');
34762f4807SAndreas Gohr            $this->db = new SQLiteDB('statistics', DOKU_PLUGIN . 'statistics/db/');
35d5ef99ddSAndreas Gohr        }
36d5ef99ddSAndreas Gohr        return $this->db;
37d5ef99ddSAndreas Gohr    }
38d5ef99ddSAndreas Gohr
39d5ef99ddSAndreas Gohr
40d5ef99ddSAndreas Gohr    /**
416b6f8822SAndreas Gohr     * Return an instance of the query class
426b6f8822SAndreas Gohr     *
43b6632b6eSAndreas Gohr     * @return Query
446b6f8822SAndreas Gohr     */
45211caa5dSAndreas Gohr    public function getQuery(): Query
46a8acb244SAndreas Gohr    {
476b6f8822SAndreas Gohr        if (is_null($this->oQuery)) {
48b6632b6eSAndreas Gohr            $this->oQuery = new Query($this);
496b6f8822SAndreas Gohr        }
506b6f8822SAndreas Gohr        return $this->oQuery;
516b6f8822SAndreas Gohr    }
526b6f8822SAndreas Gohr
536b6f8822SAndreas Gohr    /**
546b6f8822SAndreas Gohr     * Return an instance of the logger class
556b6f8822SAndreas Gohr     *
56aab59130SAndreas Gohr     * @return Logger
576b6f8822SAndreas Gohr     */
58569a5066SAndreas Gohr    public function getLogger(): Logger
59a8acb244SAndreas Gohr    {
6041d1fffcSAndreas Gohr        return new Logger($this);
616b6f8822SAndreas Gohr    }
626b6f8822SAndreas Gohr
636b6f8822SAndreas Gohr    /**
646b6f8822SAndreas Gohr     * Return an instance of the Graph class
656b6f8822SAndreas Gohr     *
661664ba1dSAndreas Gohr     * @return StatisticsGraph
676b6f8822SAndreas Gohr     */
68211caa5dSAndreas Gohr    public function getGraph($from, $to, $width, $height)
69a8acb244SAndreas Gohr    {
706b6f8822SAndreas Gohr        if (is_null($this->oGraph)) {
71f0a4cceeSAnna Dabrowska            $this->oGraph = new StatisticsGraph($this, $from, $to, $width, $height);
726b6f8822SAndreas Gohr        }
736b6f8822SAndreas Gohr        return $this->oGraph;
746b6f8822SAndreas Gohr    }
756b6f8822SAndreas Gohr
766b6f8822SAndreas Gohr    /**
774f41a2ccSAndreas Gohr     * Just send a 1x1 pixel blank gif to the browser
784f41a2ccSAndreas Gohr     *
794f41a2ccSAndreas Gohr     * @called from log.php
804f41a2ccSAndreas Gohr     *
814f41a2ccSAndreas Gohr     * @author Andreas Gohr <andi@splitbrain.org>
824f41a2ccSAndreas Gohr     * @author Harry Fuecks <fuecks@gmail.com>
834f41a2ccSAndreas Gohr     */
84a8acb244SAndreas Gohr    public function sendGIF($transparent = true)
85a8acb244SAndreas Gohr    {
86259897e1SAndreas Gohr        if ($transparent) {
874f41a2ccSAndreas Gohr            $img = base64_decode('R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAEALAAAAAABAAEAAAIBTAA7');
88259897e1SAndreas Gohr        } else {
89259897e1SAndreas Gohr            $img = base64_decode('R0lGODdhAQABAIAAAP///////ywAAAAAAQABAAACAkQBADs=');
90259897e1SAndreas Gohr        }
914f41a2ccSAndreas Gohr        header('Content-Type: image/gif');
924f41a2ccSAndreas Gohr        header('Content-Length: ' . strlen($img));
934f41a2ccSAndreas Gohr        header('Connection: Close');
94a8acb244SAndreas Gohr        echo $img;
954f41a2ccSAndreas Gohr        flush();
964f41a2ccSAndreas Gohr        // Browser should drop connection after this
97211caa5dSAndreas Gohr        // Thinks it got the whole image
984f41a2ccSAndreas Gohr    }
99*ba6b3b10SAndreas Gohr
100*ba6b3b10SAndreas Gohr    /**
101*ba6b3b10SAndreas Gohr     * Return the location information for an IP address
102*ba6b3b10SAndreas Gohr     *
103*ba6b3b10SAndreas Gohr     * @throws IpResolverException
104*ba6b3b10SAndreas Gohr     * @noinspection HttpUrlsUsage
105*ba6b3b10SAndreas Gohr     */
106*ba6b3b10SAndreas Gohr    public function resolveIP($ip)
107*ba6b3b10SAndreas Gohr    {
108*ba6b3b10SAndreas Gohr        $http = $this->httpClient ?: new DokuHTTPClient();
109*ba6b3b10SAndreas Gohr        $http->timeout = 7;
110*ba6b3b10SAndreas Gohr        $json = $http->get('http://ip-api.com/json/' . $ip); // yes, it's HTTP only
111*ba6b3b10SAndreas Gohr
112*ba6b3b10SAndreas Gohr        if (!$json) {
113*ba6b3b10SAndreas Gohr            throw new IpResolverException('Failed talk to ip-api.com.');
114*ba6b3b10SAndreas Gohr        }
115*ba6b3b10SAndreas Gohr        try {
116*ba6b3b10SAndreas Gohr            $data = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
117*ba6b3b10SAndreas Gohr        } catch (\JsonException $e) {
118*ba6b3b10SAndreas Gohr            throw new IpResolverException('Failed to decode JSON from ip-api.com.', $e->getTrace(), 0, $e);
119*ba6b3b10SAndreas Gohr        }
120*ba6b3b10SAndreas Gohr        if (!isset($data['status'])) {
121*ba6b3b10SAndreas Gohr            throw new IpResolverException('Invalid ip-api.com result for' . $ip, $data);
122*ba6b3b10SAndreas Gohr        }
123*ba6b3b10SAndreas Gohr        // we do not check for 'success' status here. when the API can't resolve the IP we still log it
124*ba6b3b10SAndreas Gohr        // without location data, so we won't re-query it in the next 30 days.
125*ba6b3b10SAndreas Gohr
126*ba6b3b10SAndreas Gohr        return $data;
127*ba6b3b10SAndreas Gohr    }
1286b6f8822SAndreas Gohr}
129