diff --git a/action.php b/action.php
index ea65e94..34bfdda 100644
--- a/action.php
+++ b/action.php
@@ -9,7 +9,7 @@
if(!defined('DOKU_INC')) die();
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN', DOKU_INC . 'lib/plugins/');
-require_once(DOKU_PLUGIN . 'action.php');
+// Using autoloading instead of require_once for better compatibility
class action_plugin_statistics extends DokuWiki_Action_Plugin {
@@ -113,13 +113,13 @@ function loglogins(Doku_Event $event, $param) {
$act = $this->_act_clean($event->data);
if($act == 'logout') {
$type = 'o';
- } elseif($_SERVER['REMOTE_USER'] && $act == 'login') {
- if($_REQUEST['r']) {
+ } elseif(isset($_SERVER['REMOTE_USER']) && $_SERVER['REMOTE_USER'] && $act == 'login') {
+ if(isset($_REQUEST['r']) && $_REQUEST['r']) {
$type = 'p';
} else {
$type = 'l';
}
- } elseif($_REQUEST['u'] && !$_REQUEST['http_credentials'] && !$_SERVER['REMOTE_USER']) {
+ } elseif(isset($_REQUEST['u']) && $_REQUEST['u'] && !isset($_REQUEST['http_credentials']) && !isset($_SERVER['REMOTE_USER'])) {
$type = 'f';
}
if(!$type) return;
diff --git a/admin.php b/admin.php
index 6da1f4d..fbec131 100644
--- a/admin.php
+++ b/admin.php
@@ -108,11 +108,14 @@ public function getMenuSort() {
* handle user request
*/
public function handle() {
- $this->opt = preg_replace('/[^a-z]+/', '', $_REQUEST['opt']);
+ $this->opt = preg_replace('/[^a-z]+/', '', isset($_REQUEST['opt']) ? $_REQUEST['opt'] : '');
if(!in_array($this->opt, $this->allowedpages)) $this->opt = 'dashboard';
- $this->start = (int) $_REQUEST['s'];
- $this->setTimeframe($_REQUEST['f'], $_REQUEST['t']);
+ $this->start = (int) (isset($_REQUEST['s']) ? $_REQUEST['s'] : 0);
+ $this->setTimeframe(
+ isset($_REQUEST['f']) ? $_REQUEST['f'] : '',
+ isset($_REQUEST['t']) ? $_REQUEST['t'] : ''
+ );
}
/**
diff --git a/helper.php b/helper.php
index 7f33d34..94518ba 100644
--- a/helper.php
+++ b/helper.php
@@ -102,7 +102,10 @@ public function runSQL($sql_string) {
$result = mysqli_query($link, $sql_string);
if($result === false) {
- dbglog('DB Error: ' . mysqli_error($link) . ' ' . hsc($sql_string), -1);
+ // Using modern logger instead of deprecated dbglog
+ if (class_exists('\dokuwiki\Logger')) {
+ \dokuwiki\Logger::error('DB Error: ' . mysqli_error($link) . ' ' . hsc($sql_string));
+ }
msg('DB Error: ' . mysqli_error($link) . ' ' . hsc($sql_string), -1);
return null;
}
diff --git a/img.php b/img.php
index 449663e..e61390b 100644
--- a/img.php
+++ b/img.php
@@ -15,7 +15,12 @@
$plugin = plugin_load('helper', 'statistics');
try {
if(!auth_ismanager()) throw new Exception('Access denied');
- $plugin->Graph()->render($_REQUEST['img'], $_REQUEST['f'], $_REQUEST['t'], $_REQUEST['s']);
+ $plugin->Graph()->render(
+ isset($_REQUEST['img']) ? $_REQUEST['img'] : '',
+ isset($_REQUEST['f']) ? $_REQUEST['f'] : '',
+ isset($_REQUEST['t']) ? $_REQUEST['t'] : '',
+ isset($_REQUEST['s']) ? $_REQUEST['s'] : ''
+ );
} catch(Exception $e) {
$plugin->sendGIF(false);
}
diff --git a/inc/StatisticsBrowscap.class.php b/inc/StatisticsBrowscap.class.php
index c6f7bea..10a51cf 100644
--- a/inc/StatisticsBrowscap.class.php
+++ b/inc/StatisticsBrowscap.class.php
@@ -24,7 +24,7 @@ public function __construct() {
* @return string
*/
protected function _getRemoteData($url) {
- $http = new DokuHTTPClient($url);
+ $http = new \dokuwiki\HTTP\DokuHTTPClient($url);
$file = $http->get($url);
if(!$file)
throw new Exception('Your server can\'t connect to external resources. Please update the file manually.');
diff --git a/inc/StatisticsGraph.class.php b/inc/StatisticsGraph.class.php
index a2a53b0..887332a 100644
--- a/inc/StatisticsGraph.class.php
+++ b/inc/StatisticsGraph.class.php
@@ -44,19 +44,49 @@ protected function PieChart($data) {
$Chart = new PieChart(400, 200, $Canvas);
$Chart->setFontProperties(dirname(__FILE__) . '/pchart/Fonts/DroidSans.ttf', 8);
- $DataSet->AddPoints(array_values($data), 'Serie1');
- $DataSet->AddPoints(array_keys($data), 'Serie2');
+ // Ensure data values are numeric
+ $values = array_map(function($v) { return is_numeric($v) ? (int)$v : 0; }, array_values($data));
+ $keys = array_keys($data);
+
+ // Ensure arrays have at least one element
+ if(empty($values) || empty($keys)) {
+ $values = array(0);
+ $keys = array('No Data');
+ }
+
+ // Check if all values are zero
+ $totalSum = array_sum($values);
+ if($totalSum == 0 && count($values) > 1) {
+ // If all values are zero, show a single "No Data" entry
+ $values = array(1); // Use 1 instead of 0 to avoid division by zero in chart rendering
+ $keys = array('No Data');
+ }
+
+ $DataSet->AddPoints($values, 'Serie1');
+ $DataSet->AddPoints($keys, 'Serie2');
$DataSet->AddAllSeries();
$DataSet->SetAbscissaLabelSeries("Serie2");
+ // Final data validation before drawing pie chart
+ $pieData = $DataSet->getData();
+ if (is_array($pieData)) {
+ foreach ($pieData as $serieKey => $serieData) {
+ if (is_array($serieData)) {
+ $pieData[$serieKey] = array_map(function($v) {
+ return is_numeric($v) ? (float)$v : 0.0;
+ }, $serieData);
+ }
+ }
+ }
+
$Chart->drawBasicPieGraph(
- $DataSet->getData(),
+ $pieData,
$DataSet->GetDataDescription(),
120, 100, 60, PIE_PERCENTAGE
);
$Chart->drawPieLegend(
230, 15,
- $DataSet->GetData(),
+ $pieData,
$DataSet->GetDataDescription(),
new Color(250)
);
@@ -76,14 +106,36 @@ protected function sumUpPieChart($query, $key, $max=4){
$result = $this->hlp->Query()->$query($this->tlimit, $this->start, 0, false);
$data = array();
$top = 0;
+
+ // Initialize 'other' key
+ if (!isset($data['other'])) {
+ $data['other'] = 0;
+ }
+
foreach($result as $row) {
if($top < $max) {
- $data[$row[$key]] = $row['cnt'];
+ $keyValue = isset($row[$key]) ? $row[$key] : 'unknown';
+ $cntValue = isset($row['cnt']) ? (is_numeric($row['cnt']) ? (int)$row['cnt'] : 0) : 0;
+ $data[$keyValue] = $cntValue;
} else {
- $data['other'] += $row['cnt'];
+ $cntValue = isset($row['cnt']) ? (is_numeric($row['cnt']) ? (int)$row['cnt'] : 0) : 0;
+ if (!isset($data['other'])) {
+ $data['other'] = 0;
+ }
+ $data['other'] += $cntValue;
}
$top++;
}
+
+ // Remove empty 'other' category if it wasn't used
+ if (isset($data['other']) && $data['other'] == 0 && count($data) > 1) {
+ unset($data['other']);
+ }
+
+ // Ensure we have at least some data
+ if (empty($data)) {
+ $data = array('No Data' => 0);
+ }
$this->PieChart($data);
}
@@ -108,16 +160,30 @@ protected function history($info) {
$data = array();
$times = array();
foreach($result as $row) {
- $data[] = $row['cnt'];
+ $cntValue = isset($row['cnt']) ? (is_numeric($row['cnt']) ? (int)$row['cnt'] : 0) : 0;
+ $data[] = $cntValue;
if($interval == 'months') {
- $times[] = substr($row['time'], 0, 4) . '-' . substr($row['time'], 4, 2);
+ $time = isset($row['time']) ? $row['time'] : '';
+ $times[] = substr($time, 0, 4) . '-' . substr($time, 4, 2);
} elseif ($interval == 'weeks') {
- $times[] = $row['EXTRACT(YEAR FROM dt)'] . '-' . $row['time'];
+ $year = isset($row['EXTRACT(YEAR FROM dt)']) ? $row['EXTRACT(YEAR FROM dt)'] : '';
+ $time = isset($row['time']) ? $row['time'] : '';
+ $times[] = $year . '-' . $time;
}else {
- $times[] = substr($row['time'], -5);
+ $time = isset($row['time']) ? $row['time'] : '';
+ $times[] = substr($time, -5);
}
}
+ // Ensure data contains only numeric values
+ $data = array_map(function($v) { return is_numeric($v) ? (int)$v : 0; }, $data);
+
+ // Ensure arrays have at least one element
+ if(empty($data) || empty($times)) {
+ $data = array(0);
+ $times = array('No Data');
+ }
+
$DataSet = new pData();
$DataSet->AddPoints($data, 'Serie1');
$DataSet->AddPoints($times, 'Times');
@@ -136,7 +202,18 @@ protected function history($info) {
$DataSet, new ScaleStyle(SCALE_NORMAL, new Color(127)),
45, 1, false, ceil(count($times) / 12)
);
- $Chart->drawLineGraph($DataSet->GetData(), $DataSet->GetDataDescription());
+ // Final data validation before drawing
+ $chartData = $DataSet->GetData();
+ if (is_array($chartData)) {
+ foreach ($chartData as $serieKey => $serieData) {
+ if (is_array($serieData)) {
+ $chartData[$serieKey] = array_map(function($v) {
+ return is_numeric($v) ? (float)$v : 0.0;
+ }, $serieData);
+ }
+ }
+ }
+ $Chart->drawLineGraph($chartData, $DataSet->GetDataDescription());
$DataSet->removeSeries('Times');
$DataSet->removeSeriesName('Times');
@@ -187,9 +264,21 @@ public function viewport() {
$data3 = array();
foreach($result as $row) {
- $data1[] = $row['res_x'];
- $data2[] = $row['res_y'];
- $data3[] = $row['cnt'];
+ $data1[] = isset($row['res_x']) ? (is_numeric($row['res_x']) ? (int)$row['res_x'] : 0) : 0;
+ $data2[] = isset($row['res_y']) ? (is_numeric($row['res_y']) ? (int)$row['res_y'] : 0) : 0;
+ $data3[] = isset($row['cnt']) ? (is_numeric($row['cnt']) ? (int)$row['cnt'] : 0) : 0;
+ }
+
+ // Ensure all data arrays contain only numeric values
+ $data1 = array_map(function($v) { return is_numeric($v) ? (int)$v : 0; }, $data1);
+ $data2 = array_map(function($v) { return is_numeric($v) ? (int)$v : 0; }, $data2);
+ $data3 = array_map(function($v) { return is_numeric($v) ? (int)$v : 0; }, $data3);
+
+ // Ensure all arrays have at least one element
+ if(empty($data1) || empty($data2) || empty($data3)) {
+ $data1 = array(0);
+ $data2 = array(0);
+ $data3 = array(0);
}
$DataSet = new pData;
@@ -208,7 +297,23 @@ public function viewport() {
'Serie2', 'Serie1'
);
- $Chart->drawXYPlotGraph($DataSet, 'Serie2', 'Serie1', 0, 20, 2, null, false, 'Serie3');
+ // Validate DataSet before XY plot
+ $validatedDataSet = new pData;
+ $originalData = $DataSet->GetData();
+ if (is_array($originalData)) {
+ foreach ($originalData as $serieKey => $serieData) {
+ if (is_array($serieData)) {
+ $cleanData = array_map(function($v) {
+ return is_numeric($v) ? (float)$v : 0.0;
+ }, $serieData);
+ $validatedDataSet->AddPoints($cleanData, $serieKey);
+ }
+ }
+ $validatedDataSet->AddAllSeries();
+ } else {
+ $validatedDataSet = $DataSet;
+ }
+ $Chart->drawXYPlotGraph($validatedDataSet, 'Serie2', 'Serie1', 0, 20, 2, null, false, 'Serie3');
header('Content-Type: image/png');
$Chart->Render('');
}
@@ -220,9 +325,21 @@ public function resolution() {
$data3 = array();
foreach($result as $row) {
- $data1[] = $row['res_x'];
- $data2[] = $row['res_y'];
- $data3[] = $row['cnt'];
+ $data1[] = isset($row['res_x']) ? (is_numeric($row['res_x']) ? (int)$row['res_x'] : 0) : 0;
+ $data2[] = isset($row['res_y']) ? (is_numeric($row['res_y']) ? (int)$row['res_y'] : 0) : 0;
+ $data3[] = isset($row['cnt']) ? (is_numeric($row['cnt']) ? (int)$row['cnt'] : 0) : 0;
+ }
+
+ // Ensure all data arrays contain only numeric values
+ $data1 = array_map(function($v) { return is_numeric($v) ? (int)$v : 0; }, $data1);
+ $data2 = array_map(function($v) { return is_numeric($v) ? (int)$v : 0; }, $data2);
+ $data3 = array_map(function($v) { return is_numeric($v) ? (int)$v : 0; }, $data3);
+
+ // Ensure all arrays have at least one element
+ if(empty($data1) || empty($data2) || empty($data3)) {
+ $data1 = array(0);
+ $data2 = array(0);
+ $data3 = array(0);
}
$DataSet = new pData;
@@ -241,7 +358,23 @@ public function resolution() {
'Serie2', 'Serie1'
);
- $Chart->drawXYPlotGraph($DataSet, 'Serie2', 'Serie1', 0, 20, 2, null, false, 'Serie3');
+ // Validate DataSet before XY plot
+ $validatedDataSet = new pData;
+ $originalData = $DataSet->GetData();
+ if (is_array($originalData)) {
+ foreach ($originalData as $serieKey => $serieData) {
+ if (is_array($serieData)) {
+ $cleanData = array_map(function($v) {
+ return is_numeric($v) ? (float)$v : 0.0;
+ }, $serieData);
+ $validatedDataSet->AddPoints($cleanData, $serieKey);
+ }
+ }
+ $validatedDataSet->AddAllSeries();
+ } else {
+ $validatedDataSet = $DataSet;
+ }
+ $Chart->drawXYPlotGraph($validatedDataSet, 'Serie2', 'Serie1', 0, 20, 2, null, false, 'Serie3');
header('Content-Type: image/png');
$Chart->Render('');
}
@@ -273,12 +406,25 @@ public function dashboardviews() {
$times = array();
foreach($result as $time => $row) {
- $data1[] = (int) $row['pageviews'];
- $data2[] = (int) $row['sessions'];
- $data3[] = (int) $row['visitors'];
+ $data1[] = isset($row['pageviews']) ? (is_numeric($row['pageviews']) ? (int)$row['pageviews'] : 0) : 0;
+ $data2[] = isset($row['sessions']) ? (is_numeric($row['sessions']) ? (int)$row['sessions'] : 0) : 0;
+ $data3[] = isset($row['visitors']) ? (is_numeric($row['visitors']) ? (int)$row['visitors'] : 0) : 0;
$times[] = $time . ($hours ? 'h' : '');
}
+ // Ensure all data arrays contain only numeric values
+ $data1 = array_map(function($v) { return is_numeric($v) ? (int)$v : 0; }, $data1);
+ $data2 = array_map(function($v) { return is_numeric($v) ? (int)$v : 0; }, $data2);
+ $data3 = array_map(function($v) { return is_numeric($v) ? (int)$v : 0; }, $data3);
+
+ // Ensure all arrays have the same length and at least one element
+ if(empty($data1) || empty($data2) || empty($data3) || empty($times)) {
+ $data1 = array(0);
+ $data2 = array(0);
+ $data3 = array(0);
+ $times = array('No Data');
+ }
+
$DataSet = new pData();
$DataSet->AddPoints($data1, 'Serie1');
$DataSet->AddPoints($data2, 'Serie2');
@@ -300,7 +446,18 @@ public function dashboardviews() {
$DataSet, new ScaleStyle(SCALE_NORMAL, new Color(127)),
($hours ? 0 : 45), 1, false, ceil(count($times) / 12)
);
- $Chart->drawLineGraph($DataSet->GetData(), $DataSet->GetDataDescription());
+ // Final data validation before drawing
+ $chartData = $DataSet->GetData();
+ if (is_array($chartData)) {
+ foreach ($chartData as $serieKey => $serieData) {
+ if (is_array($serieData)) {
+ $chartData[$serieKey] = array_map(function($v) {
+ return is_numeric($v) ? (float)$v : 0.0;
+ }, $serieData);
+ }
+ }
+ }
+ $Chart->drawLineGraph($chartData, $DataSet->GetDataDescription());
$DataSet->removeSeries('Times');
$DataSet->removeSeriesName('Times');
@@ -323,12 +480,25 @@ public function dashboardwiki() {
$times = array();
foreach($result as $time => $row) {
- $data1[] = (int) $row['E'];
- $data2[] = (int) $row['C'];
- $data3[] = (int) $row['D'];
+ $data1[] = isset($row['E']) ? (is_numeric($row['E']) ? (int)$row['E'] : 0) : 0;
+ $data2[] = isset($row['C']) ? (is_numeric($row['C']) ? (int)$row['C'] : 0) : 0;
+ $data3[] = isset($row['D']) ? (is_numeric($row['D']) ? (int)$row['D'] : 0) : 0;
$times[] = $time . ($hours ? 'h' : '');
}
+ // Ensure all data arrays contain only numeric values
+ $data1 = array_map(function($v) { return is_numeric($v) ? (int)$v : 0; }, $data1);
+ $data2 = array_map(function($v) { return is_numeric($v) ? (int)$v : 0; }, $data2);
+ $data3 = array_map(function($v) { return is_numeric($v) ? (int)$v : 0; }, $data3);
+
+ // Ensure all arrays have the same length and at least one element
+ if(empty($data1) || empty($data2) || empty($data3) || empty($times)) {
+ $data1 = array(0);
+ $data2 = array(0);
+ $data3 = array(0);
+ $times = array('No Data');
+ }
+
$DataSet = new pData();
$DataSet->AddPoints($data1, 'Serie1');
$DataSet->AddPoints($data2, 'Serie2');
@@ -350,7 +520,18 @@ public function dashboardwiki() {
$DataSet, new ScaleStyle(SCALE_NORMAL, new Color(127)),
($hours ? 0 : 45), 1, false, ceil(count($times) / 12)
);
- $Chart->drawLineGraph($DataSet->GetData(), $DataSet->GetDataDescription());
+ // Final data validation before drawing
+ $chartData = $DataSet->GetData();
+ if (is_array($chartData)) {
+ foreach ($chartData as $serieKey => $serieData) {
+ if (is_array($serieData)) {
+ $chartData[$serieKey] = array_map(function($v) {
+ return is_numeric($v) ? (float)$v : 0.0;
+ }, $serieData);
+ }
+ }
+ }
+ $Chart->drawLineGraph($chartData, $DataSet->GetDataDescription());
$DataSet->removeSeries('Times');
$DataSet->removeSeriesName('Times');
diff --git a/inc/StatisticsLogger.class.php b/inc/StatisticsLogger.class.php
index ecc00bd..d0b5344 100644
--- a/inc/StatisticsLogger.class.php
+++ b/inc/StatisticsLogger.class.php
@@ -19,13 +19,13 @@ class StatisticsLogger {
public function __construct(helper_plugin_statistics $hlp) {
$this->hlp = $hlp;
- $this->ua_agent = trim($_SERVER['HTTP_USER_AGENT']);
+ $this->ua_agent = trim(isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '');
$bc = new StatisticsBrowscap();
$ua = $bc->getBrowser($this->ua_agent);
$this->ua_name = $ua->Browser;
$this->ua_type = 'browser';
- if($ua->Crawler) $this->ua_type = 'robot';
- if($ua->isSyndicationReader) $this->ua_type = 'feedreader';
+ if(isset($ua->Crawler) && $ua->Crawler) $this->ua_type = 'robot';
+ if(isset($ua->isSyndicationReader) && $ua->isSyndicationReader) $this->ua_type = 'feedreader';
$this->ua_version = $ua->Version;
$this->ua_platform = $ua->Platform;
@@ -38,7 +38,7 @@ public function __construct(helper_plugin_statistics $hlp) {
* get the unique user ID
*/
protected function getUID() {
- $uid = $_REQUEST['uid'];
+ $uid = isset($_REQUEST['uid']) ? $_REQUEST['uid'] : null;
if(!$uid) $uid = get_doku_pref('plgstats', false);
if(!$uid) $uid = session_id();
return $uid;
@@ -52,7 +52,7 @@ protected function getUID() {
* @return string
*/
protected function getSession() {
- $ses = $_REQUEST['ses'];
+ $ses = isset($_REQUEST['ses']) ? $_REQUEST['ses'] : null;
if(!$ses) $ses = get_doku_pref('plgstatsses', false);
if(!$ses) $ses = session_id();
return $ses;
@@ -65,7 +65,7 @@ protected function getSession() {
* regardless from where the log is initiated
*/
public function log_lastseen() {
- if(empty($_SERVER['REMOTE_USER'])) return;
+ if(!isset($_SERVER['REMOTE_USER']) || empty($_SERVER['REMOTE_USER'])) return;
$user = addslashes($_SERVER['REMOTE_USER']);
$sql = "REPLACE INTO " . $this->hlp->prefix . "lastseen
@@ -118,7 +118,7 @@ public function log_groups($type, $groups) {
* Will not write anything if the referer isn't a search engine
*/
public function log_externalsearch($referer, &$type) {
- $referer = utf8_strtolower($referer);
+ $referer = \dokuwiki\Utf8\PhpString::strtolower($referer);
include(dirname(__FILE__) . '/searchengines.php');
/** @var array $SEARCHENGINES */
@@ -128,8 +128,8 @@ public function log_externalsearch($referer, &$type) {
// parse the referer
$urlparts = parse_url($referer);
$domain = $urlparts['host'];
- $qpart = $urlparts['query'];
- if(!$qpart) $qpart = $urlparts['fragment']; //google does this
+ $qpart = isset($urlparts['query']) ? $urlparts['query'] : '';
+ if(!$qpart) $qpart = isset($urlparts['fragment']) ? $urlparts['fragment'] : ''; //google does this
$params = array();
parse_str($qpart, $params);
@@ -168,14 +168,19 @@ public function log_externalsearch($referer, &$type) {
$query = preg_replace('/^(cache|related):[^\+]+/', '', $query); // non-search queries
$query = preg_replace('/ +/', ' ', $query); // ws compact
$query = trim($query);
- if(!utf8_check($query)) $query = utf8_encode($query); // assume latin1 if not utf8
+ if(!\dokuwiki\Utf8\Clean::isUtf8($query)) {
+ // Convert from latin1 to UTF-8 if not already UTF-8
+ $query = mb_convert_encoding($query, 'UTF-8', 'ISO-8859-1');
+ }
// no query? no log
if(!$query) return;
// log it!
- $words = explode(' ', utf8_stripspecials($query, ' ', '\._\-:\*'));
- $this->log_search($_REQUEST['p'], $query, $words, $name);
+ // Replace deprecated utf8_stripspecials with modern equivalent
+ $cleaned_query = preg_replace('/[^\w\s\._\-:\*]/u', '', $query);
+ $words = explode(' ', $cleaned_query);
+ $this->log_search(isset($_REQUEST['p']) ? $_REQUEST['p'] : '', $query, $words, $name);
}
/**
@@ -244,9 +249,9 @@ public function log_ip($ip) {
WHERE ip ='" . addslashes($ip) . "'
AND lastupd > DATE_SUB(CURDATE(),INTERVAL 30 DAY)";
$result = $this->hlp->runSQL($sql);
- if($result[0]['ip']) return;
+ if($result && isset($result[0]) && isset($result[0]['ip']) && $result[0]['ip']) return;
- $http = new DokuHTTPClient();
+ $http = new \dokuwiki\HTTP\DokuHTTPClient();
$http->timeout = 10;
$data = $http->get('http://api.hostip.info/get_html.php?ip=' . $ip);
@@ -273,12 +278,12 @@ public function log_ip($ip) {
* called from log.php
*/
public function log_outgoing() {
- if(!$_REQUEST['ol']) return;
+ if(!isset($_REQUEST['ol']) || !$_REQUEST['ol']) return;
$link = addslashes($_REQUEST['ol']);
$link_md5 = md5($link);
$session = addslashes($this->getSession());
- $page = addslashes($_REQUEST['p']);
+ $page = addslashes(isset($_REQUEST['p']) ? $_REQUEST['p'] : '');
$sql = "INSERT DELAYED INTO " . $this->hlp->prefix . "outlinks
SET dt = NOW(),
@@ -299,13 +304,13 @@ public function log_outgoing() {
* called from log.php
*/
public function log_access() {
- if(!$_REQUEST['p']) return;
+ if(!isset($_REQUEST['p']) || !$_REQUEST['p']) return;
global $USERINFO;
# FIXME check referer against blacklist and drop logging for bad boys
// handle referer
- $referer = trim($_REQUEST['r']);
+ $referer = trim(isset($_REQUEST['r']) ? $_REQUEST['r'] : '');
if($referer) {
$ref = addslashes($referer);
$ref_md5 = ($ref) ? md5($referer) : '';
@@ -330,13 +335,13 @@ public function log_access() {
$page = addslashes($_REQUEST['p']);
$ip = addslashes(clientIP(true));
- $sx = (int) $_REQUEST['sx'];
- $sy = (int) $_REQUEST['sy'];
- $vx = (int) $_REQUEST['vx'];
- $vy = (int) $_REQUEST['vy'];
- $js = (int) $_REQUEST['js'];
+ $sx = (int) (isset($_REQUEST['sx']) ? $_REQUEST['sx'] : 0);
+ $sy = (int) (isset($_REQUEST['sy']) ? $_REQUEST['sy'] : 0);
+ $vx = (int) (isset($_REQUEST['vx']) ? $_REQUEST['vx'] : 0);
+ $vy = (int) (isset($_REQUEST['vy']) ? $_REQUEST['vy'] : 0);
+ $js = (int) (isset($_REQUEST['js']) ? $_REQUEST['js'] : 0);
$uid = addslashes($this->uid);
- $user = addslashes($_SERVER['REMOTE_USER']);
+ $user = addslashes(isset($_SERVER['REMOTE_USER']) ? $_SERVER['REMOTE_USER'] : '');
$session = addslashes($this->getSession());
$sql = "INSERT DELAYED INTO " . $this->hlp->prefix . "access
@@ -410,7 +415,7 @@ public function log_media($media, $mime, $inline, $size) {
$ip = addslashes(clientIP(true));
$uid = addslashes($this->uid);
- $user = addslashes($_SERVER['REMOTE_USER']);
+ $user = addslashes(isset($_SERVER['REMOTE_USER']) ? $_SERVER['REMOTE_USER'] : '');
$session = addslashes($this->getSession());
$sql = "INSERT DELAYED INTO " . $this->hlp->prefix . "media
@@ -433,7 +438,10 @@ public function log_media($media, $mime, $inline, $size) {
$ok = $this->hlp->runSQL($sql);
if(is_null($ok)) {
global $MSG;
- dbglog($MSG);
+ // Using modern logger instead of deprecated dbglog
+ if (class_exists('\dokuwiki\Logger')) {
+ \dokuwiki\Logger::debug($MSG);
+ }
}
}
@@ -444,7 +452,7 @@ public function log_edit($page, $type) {
global $USERINFO;
$ip = addslashes(clientIP(true));
- $user = addslashes($_SERVER['REMOTE_USER']);
+ $user = addslashes(isset($_SERVER['REMOTE_USER']) ? $_SERVER['REMOTE_USER'] : '');
$session = addslashes($this->getSession());
$uid = addslashes($this->uid);
$page = addslashes($page);
@@ -470,7 +478,7 @@ public function log_edit($page, $type) {
* Log login/logoffs and user creations
*/
public function log_login($type, $user = '') {
- if(!$user) $user = $_SERVER['REMOTE_USER'];
+ if(!$user) $user = isset($_SERVER['REMOTE_USER']) ? $_SERVER['REMOTE_USER'] : '';
$ip = addslashes(clientIP(true));
$user = addslashes($user);
diff --git a/inc/StatisticsQuery.class.php b/inc/StatisticsQuery.class.php
index 774b663..cda4de1 100644
--- a/inc/StatisticsQuery.class.php
+++ b/inc/StatisticsQuery.class.php
@@ -37,10 +37,10 @@ public function aggregate($tlimit) {
AND ua_type = 'browser'";
$result = $this->hlp->runSQL($sql);
- $data['users'] = max($result[0]['users'] - 1, 0); // subtract empty user
- $data['sessions'] = $result[0]['sessions'];
- $data['pageviews'] = $result[0]['views'];
- $data['visitors'] = $result[0]['visitors'];
+ $data['users'] = ($result && isset($result[0])) ? max($result[0]['users'] - 1, 0) : 0; // subtract empty user
+ $data['sessions'] = ($result && isset($result[0])) ? $result[0]['sessions'] : 0;
+ $data['pageviews'] = ($result && isset($result[0])) ? $result[0]['views'] : 0;
+ $data['visitors'] = ($result && isset($result[0])) ? $result[0]['visitors'] : 0;
// calculate bounce rate
if($data['sessions']) {
@@ -49,7 +49,7 @@ public function aggregate($tlimit) {
WHERE $tlimit
AND views = 1";
$result = $this->hlp->runSQL($sql);
- $data['bouncerate'] = $result[0]['cnt'] * 100 / $data['sessions'];
+ $data['bouncerate'] = ($result && isset($result[0])) ? $result[0]['cnt'] * 100 / $data['sessions'] : 0;
// new visitors
$result = "SELECT COUNT(*) as cnt
@@ -62,7 +62,7 @@ public function aggregate($tlimit) {
AND B.uid = B.uid
)";
$result = $this->hlp->runSQL($sql);
- $data['newvisitors'] = $result[0]['cnt'] * 100 / $data['sessions'];
+ $data['newvisitors'] = ($result && isset($result[0])) ? $result[0]['cnt'] * 100 / $data['sessions'] : 0;
}
// calculate avg. number of views per session
@@ -70,7 +70,7 @@ public function aggregate($tlimit) {
FROM " . $this->hlp->prefix . "session as A
WHERE $tlimit";
$result = $this->hlp->runSQL($sql);
- $data['avgpages'] = $result[0]['cnt'];
+ $data['avgpages'] = ($result && isset($result[0])) ? $result[0]['cnt'] : 0;
/* not used currently
$sql = "SELECT COUNT(id) as robots
@@ -78,7 +78,7 @@ public function aggregate($tlimit) {
WHERE $tlimit
AND ua_type = 'robot'";
$result = $this->hlp->runSQL($sql);
- $data['robots'] = $result[0]['robots'];
+ $data['robots'] = ($result && isset($result[0])) ? $result[0]['robots'] : 0;
*/
// average time spent on the site
@@ -88,7 +88,7 @@ public function aggregate($tlimit) {
AND dt != end
AND DATE(dt) = DATE(end)";
$result = $this->hlp->runSQL($sql);
- $data['timespent'] = $result[0]['time'];
+ $data['timespent'] = ($result && isset($result[0])) ? $result[0]['time'] : 0;
// logins
$sql = "SELECT COUNT(*) as logins
@@ -96,7 +96,7 @@ public function aggregate($tlimit) {
WHERE $tlimit
AND (type = 'l' OR type = 'p')";
$result = $this->hlp->runSQL($sql);
- $data['logins'] = $result[0]['logins'];
+ $data['logins'] = ($result && isset($result[0])) ? $result[0]['logins'] : 0;
// registrations
$sql = "SELECT COUNT(*) as registrations
@@ -104,14 +104,14 @@ public function aggregate($tlimit) {
WHERE $tlimit
AND type = 'C'";
$result = $this->hlp->runSQL($sql);
- $data['registrations'] = $result[0]['registrations'];
+ $data['registrations'] = ($result && isset($result[0])) ? $result[0]['registrations'] : 0;
// current users
$sql = "SELECT COUNT(*) as current
FROM ". $this->hlp->prefix . "lastseen
WHERE `dt` >= NOW() - INTERVAL 10 MINUTE";
$result = $this->hlp->runSQL($sql);
- $data['current'] = $result[0]['current'];
+ $data['current'] = ($result && isset($result[0])) ? $result[0]['current'] : 0;
return $data;
}
diff --git a/inc/pchart/PieChart.php b/inc/pchart/PieChart.php
index 4506118..f220f6a 100644
--- a/inc/pchart/PieChart.php
+++ b/inc/pchart/PieChart.php
@@ -178,8 +178,17 @@ public function drawBasicPieGraph($Data, $DataDescription, $XPos, $YPos, $Radius
throw new Exception("Pie chart can only accept one serie of data.");
/** @todo Proper exception type needed here */
- $SpliceRatio = 360 / $PieSum;
- $SplicePercent = 100 / $PieSum;
+ /* Check for division by zero */
+ if($PieSum == 0) {
+ // When all data values are zero, create a single slice representing "No Data"
+ $SpliceRatio = 360;
+ $SplicePercent = 100;
+ // Reset iValues to have a single 1 value to represent the full circle
+ $iValues = array(1);
+ } else {
+ $SpliceRatio = 360 / $PieSum;
+ $SplicePercent = 100 / $PieSum;
+ }
/* Calculate all polygons */
$Angle = 0;
diff --git a/lang/zh-tw/lang.php b/lang/zh-tw/lang.php
new file mode 100644
index 0000000..0153cda
--- /dev/null
+++ b/lang/zh-tw/lang.php
@@ -0,0 +1,112 @@
+
+ */
+
+// 用於管理插件,顯示在管理選單中的提示
+$lang['menu'] = '存取與使用統計';
+
+$lang['more'] = '更多';
+$lang['prev'] = '上一頁';
+$lang['next'] = '下一頁';
+
+// 時間選擇
+$lang['time_select'] = '選擇時間範圍:';
+$lang['time_today'] = '今天';
+$lang['time_last1'] = '昨天';
+$lang['time_last7'] = '最近7天';
+$lang['time_last30'] = '最近30天';
+$lang['time_go'] = '確定';
+$lang['days'] = '天';
+$lang['weeks'] = '週';
+$lang['months'] = '月';
+
+// 不同頁面
+$lang['dashboard'] = '儀表板';
+$lang['page'] = '頁面';
+$lang['edits'] = '編輯';
+$lang['images'] = '圖片';
+$lang['downloads'] = '下載';
+$lang['referer'] = '來源連結';
+$lang['newreferer'] = '新增來源連結';
+$lang['outlinks'] = '外部連結';
+$lang['searchphrases'] = '外部搜尋詞組';
+$lang['searchwords'] = '外部搜尋關鍵字';
+$lang['internalsearchphrases'] = '內部搜尋詞組';
+$lang['internalsearchwords'] = '內部搜尋關鍵字';
+$lang['searchengines'] = '搜尋引擎';
+$lang['browsers'] = '瀏覽器';
+$lang['os'] = '作業系統';
+$lang['countries'] = '國家';
+$lang['resolution'] = '螢幕大小';
+$lang['viewport'] = '瀏覽器視窗';
+$lang['seenusers'] = '活躍用戶';
+$lang['history'] = '成長歷史';
+$lang['topuser'] = '熱門用戶';
+$lang['topeditor'] = '熱門編輯者';
+$lang['topgroup'] = '熱門群組';
+$lang['topgroupedit'] = '熱門編輯群組';
+$lang['content'] = '(內容)';
+$lang['users'] = '(用戶和群組)';
+$lang['links'] = '(連結)';
+$lang['search'] = '(搜尋)';
+$lang['technology'] = '(技術)';
+$lang['trafficsum'] = '%s 個請求產生了 %s 的流量。';
+
+
+// 介紹文字
+$lang['intro_dashboard'] = '此頁面為您提供在所選時間範圍內,您的維基發生了什麼的快速概覽。
欲獲得詳細資訊和圖表,請從目錄中選擇一個主題。';
+$lang['intro_page'] = '以下是在所選時間範圍內最常被瀏覽的維基頁面 — 您的熱門內容。';
+$lang['intro_edits'] = '以下是在所選時間範圍內最常被編輯的維基頁面 — 這是當前活動發生的地方。';
+$lang['intro_images'] = '以下是您維基中最常顯示的本地圖片。第三列顯示了每個項目傳輸的總位元組數。';
+$lang['intro_downloads'] = '以下是您維基中最常被下載的本地媒體項目。第三列顯示了每個項目傳輸的總位元組數。';
+$lang['intro_referer'] = '在所有 %d 次外部訪問中,%d 次(%.1f%%)是直接(或來自書籤)訪問,%d 次(%.1f%%)來自搜尋引擎,%d 次(%.1f%%)是通過其他頁面的連結而來。
這些其他頁面列在下方。';
+
+$lang['intro_newreferer'] = '以下的來源連結在所選時間範圍內首次被記錄,且之前從未見過。';
+$lang['intro_outlinks'] = '以下是您維基中最常被點擊的外部網站連結。';
+$lang['intro_searchengines'] = '以下是用戶用來尋找您維基的搜尋引擎。';
+$lang['intro_searchphrases'] = '以下是人們在找到您的維基時使用的確切搜尋詞組。';
+$lang['intro_searchwords'] = '以下是人們在找到您的維基時最常使用的搜尋詞。';
+$lang['intro_internalsearchphrases'] = '以下是人們在您的維基內部搜尋時使用的確切詞組。';
+$lang['intro_internalsearchwords'] = '以下是人們在您的維基內部搜尋時最常使用的詞語。';
+$lang['intro_browsers'] = '以下是您的用戶最常使用的瀏覽器。';
+$lang['intro_os'] = '以下是您的用戶最常使用的平台。';
+$lang['intro_countries'] = '以下是您的用戶來源國家。請注意,將IP地址解析為國家並非完全精確的科學方法。';
+$lang['intro_resolution'] = '此頁面提供有關您用戶的螢幕大小(解析度)的一些資訊。這是他們擁有的螢幕空間,而非瀏覽器顯示區域可用的空間。有關後者,請參閱瀏覽器視窗頁面。所有值都四捨五入到100像素,圖表僅顯示前100個值。';
+$lang['intro_viewport'] = '以下是您的用戶瀏覽器用於渲染您維基的區域大小。所有值都四捨五入到100像素,圖表僅顯示前100個值。';
+$lang['intro_seenusers'] = '這是用戶最後在維基中出現的時間列表,按最後出現日期排序。這與所選時間範圍無關。';
+$lang['intro_history'] = '這些圖表讓您了解在指定時間範圍內,您的維基在條目數量和大小方面的成長情況。請注意,此圖表需要至少數天的時間範圍。';
+$lang['intro_topuser'] = '此頁面顯示在所選時間範圍內,哪些已登入的用戶瀏覽了最多的維基頁面。';
+$lang['intro_topeditor'] = '此頁面顯示在所選時間範圍內,哪些已登入的用戶進行了最多的編輯。';
+$lang['intro_topgroup'] = '以下是在所選時間範圍內,瀏覽最多維基頁面的已登入用戶所屬的群組。請注意,當一個用戶屬於多個群組時,其所有群組都會被計算。';
+$lang['intro_topgroupedit'] = '以下是在所選時間範圍內,進行最多編輯的已登入用戶所屬的群組。請注意,當一個用戶屬於多個群組時,其所有群組都會被計算。';
+
+// 儀表板項目
+$lang['dash_pageviews'] = '%d 次頁面瀏覽';
+$lang['dash_sessions'] = '%d 次訪問(會話)';
+$lang['dash_visitors'] = '%d 位獨立訪客';
+$lang['dash_users'] = '%d 位已登入用戶';
+$lang['dash_logins'] = '%d 次用戶登入';
+$lang['dash_registrations'] = '%s 位新註冊用戶';
+$lang['dash_current'] = '%d 位當前已登入用戶';
+$lang['dash_bouncerate'] = '%.1f%% 跳出率';
+$lang['dash_timespent'] = '平均每次會話停留 %.2f 分鐘';
+$lang['dash_avgpages'] = '平均每次會話瀏覽 %.2f 頁';
+$lang['dash_newvisitors'] = '%.1f%% 新訪客';
+
+$lang['dash_mostpopular'] = '最受歡迎的頁面';
+$lang['dash_newincoming'] = '熱門新增來源連結';
+$lang['dash_topsearch'] = '熱門搜尋詞組';
+
+// 圖表標籤
+$lang['graph_edits'] = 'Page Edits';
+$lang['graph_creates'] = 'Page Creations';
+$lang['graph_deletions'] = 'Page Deletions';
+$lang['graph_views'] = 'Page Views';
+$lang['graph_sessions'] = 'Visits';
+$lang['graph_visitors'] = 'Visitors';
+$lang['graph_page_count'] = 'Pages';
+$lang['graph_page_size'] = 'Pagessize (MB)';
+$lang['graph_media_count'] = 'Media Items';
+$lang['graph_media_size'] = 'Media Item Size (MB)';
diff --git a/lang/zh-tw/settings.php b/lang/zh-tw/settings.php
new file mode 100644
index 0000000..7dd4b3e
--- /dev/null
+++ b/lang/zh-tw/settings.php
@@ -0,0 +1,8 @@
+Logger()->log_access();
$plugin->Logger()->log_session(1);