3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
6 * Handle Telemetry data
10 * Copyright © 2017 GLPI and Contributors
11 * Copyright © 2017-2018 The Galette Team
13 * This file is part of Galette (http://galette.tuxfamily.org).
15 * Galette is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation, either version 3 of the License, or
18 * (at your option) any later version.
20 * Galette is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with Galette. If not, see <http://www.gnu.org/licenses/>.
31 * @author Johan Cwiklinski <johan@x-tnd.be>
32 * @copyright 2017 GLPI and Contributors
33 * @copyright 2017-2018 The Galette Team
34 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
35 * @link http://galette.tuxfamily.org
36 * @since Available since 0.9
39 namespace Galette\Util
;
43 use Galette\Core\Preferences
;
44 use Galette\Core\Plugins
;
47 * Handle Telemetry data
52 * @author Johan Cwiklinski <johan@x-tnd.be>
53 * @copyright 2017 GLPI and Contributors
54 * @copyright 2017-2018 The Galette Team
55 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
56 * @link http://galette.tuxfamily.org
57 * @since Available since 0.9
64 private $quick = false;
69 * @param Db $zdb Database instance
70 * @param Preferences $prefs Preferences instance
71 * @param Plugins $plugins Plugins instance
73 public function __construct(Db
$zdb, Preferences
$prefs, Plugins
$plugins)
76 $this->prefs
= $prefs;
77 $this->plugins
= $plugins;
81 * Grab telemetry information
85 public function getTelemetryInfos()
88 'galette' => $this->grabGaletteInfos(),
90 'db' => $this->grabDbInfos(),
91 'web_server' => $this->grabWebserverInfos(),
92 'php' => $this->grabPhpInfos(),
93 'os' => $this->grabOsInfos()
100 * Grab Galette part information
104 public function grabGaletteInfos()
107 'uuid' => $this->getInstanceUuid(),
108 'version' => GALETTE_VERSION
,
110 'default_language' => $this->prefs
->pref_lang
,
112 'avg_members' => $this->getAverage(\Galette\Entity\Adherent
::TABLE
),
113 'avg_contributions' => $this->getAverage(\Galette\Entity\Contribution
::TABLE
),
114 'avg_transactions' => $this->getAverage(\Galette\Entity\Transaction
::TABLE
)
118 $plugins = $this->plugins
->getModules();
119 foreach ($plugins as $plugin) {
120 $galette['plugins'][] = [
121 'key' => $plugin['name'],
122 'version' => $plugin['version']
130 * Grab DB part information
134 public function grabDbInfos()
136 $dbinfos = $this->zdb
->getInfos();
141 * Grab web server part information
145 public function grabWebserverInfos()
151 // check if host is present (do no throw php warning in contrary of get_headers)
152 if (PHP_SAPI
!== 'cli') {
153 $headers = get_headers($this->prefs
->getURL());
156 if (is_array($headers)) {
157 //BEGIN EXTRACTING SERVER DETAILS
158 $pattern = '#^Server:*#i';
159 $matches = preg_grep($pattern, $headers);
161 if (count($matches)) {
162 $infos = current($matches);
163 $pattern = '#Server: ([^ ]+)/([^ ]+)#i';
164 preg_match($pattern, $infos, $srv_infos);
165 if (count($srv_infos) == 3) {
166 $engine = $srv_infos[1];
167 $version = $srv_infos[2];
174 'version' => $version
181 * Grab PHP part information
185 public function grabPhpInfos()
188 'version' => str_replace(PHP_EXTRA_VERSION
, '', PHP_VERSION
),
189 'modules' => get_loaded_extensions(),
191 'max_execution_time' => ini_get('max_execution_time'),
192 'memory_limit' => ini_get('memory_limit'),
193 'post_max_size' => ini_get('post_max_size'),
194 'safe_mode' => ini_get('safe_mode'),
195 'session' => ini_get('session.save_handler'),
196 'upload_max_filesize' => ini_get('upload_max_filesize')
204 * Grab OS part information
208 public function grabOsInfos()
211 'family' => php_uname('s'),
212 'distribution' => '',
213 'version' => php_uname('r')
222 * @param string $table Table to query
223 * @param array $where Where clause, if any
227 public function getCount($table, $where = [])
229 $select = $this->zdb
->select($table);
231 'cnt' => new \Laminas\Db\Sql\
Expression(
235 $results = $this->zdb
->execute($select);
236 $result = $results->current();
237 return (int)$result->cnt
;
241 * Calculate average parts
243 * @param string $table Table to query
244 * @param array $where Where clause, if any
248 private function getAverage($table, $where = [])
250 $count = $this->getCount($table, $where);
254 } elseif ($count <= 250) {
256 } elseif ($count <= 500) {
258 } elseif ($count <= 1000) {
260 } elseif ($count <= 5000) {
267 * Send telemetry information
271 public function send()
273 $data = $this->getTelemetryInfos();
274 $infos = json_encode(['data' => $data]);
276 $uri = GALETTE_TELEMETRY_URI
. 'telemetry';
277 $ch = curl_init($uri);
280 CURLOPT_USERAGENT
=> 'Galette/' . GALETTE_VERSION
,
281 CURLOPT_RETURNTRANSFER
=> 1,
282 CURLOPT_POSTFIELDS
=> $infos,
283 CURLOPT_HTTPHEADER
=> ['Content-Type:application/json']
285 if ($this->quick
=== true) {
286 //set entire curl call timeout
287 $opts[CURLOPT_TIMEOUT
] = 3;
288 //set curl connection timeout
289 $opts[CURLOPT_CONNECTTIMEOUT
] = 2;
292 curl_setopt_array($ch, $opts);
293 $content = json_decode(curl_exec($ch));
294 $errstr = curl_error($ch);
297 if ($content && property_exists($content, 'message')) {
298 if (property_exists($content, 'errors')) {
300 foreach ($content->errors
as $error) {
301 $errors .= "\n" . $error->property
. ': ' . $error->message
;
303 throw new \
RuntimeException($errors);
306 $this->prefs
->pref_telemetry_date
= date('Y-m-d H:i:s');
307 $this->prefs
->store();
312 $message = 'Something went wrong sending telemetry information';
314 $message .= ": $errstr";
320 throw new \
RuntimeException($message);
327 * @param string $type UUID type (either instance or registration)
331 private function getUuid($type)
333 $param = 'pref_' . $type . '_uuid';
334 $uuid = $this->prefs
->$param;
336 $uuid = self
::generateUuid($type);
346 private function getInstanceUuid()
348 return $this->getUuid('instance');
352 * Get registration UUID
356 final public function getRegistrationUuid()
358 return $this->getUuid('registration');
363 * Generates an unique identifier and store it
365 * @param string $type UUID type (either instance or registration)
369 final public function generateUuid($type)
371 $uuid = $this->getRandomString(40);
372 $param = 'pref_' . $type . '_uuid';
373 $this->prefs
->$param = $uuid;
374 $this->prefs
->store();
379 * Generates an unique identifier for current instance and store it
383 final public function generateInstanceUuid()
385 return self
::generateUuid('instance');
389 * Generates an unique identifier for current instance and store it
393 final public function generateRegistrationUuid()
395 return self
::generateUuid('registration');
399 * Get date telemetry has been sent
403 public function getSentDate()
405 return $this->prefs
->pref_telemetry_date
;
409 * Get date of registration
413 public function getRegistrationDate()
415 return $this->prefs
->pref_registration_date
;
419 * Does telemetry infos has been sent already?
423 public function isSent()
425 return $this->getSentDate() != false;
429 * Is instance registered?
433 public function isRegistered()
435 return $this->getRegistrationDate() != false;
439 * Get a random string
441 * @param integer $length of the random string
445 * @see https://stackoverflow.com/questions/4356289/php-random-string-generator/31107425#31107425
447 private function getRandomString($length)
449 $keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
451 $max = mb_strlen($keyspace, '8bit') - 1;
452 for ($i = 0; $i < $length; ++
$i) {
453 $str .= $keyspace[random_int(0, $max)];
460 * Will set a short timeout on curl calls
464 public function setQuick()