1<?php 2// must be run within Dokuwiki 3if (!defined('DOKU_INC')) die(); 4 5/** 6 * statdisplay plugin table helper component 7 * 8 * @author Andreas Gohr <gohr@cosmocode.de> 9 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 10 */ 11class helper_plugin_statdisplay_table extends DokuWiki_Plugin 12{ 13 /** @var helper_plugin_statdisplay_log */ 14 private $log = null; 15 16 /** @var Doku_Renderer */ 17 private $R = null; 18 19 /** 20 * @param Doku_Renderer $R 21 * @param string $command type of statistic 22 * @param string $from restrict to this month 23 * @param string $to end interval 24 * @return void 25 */ 26 public function table($R, $command, $from = '', $to = '') 27 { 28 $this->R = $R; 29 $this->log = plugin_load('helper', 'statdisplay_log'); 30 31 switch ($command) { 32 case 'all': 33 $this->summary($from, $to); 34 break; 35 case 'one month': 36 $this->month($from); 37 break; 38 case 'month by day': 39 $this->monthby('day', $from); 40 break; 41 case 'month by hour': 42 $this->monthby('hour', $from); 43 break; 44 case 'top referers': 45 $this->referer($from); 46 break; 47 case 'top entries': 48 $this->entry($from); 49 break; 50 case 'top urls': 51 $this->url($from); 52 break; 53 case 'top bytes': 54 break; 55 case 'user agents': 56 $this->ua($from); 57 break; 58 case 'progress bar': 59 $this->progress(); 60 break; 61 case 'traffic by user': 62 $this->userdownloads($from); 63 break; 64 default: 65 $R->cdata('No such table: ' . $command); 66 67 } 68 } 69 70 private function progress() 71 { 72 $pct = sprintf('%.2f', $this->log->progress()); 73 $this->R->doc .= '<div class="statdisplay-progress" title="' . $pct . '%"><span style="width: ' . $pct . '%"></span></div>'; 74 } 75 76 /** 77 * Print referers for a given month 78 * 79 * @param string $date 80 */ 81 private function referer($date = '') 82 { 83 if (!$date) $date = date('Y-m'); 84 $this->listtable( 85 $this->log->logdata[$date]['referer_url'], 86 $this->log->logdata[$date]['referer']['count'], 87 sprintf($this->getLang('t_topReferrer'), $date) 88 ); 89 } 90 91 /** 92 * Print top entry pages for a given month 93 * 94 * @param string $date 95 */ 96 private function entry($date = '') 97 { 98 if (!$date) $date = date('Y-m'); 99 $this->listtable( 100 $this->log->logdata[$date]['entry'], 101 $this->log->logdata[$date]['page']['all']['count'], 102 sprintf($this->getLang('t_topEntry'), $date) 103 ); 104 } 105 106 /** 107 * Print top user agents for a given month 108 * 109 * @param string $date 110 */ 111 private function ua($date = '') 112 { 113 if (!$date) $date = date('Y-m'); 114 $this->listtable( 115 $this->log->logdata[$date]['useragent'], 116 $this->log->logdata[$date]['page']['all']['count'], 117 sprintf($this->getLang('t_topUserAgents'), $date) 118 ); 119 } 120 121 /** 122 * Print top pages for a given month 123 * 124 * @param string $date 125 */ 126 private function url($date = '') 127 { 128 if (!$date) $date = date('Y-m'); 129 $this->listtable( 130 $this->log->logdata[$date]['page_url'], 131 $this->log->logdata[$date]['page']['all']['count'], 132 sprintf($this->getLang('t_topPages'), $date) 133 ); 134 } 135 136 /** 137 * Print daily or hourly statistics 138 * 139 * @param string $by either 'day' or 'hour' 140 * @param string $date 141 */ 142 private function monthby($by, $date = '') 143 { 144 if (!$date) $date = date('Y-m'); 145 $data = $this->log->logdata[$date]; 146 147 $title = sprintf($this->getLang('t_' . $by), $date); 148 149 $this->R->table_open(); 150 151 $this->R->tablerow_open(); 152 $this->head($title, 11); 153 $this->R->tablerow_close(); 154 155 $this->R->tablerow_open(); 156 $this->head($this->getLang($by)); 157 $this->head($this->getLang('hits'), 2); 158 $this->head($this->getLang('media'), 2); 159 $this->head($this->getLang('pages'), 2); 160 $this->head($this->getLang('visitors'), 2); 161 $this->head($this->getLang('traffic'), 2); 162 $this->R->tablerow_close(); 163 164 $keys = array_keys((array)$data['hits'][$by]); 165 sort($keys); 166 foreach ($keys as $idx) { 167 $this->R->tablerow_open(); 168 $this->hcell($idx); 169 170 $this->cell($data['hits'][$by][$idx]['count']); 171 $this->cell($this->pct($data['hits'][$by][$idx]['count'], $data['hits']['all']['count'])); 172 173 $this->cell($data['media'][$by][$idx]['count']); 174 $this->cell($this->pct($data['media'][$by][$idx]['count'], $data['media']['all']['count'])); 175 176 $this->cell($data['page'][$by][$idx]['count']); 177 $this->cell($this->pct($data['page'][$by][$idx]['count'], $data['page']['all']['count'])); 178 179 $this->cell($data['hits'][$by][$idx]['visitor']); 180 $this->cell($this->pct($data['hits'][$by][$idx]['visitor'], $data['hits']['all']['visitor'])); 181 182 $this->cell(filesize_h($data['hits'][$by][$idx]['bytes'])); 183 $this->cell($this->pct($data['hits'][$by][$idx]['bytes'], $data['hits']['all']['bytes'])); 184 185 $this->R->tablerow_close(); 186 } 187 188 $this->R->table_close(); 189 } 190 191 /** 192 * print a single month 193 * 194 * @param $date 195 */ 196 private function month($date = '') 197 { 198 if (!$date) $date = date('Y-m'); 199 $data = $this->log->logdata[$date]; 200 201 $this->R->table_open(); 202 203 $this->R->tablerow_open(); 204 $this->head(sprintf($this->getLang('t_statisticMonth'), $date), 3); 205 $this->R->tablerow_close(); 206 207 $this->R->tablerow_open(); 208 $this->hcell($this->getLang('totalHits')); 209 $this->cell($data['page']['all']['count'] + $data['media']['all']['count'], 2); 210 $this->R->tablerow_close(); 211 212 $this->R->tablerow_open(); 213 $this->hcell($this->getLang('totalFiles')); 214 $this->cell($data['media']['all']['count'], 2); 215 $this->R->tablerow_close(); 216 217 $this->R->tablerow_open(); 218 $this->hcell($this->getLang('totalPages')); 219 $this->cell($data['page']['all']['count'], 2); 220 $this->R->tablerow_close(); 221 222 $this->R->tablerow_open(); 223 $this->hcell($this->getLang('totalVisitors')); 224 $this->cell($data['page']['all']['visitor'], 2); 225 $this->R->tablerow_close(); 226 227 $this->R->tablerow_open(); 228 $this->hcell($this->getLang('totalBytes')); 229 $this->cell(filesize_h($data['page']['all']['bytes']), 2); 230 $this->R->tablerow_close(); 231 232 $this->R->tablerow_open(); 233 $this->head(''); 234 $this->head($this->getLang('avg')); 235 $this->head($this->getLang('max')); 236 $this->R->tablerow_close(); 237 238 $this->R->tablerow_open(); 239 $this->hcell($this->getLang('hitsHour')); 240 $this->cell($this->log->avg($data['hits']['hour'], 'count')); 241 $this->cell($this->log->max($data['hits']['hour'], 'count')); 242 $this->R->tablerow_close(); 243 244 $this->R->tablerow_open(); 245 $this->hcell($this->getLang('hitsDay')); 246 $this->cell($this->log->avg($data['hits']['day'], 'count')); 247 $this->cell($this->log->max($data['hits']['day'], 'count')); 248 $this->R->tablerow_close(); 249 250 $this->R->tablerow_open(); 251 $this->hcell($this->getLang('filesDay')); 252 $this->cell($this->log->avg($data['media']['day'], 'count')); 253 $this->cell($this->log->max($data['media']['day'], 'count')); 254 $this->R->tablerow_close(); 255 256 $this->R->tablerow_open(); 257 $this->hcell($this->getLang('pagesDay')); 258 $this->cell($this->log->avg($data['page']['day'], 'count')); 259 $this->cell($this->log->max($data['page']['day'], 'count')); 260 $this->R->tablerow_close(); 261 262 $this->R->tablerow_open(); 263 $this->hcell($this->getLang('bytesDay')); 264 $this->cell(filesize_h($this->log->avg($data['hits']['day'], 'bytes'))); 265 $this->cell(filesize_h($this->log->max($data['hits']['day'], 'bytes'))); 266 $this->R->tablerow_close(); 267 268 $this->R->tablerow_open(); 269 $this->head($this->getLang('hitsStatusCode'), 3); 270 $this->R->tablerow_close(); 271 272 foreach ((array)$this->log->logdata[$date]['status']['all'] as $code => $count) { 273 $this->R->tablerow_open(); 274 $this->hcell('Status ' . $code . ' - ' . $this->getLang('status_' . $code)); 275 $this->cell($count, 2); 276 $this->R->tablerow_close(); 277 } 278 279 $this->R->table_close(); 280 } 281 282 /** 283 * print the whole summary table 284 * 285 * @param string $from unused 286 * @param string $to unsused 287 */ 288 private function summary($from = '', $to = '') 289 { 290 $this->R->table_open(); 291 292 $this->R->tablerow_open(); 293 $this->head($this->getLang('summaryMonth'), 10); 294 $this->R->tablerow_close(); 295 296 $this->R->tablerow_open(); 297 $this->head($this->getLang('month'), 1, 2); 298 $this->head($this->getLang('dailyavg'), 4); 299 $this->head($this->getLang('totals'), 5); 300 $this->R->tablerow_close(); 301 302 $this->R->tablerow_open(); 303 $this->head($this->getLang('hits')); 304 $this->head($this->getLang('files')); 305 $this->head($this->getLang('pages')); 306 $this->head($this->getLang('visitors')); 307 $this->head($this->getLang('hits')); 308 $this->head($this->getLang('files')); 309 $this->head($this->getLang('pages')); 310 $this->head($this->getLang('visitors')); 311 $this->head($this->getLang('bytes')); 312 313 $this->R->tablerow_close(); 314 315 foreach ((array)$this->log->logdata as $month => $data) { 316 if ($month[0] == '_') continue; 317 if (!empty($from) && $month < $from) continue; 318 if (!empty($to) && $month > $to) break; 319 320 321 322 323 $this->R->tablerow_open(); 324 325 $this->cell($month, 1, false); // Month 326 // ---- averages ---- 327 $this->cell(round($this->log->avg($data['hits']['day'] ?? [], 'count'))); // Hits 328 $this->cell(round($this->log->avg($data['media']['day'] ?? [], 'count'))); // Files 329 $this->cell(round($this->log->avg($data['page']['day'] ?? [], 'count'))); // Pages 330 $this->cell(round($this->log->avg($data['hits']['day'] ?? [], 'visitor'))); // Visits 331 // ---- totals ---- 332 $this->cell($data['hits']['all']['count']); // Hits 333 $this->cell($data['media']['all']['count']); // Files 334 $this->cell($data['page']['all']['count']); // Pages 335 $this->cell($data['hits']['all']['visitor']); // Visitors 336 $this->cell(filesize_h($data['hits']['all']['bytes'])); // kBytes 337 338 $this->R->tablerow_close(); 339 } 340 341 $this->R->table_close(); 342 } 343 344 /** 345 * @param string $date month to display 346 */ 347 private function userdownloads($date) 348 { 349 $usertraffic = $this->log->usertraffic($date); 350 351 $this->listtable($usertraffic, $this->log->sum($usertraffic), $this->getLang('t_usertraffic'), true); 352 } 353 354 /** 355 * Print a simple listing table 356 * 357 * @param array $data 358 * @param float $max 359 * @param string $title 360 * @param bool $istraffic 361 * @return void 362 */ 363 private function listtable(&$data, $max, $title, $istraffic = false) 364 { 365 if (!$data) $data = array(); 366 367 arsort($data); 368 $row = 1; 369 370 $this->R->table_open(); 371 372 $this->R->tablerow_open(); 373 $this->head($title, 4); 374 $this->R->tablerow_close(); 375 376 $this->R->tablerow_open(); 377 $this->head('#'); 378 $this->head($this->getLang('name')); 379 if ($istraffic) { 380 $this->head($this->getLang('traffic'), 2); 381 } else { 382 $this->head($this->getLang('hits'), 2); 383 } 384 $this->R->tablerow_close(); 385 386 foreach ($data as $key => $count) { 387 if ($istraffic) { 388 $val = filesize_h($count); 389 } else { 390 $val = $count; 391 } 392 393 $this->R->tablerow_open(); 394 $this->cell($row); 395 $this->hcell($key); 396 $this->cell($val); 397 $this->cell($this->pct($count, $max)); 398 $this->R->tablerow_close(); 399 $row++; 400 if ($row > $this->log->top_limit) break; 401 } 402 403 $this->R->table_close(); 404 } 405 406 /** 407 * Calculate and format a percent value 408 * 409 * @param $val 410 * @param $max 411 * @return string 412 */ 413 private function pct($val, $max) 414 { 415 if (!$max) return '0.00%'; 416 417 return sprintf("%.2f%%", $val * 100 / $max); 418 } 419 420 /** 421 * print a table header cell 422 * 423 * @param string $data 424 * @param int $col 425 * @param int $row 426 */ 427 private function head($data = '', $col = 1, $row = 1) 428 { 429 $this->R->tableheader_open($col, 'center', $row); 430 $this->R->cdata($data); 431 $this->R->tableheader_close(); 432 } 433 434 /** 435 * print a non numeric data cell 436 * 437 * @param string $data 438 * @param int $span 439 */ 440 private function hcell($data = '', $span = 1) 441 { 442 $this->cell($data, $span, false); 443 } 444 445 /** 446 * print a numeric data cell 447 * 448 * @param string $data 449 * @param int $span 450 * @param bool $number 451 */ 452 private function cell($data = '', $span = 1, $number = true) 453 { 454 if ($number) { 455 if (!$data) $data = 0; 456 $align = 'right'; 457 } else { 458 $align = null; 459 } 460 461 $this->R->tablecell_open($span, $align); 462 $this->R->cdata($data); 463 $this->R->tablecell_close(); 464 } 465} 466