Code

Applied in_array strict patches from trunk
[gosa.git] / gosa-core / plugins / generic / statistics / class_statistics.inc
1 <?php
3 class statistics extends plugin
4 {
5     var $plHeadline = 'Statistics';
6     var $plDescription = 'GOsa usage statistics';
7     var $plShortIcon = 'statistics.png';
8     var $plIcon = 'plugin.png';
9     
10     var $rpcHandle = NULL;
11     var $rpcConfigured = FALSE;
13     // Graph data 
14     var $statisticData = array();       // Via rpc received stats
16     // Font used in graphs
17     var $font = "./themes/default/fonts/LiberationSans-Regular.ttf";
19     // Datepicker initial
20     var $graph1DatePicker1 = 0;
21     var $graph1DatePicker2 = 0;
23     // A collection of timestamps for unsubmitted statistics data.
24     var $unsbmittedFiles = NULL;
26     var $graphs = array();
27     var $selectedGraphType = 0;
29     var $serverAccessible = FALSE;
30     var $instanceRegistered = FALSE;
31     var $registrationNotWanted = FALSE;
33     var $initialized = FALSE;
35     function __construct($config)
36     {
37         plugin::plugin($config, NULL);
38     }
40     function init()
41     {
42         // Detect registration status first
43         $this->serverAccessible = $this->config->registration->isServerAccessible();
44         $this->registrationNotWanted = $this->config->registration->registrationNotWanted();
45         $this->instanceRegistered = $this->config->registration->isInstanceRegistered();
46         if($this->instanceRegistered){
47             $this->graphs[] = new categoryActionsOverTime($this->config); 
48             $this->graphs[] = new memoryUsageChart($this->config); 
49             $this->graphs[] = new cpuLoadChart($this->config); 
50             $this->graphs[] = new renderTimeChart($this->config); 
51             $this->graphs[] = new durationTimeChart($this->config); 
52             $this->graphs[] = new objectCountChart($this->config); 
53             $this->graphs[] = new actionSelectChart($this->config); 
54             $this->graphs[] = new passwordChangeChart($this->config); 
55             $this->staticChart1 = new pieChart1($this->config); 
56             $this->staticChart2 = new pieChart2($this->config); 
59             // Init start and stop times for graph 1
60             $this->graph1DatePicker1 = date('d.m.Y', time() - 28 * 24 * 60 *60);
61             $this->graph1DatePicker2 = date('d.m.Y', time());
63             // First try to retrieve values via RPC
64             $this->rpcConfigured = TRUE;
65             $this->rpcHandle = $this->config->getRpcHandle(
66                     $this->config->registration->getRegistrationServer(),
67                     $this->config->getInstanceUUID(),
68                     $this->config->configRegistry->getPropertyValue('GOsaRegistration','instancePassword'),
69                     TRUE);
71             $this->initialized = TRUE;
72         }
73     }
76     /*! \brief      Returns a list local stored statistic files
77         @param      Array   A list of filenames and dates.
78      */ 
79     function getLocalStatisticsFiles()
80     {
81         $res = stats::getLocalStatFiles();
82         $tmp = array();
83         if(count($res)){
84             foreach($res as $file){
85                 $date = strtotime($file);
86                 if($date){
87                     $tmp[$file] = $date;
88                 }
89             }
90         }
91         return($tmp);
92     }
94    
95     /*! \brief      Returns a list of not transmitted stat files (except files for the current day)
96      *  @return     Array   A list of unsubmitted statistic files.
97      */ 
98     function getUnsubmittedStatistics()
99     {
100         $alreadyTransmitted = $this->getStatisticsDatesFromServer();
101         if($alreadyTransmitted == NULL){
102             return(NULL);
103         }
105         $available = $this->getLocalStatisticsFiles();
107         $unsubmitted = array();
108         foreach($available as $key => $day){
109             if(!isset($alreadyTransmitted[$key])) $unsubmitted [$key] = $day;
110         }
112         // Exclude statistic collection from today, they are still active and cannot be submitted.
113         $curDate =  date('Y-m-d');
114         if(isset($unsubmitted)) unset($unsubmitted[$curDate]);
115         return($unsubmitted);  
116     }
119     /*! \brief      Request a list of dates for which the server can return statistics.
120         @param      Array   A list of dates    $ret=[iso-str] = timestamp
121      */ 
122     function getStatisticsDatesFromServer()
123     {
124         // Do not request anything while rpc isn't configured.
125         if(!$this->rpcConfigured){
126             return(array());
127         }
128         
129         // Try to gather statistic dates from the backenbd.
130         $res = $this->rpcHandle->getInstanceStatDates();
131         $dates = array();
132         if(!$this->rpcHandle->success()){
133             msg_dialog::display(_("Error"),msgPool::rpcError($this->rpcHandle->get_error()),ERROR_DIALOG);
134             return(NULL);
135         }else{
136             foreach($res as $date){
137                 $dates[$date] = strtotime($date);
138             }
139         }
140         $this->rpcHandle_Error = !$this->rpcHandle->success();
141         return($dates);
142     }
145     function execute()
146     {
148         if(!$this->initialized) $this->init();
150         $smarty = get_smarty();
151        
152         // Check registration status, we need at least 'registered'. 
153         $smarty->assign("instanceRegistered", $this->instanceRegistered);
154         $smarty->assign("serverAccessible", $this->serverAccessible);
155         $smarty->assign("registrationNotWanted", $this->registrationNotWanted);
156         $plist = session::get('plist');
157         $id = array_search('dashBoard', $plist->pluginList);
158         $smarty->assign('dashBoardId', $id);
160         // If we have an unregistered instance of GOsa, display a message which
161         //  allows to registrate GOsa
162         if(!$this->instanceRegistered || !$this->serverAccessible){
163             return($smarty->fetch(get_template_path('statistics.tpl', TRUE)));
164         }
166         $smarty->assign('graph1DatePicker1', $this->graph1DatePicker1);
167         $smarty->assign('graph1DatePicker2', $this->graph1DatePicker2);
169         // Get list of unsubmitted files.
170         if($this->unsbmittedFiles == NULL){
171             $this->unsbmittedFiles = $this->getUnsubmittedStatistics();
172         }
174         // Do not render anything if we are not prepared to send and receive data via rpc.
175         $smarty->assign("rpcConfigured", $this->rpcConfigured);
176         $smarty->assign("validRpcHandle", TRUE);
177         if(!$this->rpcHandle){
178             $smarty->assign("validRpcHandle", FALSE);
179             return($smarty->fetch(get_template_path('statistics.tpl', TRUE)));
180         }
182         // Assign list of selectable graphs 
183         $tmp = array();
184         foreach($this->graphs as $id => $gClass){
185             $tmp[$id] = $gClass->getTitle();
186         }
187         $smarty->assign("selectedGraphType", $this->selectedGraphType);
188         $smarty->assign("availableGraphs", $tmp);
190         // Send stats 
191         if(isset($_POST['transmitStatistics'])){
192             $this->unsbmittedFiles = $this->getUnsubmittedStatistics();
193             foreach($this->unsbmittedFiles as $filename => $date){
195                 $strDate = date('Y-m-d', $date);
196                 $tmp = stats::generateStatisticDump($filename);
197                 $dump = array();
198                 $invalidDateCount = 0;
199                 foreach($tmp as $entry){
200                    
201                     // Check if the result date equals the report file date
202                     //  - If not update the entry. 
203                     if($entry['date'] != $strDate){
204                         $entry['date'] = $strDate;
205                         $invalidDateCount ++;
206                     }
207                     $dump[] = array_values($entry);
208                 }
210                 // Merge result with ldap object count 
211                 $objectCount = stats::getLdapObjectCount($this->config, TRUE, date('Y-m-d', $date));
212                 foreach($objectCount as $entry){
214                     // Check if the result date equals the report file date
215                     //  - If not update the entry. 
216                     if($entry['date'] != $strDate){
217                         $entry['date'] = $strDate;
218                         $invalidDateCount ++;
219                     }
220                     $dump[] = array_values($entry);
221                 }
223                 // Warn about invalid dates transmitted
224                 if($invalidDateCount) trigger_error(sprintf("Report contained %s entries with invalid date string!",$invalidDateCount));
225             
226                 // Send in our report now.
227                 $res = $this->rpcHandle->updateInstanceStatus($dump);
228                 if(!$this->rpcHandle->success()){
229                     msg_dialog::display(_("Error"),msgPool::rpcError($this->rpcHandle->get_error()),ERROR_DIALOG);
230                 }else{
231                     stats::removeStatsFile($filename);
232                 }
233                 $this->rpcHandle_Error = !$this->rpcHandle->success();
234             }
235             $this->unsbmittedFiles = $this->getUnsubmittedStatistics();
236         }
238         // Transmit daily statistics to GOsa-Server
239         if((isset($_POST['receiveStatistics']) || !count($this->statisticData)) && $this->rpcConfigured){
240             $start = strtotime($this->graph1DatePicker1);
241             $stop  = strtotime($this->graph1DatePicker2);
242             $res = $this->rpcHandle->getInstanceStats($start,$stop);
243             if(!$this->rpcHandle->success()){
244                 msg_dialog::display(_("Error"),msgPool::rpcError($this->rpcHandle->get_error()),ERROR_DIALOG);
245             }elseif($res){
246                 $this->statisticData = $this->prepareGraphData($res); 
247             }
248             $this->rpcHandle_Error = !$this->rpcHandle->success();
249         }
250        
251         // Update graphs 
252         $this->reloadGraphs();
254         $smarty->assign('staticChart1_ID', $this->staticChart1->getGraphID());
255         $smarty->assign('staticChart2_ID', $this->staticChart2->getGraphID());
257         $curGraph = $this->graphs[$this->selectedGraphType];
258         $smarty->assign('curGraphID', $curGraph->getGraphID());
259         $smarty->assign('curGraphOptions', $curGraph->getGraphOptions());
260         $smarty->assign('curSeriesSelector', $curGraph->getSeriesSelector());
261         $smarty->assign('unsbmittedFiles', count($this->unsbmittedFiles));
262         $smarty->assign('unsbmittedFilesMsg', sprintf(
263                     _("You have currently %s unsubmitted statistic collection, do you want to transmit them now?"),
264                     count($this->unsbmittedFiles)));
265     
266         $smarty->assign('rpcHandle_Error', $this->rpcHandle_Error);
267         return($smarty->fetch(get_template_path('statistics.tpl', TRUE)));
268     }
271     /*! \brief      Prepares the graph data we've received from the rpc-service.
272      *              This method will construct a usable data-array with converted 
273      *               date strings.
274      */
275     function prepareGraphData($res)
276     {   
277         // Object categories which has to mapped to 'systems'
278         $mapSystems = array('server','terminal','workstation', 'opsi', 
279                 'component','phone', 'winworkstation', 'printer', 'incoming');
281         /* Build up array which represents the amount of errors per
282          *  interval.
283          */
284         $gData = array();
285         foreach($res['errorsPerInterval'] as $dateStr => $data){
286             $date = strtotime($dateStr);
287             $gData['errorsPerInterval'][$date] = $data;
288         }
289         ksort($gData['errorsPerInterval']);
292         /* Build up timeline
293          */
294         $Xam = 5; 
295         $cnt = 0;
296         $numCnt = $res['errorsPerInterval'];
297         foreach($gData['errorsPerInterval'] as $date => $data){
298             if((count($numCnt) <= $Xam) || 
299                     ($cnt % (floor(count($numCnt) / $Xam )) == 0)){
300                 $gData['dates'][$date] = date('d.m.Y', $date);
301             }else{
302                 $gData['dates'][$date] = ' ';
303             }
304             $cnt ++;
305         }
306         ksort($gData['dates']);
307         
308         /* Build up 'actions per category' array, this will later
309          *   be represented using a pie chart.
310          */
311         $gData['actionsPerCategory'] = $res['actionsPerCategory'];
312         arsort($gData['actionsPerCategory']);
315         /* Build up system-info array per interval.
316          */
317         foreach($res['usagePerInterval'] as $dateStr => $data){
318             $date = strtotime($dateStr);
319             foreach($data as $type => $count){
320                 $gData['usagePerInterval'][$type][$date] = $count;
321             }
322         }
323         foreach($gData['usagePerInterval'] as $key => $data)
324             ksort($gData['usagePerInterval'][$key]);
327         /* Prepare actions-per-interval array.
328          */   
329         $gData['actionsGraph'] = array(); 
330         foreach($res['actionsGraph'] as $category => $data){
331             if(empty($category)) continue;
332             foreach($data as $dateStr => $count){
333                 $date = strtotime($dateStr);
334                 $gData['actionsGraph'][$category][$date]=$count;
335             }
336             ksort($gData['actionsGraph'][$category]);
337         }
339         /* Prepare actions-per-interval array.
340          */   
341         $gData['actionTypeGraph'] = array(); 
342         foreach($res['actionTypeGraph'] as $action => $aData){
343             foreach($aData as $category => $data){
344                 if(empty($category)) continue;
346                 $list = preg_split("/, /", $category);
347                 if(count(array_intersect($mapSystems, $list))){ 
348                     $category = 'systems';
349                 }
351                 // Add missing date stamps
352                 foreach($gData['dates'] as $timestamp => $value){
353                     $gData['actionTypeGraph'][$action][$category][$timestamp]=0;
354                 }
356                 foreach($data as $dateStr => $count){
357                     $date = strtotime($dateStr);
358                     $gData['actionTypeGraph'][$action][$category][$date]=$count;
359                 }
360                 ksort($gData['actionTypeGraph'][$action][$category]);
361             }
362         }
364         /* Prepare object count per interval array.
365          */   
366         $gData['objectCountPerInterval'] = array(); 
367         foreach($res['objectCountPerInterval'] as $category => $data){
368             if(empty($category)) continue;
369             if(in_array_strict($category,$mapSystems)){
370                 $category = 'systems';
371             }
373             // Skip series which are not interesting for us
374             if(!in_array_strict($category,array('users','groups','department','systems','ogroups','fai'))){
375                 $category = 'remaining';
376             }
378             foreach($data as $dateStr => $count){
379                 $date = strtotime($dateStr);
381                 if(!isset($gData['objectCountPerInterval'][$category][$date])){
382                     $gData['objectCountPerInterval'][$category][$date]=0;
383                 }
384                 $gData['objectCountPerInterval'][$category][$date] += $count;
385             }
386             ksort($gData['objectCountPerInterval'][$category]);
387         }
388         // Move remaining to the end of the list
389         if(isset($gData['objectCountPerInterval']['remaining'])){
390             $data = $gData['objectCountPerInterval']['remaining'];
391             unset($gData['objectCountPerInterval']['remaining']);
392             $gData['objectCountPerInterval']['remaining'] = $data;
393         }
395         // Clean data from unusable categories like ('terminals workstations, ...')
396         foreach($gData as $serieName => $seriesData){
397             foreach($seriesData as $key => $data){
398                 $list = preg_split("/, /", $key);
399                 if(count(array_intersect($mapSystems, $list))){
400                     unset($gData[$serieName][$key]);
401                     $gData[$serieName]['systems'] = $data;
402                 }
403             }
404         }
406         // Get info about used password hashes 
407         $gData['usedPasswordHashes'] = array();
408         foreach($res['usedPasswordHashes'] as $category => $data){
410             // Add missing date stamps
411             foreach($gData['dates'] as $timestamp => $value){
412                 $gData['usedPasswordHashes'][$category][$timestamp]=0;
413             }
415             foreach($data as $dateStr => $count){
416                 $date = strtotime($dateStr);
417                 $gData['usedPasswordHashes'][$category][$date]=$count;
418             }
419             ksort($gData['usedPasswordHashes'][$category]);
420         }
422         // Get action usage, to be able to render a pie chart about most done actions.
423         $gData['actionsPerPluginAction'] = $res['actionsPerPluginAction'];
424         return($gData);
425     }
428     function check()
429     {
430         $messages = plugin::check();
431         return($messages);
432     }
435     function save_object()
436     {
437         // Nothing to do for not registered accounts.
438         if(!$this->serverAccessible || !$this->instanceRegistered) return;
440         plugin::save_object();
441         if(isset($_POST['graph1DatePicker1'])) $this->graph1DatePicker1 = get_post('graph1DatePicker1');
442         if(isset($_POST['graph1DatePicker2'])) $this->graph1DatePicker2 = get_post('graph1DatePicker2');
443    
444         if(isset($_POST['selectedGraphType'])) $this->selectedGraphType = get_post('selectedGraphType');
446         $this->staticChart1->save_object();
447         $this->staticChart2->save_object();
449         $curGraph = $this->graphs[$this->selectedGraphType];
450         $curGraph->save_object();
451     }
454     /*! \brief  Reload the graph images.
455      */ 
456     function reloadGraphs()
457     {
458         new pChartInclude();
460         $gData = $this->statisticData;
461         if(!count($gData)){
462             return;
463         }
464         $curGraph = $this->graphs[$this->selectedGraphType];
465         $curGraph->setGraphData($gData);
466         $curGraph->render();
468         $this->staticChart1->setGraphData($gData);
469         $this->staticChart1->render();
470         $this->staticChart2->setGraphData($gData);
471         $this->staticChart2->render();
472     }
474 ?>