2009-11-17 10:24:10 +01:00
< ? php
/**
* EGgroupware admin - submit EGroupware usage statistic
*
* @ link http :// www . egroupware . org
* @ author Ralf Becker < RalfBecker - AT - outdoor - training . de >
* @ package admin
2018-12-10 15:41:48 +01:00
* @ copyright ( c ) 2009 - 18 by Ralf Becker < RalfBecker - AT - outdoor - training . de >
2009-11-17 10:24:10 +01:00
* @ license http :// opensource . org / licenses / gpl - license . php GPL - GNU General Public License
*/
2016-04-27 21:12:20 +02:00
use EGroupware\Api ;
use EGroupware\Api\Egw ;
2016-05-14 12:40:15 +02:00
use EGroupware\Api\Etemplate ;
2016-04-27 21:12:20 +02:00
2009-11-17 10:24:10 +01:00
/**
* Submit statistical data to egroupware . org
*/
class admin_statistics
{
const CONFIG_APP = 'admin' ;
const CONFIG_LAST_SUBMIT = 'last_statistics_submit' ;
const CONFIG_POSTPONE_SUBMIT = 'postpone_statistics_submit' ;
const CONFIG_SUBMIT_ID = 'statistics_submit_id' ;
2009-11-17 21:31:48 +01:00
const CONFIG_COUNTRY = 'country_submit' ;
const CONFIG_USAGE_TYPE = 'usage_type_submit' ;
2009-11-17 10:24:10 +01:00
const CONFIG_INSTALL_TYPE = 'install_type_submit' ;
2011-05-31 11:25:36 +02:00
const SUBMIT_URL = 'https://www.egroupware.org/usage-statistic' ;
2018-12-10 15:41:48 +01:00
const STATISTIC_URL = 'https://www.egroupware.org/usage-statistic' ;
2009-11-17 10:24:10 +01:00
const SUBMISION_RATE = 2592000 ; // 30 days
/**
* Which methods of this class can be called as menuation
*
* @ var array
*/
public $public_functions = array (
'submit' => true ,
);
/**
* Display and allow to submit statistical data
*
2016-04-27 21:12:20 +02:00
* @ param array $_content = null
2009-11-17 10:24:10 +01:00
*/
2016-04-27 21:12:20 +02:00
public function submit ( $_content = null )
2009-11-17 10:24:10 +01:00
{
2016-04-27 21:12:20 +02:00
if ( is_array ( $_content ))
2009-11-17 10:24:10 +01:00
{
2016-04-27 21:12:20 +02:00
$config = new Api\Config ( self :: CONFIG_APP );
if ( $_content [ 'postpone' ])
2009-11-17 10:24:10 +01:00
{
2016-04-27 21:12:20 +02:00
Api\Config :: save_value ( self :: CONFIG_POSTPONE_SUBMIT , time () + $_content [ 'postpone' ], self :: CONFIG_APP );
2009-11-17 10:24:10 +01:00
$what = 'postpone' ;
}
2016-04-27 21:12:20 +02:00
elseif ( ! $_content [ 'cancel' ])
2009-11-17 10:24:10 +01:00
{
2016-04-27 21:12:20 +02:00
Api\Config :: save_value ( self :: CONFIG_LAST_SUBMIT , time (), self :: CONFIG_APP );
Api\Config :: save_value ( self :: CONFIG_SUBMIT_ID , empty ( $_content [ 'submit_id' ]) ? '***none***' : $_content [ 'submit_id' ], self :: CONFIG_APP );
Api\Config :: save_value ( self :: CONFIG_COUNTRY , empty ( $_content [ 'country' ]) ? '***multinational***' : $_content [ 'country' ], self :: CONFIG_APP );
Api\Config :: save_value ( self :: CONFIG_USAGE_TYPE , $_content [ 'usage_type' ], self :: CONFIG_APP );
Api\Config :: save_value ( self :: CONFIG_INSTALL_TYPE , $_content [ 'install_type' ], self :: CONFIG_APP );
Api\Config :: save_value ( self :: CONFIG_POSTPONE_SUBMIT , null , self :: CONFIG_APP ); // remove evtl. postpone time
2016-05-14 12:40:15 +02:00
$what = 'submitted' ;
2009-11-17 10:24:10 +01:00
}
2016-05-14 12:40:15 +02:00
Egw :: redirect_link ( '/admin/index.php' , 'ajax=true&statistics=' . ( $what ? $what : 'canceled' ), 'admin' );
2009-11-17 10:24:10 +01:00
}
$sel_options [ 'usage_type' ] = array (
2009-11-22 10:03:46 +01:00
'commercial' => lang ( 'Commercial: all sorts of companies' ),
2009-11-17 10:24:10 +01:00
'governmental' => lang ( 'Governmental: incl. state or municipal authorities or services' ),
'educational' => lang ( 'Educational: Universities, Schools, ...' ),
'non-profit' => lang ( 'Non profit: Clubs, associations, ...' ),
'personal' => lang ( 'Personal: eg. within a family' ),
'other' => lang ( 'Other' ),
);
$sel_options [ 'install_type' ] = array (
2019-10-29 13:09:06 +01:00
'docker' => lang ( 'Docker' ),
2009-11-17 10:24:10 +01:00
'package' => lang ( 'RPM or Debian package' ),
2016-05-14 12:40:15 +02:00
'git' => lang ( 'Git clone' ),
2019-10-29 13:09:06 +01:00
'archive' => lang ( 'Archive: zip or tar' ),
2009-11-17 10:24:10 +01:00
'other' => lang ( 'Other' ),
);
$sel_options [ 'postpone' ] = array (
//10 => '10 secs',
3600 => lang ( 'one hour' ),
2 * 3600 => lang ( 'two hours' ),
24 * 3600 => lang ( 'one day' ),
2 * 24 * 3600 => lang ( 'two days' ),
7 * 24 * 3600 => lang ( 'one week' ),
14 * 24 * 3600 => lang ( 'two weeks' ),
30 * 24 * 3600 => lang ( 'one month' ),
2009-11-22 10:03:46 +01:00
60 * 24 * 3600 => lang ( 'two months' ),
2009-11-17 10:24:10 +01:00
);
2016-04-27 21:12:20 +02:00
$config = Api\Config :: read ( self :: CONFIG_APP );
2009-11-17 10:24:10 +01:00
//_debug_array($config);
$content = array_merge ( self :: gather_data (), array (
2016-05-14 12:40:15 +02:00
'statistic_url' => self :: STATISTIC_URL ,
2009-11-17 10:24:10 +01:00
'submit_host' => parse_url ( self :: SUBMIT_URL , PHP_URL_HOST ),
'submit_url' => self :: SUBMIT_URL ,
'last_submitted' => $config [ self :: CONFIG_LAST_SUBMIT ],
));
//_debug_array($content);
2009-11-17 21:31:48 +01:00
// show previous submit ID
2009-11-17 10:24:10 +01:00
if ( $config [ 'statistics_submit_id' ])
{
$content [ 'submit_id' ] = $config [ 'statistics_submit_id' ] == '***none***' ? '' : $config [ 'statistics_submit_id' ];
}
2016-04-27 21:12:20 +02:00
// show previous Api\Country
2009-11-17 21:31:48 +01:00
if ( $config [ self :: CONFIG_COUNTRY ])
{
$content [ 'country' ] = $config [ self :: CONFIG_COUNTRY ] == '***multinational***' ? '' : $config [ self :: CONFIG_COUNTRY ];
}
// show previous usage_type
if ( $config [ self :: CONFIG_USAGE_TYPE ])
{
$content [ 'usage_type' ] = $config [ self :: CONFIG_USAGE_TYPE ];
}
2009-11-17 10:24:10 +01:00
// check if we detected svn or rpm/deb packages --> readonly
2009-11-17 13:47:39 +01:00
if ( $content [ 'install_type' ] && isset ( $sel_options [ 'install_type' ][ $content [ 'install_type' ]]))
2009-11-17 10:24:10 +01:00
{
2009-11-17 13:47:39 +01:00
$sel_options [ 'install_type' ] = array ( $content [ 'install_type' ] => $sel_options [ 'install_type' ][ $content [ 'install_type' ]]);
2009-11-17 10:24:10 +01:00
}
// else default to previous type
elseif ( $config [ self :: CONFIG_INSTALL_TYPE ])
{
$content [ 'install_type' ] = $config [ self :: CONFIG_INSTALL_TYPE ];
}
// check if we are due for a new submission
if ( ! isset ( $config [ self :: CONFIG_LAST_SUBMIT ]) || $config [ self :: CONFIG_LAST_SUBMIT ] <= time () - self :: SUBMISION_RATE )
{
// clear etemplate_exec_id and replace form.action, before submitting the form
2016-05-14 12:40:15 +02:00
$content [ 'onclick' ] = " return app.admin.submit_statistic(this.form,' $content[submit_url] '); " ;
2009-11-17 10:24:10 +01:00
}
else // we are not due --> tell it the user
{
$readonlys [ 'submit' ] = $readonlys [ 'postpone' ] = true ;
$content [ 'msg' ] = lang ( 'Your last submission was less then %1 days ago!' ,
ceil (( time () - $config [ self :: CONFIG_LAST_SUBMIT ]) / 24 / 3600 ));
}
$GLOBALS [ 'egw_info' ][ 'flags' ][ 'app_header' ] = lang ( 'Submit statistic information' );
2016-05-14 12:40:15 +02:00
$tmpl = new Etemplate ( 'admin.statistics' );
2016-04-27 21:12:20 +02:00
$tmpl -> exec ( 'admin.admin_statistics.submit' , $content , $sel_options , $readonlys );
2009-11-17 10:24:10 +01:00
}
/**
* Gather statistical data to submit
*
* @ return array key => value pairs
*/
protected static function gather_data ()
{
// submit id is sha1 hash from install_id
$data [ 'submit_id' ] = sha1 ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'install_id' ]);
$data [ 'country' ] = $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'country' ];
2019-10-29 13:09:06 +01:00
// maintenance release (incl. EPL)
$data [ 'version' ] = $GLOBALS [ 'egw_info' ][ 'server' ][ 'versions' ][ 'maintenance_release' ];
2009-11-17 10:24:10 +01:00
// sessions in the last 30 days
$data [ 'sessions' ] = $GLOBALS [ 'egw' ] -> db -> query ( 'SELECT COUNT(*) FROM egw_access_log WHERE li > ' . ( time () - 30 * 24 * 3600 )) -> fetchColumn ();
// total accounts from accounts table or ldap
$GLOBALS [ 'egw' ] -> accounts -> search ( array (
'type' => 'accounts' ,
'start' => 0 ,
));
$data [ 'users' ] = $GLOBALS [ 'egw' ] -> accounts -> total ;
$data [ 'php' ] = PHP_VERSION . ': ' . PHP_SAPI ;
$data [ 'os' ] = PHP_OS ;
2012-04-26 09:12:41 +02:00
// @ required to get ride of warning, if files are outside of open_basedir
2019-10-29 13:09:06 +01:00
$matches = null ;
if ( @ file_exists ( $file = '/etc/lsb-release' ) && preg_match ( '/^DISTRIB_DESCRIPTION="?([^"]+)"?/mi' , file_get_contents ( $file ), $matches ))
{
$data [ 'os' ] .= ': ' . $matches [ 1 ];
}
elseif ( @ file_exists ( $file = '/etc/SuSE-release' ) || @ file_exists ( $file = '/etc/redhat-release' ) || @ file_exists ( $file = '/etc/debian_version' ))
2009-11-17 10:24:10 +01:00
{
$data [ 'os' ] .= ': ' . str_replace ( array ( " \n " , " \r " ), '' , implode ( ',' , file ( $file )));
}
2016-05-14 12:40:15 +02:00
if ( file_exists ( EGW_INCLUDE_ROOT . '/.git' ))
{
$data [ 'install_type' ] = 'git' ;
}
2019-10-29 13:09:06 +01:00
elseif ( file_exists ( '/entrypoint.sh' ))
2009-11-17 10:24:10 +01:00
{
2019-10-29 13:09:06 +01:00
$data [ 'install_type' ] = 'docker' ;
2009-11-17 10:24:10 +01:00
}
elseif ( EGW_INCLUDE_ROOT == '/usr/share/egroupware' && PHP_OS == 'Linux' && is_link ( '/usr/share/egroupware/header.inc.php' ))
{
$data [ 'install_type' ] = 'package' ;
}
2016-04-27 21:12:20 +02:00
foreach ( array_keys ( $GLOBALS [ 'egw_info' ][ 'apps' ]) as $app )
2009-11-17 10:24:10 +01:00
{
if ( in_array ( $app , array (
2016-04-27 21:12:20 +02:00
'admin' , 'phpgwapi' , 'api' , 'sambaadmin' , 'developer_tools' ,
'home' , 'preferences' , 'etemplate' , 'registration' , 'manual' ,
2009-11-17 10:24:10 +01:00
)))
{
continue ; // --> ignore to not submit too much
}
if (( $users = self :: gather_app_users ( $app ))) // ignore apps noone is allowed to run
{
$data [ 'apps' ][ $app ] = $app . ':' . round ( 100.0 * $users / $data [ 'users' ]) . '%' ;
if (( $entries = self :: gather_app_entries ( $app )))
{
$data [ 'apps' ][ $app ] .= ':' . $entries ;
}
}
}
ksort ( $data [ 'apps' ]);
$data [ 'apps' ] = implode ( " \n " , $data [ 'apps' ]);
return $data ;
}
/**
* Get percentage of users allowed to use an application
*
* @ param string $app
* @ return int number of users allowed to run application
*/
static function gather_app_users ( $app )
{
$users = array ();
if (( $access = $GLOBALS [ 'egw' ] -> acl -> get_ids_for_location ( 'run' , 1 , $app )))
{
foreach ( $access as $uid )
{
if ( $uid > 0 )
{
$users [] = $uid ;
}
elseif (( $members = $GLOBALS [ 'egw' ] -> accounts -> members ( $uid , true )))
{
$users = array_merge ( $users , $members );
}
}
$users = array_unique ( $users );
}
return count ( $users );
}
/**
* Get percentage of users allowed to use an application
*
* @ param string $app
* @ return int
*/
static function gather_app_entries ( $app )
{
// main table for each application
static $app2table = array (
'addressbook' => 'egw_addressbook' ,
'bookmarks' => 'egw_bookmarks' ,
'calendar' => 'egw_cal_dates' ,
'infolog' => 'egw_infolog' ,
'filemanager' => 'egw_sqlfs' ,
'gallery' => 'g2_Item' ,
'news_admin' => 'egw_news WHERE news_submittedby > 0' , // exclude imported rss feeds
'polls' => 'egw_polls' ,
'projectmanager' => 'egw_pm_projects' ,
'phpbrain' => 'egw_kb_articles' ,
'resources' => 'egw_resources' ,
'sitemgr' => 'egw_sitemgr_pages' ,
'syncml' => 'egw_syncmlsummary' ,
'timesheet' => 'egw_timesheet' ,
'tracker' => 'egw_tracker' ,
'wiki' => 'egw_wiki_pages' ,
'mydms' => 'phpgw_mydms_Documents' ,
);
if (( $table = $app2table [ $app ]))
{
2011-01-05 09:32:16 +01:00
try {
$entries = ( int ) $GLOBALS [ 'egw' ] -> db -> query ( 'SELECT COUNT(*) FROM ' . $table ) -> fetchColumn ();
//echo "$app ($table): $entries<br />\n";
}
2016-04-27 21:12:20 +02:00
catch ( Api\Db\Exception $e ) {
unset ( $e );
2011-01-05 09:32:16 +01:00
$entries = null ;
}
2009-11-17 10:24:10 +01:00
}
return $entries ;
}
/**
* Check if next submission is due , in which case we call submit and NOT return to the admin hook
*
2014-07-17 16:02:11 +02:00
* @ param boolean $redirect should we redirect or return true
* @ return boolean true if statistic submission is due
2009-11-17 10:24:10 +01:00
*/
2014-07-17 16:02:11 +02:00
public static function check ( $redirect = true )
2009-11-17 10:24:10 +01:00
{
2016-04-27 21:12:20 +02:00
$config = Api\Config :: read ( self :: CONFIG_APP );
2009-11-17 10:24:10 +01:00
if ( isset ( $config [ self :: CONFIG_POSTPONE_SUBMIT ]) && $config [ self :: CONFIG_POSTPONE_SUBMIT ] > time () ||
isset ( $config [ self :: CONFIG_LAST_SUBMIT ]) && $config [ self :: CONFIG_LAST_SUBMIT ] > time () - self :: SUBMISION_RATE )
{
2014-07-17 16:02:11 +02:00
return false ;
2009-11-17 10:24:10 +01:00
}
2014-07-17 16:02:11 +02:00
if ( ! $redirect ) return true ;
2009-11-17 10:24:10 +01:00
//die('Due for new statistics submission: last_submit='.$config[self::CONFIG_LAST_SUBMIT ].', postpone='.$config[self::CONFIG_POSTPONE_SUBMIT].', '.function_backtrace());
2016-04-27 21:12:20 +02:00
Egw :: redirect_link ( '/index.php' , array (
2014-07-17 16:02:11 +02:00
'menuaction' => 'admin.admin_ui.index' ,
'ajax' => 'true' ,
'load' => 'admin.admin_statistics.submit' ,
));
2009-11-17 10:24:10 +01:00
}
}