1<?php 2/** 3 * Popularity Feedback Plugin 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 */ 7 8class helper_plugin_popularity extends Dokuwiki_Plugin 9{ 10 /** 11 * The url where the data should be sent 12 */ 13 public $submitUrl = 'http://update.dokuwiki.org/popularity.php'; 14 15 /** 16 * Name of the file which determine if the the autosubmit is enabled, 17 * and when it was submited for the last time 18 */ 19 public $autosubmitFile; 20 21 /** 22 * File where the last error which happened when we tried to autosubmit, will be log 23 */ 24 public $autosubmitErrorFile; 25 26 /** 27 * Name of the file which determine when the popularity data was manually 28 * submitted for the last time 29 * (If this file doesn't exist, the data has never been sent) 30 */ 31 public $popularityLastSubmitFile; 32 33 /** 34 * helper_plugin_popularity constructor. 35 */ 36 public function __construct() 37 { 38 global $conf; 39 $this->autosubmitFile = $conf['cachedir'].'/autosubmit.txt'; 40 $this->autosubmitErrorFile = $conf['cachedir'].'/autosubmitError.txt'; 41 $this->popularityLastSubmitFile = $conf['cachedir'].'/lastSubmitTime.txt'; 42 } 43 44 /** 45 * Check if autosubmit is enabled 46 * 47 * @return boolean TRUE if we should send data once a month, FALSE otherwise 48 */ 49 public function isAutoSubmitEnabled() 50 { 51 return file_exists($this->autosubmitFile); 52 } 53 54 /** 55 * Send the data, to the submit url 56 * 57 * @param string $data The popularity data 58 * @return string An empty string if everything worked fine, a string describing the error otherwise 59 */ 60 public function sendData($data) 61 { 62 $error = ''; 63 $httpClient = new DokuHTTPClient(); 64 $status = $httpClient->sendRequest($this->submitUrl, array('data' => $data), 'POST'); 65 if (! $status) { 66 $error = $httpClient->error; 67 } 68 return $error; 69 } 70 71 /** 72 * Compute the last time the data was sent. If it has never been sent, we return 0. 73 * 74 * @return int 75 */ 76 public function lastSentTime() 77 { 78 $manualSubmission = @filemtime($this->popularityLastSubmitFile); 79 $autoSubmission = @filemtime($this->autosubmitFile); 80 81 return max((int) $manualSubmission, (int) $autoSubmission); 82 } 83 84 /** 85 * Gather all information 86 * 87 * @return string The popularity data as a string 88 */ 89 public function gatherAsString() 90 { 91 $data = $this->gather(); 92 $string = ''; 93 foreach ($data as $key => $val) { 94 if (is_array($val)) foreach ($val as $v) { 95 $string .= hsc($key)."\t".hsc($v)."\n"; 96 } else { 97 $string .= hsc($key)."\t".hsc($val)."\n"; 98 } 99 } 100 return $string; 101 } 102 103 /** 104 * Gather all information 105 * 106 * @return array The popularity data as an array 107 */ 108 protected function gather() 109 { 110 global $conf; 111 /** @var $auth DokuWiki_Auth_Plugin */ 112 global $auth; 113 $data = array(); 114 $phptime = ini_get('max_execution_time'); 115 @set_time_limit(0); 116 $pluginInfo = $this->getInfo(); 117 118 // version 119 $data['anon_id'] = md5(auth_cookiesalt()); 120 $data['version'] = getVersion(); 121 $data['popversion'] = $pluginInfo['date']; 122 $data['language'] = $conf['lang']; 123 $data['now'] = time(); 124 $data['popauto'] = (int) $this->isAutoSubmitEnabled(); 125 126 // some config values 127 $data['conf_useacl'] = $conf['useacl']; 128 $data['conf_authtype'] = $conf['authtype']; 129 $data['conf_template'] = $conf['template']; 130 131 // number and size of pages 132 $list = array(); 133 search($list, $conf['datadir'], array($this, 'searchCountCallback'), array('all'=>false), ''); 134 $data['page_count'] = $list['file_count']; 135 $data['page_size'] = $list['file_size']; 136 $data['page_biggest'] = $list['file_max']; 137 $data['page_smallest'] = $list['file_min']; 138 $data['page_nscount'] = $list['dir_count']; 139 $data['page_nsnest'] = $list['dir_nest']; 140 if ($list['file_count']) $data['page_avg'] = $list['file_size'] / $list['file_count']; 141 $data['page_oldest'] = $list['file_oldest']; 142 unset($list); 143 144 // number and size of media 145 $list = array(); 146 search($list, $conf['mediadir'], array($this, 'searchCountCallback'), array('all'=>true)); 147 $data['media_count'] = $list['file_count']; 148 $data['media_size'] = $list['file_size']; 149 $data['media_biggest'] = $list['file_max']; 150 $data['media_smallest'] = $list['file_min']; 151 $data['media_nscount'] = $list['dir_count']; 152 $data['media_nsnest'] = $list['dir_nest']; 153 if ($list['file_count']) $data['media_avg'] = $list['file_size'] / $list['file_count']; 154 unset($list); 155 156 // number and size of cache 157 $list = array(); 158 search($list, $conf['cachedir'], array($this, 'searchCountCallback'), array('all'=>true)); 159 $data['cache_count'] = $list['file_count']; 160 $data['cache_size'] = $list['file_size']; 161 $data['cache_biggest'] = $list['file_max']; 162 $data['cache_smallest'] = $list['file_min']; 163 if ($list['file_count']) $data['cache_avg'] = $list['file_size'] / $list['file_count']; 164 unset($list); 165 166 // number and size of index 167 $list = array(); 168 search($list, $conf['indexdir'], array($this, 'searchCountCallback'), array('all'=>true)); 169 $data['index_count'] = $list['file_count']; 170 $data['index_size'] = $list['file_size']; 171 $data['index_biggest'] = $list['file_max']; 172 $data['index_smallest'] = $list['file_min']; 173 if ($list['file_count']) $data['index_avg'] = $list['file_size'] / $list['file_count']; 174 unset($list); 175 176 // number and size of meta 177 $list = array(); 178 search($list, $conf['metadir'], array($this, 'searchCountCallback'), array('all'=>true)); 179 $data['meta_count'] = $list['file_count']; 180 $data['meta_size'] = $list['file_size']; 181 $data['meta_biggest'] = $list['file_max']; 182 $data['meta_smallest'] = $list['file_min']; 183 if ($list['file_count']) $data['meta_avg'] = $list['file_size'] / $list['file_count']; 184 unset($list); 185 186 // number and size of attic 187 $list = array(); 188 search($list, $conf['olddir'], array($this, 'searchCountCallback'), array('all'=>true)); 189 $data['attic_count'] = $list['file_count']; 190 $data['attic_size'] = $list['file_size']; 191 $data['attic_biggest'] = $list['file_max']; 192 $data['attic_smallest'] = $list['file_min']; 193 if ($list['file_count']) $data['attic_avg'] = $list['file_size'] / $list['file_count']; 194 $data['attic_oldest'] = $list['file_oldest']; 195 unset($list); 196 197 // user count 198 if ($auth && $auth->canDo('getUserCount')) { 199 $data['user_count'] = $auth->getUserCount(); 200 } 201 202 // calculate edits per day 203 $list = @file($conf['metadir'].'/_dokuwiki.changes'); 204 $count = count($list); 205 if ($count > 2) { 206 $first = (int) substr(array_shift($list), 0, 10); 207 $last = (int) substr(array_pop($list), 0, 10); 208 $dur = ($last - $first)/(60*60*24); // number of days in the changelog 209 $data['edits_per_day'] = $count/$dur; 210 } 211 unset($list); 212 213 // plugins 214 $data['plugin'] = plugin_list(); 215 216 // pcre info 217 if (defined('PCRE_VERSION')) $data['pcre_version'] = PCRE_VERSION; 218 $data['pcre_backtrack'] = ini_get('pcre.backtrack_limit'); 219 $data['pcre_recursion'] = ini_get('pcre.recursion_limit'); 220 221 // php info 222 $data['os'] = PHP_OS; 223 $data['webserver'] = $_SERVER['SERVER_SOFTWARE']; 224 $data['php_version'] = phpversion(); 225 $data['php_sapi'] = php_sapi_name(); 226 $data['php_memory'] = php_to_byte(ini_get('memory_limit')); 227 $data['php_exectime'] = $phptime; 228 $data['php_extension'] = get_loaded_extensions(); 229 230 // plugin usage data 231 $this->addPluginUsageData($data); 232 233 return $data; 234 } 235 236 /** 237 * Triggers event to let plugins add their own data 238 * 239 * @param $data 240 */ 241 protected function addPluginUsageData(&$data) 242 { 243 $pluginsData = array(); 244 trigger_event('PLUGIN_POPULARITY_DATA_SETUP', $pluginsData); 245 foreach ($pluginsData as $plugin => $d) { 246 if (is_array($d)) { 247 foreach ($d as $key => $value) { 248 $data['plugin_' . $plugin . '_' . $key] = $value; 249 } 250 } else { 251 $data['plugin_' . $plugin] = $d; 252 } 253 } 254 } 255 256 /** 257 * Callback to search and count the content of directories in DokuWiki 258 * 259 * @param array &$data Reference to the result data structure 260 * @param string $base Base usually $conf['datadir'] 261 * @param string $file current file or directory relative to $base 262 * @param string $type Type either 'd' for directory or 'f' for file 263 * @param int $lvl Current recursion depht 264 * @param array $opts option array as given to search() 265 * @return bool 266 */ 267 public function searchCountCallback(&$data, $base, $file, $type, $lvl, $opts) 268 { 269 // traverse 270 if ($type == 'd') { 271 if ($data['dir_nest'] < $lvl) $data['dir_nest'] = $lvl; 272 $data['dir_count']++; 273 return true; 274 } 275 276 //only search txt files if 'all' option not set 277 if ($opts['all'] || substr($file, -4) == '.txt') { 278 $size = filesize($base.'/'.$file); 279 $date = filemtime($base.'/'.$file); 280 $data['file_count']++; 281 $data['file_size'] += $size; 282 if (!isset($data['file_min']) || $data['file_min'] > $size) $data['file_min'] = $size; 283 if ($data['file_max'] < $size) $data['file_max'] = $size; 284 if (!isset($data['file_oldest']) || $data['file_oldest'] > $date) $data['file_oldest'] = $date; 285 } 286 287 return false; 288 } 289} 290