Completed
Push — sidebaracl ( 7a112d...7c3e4a )
by Andreas
04:38
created

helper_plugin_popularity   B

Complexity

Total Complexity 41

Size/Duplication

Total Lines 333
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 3
Metric Value
wmc 41
lcom 2
cbo 3
dl 0
loc 333
rs 8.2769

10 Methods

Rating   Name   Duplication   Size   Complexity  
A isAutoSubmitEnabled() 0 3 1
A gatherAsString() 0 12 4
A _add_plugin_usage_data() 0 13 4
A __construct() 0 6 1
B getMethods() 0 29 1
A sendData() 0 9 2
A lastSentTime() 0 6 1
F _gather() 0 126 11
C _search_count() 0 21 10
B _to_byte() 0 22 6

How to fix   Complexity   

Complex Class

Complex classes like helper_plugin_popularity often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use helper_plugin_popularity, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Popularity Feedback Plugin
4
 *
5
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6
 */
7
8
class helper_plugin_popularity extends Dokuwiki_Plugin {
9
    /**
10
     * The url where the data should be sent
11
     */
12
    var $submitUrl = 'http://update.dokuwiki.org/popularity.php';
13
14
    /**
15
     * Name of the file which determine if the the autosubmit is enabled,
16
     * and when it was submited for the last time
17
     */
18
    var $autosubmitFile;
19
20
    /**
21
     * File where the last error which happened when we tried to autosubmit, will be log
22
     */
23
    var $autosubmitErrorFile;
24
25
    /**
26
     * Name of the file which determine when the popularity data was manually
27
     * submitted for the last time
28
     * (If this file doesn't exist, the data has never been sent)
29
     */
30
    var $popularityLastSubmitFile;
31
32
33
    function __construct(){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
34
        global $conf;
35
        $this->autosubmitFile = $conf['cachedir'].'/autosubmit.txt';
36
        $this->autosubmitErrorFile = $conf['cachedir'].'/autosubmitError.txt';
37
        $this->popularityLastSubmitFile = $conf['cachedir'].'/lastSubmitTime.txt';
38
    }
39
40
    /**
41
     * Return methods of this helper
42
     *
43
     * @return array with methods description
44
     */
45
    function getMethods(){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
46
        $result = array();
47
        $result[] = array(
48
                'name'   => 'isAutoSubmitEnabled',
49
                'desc'   => 'Check if autosubmit is enabled',
50
                'params' => array(),
51
                'return' => array('result' => 'bool')
52
                );
53
        $result[] = array(
54
                'name'   => 'sendData',
55
                'desc'   => 'Send the popularity data',
56
                'params' => array('data' => 'string'),
57
                'return' => array()
58
                );
59
        $result[] = array(
60
                'name' => 'gatherAsString',
61
                'desc' => 'Gather the popularity data',
62
                'params' => array(),
63
                'return' => array('data' => 'string')
64
                );
65
        $result[] = array(
66
                'name'   => 'lastSentTime',
67
                'desc'   => 'Compute the last time popularity data was sent',
68
                'params' => array(),
69
                'return' => array('data' => 'int')
70
                );
71
        return $result;
72
73
    }
74
75
    /**
76
     * Check if autosubmit is enabled
77
     *
78
     * @return boolean TRUE if we should send data once a month, FALSE otherwise
79
     */
80
    function isAutoSubmitEnabled(){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
81
        return file_exists($this->autosubmitFile);
82
    }
83
84
    /**
85
     * Send the data, to the submit url
86
     *
87
     * @param string $data The popularity data
88
     * @return string An empty string if everything worked fine, a string describing the error otherwise
89
     */
90
    function sendData($data){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
91
        $error = '';
92
        $httpClient = new DokuHTTPClient();
93
        $status = $httpClient->sendRequest($this->submitUrl, array('data' => $data), 'POST');
94
        if ( ! $status ){
95
            $error = $httpClient->error;
0 ignored issues
show
Bug introduced by
The property error cannot be accessed from this context as it is declared private in class HTTPClient.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
96
        }
97
        return $error;
98
    }
99
100
    /**
101
     * Compute the last time the data was sent. If it has never been sent, we return 0.
102
     *
103
     * @return int
104
     */
105
    function lastSentTime(){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
106
        $manualSubmission = @filemtime($this->popularityLastSubmitFile);
107
        $autoSubmission   = @filemtime($this->autosubmitFile);
108
109
        return max((int) $manualSubmission, (int) $autoSubmission);
110
    }
111
112
    /**
113
     * Gather all information
114
     *
115
     * @return string The popularity data as a string
116
     */
117
    function gatherAsString(){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
118
        $data = $this->_gather();
119
        $string = '';
120
        foreach($data as $key => $val){
121
            if(is_array($val)) foreach($val as $v){
122
                $string .=  hsc($key)."\t".hsc($v)."\n";
123
            }else{
124
                $string .= hsc($key)."\t".hsc($val)."\n";
125
            }
126
        }
127
        return $string;
128
    }
129
130
    /**
131
     * Gather all information
132
     *
133
     * @return array The popularity data as an array
134
     */
135
    function _gather(){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
136
        global $conf;
137
        /** @var $auth DokuWiki_Auth_Plugin */
138
        global $auth;
139
        $data = array();
140
        $phptime = ini_get('max_execution_time');
141
        @set_time_limit(0);
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
142
        $pluginInfo = $this->getInfo();
143
144
        // version
145
        $data['anon_id'] = md5(auth_cookiesalt());
146
        $data['version'] = getVersion();
147
        $data['popversion'] = $pluginInfo['date'];
148
        $data['language'] = $conf['lang'];
149
        $data['now']      = time();
150
        $data['popauto']  = (int) $this->isAutoSubmitEnabled();
151
152
        // some config values
153
        $data['conf_useacl']   = $conf['useacl'];
154
        $data['conf_authtype'] = $conf['authtype'];
155
        $data['conf_template'] = $conf['template'];
156
157
        // number and size of pages
158
        $list = array();
159
        search($list,$conf['datadir'],array($this,'_search_count'),array('all'=>false),'');
160
        $data['page_count']    = $list['file_count'];
161
        $data['page_size']     = $list['file_size'];
162
        $data['page_biggest']  = $list['file_max'];
163
        $data['page_smallest'] = $list['file_min'];
164
        $data['page_nscount']  = $list['dir_count'];
165
        $data['page_nsnest']   = $list['dir_nest'];
166
        if($list['file_count']) $data['page_avg'] = $list['file_size'] / $list['file_count'];
167
        $data['page_oldest']   = $list['file_oldest'];
168
        unset($list);
169
170
        // number and size of media
171
        $list = array();
172
        search($list,$conf['mediadir'],array($this,'_search_count'),array('all'=>true));
173
        $data['media_count']    = $list['file_count'];
174
        $data['media_size']     = $list['file_size'];
175
        $data['media_biggest']  = $list['file_max'];
176
        $data['media_smallest'] = $list['file_min'];
177
        $data['media_nscount']  = $list['dir_count'];
178
        $data['media_nsnest']   = $list['dir_nest'];
179
        if($list['file_count']) $data['media_avg'] = $list['file_size'] / $list['file_count'];
180
        unset($list);
181
182
        // number and size of cache
183
        $list = array();
184
        search($list,$conf['cachedir'],array($this,'_search_count'),array('all'=>true));
185
        $data['cache_count']    = $list['file_count'];
186
        $data['cache_size']     = $list['file_size'];
187
        $data['cache_biggest']  = $list['file_max'];
188
        $data['cache_smallest'] = $list['file_min'];
189
        if($list['file_count']) $data['cache_avg'] = $list['file_size'] / $list['file_count'];
190
        unset($list);
191
192
        // number and size of index
193
        $list = array();
194
        search($list,$conf['indexdir'],array($this,'_search_count'),array('all'=>true));
195
        $data['index_count']    = $list['file_count'];
196
        $data['index_size']     = $list['file_size'];
197
        $data['index_biggest']  = $list['file_max'];
198
        $data['index_smallest'] = $list['file_min'];
199
        if($list['file_count']) $data['index_avg'] = $list['file_size'] / $list['file_count'];
200
        unset($list);
201
202
        // number and size of meta
203
        $list = array();
204
        search($list,$conf['metadir'],array($this,'_search_count'),array('all'=>true));
205
        $data['meta_count']    = $list['file_count'];
206
        $data['meta_size']     = $list['file_size'];
207
        $data['meta_biggest']  = $list['file_max'];
208
        $data['meta_smallest'] = $list['file_min'];
209
        if($list['file_count']) $data['meta_avg'] = $list['file_size'] / $list['file_count'];
210
        unset($list);
211
212
        // number and size of attic
213
        $list = array();
214
        search($list,$conf['olddir'],array($this,'_search_count'),array('all'=>true));
215
        $data['attic_count']    = $list['file_count'];
216
        $data['attic_size']     = $list['file_size'];
217
        $data['attic_biggest']  = $list['file_max'];
218
        $data['attic_smallest'] = $list['file_min'];
219
        if($list['file_count']) $data['attic_avg'] = $list['file_size'] / $list['file_count'];
220
        $data['attic_oldest']   = $list['file_oldest'];
221
        unset($list);
222
223
        // user count
224
        if($auth && $auth->canDo('getUserCount')){
225
            $data['user_count'] = $auth->getUserCount();
226
        }
227
228
        // calculate edits per day
229
        $list = @file($conf['metadir'].'/_dokuwiki.changes');
230
        $count = count($list);
231
        if($count > 2){
232
            $first = (int) substr(array_shift($list),0,10);
233
            $last  = (int) substr(array_pop($list),0,10);
234
            $dur = ($last - $first)/(60*60*24); // number of days in the changelog
235
            $data['edits_per_day'] = $count/$dur;
236
        }
237
        unset($list);
238
239
        // plugins
240
        $data['plugin'] = plugin_list();
241
242
        // pcre info
243
        if(defined('PCRE_VERSION')) $data['pcre_version'] = PCRE_VERSION;
244
        $data['pcre_backtrack'] = ini_get('pcre.backtrack_limit');
245
        $data['pcre_recursion'] = ini_get('pcre.recursion_limit');
246
247
        // php info
248
        $data['os'] = PHP_OS;
249
        $data['webserver'] = $_SERVER['SERVER_SOFTWARE'];
250
        $data['php_version'] = phpversion();
251
        $data['php_sapi'] = php_sapi_name();
252
        $data['php_memory'] = $this->_to_byte(ini_get('memory_limit'));
253
        $data['php_exectime'] = $phptime;
254
        $data['php_extension'] = get_loaded_extensions();
255
256
        // plugin usage data
257
        $this->_add_plugin_usage_data($data);
258
259
        return $data;
260
    }
261
262
    protected function _add_plugin_usage_data(&$data){
263
        $pluginsData = array();
264
        trigger_event('PLUGIN_POPULARITY_DATA_SETUP', $pluginsData);
265
        foreach($pluginsData as $plugin => $d){
266
           if ( is_array($d) ) {
267
               foreach($d as $key => $value){
268
                   $data['plugin_' . $plugin . '_' . $key] = $value;
269
               }
270
           } else {
271
               $data['plugin_' . $plugin] = $d;
272
           }
273
        }
274
    }
275
276
    /**
277
     * Callback to search and count the content of directories in DokuWiki
278
     *
279
     * @param array &$data  Reference to the result data structure
280
     * @param string $base  Base usually $conf['datadir']
281
     * @param string $file  current file or directory relative to $base
282
     * @param string $type  Type either 'd' for directory or 'f' for file
283
     * @param int    $lvl   Current recursion depht
284
     * @param array  $opts  option array as given to search()
285
     * @return bool
286
     */
287
    function _search_count(&$data,$base,$file,$type,$lvl,$opts){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
288
        // traverse
289
        if($type == 'd'){
290
            if($data['dir_nest'] < $lvl) $data['dir_nest'] = $lvl;
291
            $data['dir_count']++;
292
            return true;
293
        }
294
295
        //only search txt files if 'all' option not set
296
        if($opts['all'] || substr($file,-4) == '.txt'){
297
            $size = filesize($base.'/'.$file);
298
            $date = filemtime($base.'/'.$file);
299
            $data['file_count']++;
300
            $data['file_size'] += $size;
301
            if(!isset($data['file_min']) || $data['file_min'] > $size) $data['file_min'] = $size;
302
            if($data['file_max'] < $size) $data['file_max'] = $size;
303
            if(!isset($data['file_oldest']) || $data['file_oldest'] > $date) $data['file_oldest'] = $date;
304
        }
305
306
        return false;
307
    }
308
309
    /**
310
     * Convert php.ini shorthands to byte
311
     *
312
     * @author <gilthans dot NO dot SPAM at gmail dot com>
313
     * @link   http://de3.php.net/manual/en/ini.core.php#79564
314
     *
315
     * @param string $v
316
     * @return int|string
317
     */
318
    function _to_byte($v){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
319
        $l = substr($v, -1);
320
        $ret = substr($v, 0, -1);
321
        switch(strtoupper($l)){
322
            /** @noinspection PhpMissingBreakStatementInspection */
323
            case 'P':
324
                $ret *= 1024;
325
            /** @noinspection PhpMissingBreakStatementInspection */
326
            case 'T':
327
                $ret *= 1024;
328
            /** @noinspection PhpMissingBreakStatementInspection */
329
            case 'G':
330
                $ret *= 1024;
331
            /** @noinspection PhpMissingBreakStatementInspection */
332
            case 'M':
333
                $ret *= 1024;
334
            case 'K':
335
                $ret *= 1024;
336
            break;
337
        }
338
        return $ret;
339
    }
340
}
341