1<?php
2/**
3 * Download Counter Action Plugin
4 *
5 * @license    GPLv3 (http://www.gnu.org/licenses/gpl.html)
6 * @link       http://www.dokuwiki.org/plugin:dlcount
7 * @author     Markus Birth <markus@birth-online.de>
8 */
9
10if(!defined('DOKU_INC')) die();
11if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
12require_once(DOKU_PLUGIN.'admin.php');
13
14class admin_plugin_dlcount extends DokuWiki_Admin_Plugin {
15
16    const DATADIR = '_media';   // below $conf['metadir'], no trailing slash
17    const SUFFIX  = '.meta';
18
19    /**
20     * return some info
21     */
22    function getInfo(){
23        return confToHash(dirname(__FILE__).'/INFO.txt');
24    }
25
26    /**
27     * return true if the plugin should only be accessed by wiki admins (default: true)
28     */
29//    function forAdminOnly() {
30//        return true;
31//    }
32
33    /**
34     * return the menu string to be displayed in the main admin menu
35     */
36//    function getMenuText($language) {
37//        return 'dlcount';
38//    }
39
40    /**
41     * return sort order for position in admin menu
42     */
43//    function getMenuSort() {
44//        return 999;
45//    }
46
47    function glob_recursive($mask) {
48        $result = glob($mask);
49        if ($result === false) return array();
50        $dirs = explode(DIRECTORY_SEPARATOR, $mask);
51        $dirmask = array_pop($dirs);
52        $dirs  = glob(implode(DIRECTORY_SEPARATOR, $dirs) . '/*', GLOB_ONLYDIR);
53        if ($dirs === false) return $result;
54        foreach ($dirs as $dir) {
55            $partresult = $this->glob_recursive($dir . '/' . $dirmask);
56            $result = array_merge($result, $partresult);
57        }
58        return $result;
59    }
60
61    /**
62     * handle user request
63     */
64    function handle() {
65        global $conf;
66        $mediametadir = $conf['metadir'] . '/' . self::DATADIR;
67        $this->mediafiles = $this->glob_recursive($conf['mediadir'] . '/*.*');
68        $this->dlcount = array();
69        $this->lastdl  = array();
70        foreach ($this->mediafiles as $idx=>$mediafile) {
71            list ($ext, $mime, $dl) = mimetype($mediafile);
72            // skip images as their downloads are NOT counted
73            if (substr($mime, 0, 5) == 'image') {
74                unset($this->mediafiles[$idx]);
75                continue;
76            }
77            $mediaWN = $this->getWNfromMediaFN($mediafile);
78            $metaFN = $mediametadir . '/' . str_replace(':', DIRECTORY_SEPARATOR, $mediaWN) . self::SUFFIX;
79            if (!file_exists($metaFN)) {
80                $this->dlcount[$mediaWN] = 0;
81                $this->lastdl[$mediaWN] = -1;
82            } else {
83                $meta = unserialize(io_readFile($metaFN, false));
84                $this->dlcount[$mediaWN] = $meta['dlcount'];
85                $this->lastdl[$mediaWN]  = $meta['lastdl'];
86            }
87        }
88        arsort($this->dlcount);
89        arsort($this->lastdl);
90    }
91
92    /**
93     * output appropriate html
94     */
95    function html() {
96        ptln(sprintf($this->getLang('mediafiles_found'), count($this->mediafiles)) . '<br /><br />');
97        ptln('<strong>' . $this->getLang('top_dl_files') . ':</strong><br />');
98        ptln('<table class="inline"><tr><th>#</th><th>' . $this->getLang('filename') . '</th><th>' . $this->getLang('downloads') . '</th><th>' . $this->getLang('last_download') . '</th></tr>');
99        $top = 1;
100        foreach ($this->dlcount as $fn=>$dlc) {
101            $lastdl = $this->getLang('never');
102            $lastdltime = $this->time_translate(time() - $this->lastdl[$fn]);
103            if ($this->lastdl[$fn] > 0) $lastdl = sprintf($this->getLang('ago'), $lastdltime);
104            ptln('<tr><th class="rightalign">' . $top++ . '</th><td>' . $fn . '</td><td class="rightalign">' . $dlc . '</td><td class="rightalign">' . $lastdl . '</td></tr>');
105            if ($top > $this->getConf('top_n_statistics')) break;
106        }
107        ptln('</table><br /><br />');
108
109        ptln('<strong>' . $this->getLang('most_recent_dl_files') . ':</strong><br />');
110        ptln('<table class="inline"><tr><th>#</th><th>' . $this->getLang('filename') . '</th><th>' . $this->getLang('downloads') . '</th><th>' . $this->getLang('last_download') . '</th></tr>');
111        $top = 1;
112        foreach ($this->lastdl as $fn=>$dlt) {
113            $lastdl = $this->getLang('never');
114            $lastdltime = $this->time_translate(time() - $dlt);
115            if ($dlt > 0) $lastdl = sprintf($this->getLang('ago'), $lastdltime);
116            ptln('<tr><th class="rightalign">' . $top++ . '</th><td>' . $fn . '</td><td class="rightalign">' . $this->dlcount[$fn] . '</td><td class="rightalign">' . $lastdl . '</td></tr>');
117            if ($top > $this->getConf('top_n_statistics')) break;
118        }
119        ptln('</table><br /><br />');
120
121        ptln('<strong>' . $this->getLang('least_recent_dl_files') . ':</strong><br />');
122        ptln('<table class="inline"><tr><th>#</th><th>' . $this->getLang('filename') . '</th><th>' . $this->getLang('downloads') . '</th><th>' . $this->getLang('last_download') . '</th></tr>');
123        $top = count($this->lastdl);
124        foreach (array_reverse($this->lastdl) as $fn=>$dlt) {
125            $lastdl = $this->getLang('never');
126            $lastdltime = $this->time_translate(time() - $dlt);
127            if ($dlt > 0) $lastdl = sprintf($this->getLang('ago'), $lastdltime);
128            ptln('<tr><th class="rightalign">' . $top-- . '</th><td>' . $fn . '</td><td class="rightalign">' . $this->dlcount[$fn] . '</td><td class="rightalign">' . $lastdl . '</td></tr>');
129            if ($top <= count($this->lastdl)-$this->getConf('top_n_statistics')) break;
130        }
131        ptln('</table><br /><br />');
132    }
133
134    function getWNfromMetaFN($metafn) {
135        $fixedpos = strpos($metafn, '/'.self::DATADIR.'/')+strlen('/'.self::DATADIR);
136        $wn = substr($metafn, $fixedpos);
137        $wn = str_replace(DIRECTORY_SEPARATOR, ':', $wn);
138        return $wn;
139    }
140
141    function getWNfromMediaFN($mediafn) {
142        global $conf;
143        $fixedpos = strpos($mediafn, '/'.$conf['mediadir'].'/') + strlen('/'.$conf['mediadir']);
144        $wn = substr($mediafn, $fixedpos);
145        $wn = str_replace(DIRECTORY_SEPARATOR, ':', $wn);
146        return $wn;
147    }
148
149    // BEGIN: borrowed and modified from http://de3.php.net/manual/en/function.filesize.php
150    function size_translate($filesize) {
151        $array = array(
152            'TiB' => 1024 * 1024 * 1024 * 1024,
153            'GiB' => 1024 * 1024 * 1024,
154            'MiB' => 1024 * 1024,
155            'KiB' => 1024,
156        );
157        if($filesize <= 1024) {
158            return $filesize . ' B';
159        }
160        foreach ($array as $name=>$size) {
161            if($filesize >= $size) {
162                return round((round($filesize / $size * 100) / 100), 2) . ' ' . $name;
163            }
164        }
165        return $filesize;
166    }
167    // END: borrowed and modified from http://de3.php.net/manual/en/function.filesize.php
168
169
170    // BEGIN: borrowed and modified from http://de3.php.net/manual/en/function.filesize.php
171    function time_translate($seconds) {
172        $array = array(
173            'y' => 60 * 60 * 24 * 365.25,
174            'M' => 60 * 60 * 24 * 30.5,
175            'w' => 60 * 60 * 24 * 7,
176            'd' => 60 * 60 * 24,
177            'h' => 60 * 60,
178            'm' => 60,
179            's' => 1,
180        );
181        foreach ($array as $name=>$secs) {
182            if ($seconds < $secs && $secs != end($array)) continue;
183            $resv = floor($seconds / $secs);
184            $res .= ' ' . $resv . $name;
185            $seconds -= $resv*$secs;
186        }
187        return trim($res);
188    }
189    // END: borrowed and modified from http://de3.php.net/manual/en/function.filesize.php
190
191}