1 | <?php |
||||
2 | /** |
||||
3 | * EGgroupware admin - submit EGroupware usage statistic |
||||
4 | * |
||||
5 | * @link http://www.egroupware.org |
||||
6 | * @author Ralf Becker <RalfBecker-AT-outdoor-training.de> |
||||
7 | * @package admin |
||||
8 | * @copyright (c) 2009-18 by Ralf Becker <RalfBecker-AT-outdoor-training.de> |
||||
9 | * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License |
||||
10 | */ |
||||
11 | |||||
12 | use EGroupware\Api; |
||||
13 | use EGroupware\Api\Egw; |
||||
14 | use EGroupware\Api\Etemplate; |
||||
15 | |||||
16 | /** |
||||
17 | * Submit statistical data to egroupware.org |
||||
18 | */ |
||||
19 | class admin_statistics |
||||
20 | { |
||||
21 | const CONFIG_APP = 'admin'; |
||||
22 | const CONFIG_LAST_SUBMIT = 'last_statistics_submit'; |
||||
23 | const CONFIG_POSTPONE_SUBMIT = 'postpone_statistics_submit'; |
||||
24 | const CONFIG_SUBMIT_ID = 'statistics_submit_id'; |
||||
25 | const CONFIG_COUNTRY = 'country_submit'; |
||||
26 | const CONFIG_USAGE_TYPE = 'usage_type_submit'; |
||||
27 | const CONFIG_INSTALL_TYPE = 'install_type_submit'; |
||||
28 | |||||
29 | const SUBMIT_URL = 'https://www.egroupware.org/usage-statistic'; |
||||
30 | const STATISTIC_URL = 'https://www.egroupware.org/usage-statistic'; |
||||
31 | |||||
32 | const SUBMISION_RATE = 2592000; // 30 days |
||||
33 | |||||
34 | /** |
||||
35 | * Which methods of this class can be called as menuation |
||||
36 | * |
||||
37 | * @var array |
||||
38 | */ |
||||
39 | public $public_functions = array( |
||||
40 | 'submit' => true, |
||||
41 | ); |
||||
42 | |||||
43 | /** |
||||
44 | * Display and allow to submit statistical data |
||||
45 | * |
||||
46 | * @param array $_content =null |
||||
47 | */ |
||||
48 | public function submit($_content=null) |
||||
49 | { |
||||
50 | if (is_array($_content)) |
||||
51 | { |
||||
52 | $config = new Api\Config(self::CONFIG_APP); |
||||
0 ignored issues
–
show
Unused Code
introduced
by
![]() |
|||||
53 | if ($_content['postpone']) |
||||
54 | { |
||||
55 | Api\Config::save_value(self::CONFIG_POSTPONE_SUBMIT,time()+$_content['postpone'],self::CONFIG_APP); |
||||
56 | $what = 'postpone'; |
||||
57 | } |
||||
58 | elseif(!$_content['cancel']) |
||||
59 | { |
||||
60 | Api\Config::save_value(self::CONFIG_LAST_SUBMIT,time(),self::CONFIG_APP); |
||||
61 | Api\Config::save_value(self::CONFIG_SUBMIT_ID,empty($_content['submit_id']) ? '***none***' : $_content['submit_id'],self::CONFIG_APP); |
||||
62 | Api\Config::save_value(self::CONFIG_COUNTRY,empty($_content['country']) ? '***multinational***' : $_content['country'],self::CONFIG_APP); |
||||
63 | Api\Config::save_value(self::CONFIG_USAGE_TYPE,$_content['usage_type'],self::CONFIG_APP); |
||||
64 | Api\Config::save_value(self::CONFIG_INSTALL_TYPE,$_content['install_type'],self::CONFIG_APP); |
||||
65 | Api\Config::save_value(self::CONFIG_POSTPONE_SUBMIT,null,self::CONFIG_APP); // remove evtl. postpone time |
||||
66 | $what = 'submitted'; |
||||
67 | } |
||||
68 | Egw::redirect_link('/admin/index.php','ajax=true&statistics='.($what ? $what : 'canceled'),'admin'); |
||||
69 | } |
||||
70 | $sel_options['usage_type'] = array( |
||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||
71 | 'commercial' => lang('Commercial: all sorts of companies'), |
||||
72 | 'governmental' => lang('Governmental: incl. state or municipal authorities or services'), |
||||
73 | 'educational' => lang('Educational: Universities, Schools, ...'), |
||||
74 | 'non-profit' => lang('Non profit: Clubs, associations, ...'), |
||||
75 | 'personal' => lang('Personal: eg. within a family'), |
||||
76 | 'other' => lang('Other'), |
||||
77 | ); |
||||
78 | $sel_options['install_type'] = array( |
||||
79 | 'docker' => lang('Docker'), |
||||
80 | 'package' => lang('RPM or Debian package'), |
||||
81 | 'git' => lang('Git clone'), |
||||
82 | 'archive' => lang('Archive: zip or tar'), |
||||
83 | 'other' => lang('Other'), |
||||
84 | ); |
||||
85 | $sel_options['postpone'] = array( |
||||
86 | //10 => '10 secs', |
||||
87 | 3600 => lang('one hour'), |
||||
88 | 2*3600 => lang('two hours'), |
||||
89 | 24*3600 => lang('one day'), |
||||
90 | 2*24*3600 => lang('two days'), |
||||
91 | 7*24*3600 => lang('one week'), |
||||
92 | 14*24*3600 => lang('two weeks'), |
||||
93 | 30*24*3600 => lang('one month'), |
||||
94 | 60*24*3600 => lang('two months'), |
||||
95 | ); |
||||
96 | $config = Api\Config::read(self::CONFIG_APP); |
||||
97 | //_debug_array($config); |
||||
98 | $content = array_merge(self::gather_data(),array( |
||||
99 | 'statistic_url' => self::STATISTIC_URL, |
||||
100 | 'submit_host' => parse_url(self::SUBMIT_URL,PHP_URL_HOST), |
||||
101 | 'submit_url' => self::SUBMIT_URL, |
||||
102 | 'last_submitted' => $config[self::CONFIG_LAST_SUBMIT], |
||||
103 | )); |
||||
104 | //_debug_array($content); |
||||
105 | |||||
106 | // show previous submit ID |
||||
107 | if ($config['statistics_submit_id']) |
||||
108 | { |
||||
109 | $content['submit_id'] = $config['statistics_submit_id'] == '***none***' ? '' : $config['statistics_submit_id']; |
||||
110 | } |
||||
111 | // show previous Api\Country |
||||
112 | if ($config[self::CONFIG_COUNTRY]) |
||||
113 | { |
||||
114 | $content['country'] = $config[self::CONFIG_COUNTRY] == '***multinational***' ? '' : $config[self::CONFIG_COUNTRY]; |
||||
115 | } |
||||
116 | // show previous usage_type |
||||
117 | if ($config[self::CONFIG_USAGE_TYPE]) |
||||
118 | { |
||||
119 | $content['usage_type'] = $config[self::CONFIG_USAGE_TYPE]; |
||||
120 | } |
||||
121 | // check if we detected svn or rpm/deb packages --> readonly |
||||
122 | if ($content['install_type'] && isset($sel_options['install_type'][$content['install_type']])) |
||||
123 | { |
||||
124 | $sel_options['install_type'] = array($content['install_type'] => $sel_options['install_type'][$content['install_type']]); |
||||
125 | } |
||||
126 | // else default to previous type |
||||
127 | elseif($config[self::CONFIG_INSTALL_TYPE]) |
||||
128 | { |
||||
129 | $content['install_type'] = $config[self::CONFIG_INSTALL_TYPE]; |
||||
130 | } |
||||
131 | // check if we are due for a new submission |
||||
132 | if (!isset($config[self::CONFIG_LAST_SUBMIT]) || $config[self::CONFIG_LAST_SUBMIT ] <= time()-self::SUBMISION_RATE) |
||||
133 | { |
||||
134 | // clear etemplate_exec_id and replace form.action, before submitting the form |
||||
135 | $content['onclick'] = "return app.admin.submit_statistic(this.form,'$content[submit_url]');"; |
||||
136 | } |
||||
137 | else // we are not due --> tell it the user |
||||
138 | { |
||||
139 | $readonlys['submit'] = $readonlys['postpone'] = true; |
||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||
140 | $content['msg'] = lang('Your last submission was less then %1 days ago!', |
||||
141 | ceil((time()-$config[self::CONFIG_LAST_SUBMIT])/24/3600)); |
||||
0 ignored issues
–
show
The call to
lang() has too many arguments starting with ceil(time() - $config[se...ST_SUBMIT] / 24 / 3600) .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() |
|||||
142 | } |
||||
143 | $GLOBALS['egw_info']['flags']['app_header'] = lang('Submit statistic information'); |
||||
144 | $tmpl = new Etemplate('admin.statistics'); |
||||
145 | $tmpl->exec('admin.admin_statistics.submit',$content,$sel_options,$readonlys); |
||||
146 | } |
||||
147 | |||||
148 | /** |
||||
149 | * Gather statistical data to submit |
||||
150 | * |
||||
151 | * @return array key => value pairs |
||||
152 | */ |
||||
153 | protected static function gather_data() |
||||
154 | { |
||||
155 | // submit id is sha1 hash from install_id |
||||
156 | $data['submit_id'] = sha1($GLOBALS['egw_info']['server']['install_id']); |
||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||
157 | |||||
158 | $data['country'] = $GLOBALS['egw_info']['user']['preferences']['common']['country']; |
||||
159 | |||||
160 | // maintenance release (incl. EPL) |
||||
161 | $data['version'] = $GLOBALS['egw_info']['server']['versions']['maintenance_release']; |
||||
162 | |||||
163 | // sessions in the last 30 days |
||||
164 | $data['sessions'] = $GLOBALS['egw']->db->query('SELECT COUNT(*) FROM egw_access_log WHERE li > '.(time()-30*24*3600))->fetchColumn(); |
||||
165 | |||||
166 | // total accounts from accounts table or ldap |
||||
167 | $GLOBALS['egw']->accounts->search(array( |
||||
168 | 'type' => 'accounts', |
||||
169 | 'start' => 0, |
||||
170 | )); |
||||
171 | $data['users'] = $GLOBALS['egw']->accounts->total; |
||||
172 | |||||
173 | $data['php'] = PHP_VERSION.': '.PHP_SAPI; |
||||
174 | $data['os'] = PHP_OS; |
||||
175 | // @ required to get ride of warning, if files are outside of open_basedir |
||||
176 | $matches = null; |
||||
177 | if (@file_exists($file = '/etc/lsb-release') && preg_match('/^DISTRIB_DESCRIPTION="?([^"]+)"?/mi', file_get_contents($file), $matches)) |
||||
178 | { |
||||
179 | $data['os'] .= ': '.$matches[1]; |
||||
180 | } |
||||
181 | elseif (@file_exists($file = '/etc/SuSE-release') || @file_exists($file = '/etc/redhat-release') || @file_exists($file = '/etc/debian_version')) |
||||
182 | { |
||||
183 | $data['os'] .= ': '.str_replace(array("\n","\r"),'',implode(',',file($file))); |
||||
184 | } |
||||
185 | if(file_exists(EGW_INCLUDE_ROOT.'/.git')) |
||||
186 | { |
||||
187 | $data['install_type'] = 'git'; |
||||
188 | } |
||||
189 | elseif (file_exists('/entrypoint.sh')) |
||||
190 | { |
||||
191 | $data['install_type'] = 'docker'; |
||||
192 | } |
||||
193 | elseif(EGW_INCLUDE_ROOT == '/usr/share/egroupware' && PHP_OS == 'Linux' && is_link('/usr/share/egroupware/header.inc.php')) |
||||
194 | { |
||||
195 | $data['install_type'] = 'package'; |
||||
196 | } |
||||
197 | foreach(array_keys($GLOBALS['egw_info']['apps']) as $app) |
||||
198 | { |
||||
199 | if (in_array($app,array( |
||||
200 | 'admin','phpgwapi','api','sambaadmin','developer_tools', |
||||
201 | 'home','preferences','etemplate','registration','manual', |
||||
202 | ))) |
||||
203 | { |
||||
204 | continue; // --> ignore to not submit too much |
||||
205 | } |
||||
206 | if (($users = self::gather_app_users($app))) // ignore apps noone is allowed to run |
||||
207 | { |
||||
208 | $data['apps'][$app] = $app.':'.round(100.0*$users/$data['users']).'%'; |
||||
209 | if (($entries = self::gather_app_entries($app))) |
||||
210 | { |
||||
211 | $data['apps'][$app] .= ':'.$entries; |
||||
212 | } |
||||
213 | } |
||||
214 | } |
||||
215 | ksort($data['apps']); |
||||
216 | $data['apps'] = implode("\n",$data['apps']); |
||||
217 | |||||
218 | return $data; |
||||
219 | } |
||||
220 | |||||
221 | /** |
||||
222 | * Get percentage of users allowed to use an application |
||||
223 | * |
||||
224 | * @param string $app |
||||
225 | * @return int number of users allowed to run application |
||||
226 | */ |
||||
227 | static function gather_app_users($app) |
||||
228 | { |
||||
229 | $users = array(); |
||||
230 | if (($access = $GLOBALS['egw']->acl->get_ids_for_location('run',1,$app))) |
||||
231 | { |
||||
232 | foreach($access as $uid) |
||||
233 | { |
||||
234 | if ($uid > 0) |
||||
235 | { |
||||
236 | $users[] = $uid; |
||||
237 | } |
||||
238 | elseif (($members = $GLOBALS['egw']->accounts->members($uid,true))) |
||||
239 | { |
||||
240 | $users = array_merge($users,$members); |
||||
241 | } |
||||
242 | } |
||||
243 | $users = array_unique($users); |
||||
244 | } |
||||
245 | return count($users); |
||||
246 | } |
||||
247 | |||||
248 | /** |
||||
249 | * Get percentage of users allowed to use an application |
||||
250 | * |
||||
251 | * @param string $app |
||||
252 | * @return int |
||||
253 | */ |
||||
254 | static function gather_app_entries($app) |
||||
255 | { |
||||
256 | // main table for each application |
||||
257 | static $app2table = array( |
||||
258 | 'addressbook' => 'egw_addressbook', |
||||
259 | 'bookmarks' => 'egw_bookmarks', |
||||
260 | 'calendar' => 'egw_cal_dates', |
||||
261 | 'infolog' => 'egw_infolog', |
||||
262 | 'filemanager' => 'egw_sqlfs', |
||||
263 | 'gallery' => 'g2_Item', |
||||
264 | 'news_admin' => 'egw_news WHERE news_submittedby > 0', // exclude imported rss feeds |
||||
265 | 'polls' => 'egw_polls', |
||||
266 | 'projectmanager' => 'egw_pm_projects', |
||||
267 | 'phpbrain' => 'egw_kb_articles', |
||||
268 | 'resources' => 'egw_resources', |
||||
269 | 'sitemgr' => 'egw_sitemgr_pages', |
||||
270 | 'syncml' => 'egw_syncmlsummary', |
||||
271 | 'timesheet' => 'egw_timesheet', |
||||
272 | 'tracker' => 'egw_tracker', |
||||
273 | 'wiki' => 'egw_wiki_pages', |
||||
274 | 'mydms' => 'phpgw_mydms_Documents', |
||||
275 | ); |
||||
276 | if (($table = $app2table[$app])) |
||||
277 | { |
||||
278 | try { |
||||
279 | $entries = (int)$GLOBALS['egw']->db->query('SELECT COUNT(*) FROM '.$table)->fetchColumn(); |
||||
280 | //echo "$app ($table): $entries<br />\n"; |
||||
281 | } |
||||
282 | catch(Api\Db\Exception $e) { |
||||
283 | unset($e); |
||||
284 | $entries = null; |
||||
285 | } |
||||
286 | } |
||||
287 | return $entries; |
||||
288 | } |
||||
289 | |||||
290 | /** |
||||
291 | * Check if next submission is due, in which case we call submit and NOT return to the admin hook |
||||
292 | * |
||||
293 | * @param boolean $redirect should we redirect or return true |
||||
294 | * @return boolean true if statistic submission is due |
||||
295 | */ |
||||
296 | public static function check($redirect=true) |
||||
297 | { |
||||
298 | $config = Api\Config::read(self::CONFIG_APP); |
||||
299 | |||||
300 | if (isset($config[self::CONFIG_POSTPONE_SUBMIT]) && $config[self::CONFIG_POSTPONE_SUBMIT] > time() || |
||||
0 ignored issues
–
show
|
|||||
301 | isset($config[self::CONFIG_LAST_SUBMIT ]) && $config[self::CONFIG_LAST_SUBMIT ] > time()-self::SUBMISION_RATE) |
||||
302 | { |
||||
303 | return false; |
||||
304 | } |
||||
305 | if (!$redirect) return true; |
||||
306 | |||||
307 | //die('Due for new statistics submission: last_submit='.$config[self::CONFIG_LAST_SUBMIT ].', postpone='.$config[self::CONFIG_POSTPONE_SUBMIT].', '.function_backtrace()); |
||||
308 | Egw::redirect_link('/index.php',array( |
||||
309 | 'menuaction' => 'admin.admin_ui.index', |
||||
310 | 'ajax' => 'true', |
||||
311 | 'load' => 'admin.admin_statistics.submit', |
||||
312 | )); |
||||
313 | } |
||||
314 | } |
||||
315 |