Hi, thank you for your precisions, and sorry for this late answer (I've been a bit busy this week) 2010/11/27 Michael Hamann <michael@xxxxxxxxxxxxxxxx> > - use Doku_Form instead of manually generating the HTML for the form > I've looked a bit at it, but it seems to be a bit overkill since we only need two fields and a submit button... - for the code in the admin part that is used in the action part a > helper part or just another php file would imho be good/better style. > I never made helper plugins, so I didn't realized it would be relevant here. Here is a new patch which add such a plugin. Does it seems to make sense this way? > - Probably loading the admin/helper part only in the handler would make > sense as that handler won't be called every time the plugin is loaded > It seems to me that it would be needed every time. Indeed, it seems to me that the function which gather the data should be in the helper plugin, since the action plugin needs it. And this data is needed in the html() function. Am I wrong? Should the gather() function remains in the admin plugin. - I think when the submission of the data fails a message file should be > written [...] > > - When the manual submission fails a possibility could be > offered to submit the data directly from the browser like it is done > now. > Those are indeed interesting suggestions. I'll try to implement them this week. Regards, Guillaume
diff --git a/lib/plugins/popularity/action.php b/lib/plugins/popularity/action.php new file mode 100644 index 0000000..82ad38e --- /dev/null +++ b/lib/plugins/popularity/action.php @@ -0,0 +1,43 @@ +<?php + +require_once(DOKU_PLUGIN.'action.php'); +require_once(DOKU_PLUGIN.'popularity/admin.php'); + +class action_plugin_popularity extends Dokuwiki_Action_Plugin { + var $helper; + + function action_plugin_popularity(){ + $this->helper = $this->loadHelper('popularity', false); + } + + /** + * Register its handlers with the dokuwiki's event controller + */ + function register(&$controller) { + $controller->register_hook('INDEXER_TASKS_RUN', 'AFTER', $this, '_autosubmit', array()); + } + + function _autosubmit(&$event, $param){ + if ( !$this->helper->isAutosubmitEnabled() || $this->_isTooEarlyToSubmit() ){ + return; + } + + //Update the last time we sent data before we actually send it, + //to avoid sending it several time in a fraction of second + touch ( $this->helper->autosubmitFile ); + + $this->helper->sendData( $this->helper->gatherAsString() ); + + $event->stopPropagation(); + $event->preventDefault(); + } + + /** + * Check if it's time to send autosubmit data + * (we should have check the autosubmit is enabled first) + */ + function _isTooEarlyToSubmit(){ + $lastSubmit = @filemtime($this->helper->autosubmitFile); + return $lastSubmit + 24*60*60*30 > time(); + } +} diff --git a/lib/plugins/popularity/admin.php b/lib/plugins/popularity/admin.php index 71ea407..1224766 100644 --- a/lib/plugins/popularity/admin.php +++ b/lib/plugins/popularity/admin.php @@ -13,21 +13,14 @@ if(!defined('DOKU_INC')) die(); * need to inherit from this class */ class admin_plugin_popularity extends DokuWiki_Admin_Plugin { - var $version = '2010-09-17'; + var $version; + var $helper; + function admin_plugin_popularity(){ + $this->helper = $this->loadHelper('popularity', false); - /** - * return some info - */ - function getInfo(){ - return array( - 'author' => 'Andreas Gohr', - 'email' => 'andi@xxxxxxxxxxxxxx', - 'date' => $this->version, - 'name' => 'Popularity Feedback Plugin', - 'desc' => 'Send anonymous data about your wiki to the developers.', - 'url' => 'http://www.dokuwiki.org/plugin:popularity', - ); + $pluginInfo = $this->getInfo(); + $this->version = $pluginInfo['date']; } /** @@ -56,204 +49,50 @@ class admin_plugin_popularity extends DokuWiki_Admin_Plugin { * handle user request */ function handle() { - } - - /** - * Output HTML form - */ - function html() { - echo $this->locale_xhtml('intro'); - - flush(); - $data = $this->_gather(); - echo '<form method="post" action="http://update.dokuwiki.org/popularity.php"; accept-charset="utf-8">'; - echo '<fieldset style="width: 60%;">'; - echo '<textarea class="edit" rows="10" cols="80" readonly="readonly" name="data">'; - foreach($data as $key => $val){ - if(is_array($val)) foreach($val as $v){ - echo hsc($key)."\t".hsc($v)."\n"; - }else{ - echo hsc($key)."\t".hsc($val)."\n"; - } - } - echo '</textarea><br />'; - echo '<input type="submit" class="button" value="'.$this->getLang('submit').'"/>'; - echo '</fieldset>'; - echo '</form>'; - -// dbg($data); - } - - - /** - * Gather all information - */ - function _gather(){ - global $conf; - global $auth; - $data = array(); - $phptime = ini_get('max_execution_time'); - @set_time_limit(0); - - // version - $data['anon_id'] = md5(auth_cookiesalt()); - $data['version'] = getVersion(); - $data['popversion'] = $this->version; - $data['language'] = $conf['lang']; - $data['now'] = time(); - - // some config values - $data['conf_useacl'] = $conf['useacl']; - $data['conf_authtype'] = $conf['authtype']; - $data['conf_template'] = $conf['template']; - - // number and size of pages - $list = array(); - search($list,$conf['datadir'],array($this,'_search_count'),'',''); - $data['page_count'] = $list['file_count']; - $data['page_size'] = $list['file_size']; - $data['page_biggest'] = $list['file_max']; - $data['page_smallest'] = $list['file_min']; - $data['page_nscount'] = $list['dir_count']; - $data['page_nsnest'] = $list['dir_nest']; - if($list['file_count']) $data['page_avg'] = $list['file_size'] / $list['file_count']; - $data['page_oldest'] = $list['file_oldest']; - unset($list); - - // number and size of media - $list = array(); - search($list,$conf['mediadir'],array($this,'_search_count'),array('all'=>true)); - $data['media_count'] = $list['file_count']; - $data['media_size'] = $list['file_size']; - $data['media_biggest'] = $list['file_max']; - $data['media_smallest'] = $list['file_min']; - $data['media_nscount'] = $list['dir_count']; - $data['media_nsnest'] = $list['dir_nest']; - if($list['file_count']) $data['media_avg'] = $list['file_size'] / $list['file_count']; - unset($list); - - // number and size of cache - $list = array(); - search($list,$conf['cachedir'],array($this,'_search_count'),array('all'=>true)); - $data['cache_count'] = $list['file_count']; - $data['cache_size'] = $list['file_size']; - $data['cache_biggest'] = $list['file_max']; - $data['cache_smallest'] = $list['file_min']; - if($list['file_count']) $data['cache_avg'] = $list['file_size'] / $list['file_count']; - unset($list); - - // number and size of index - $list = array(); - search($list,$conf['indexdir'],array($this,'_search_count'),array('all'=>true)); - $data['index_count'] = $list['file_count']; - $data['index_size'] = $list['file_size']; - $data['index_biggest'] = $list['file_max']; - $data['index_smallest'] = $list['file_min']; - if($list['file_count']) $data['index_avg'] = $list['file_size'] / $list['file_count']; - unset($list); - - // number and size of meta - $list = array(); - search($list,$conf['metadir'],array($this,'_search_count'),array('all'=>true)); - $data['meta_count'] = $list['file_count']; - $data['meta_size'] = $list['file_size']; - $data['meta_biggest'] = $list['file_max']; - $data['meta_smallest'] = $list['file_min']; - if($list['file_count']) $data['meta_avg'] = $list['file_size'] / $list['file_count']; - unset($list); - - // number and size of attic - $list = array(); - search($list,$conf['olddir'],array($this,'_search_count'),array('all'=>true)); - $data['attic_count'] = $list['file_count']; - $data['attic_size'] = $list['file_size']; - $data['attic_biggest'] = $list['file_max']; - $data['attic_smallest'] = $list['file_min']; - if($list['file_count']) $data['attic_avg'] = $list['file_size'] / $list['file_count']; - $data['attic_oldest'] = $list['file_oldest']; - unset($list); - - // user count - if($auth && $auth->canDo('getUserCount')){ - $data['user_count'] = $auth->getUserCount(); - } - - // calculate edits per day - $list = @file($conf['metadir'].'/_dokuwiki.changes'); - $count = count($list); - if($count > 2){ - $first = (int) substr(array_shift($list),0,10); - $last = (int) substr(array_pop($list),0,10); - $dur = ($last - $first)/(60*60*24); // number of days in the changelog - $data['edits_per_day'] = $count/$dur; + //Send the data + if ( isset($_REQUEST['data']) ){ + $this->helper->sendData( $_REQUEST['data'] ); + //Deal with the autosubmit option + $this->_enableAutosubmit( isset($_REQUEST['autosubmit']) ); } - unset($list); - - // plugins - $data['plugin'] = plugin_list(); - - // pcre info - if(defined('PCRE_VERSION')) $data['pcre_version'] = PCRE_VERSION; - $data['pcre_backtrack'] = ini_get('pcre.backtrack_limit'); - $data['pcre_recursion'] = ini_get('pcre.recursion_limit'); - - // php info - $data['os'] = PHP_OS; - $data['webserver'] = $_SERVER['SERVER_SOFTWARE']; - $data['php_version'] = phpversion(); - $data['php_sapi'] = php_sapi_name(); - $data['php_memory'] = $this->_to_byte(ini_get('memory_limit')); - $data['php_exectime'] = $phptime; - $data['php_extension'] = get_loaded_extensions(); - - return $data; } - - function _search_count(&$data,$base,$file,$type,$lvl,$opts){ - // traverse - if($type == 'd'){ - if($data['dir_nest'] < $lvl) $data['dir_nest'] = $lvl; - $data['dir_count']++; - return true; - } - - //only search txt files if 'all' option not set - if($opts['all'] || substr($file,-4) == '.txt'){ - $size = filesize($base.'/'.$file); - $date = filemtime($base.'/'.$file); - $data['file_count']++; - $data['file_size'] += $size; - if(!isset($data['file_min']) || $data['file_min'] > $size) $data['file_min'] = $size; - if($data['file_max'] < $size) $data['file_max'] = $size; - if(!isset($data['file_oldest']) || $data['file_oldest'] > $date) $data['file_oldest'] = $date; + function _enableAutosubmit( $enable ){ + if ( $enable ){ + io_saveFile( $this->helper->autosubmitFile, ' '); + } else { + @unlink($this->helper->autosubmitFile); } - - return false; } /** - * Convert php.ini shorthands to byte - * - * @author <gilthans dot NO dot SPAM at gmail dot com> - * @link http://de3.php.net/manual/en/ini.core.php#79564 + * Output HTML form */ - function _to_byte($v){ - $l = substr($v, -1); - $ret = substr($v, 0, -1); - switch(strtoupper($l)){ - case 'P': - $ret *= 1024; - case 'T': - $ret *= 1024; - case 'G': - $ret *= 1024; - case 'M': - $ret *= 1024; - case 'K': - $ret *= 1024; - break; + function html() { + if ( isset($_REQUEST['data']) ){ + echo $this->locale_xhtml('submitted'); + } else { + + echo $this->locale_xhtml('intro'); + + flush(); + echo '<form method="post" action="'. script() .'" accept-charset="utf-8">'; + echo '<fieldset style="width: 60%;">'; + echo '<textarea class="edit" rows="10" cols="80" readonly="readonly" name="data">'; + echo $this->helper->gatherAsString(); + echo '</textarea><br />'; + echo '<label for="autosubmit">'; + echo '<input type="checkbox" name="autosubmit" id="autosubmit" ' + . ($this->helper->isAutosubmitEnabled() ? 'checked' : '' ) + . '/>' . $this->getLang('autosubmit') .'<br />'; + echo '</label>'; + echo '<input type="submit" class="button" value="'.$this->getLang('submit').'"/>'; + echo '<input type="hidden" name="do" value="admin">'; + echo '<input type="hidden" name="page" value="popularity">'; + echo '</fieldset>'; + echo '</form>'; + + // dbg($data); } - return $ret; } } diff --git a/lib/plugins/popularity/helper.php b/lib/plugins/popularity/helper.php new file mode 100644 index 0000000..8dc1156 --- /dev/null +++ b/lib/plugins/popularity/helper.php @@ -0,0 +1,245 @@ +<?php + +class helper_plugin_popularity extends Dokuwiki_Plugin { + /** + * The url where the data should be sent + */ + var $submitUrl = 'http://update.dokuwiki.org/popularity.php'; + + /** + * Name of the file which determine if the the autosubmit is enabled, + * and when it was submited for the las time + */ + var $autosubmitFile; + + function helper_plugin_popularity(){ + global $conf; + $this->autosubmitFile = $conf['cachedir'].'/autosubmit.txt'; + } + + function getMethods(){ + $result = array(); + $result[] = array( + 'name' => 'isAutoSubmitEnabled', + 'desc' => 'Check if autosubmit is enabled', + 'params' => array(), + 'return' => array('result' => 'bool') + ); + $result[] = array( + 'name' => 'sendData', + 'desc' => 'Send the popularity data', + 'params' => array('data' => 'string'), + 'return' => array() + ); + $result[] = array( + 'name' => 'gatherAsString', + 'desc' => 'Gather the popularity data', + 'params' => array(), + 'return' => array('data' => 'string') + ); + return $result; + + } + + /** + * Check if autosubmit is enabled + * @return TRUE if we should send data once a month, FALSE otherwise + */ + function isAutoSubmitEnabled(){ + return @file_exists($this->autosubmitFile); + } + + function sendData($data){ + $httpClient = new DokuHTTPClient(); + $httpClient->sendRequest($this->submitUrl, $data, 'POST'); + } + + /** + * Gather all information + * @return The popularity data as a string + */ + function gatherAsString(){ + $data = $this->_gather(); + $string = ''; + foreach($data as $key => $val){ + if(is_array($val)) foreach($val as $v){ + $string .= hsc($key)."\t".hsc($v)."\n"; + }else{ + $string .= hsc($key)."\t".hsc($val)."\n"; + } + } + return $string; + } + + /** + * Gather all information + * @return The popularity data as an array + */ + function _gather(){ + global $conf; + global $auth; + $data = array(); + $phptime = ini_get('max_execution_time'); + @set_time_limit(0); + + // version + $data['anon_id'] = md5(auth_cookiesalt()); + $data['version'] = getVersion(); + $data['popversion'] = $this->version; + $data['language'] = $conf['lang']; + $data['now'] = time(); + + // some config values + $data['conf_useacl'] = $conf['useacl']; + $data['conf_authtype'] = $conf['authtype']; + $data['conf_template'] = $conf['template']; + + // number and size of pages + $list = array(); + search($list,$conf['datadir'],array($this,'_search_count'),'',''); + $data['page_count'] = $list['file_count']; + $data['page_size'] = $list['file_size']; + $data['page_biggest'] = $list['file_max']; + $data['page_smallest'] = $list['file_min']; + $data['page_nscount'] = $list['dir_count']; + $data['page_nsnest'] = $list['dir_nest']; + if($list['file_count']) $data['page_avg'] = $list['file_size'] / $list['file_count']; + $data['page_oldest'] = $list['file_oldest']; + unset($list); + + // number and size of media + $list = array(); + search($list,$conf['mediadir'],array($this,'_search_count'),array('all'=>true)); + $data['media_count'] = $list['file_count']; + $data['media_size'] = $list['file_size']; + $data['media_biggest'] = $list['file_max']; + $data['media_smallest'] = $list['file_min']; + $data['media_nscount'] = $list['dir_count']; + $data['media_nsnest'] = $list['dir_nest']; + if($list['file_count']) $data['media_avg'] = $list['file_size'] / $list['file_count']; + unset($list); + + // number and size of cache + $list = array(); + search($list,$conf['cachedir'],array($this,'_search_count'),array('all'=>true)); + $data['cache_count'] = $list['file_count']; + $data['cache_size'] = $list['file_size']; + $data['cache_biggest'] = $list['file_max']; + $data['cache_smallest'] = $list['file_min']; + if($list['file_count']) $data['cache_avg'] = $list['file_size'] / $list['file_count']; + unset($list); + + // number and size of index + $list = array(); + search($list,$conf['indexdir'],array($this,'_search_count'),array('all'=>true)); + $data['index_count'] = $list['file_count']; + $data['index_size'] = $list['file_size']; + $data['index_biggest'] = $list['file_max']; + $data['index_smallest'] = $list['file_min']; + if($list['file_count']) $data['index_avg'] = $list['file_size'] / $list['file_count']; + unset($list); + + // number and size of meta + $list = array(); + search($list,$conf['metadir'],array($this,'_search_count'),array('all'=>true)); + $data['meta_count'] = $list['file_count']; + $data['meta_size'] = $list['file_size']; + $data['meta_biggest'] = $list['file_max']; + $data['meta_smallest'] = $list['file_min']; + if($list['file_count']) $data['meta_avg'] = $list['file_size'] / $list['file_count']; + unset($list); + + // number and size of attic + $list = array(); + search($list,$conf['olddir'],array($this,'_search_count'),array('all'=>true)); + $data['attic_count'] = $list['file_count']; + $data['attic_size'] = $list['file_size']; + $data['attic_biggest'] = $list['file_max']; + $data['attic_smallest'] = $list['file_min']; + if($list['file_count']) $data['attic_avg'] = $list['file_size'] / $list['file_count']; + $data['attic_oldest'] = $list['file_oldest']; + unset($list); + + // user count + if($auth && $auth->canDo('getUserCount')){ + $data['user_count'] = $auth->getUserCount(); + } + + // calculate edits per day + $list = @file($conf['metadir'].'/_dokuwiki.changes'); + $count = count($list); + if($count > 2){ + $first = (int) substr(array_shift($list),0,10); + $last = (int) substr(array_pop($list),0,10); + $dur = ($last - $first)/(60*60*24); // number of days in the changelog + $data['edits_per_day'] = $count/$dur; + } + unset($list); + + // plugins + $data['plugin'] = plugin_list(); + + // pcre info + if(defined('PCRE_VERSION')) $data['pcre_version'] = PCRE_VERSION; + $data['pcre_backtrack'] = ini_get('pcre.backtrack_limit'); + $data['pcre_recursion'] = ini_get('pcre.recursion_limit'); + + // php info + $data['os'] = PHP_OS; + $data['webserver'] = $_SERVER['SERVER_SOFTWARE']; + $data['php_version'] = phpversion(); + $data['php_sapi'] = php_sapi_name(); + $data['php_memory'] = $this->_to_byte(ini_get('memory_limit')); + $data['php_exectime'] = $phptime; + $data['php_extension'] = get_loaded_extensions(); + + return $data; + } + + function _search_count(&$data,$base,$file,$type,$lvl,$opts){ + // traverse + if($type == 'd'){ + if($data['dir_nest'] < $lvl) $data['dir_nest'] = $lvl; + $data['dir_count']++; + return true; + } + + //only search txt files if 'all' option not set + if($opts['all'] || substr($file,-4) == '.txt'){ + $size = filesize($base.'/'.$file); + $date = filemtime($base.'/'.$file); + $data['file_count']++; + $data['file_size'] += $size; + if(!isset($data['file_min']) || $data['file_min'] > $size) $data['file_min'] = $size; + if($data['file_max'] < $size) $data['file_max'] = $size; + if(!isset($data['file_oldest']) || $data['file_oldest'] > $date) $data['file_oldest'] = $date; + } + + return false; + } + + /** + * Convert php.ini shorthands to byte + * + * @author <gilthans dot NO dot SPAM at gmail dot com> + * @link http://de3.php.net/manual/en/ini.core.php#79564 + */ + function _to_byte($v){ + $l = substr($v, -1); + $ret = substr($v, 0, -1); + switch(strtoupper($l)){ + case 'P': + $ret *= 1024; + case 'T': + $ret *= 1024; + case 'G': + $ret *= 1024; + case 'M': + $ret *= 1024; + case 'K': + $ret *= 1024; + break; + } + return $ret; + } +} diff --git a/lib/plugins/popularity/lang/en/lang.php b/lib/plugins/popularity/lang/en/lang.php index c9912b7..01e4435 100644 --- a/lib/plugins/popularity/lang/en/lang.php +++ b/lib/plugins/popularity/lang/en/lang.php @@ -2,3 +2,4 @@ $lang['name'] = 'Popularity Feedback (may take some time to load)'; $lang['submit'] = 'Send Data'; +$lang['autosubmit'] = 'Automatically send data once a month (may be (un)selected later)'; diff --git a/lib/plugins/popularity/lang/en/submitted.txt b/lib/plugins/popularity/lang/en/submitted.txt new file mode 100644 index 0000000..30f2784 --- /dev/null +++ b/lib/plugins/popularity/lang/en/submitted.txt @@ -0,0 +1,3 @@ +====== Popularity Feedback ====== + +The data has been sent succesfully. diff --git a/lib/plugins/popularity/plugin.info.txt b/lib/plugins/popularity/plugin.info.txt new file mode 100644 index 0000000..d475d20 --- /dev/null +++ b/lib/plugins/popularity/plugin.info.txt @@ -0,0 +1,7 @@ +base popularity +author Andreas Gohr +email andi@xxxxxxxxxxxxxx +date 2010-09-17 +name Popularity Feedback Plugin +desc Send anonymous data about your wiki to the developers. +url http://www.dokuwiki.org/plugin:popularity