16b6f8822SAndreas Gohr<?php 2a8acb244SAndreas Gohr 3d5ef99ddSAndreas Gohruse dokuwiki\Extension\Plugin; 4ba6b3b10SAndreas Gohruse dokuwiki\HTTP\DokuHTTPClient; 5d5ef99ddSAndreas Gohruse dokuwiki\plugin\sqlite\SQLiteDB; 6ba6b3b10SAndreas 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; 22ba6b3b10SAndreas 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 * 79*87e0f0b1SAndreas Gohr * @called from dispatch.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 } 99ba6b3b10SAndreas Gohr 100ba6b3b10SAndreas Gohr /** 101ba6b3b10SAndreas Gohr * Return the location information for an IP address 102ba6b3b10SAndreas Gohr * 103ba6b3b10SAndreas Gohr * @throws IpResolverException 104ba6b3b10SAndreas Gohr * @noinspection HttpUrlsUsage 105ba6b3b10SAndreas Gohr */ 106ba6b3b10SAndreas Gohr public function resolveIP($ip) 107ba6b3b10SAndreas Gohr { 108ba6b3b10SAndreas Gohr $http = $this->httpClient ?: new DokuHTTPClient(); 109ba6b3b10SAndreas Gohr $http->timeout = 7; 110ba6b3b10SAndreas Gohr $json = $http->get('http://ip-api.com/json/' . $ip); // yes, it's HTTP only 111ba6b3b10SAndreas Gohr 112ba6b3b10SAndreas Gohr if (!$json) { 113ba6b3b10SAndreas Gohr throw new IpResolverException('Failed talk to ip-api.com.'); 114ba6b3b10SAndreas Gohr } 115ba6b3b10SAndreas Gohr try { 116ba6b3b10SAndreas Gohr $data = json_decode($json, true, 512, JSON_THROW_ON_ERROR); 117ba6b3b10SAndreas Gohr } catch (\JsonException $e) { 118ba6b3b10SAndreas Gohr throw new IpResolverException('Failed to decode JSON from ip-api.com.', $e->getTrace(), 0, $e); 119ba6b3b10SAndreas Gohr } 120ba6b3b10SAndreas Gohr if (!isset($data['status'])) { 121ba6b3b10SAndreas Gohr throw new IpResolverException('Invalid ip-api.com result for' . $ip, $data); 122ba6b3b10SAndreas Gohr } 123ba6b3b10SAndreas Gohr // we do not check for 'success' status here. when the API can't resolve the IP we still log it 124ba6b3b10SAndreas Gohr // without location data, so we won't re-query it in the next 30 days. 125ba6b3b10SAndreas Gohr 126ba6b3b10SAndreas Gohr return $data; 127ba6b3b10SAndreas Gohr } 1286b6f8822SAndreas Gohr} 129