Issues (2963)

includes/html/functions.inc.php (2 issues)

1
<?php
2
3
/**
4
 * LibreNMS
5
 *
6
 *   This file is part of LibreNMS
7
 *
8
 * @author     LibreNMS Contributors <[email protected]>
9
 * @copyright  (C) 2006 - 2012 Adam Armstrong (as Observium)
10
 * @copyright  (C) 2013 LibreNMS Group
11
 */
12
13
use LibreNMS\Config;
0 ignored issues
show
This use statement conflicts with another class in this namespace, Config. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
14
use LibreNMS\Util\Debug;
15
use LibreNMS\Util\Number;
16
use LibreNMS\Util\Rewrite;
17
18
/**
19
 * Compare $t with the value of $vars[$v], if that exists
20
 *
21
 * @param  string  $v  Name of the var to test
22
 * @param  string  $t  Value to compare $vars[$v] to
23
 * @return bool true, if values are the same, false if $vars[$v]
24
 *              is unset or values differ
25
 */
26
function var_eq($v, $t)
27
{
28
    global $vars;
29
    if (isset($vars[$v]) && $vars[$v] == $t) {
30
        return true;
31
    }
32
33
    return false;
34
}
35
36
/**
37
 * Get the value of $vars[$v], if it exists
38
 *
39
 * @param  string  $v  Name of the var to get
40
 * @return string|bool The value of $vars[$v] if it exists, false if it does not exist
41
 */
42
function var_get($v)
43
{
44
    global $vars;
45
    if (isset($vars[$v])) {
46
        return $vars[$v];
47
    }
48
49
    return false;
50
}
51
52
function toner2colour($descr, $percent)
53
{
54
    $colour = \LibreNMS\Util\Colors::percentage(100 - $percent, null);
55
56
    if (substr($descr, -1) == 'C' || stripos($descr, 'cyan') !== false) {
57
        $colour['left'] = '55D6D3';
58
        $colour['right'] = '33B4B1';
59
    }
60
61
    if (substr($descr, -1) == 'M' || stripos($descr, 'magenta') !== false) {
62
        $colour['left'] = 'F24AC8';
63
        $colour['right'] = 'D028A6';
64
    }
65
66
    if (substr($descr, -1) == 'Y' || stripos($descr, 'yellow') !== false
67
        || stripos($descr, 'giallo') !== false
68
        || stripos($descr, 'gul') !== false
69
    ) {
70
        $colour['left'] = 'FFF200';
71
        $colour['right'] = 'DDD000';
72
    }
73
74
    if (substr($descr, -1) == 'K' || stripos($descr, 'black') !== false
75
        || stripos($descr, 'nero') !== false
76
    ) {
77
        $colour['left'] = '000000';
78
        $colour['right'] = '222222';
79
    }
80
81
    return $colour;
82
}//end toner2colour()
83
84
/**
85
 * Find all links in some text and turn them into html links.
86
 *
87
 * @param  string  $text
88
 * @return string
89
 */
90
function linkify($text)
91
{
92
    $regex = "#(http|https|ftp|ftps)://[a-z0-9\-.]*[a-z0-9\-]+(/\S*)?#i";
93
94
    return preg_replace($regex, '<a href="$0">$0</a>', $text);
95
}
96
97
function generate_link($text, $vars, $new_vars = [])
98
{
99
    return '<a href="' . \LibreNMS\Util\Url::generate($vars, $new_vars) . '">' . $text . '</a>';
100
}//end generate_link()
101
102
function escape_quotes($text)
103
{
104
    return str_replace('"', "\'", str_replace("'", "\'", $text));
105
}//end escape_quotes()
106
107
function generate_overlib_content($graph_array, $text)
108
{
109
    $overlib_content = '<div class=overlib><span class=overlib-text>' . $text . '</span><br />';
110
    foreach (['day', 'week', 'month', 'year'] as $period) {
111
        $graph_array['from'] = Config::get("time.$period");
112
        $overlib_content .= escape_quotes(\LibreNMS\Util\Url::graphTag($graph_array));
113
    }
114
115
    $overlib_content .= '</div>';
116
117
    return $overlib_content;
118
}//end generate_overlib_content()
119
120
function generate_device_link($device, $text = null, $vars = [], $start = 0, $end = 0, $escape_text = 1, $overlib = 1)
121
{
122
    $deviceModel = DeviceCache::get((int) $device['device_id']);
123
124
    return \LibreNMS\Util\Url::deviceLink($deviceModel, $text, $vars, $start, $end, $escape_text, $overlib);
125
}
126
127
function bill_permitted($bill_id)
128
{
129
    if (Auth::user()->hasGlobalRead()) {
130
        return true;
131
    }
132
133
    return \Permissions::canAccessBill($bill_id, Auth::id());
134
}
135
136
function port_permitted($port_id, $device_id = null)
137
{
138
    if (! is_numeric($device_id)) {
139
        $device_id = get_device_id_by_port_id($port_id);
140
    }
141
142
    if (device_permitted($device_id)) {
143
        return true;
144
    }
145
146
    return \Permissions::canAccessPort($port_id, Auth::id());
147
}
148
149
function application_permitted($app_id, $device_id = null)
150
{
151
    if (! is_numeric($app_id)) {
152
        return false;
153
    }
154
155
    if (! $device_id) {
156
        $device_id = get_device_id_by_app_id($app_id);
157
    }
158
159
    return device_permitted($device_id);
160
}
161
162
function device_permitted($device_id)
163
{
164
    if (Auth::user() && Auth::user()->hasGlobalRead()) {
165
        return true;
166
    }
167
168
    return \Permissions::canAccessDevice($device_id, Auth::id());
169
}
170
171
function alert_layout($severity)
172
{
173
    switch ($severity) {
174
        case 'critical':
175
            $icon = 'exclamation';
176
            $color = 'danger';
177
            $background = 'danger';
178
            break;
179
        case 'warning':
180
            $icon = 'warning';
181
            $color = 'warning';
182
            $background = 'warning';
183
            break;
184
        case 'ok':
185
            $icon = 'check';
186
            $color = 'success';
187
            $background = 'success';
188
            break;
189
        default:
190
            $icon = 'info';
191
            $color = 'info';
192
            $background = 'info';
193
    }
194
195
    return ['icon' => $icon,
196
        'icon_color' => $color,
197
        'background_color' => $background, ];
198
}
199
200
function generate_dynamic_graph_tag($args)
201
{
202
    $urlargs = [];
203
    $width = 0;
204
    foreach ($args as $key => $arg) {
205
        switch (strtolower($key)) {
206
            case 'width':
207
                $width = $arg;
208
                $value = '{{width}}';
209
                break;
210
            case 'from':
211
                $value = '{{start}}';
212
                break;
213
            case 'to':
214
                $value = '{{end}}';
215
                break;
216
            default:
217
                $value = $arg;
218
                break;
219
        }
220
        $urlargs[] = $key . '=' . $value;
221
    }
222
223
    return '<img style="width:' . $width . 'px;height:100%" class="graph img-responsive" data-src-template="graph.php?' . implode('&amp;', $urlargs) . '" border="0" />';
224
}//end generate_dynamic_graph_tag()
225
226
function generate_dynamic_graph_js($args)
227
{
228
    $from = (is_numeric($args['from']) ? $args['from'] : '(new Date()).getTime() / 1000 - 24*3600');
229
    $range = (is_numeric($args['to']) ? $args['to'] - $args['from'] : '24*3600');
230
231
    $output = '<script src="js/RrdGraphJS/q-5.0.2.min.js"></script>
232
        <script src="js/RrdGraphJS/moment-timezone-with-data.js"></script>
233
        <script src="js/RrdGraphJS/rrdGraphPng.js"></script>
234
          <script type="text/javascript">
235
              q.ready(function(){
236
                  var graphs = [];
237
                  q(\'.graph\').forEach(function(item){
238
                      graphs.push(
239
                          q(item).rrdGraphPng({
240
                              canvasPadding: 120,
241
                                initialStart: ' . $from . ',
242
                                initialRange: ' . $range . '
243
                          })
244
                      );
245
                  });
246
              });
247
              // needed for dynamic height
248
              window.onload = function(){ window.dispatchEvent(new Event(\'resize\')); }
249
          </script>';
250
251
    return $output;
252
}//end generate_dynamic_graph_js()
253
254
function generate_graph_js_state($args)
255
{
256
    // we are going to assume we know roughly what the graph url looks like here.
257
    // TODO: Add sensible defaults
258
    $from = (is_numeric($args['from']) ? $args['from'] : 0);
259
    $to = (is_numeric($args['to']) ? $args['to'] : 0);
260
    $width = (is_numeric($args['width']) ? $args['width'] : 0);
261
    $height = (is_numeric($args['height']) ? $args['height'] : 0);
262
    $legend = str_replace("'", '', $args['legend']);
263
264
    $state = <<<STATE
265
<script type="text/javascript" language="JavaScript">
266
document.graphFrom = $from;
267
document.graphTo = $to;
268
document.graphWidth = $width;
269
document.graphHeight = $height;
270
document.graphLegend = '$legend';
271
</script>
272
STATE;
273
274
    return $state;
275
}//end generate_graph_js_state()
276
277
function print_percentage_bar($width, $height, $percent, $left_text, $left_colour, $left_background, $right_text, $right_colour, $right_background)
278
{
279
    return \LibreNMS\Util\Html::percentageBar($width, $height, $percent, $left_text, $right_text, null, null, [
280
        'left' => $left_background,
281
        'left_text' => $left_colour,
282
        'right' => $right_background,
283
        'right_text' => $right_colour,
284
    ]);
285
}
286
287
function generate_entity_link($type, $entity, $text = null, $graph_type = null)
288
{
289
    global $entity_cache;
290
291
    if (is_numeric($entity)) {
292
        $entity = get_entity_by_id_cache($type, $entity);
293
    }
294
295
    switch ($type) {
296
        case 'port':
297
            $link = generate_port_link($entity, $text, $graph_type);
298
            break;
299
300
        case 'storage':
301
            if (empty($text)) {
302
                $text = $entity['storage_descr'];
303
            }
304
305
            $link = generate_link($text, ['page' => 'device', 'device' => $entity['device_id'], 'tab' => 'health', 'metric' => 'storage']);
306
            break;
307
308
        default:
309
            $link = $entity[$type . '_id'];
310
    }
311
312
    return $link;
313
}//end generate_entity_link()
314
315
/**
316
 * Extract type and subtype from a complex graph type, also makes sure variables are file name safe.
317
 *
318
 * @param  string  $type
319
 * @return array [type, subtype]
320
 */
321
function extract_graph_type($type): array
322
{
323
    preg_match('/^(?P<type>[A-Za-z0-9]+)_(?P<subtype>.+)/', $type, $graphtype);
324
    $type = basename($graphtype['type']);
325
    $subtype = basename($graphtype['subtype']);
326
327
    return [$type, $subtype];
328
}
329
330
function generate_port_link($port, $text = null, $type = null, $overlib = 1, $single_graph = 0)
331
{
332
    $graph_array = [];
333
334
    if (! $text) {
335
        $text = Rewrite::normalizeIfName($port['label'] ?? $port['ifName']);
336
    }
337
338
    if ($type) {
339
        $port['graph_type'] = $type;
340
    }
341
342
    if (! isset($port['graph_type'])) {
343
        $port['graph_type'] = 'port_bits';
344
    }
345
346
    $class = ifclass($port['ifOperStatus'], $port['ifAdminStatus']);
347
348
    if (! isset($port['hostname'])) {
349
        $port = array_merge($port, device_by_id_cache($port['device_id']));
350
    }
351
352
    $content = '<div class=list-large>' . $port['hostname'] . ' - ' . Rewrite::normalizeIfName(addslashes(\LibreNMS\Util\Clean::html($port['label'], []))) . '</div>';
353
    if ($port['port_descr_descr']) {
354
        $content .= addslashes(\LibreNMS\Util\Clean::html($port['port_descr_descr'], [])) . '<br />';
355
    } elseif ($port['ifAlias']) {
356
        $content .= addslashes(\LibreNMS\Util\Clean::html($port['ifAlias'], [])) . '<br />';
357
    }
358
359
    $content .= "<div style=\'width: 850px\'>";
360
    $graph_array['type'] = $port['graph_type'];
361
    $graph_array['legend'] = 'yes';
362
    $graph_array['height'] = '100';
363
    $graph_array['width'] = '340';
364
    $graph_array['to'] = Config::get('time.now');
365
    $graph_array['from'] = Config::get('time.day');
366
    $graph_array['id'] = $port['port_id'];
367
    $content .= \LibreNMS\Util\Url::graphTag($graph_array);
368
    if ($single_graph == 0) {
369
        $graph_array['from'] = Config::get('time.week');
370
        $content .= \LibreNMS\Util\Url::graphTag($graph_array);
371
        $graph_array['from'] = Config::get('time.month');
372
        $content .= \LibreNMS\Util\Url::graphTag($graph_array);
373
        $graph_array['from'] = Config::get('time.year');
374
        $content .= \LibreNMS\Util\Url::graphTag($graph_array);
375
    }
376
377
    $content .= '</div>';
378
379
    $url = generate_port_url($port);
380
381
    if ($overlib == 0) {
382
        return $content;
383
    } elseif (port_permitted($port['port_id'], $port['device_id'])) {
384
        return \LibreNMS\Util\Url::overlibLink($url, $text, $content, $class);
385
    } else {
386
        return Rewrite::normalizeIfName($text);
387
    }
388
}//end generate_port_link()
389
390
function generate_sensor_link($args, $text = null, $type = null)
391
{
392
    if (! $text) {
393
        $text = $args['sensor_descr'];
394
    }
395
396
    if (! $type) {
397
        $args['graph_type'] = 'sensor_' . $args['sensor_class'];
398
    } else {
399
        $args['graph_type'] = 'sensor_' . $type;
400
    }
401
402
    if (! isset($args['hostname'])) {
403
        $args = array_merge($args, device_by_id_cache($args['device_id']));
404
    }
405
406
    $content = '<div class=list-large>' . $text . '</div>';
407
408
    $content .= "<div style=\'width: 850px\'>";
409
    $graph_array = [
410
        'type' => $args['graph_type'],
411
        'legend' => 'yes',
412
        'height' => '100',
413
        'width' => '340',
414
        'to' => Config::get('time.now'),
415
        'from' => Config::get('time.day'),
416
        'id' => $args['sensor_id'],
417
    ];
418
    $content .= \LibreNMS\Util\Url::graphTag($graph_array);
419
420
    $graph_array['from'] = Config::get('time.week');
421
    $content .= \LibreNMS\Util\Url::graphTag($graph_array);
422
423
    $graph_array['from'] = Config::get('time.month');
424
    $content .= \LibreNMS\Util\Url::graphTag($graph_array);
425
426
    $graph_array['from'] = Config::get('time.year');
427
    $content .= \LibreNMS\Util\Url::graphTag($graph_array);
428
429
    $content .= '</div>';
430
431
    $url = \LibreNMS\Util\Url::generate(['page' => 'graphs', 'id' => $args['sensor_id'], 'type' => $args['graph_type'], 'from' => \LibreNMS\Config::get('time.day')], []);
432
433
    return \LibreNMS\Util\Url::overlibLink($url, $text, $content);
434
}//end generate_sensor_link()
435
436
function generate_port_url($port, $vars = [])
437
{
438
    return \LibreNMS\Util\Url::generate(['page' => 'device', 'device' => $port['device_id'], 'tab' => 'port', 'port' => $port['port_id']], $vars);
439
}//end generate_port_url()
440
441
function generate_sap_url($sap, $vars = [])
442
{
443
    return \LibreNMS\Util\Url::graphPopup(['device' => $sap['device_id'], 'page' => 'graphs', 'type' => 'device_sap', 'tab' => 'routing', 'proto' => 'mpls', 'view' => 'saps', 'traffic_id' => $sap['svc_oid'] . '.' . $sap['sapPortId'] . '.' . $sap['sapEncapValue']], $vars);
444
}//end generate_sap_url()
445
446
function generate_port_image($args)
447
{
448
    if (! $args['bg']) {
449
        $args['bg'] = 'FFFFFF00';
450
    }
451
452
    return "<img src='graph.php?type=" . $args['graph_type'] . '&amp;id=' . $args['port_id'] . '&amp;from=' . $args['from'] . '&amp;to=' . $args['to'] . '&amp;width=' . $args['width'] . '&amp;height=' . $args['height'] . '&amp;bg=' . $args['bg'] . "'>";
453
}//end generate_port_image()
454
455
/**
456
 * Create image to output text instead of a graph.
457
 *
458
 * @param  string  $text
459
 * @param  int[]  $color
460
 */
461
function graph_error($text, $color = [128, 0, 0])
462
{
463
    global $vars;
464
465
    $type = Config::get('webui.graph_type');
466
    if (! Debug::isEnabled()) {
467
        header('Content-type: ' . get_image_type($type));
468
    }
469
470
    $width = (int) ($vars['width'] ?? 150);
471
    $height = (int) ($vars['height'] ?? 60);
472
473
    if ($type === 'svg') {
474
        $rgb = implode(', ', $color);
475
        echo <<<SVG
476
<svg xmlns="http://www.w3.org/2000/svg"
477
xmlns:xhtml="http://www.w3.org/1999/xhtml"
478
viewBox="0 0 $width $height"
479
preserveAspectRatio="xMinYMin">
480
<foreignObject x="0" y="0" width="$width" height="$height" transform="translate(0,0)">
481
      <xhtml:div style="display:table; width:{$width}px; height:{$height}px; overflow:hidden;">
482
         <xhtml:div style="display:table-cell; vertical-align:middle;">
483
            <xhtml:div style="color:rgb($rgb); text-align:center; font-family:sans-serif; font-size:0.6em;">$text</xhtml:div>
484
         </xhtml:div>
485
      </xhtml:div>
486
   </foreignObject>
487
</svg>
488
SVG;
489
    } else {
490
        $img = imagecreate($width, $height);
491
        imagecolorallocatealpha($img, 255, 255, 255, 127); // transparent background
492
493
        $px = ((imagesx($img) - 7.5 * strlen($text)) / 2);
494
        $font = $width < 200 ? 3 : 5;
495
        imagestring($img, $font, $px, ($height / 2 - 8), $text, imagecolorallocate($img, ...$color));
496
497
        // Output the image
498
        imagepng($img);
499
        imagedestroy($img);
500
    }
501
}
502
503
/**
504
 * Output message to user in image format.
505
 *
506
 * @param  string  $text  string to display
507
 */
508
function graph_text_and_exit($text)
509
{
510
    global $vars;
511
512
    if ($vars['showcommand'] == 'yes') {
513
        echo $text;
514
515
        return;
516
    }
517
518
    graph_error($text, [13, 21, 210]);
519
    exit;
520
}
521
522
function print_port_thumbnail($args)
523
{
524
    echo generate_port_link($args, generate_port_image($args));
525
}//end print_port_thumbnail()
526
527
function print_optionbar_start($height = 0, $width = 0, $marginbottom = 5)
528
{
529
    echo '
530
        <div class="panel panel-default">
531
        <div class="panel-heading">
532
        ';
533
}//end print_optionbar_start()
534
535
function print_optionbar_end()
536
{
537
    echo '
538
        </div>
539
        </div>
540
        ';
541
}//end print_optionbar_end()
542
543
function devclass($device)
544
{
545
    if (isset($device['status']) && $device['status'] == '0') {
546
        $class = 'list-device-down';
547
    } else {
548
        $class = 'list-device';
549
    }
550
551
    if (isset($device['disable_notify']) && $device['disable_notify'] == '1') {
552
        $class = 'list-device-ignored';
553
        if (isset($device['status']) && $device['status'] == '1') {
554
            $class = 'list-device-ignored-up';
555
        }
556
    }
557
558
    if (isset($device['disabled']) && $device['disabled'] == '1') {
559
        $class = 'list-device-disabled';
560
    }
561
562
    return $class;
563
}//end devclass()
564
565
function getlocations()
566
{
567
    if (Auth::user()->hasGlobalRead()) {
568
        return dbFetchRows('SELECT id, location FROM locations ORDER BY location');
569
    }
570
571
    return dbFetchRows('SELECT id, L.location FROM devices AS D, locations AS L, devices_perms AS P WHERE D.device_id = P.device_id AND P.user_id = ? AND D.location_id = L.id ORDER BY location', [Auth::id()]);
572
}
573
574
/**
575
 * Get the recursive file size and count for a directory
576
 *
577
 * @param  string  $path
578
 * @return array [size, file count]
579
 */
580
function foldersize($path)
581
{
582
    $total_size = 0;
583
    $total_files = 0;
584
585
    foreach (glob(rtrim($path, '/') . '/*', GLOB_NOSORT) as $item) {
586
        if (is_dir($item)) {
587
            [$folder_size, $file_count] = foldersize($item);
588
            $total_size += $folder_size;
589
            $total_files += $file_count;
590
        } else {
591
            $total_size += filesize($item);
592
            $total_files++;
593
        }
594
    }
595
596
    return [$total_size, $total_files];
597
}
598
599
function generate_ap_link($args, $text = null, $type = null)
600
{
601
    $args = cleanPort($args);
602
    if (! $text) {
603
        $text = Rewrite::normalizeIfName($args['label']);
604
    }
605
606
    if ($type) {
607
        $args['graph_type'] = $type;
608
    }
609
610
    if (! isset($args['graph_type'])) {
611
        $args['graph_type'] = 'port_bits';
612
    }
613
614
    if (! isset($args['hostname'])) {
615
        $args = array_merge($args, device_by_id_cache($args['device_id']));
616
    }
617
618
    $content = '<div class=list-large>' . $args['text'] . ' - ' . Rewrite::normalizeIfName($args['label']) . '</div>';
619
    if ($args['ifAlias']) {
620
        $content .= \LibreNMS\Util\Clean::html($args['ifAlias'], []) . '<br />';
621
    }
622
623
    $content .= "<div style=\'width: 850px\'>";
624
    $graph_array = [];
625
    $graph_array['type'] = $args['graph_type'];
626
    $graph_array['legend'] = 'yes';
627
    $graph_array['height'] = '100';
628
    $graph_array['width'] = '340';
629
    $graph_array['to'] = Config::get('time.now');
630
    $graph_array['from'] = Config::get('time.day');
631
    $graph_array['id'] = $args['accesspoint_id'];
632
    $content .= \LibreNMS\Util\Url::graphTag($graph_array);
633
    $graph_array['from'] = Config::get('time.week');
634
    $content .= \LibreNMS\Util\Url::graphTag($graph_array);
635
    $graph_array['from'] = Config::get('time.month');
636
    $content .= \LibreNMS\Util\Url::graphTag($graph_array);
637
    $graph_array['from'] = Config::get('time.year');
638
    $content .= \LibreNMS\Util\Url::graphTag($graph_array);
639
    $content .= '</div>';
640
641
    $url = generate_ap_url($args);
642
    if (port_permitted($args['interface_id'], $args['device_id'])) {
643
        return \LibreNMS\Util\Url::overlibLink($url, $text, $content);
644
    } else {
645
        return Rewrite::normalizeIfName($text);
646
    }
647
}//end generate_ap_link()
648
649
function generate_ap_url($ap, $vars = [])
650
{
651
    return \LibreNMS\Util\Url::generate(['page' => 'device', 'device' => $ap['device_id'], 'tab' => 'accesspoints', 'ap' => $ap['accesspoint_id']], $vars);
652
}//end generate_ap_url()
653
654
// Find all the files in the given directory that match the pattern
655
656
function get_matching_files($dir, $match = '/\.php$/')
657
{
658
    $list = [];
659
    if ($handle = opendir($dir)) {
660
        while (false !== ($file = readdir($handle))) {
661
            if ($file != '.' && $file != '..' && preg_match($match, $file) === 1) {
662
                $list[] = $file;
663
            }
664
        }
665
666
        closedir($handle);
667
    }
668
669
    return $list;
670
}//end get_matching_files()
671
672
// Include all the files in the given directory that match the pattern
673
674
function include_matching_files($dir, $match = '/\.php$/')
675
{
676
    foreach (get_matching_files($dir, $match) as $file) {
677
        include_once $file;
678
    }
679
}//end include_matching_files()
680
681
function generate_pagination($count, $limit, $page, $links = 2)
682
{
683
    $end_page = ceil($count / $limit);
684
    $start = (($page - $links) > 0) ? ($page - $links) : 1;
685
    $end = (($page + $links) < $end_page) ? ($page + $links) : $end_page;
686
    $return = '<ul class="pagination">';
687
    $link_class = ($page == 1) ? 'disabled' : '';
688
    $return .= "<li><a href='' onClick='changePage(1,event);'>&laquo;</a></li>";
689
    $return .= "<li class='$link_class'><a href='' onClick='changePage($page - 1,event);'>&lt;</a></li>";
690
691
    if ($start > 1) {
692
        $return .= "<li><a href='' onClick='changePage(1,event);'>1</a></li>";
693
        $return .= "<li class='disabled'><span>...</span></li>";
694
    }
695
696
    for ($x = $start; $x <= $end; $x++) {
697
        $link_class = ($page == $x) ? 'active' : '';
698
        $return .= "<li class='$link_class'><a href='' onClick='changePage($x,event);'>$x </a></li>";
699
    }
700
701
    if ($end < $end_page) {
702
        $return .= "<li class='disabled'><span>...</span></li>";
703
        $return .= "<li><a href='' onClick='changePage($end_page,event);'>$end_page</a></li>";
704
    }
705
706
    $link_class = ($page == $end_page) ? 'disabled' : '';
707
    $return .= "<li class='$link_class'><a href='' onClick='changePage($page + 1,event);'>&gt;</a></li>";
708
    $return .= "<li class='$link_class'><a href='' onClick='changePage($end_page,event);'>&raquo;</a></li>";
709
    $return .= '</ul>';
710
711
    return $return;
712
}//end generate_pagination()
713
714
function demo_account()
715
{
716
    print_error("You are logged in as a demo account, this page isn't accessible to you");
717
}//end demo_account()
718
719
function get_client_ip()
720
{
721
    if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
722
        $client_ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
723
    } else {
724
        $client_ip = $_SERVER['REMOTE_ADDR'];
725
    }
726
727
    return $client_ip;
728
}//end get_client_ip()
729
730
function clean_bootgrid($string)
731
{
732
    $output = str_replace(["\r", "\n"], '', $string);
733
    $output = addslashes($output);
734
735
    return $output;
736
}//end clean_bootgrid()
737
738
function get_url()
739
{
740
    // http://stackoverflow.com/questions/2820723/how-to-get-base-url-with-php
741
    // http://stackoverflow.com/users/184600/ma%C4%8Dek
742
    return sprintf(
743
        '%s://%s%s',
744
        isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off' ? 'https' : 'http',
745
        $_SERVER['SERVER_NAME'],
746
        $_SERVER['REQUEST_URI']
747
    );
748
}//end get_url()
749
750
function alert_details($details)
751
{
752
    if (! is_array($details)) {
753
        $details = json_decode(gzuncompress($details), true);
754
    }
755
756
    $fault_detail = '';
757
    foreach ($details['rule'] as $o => $tmp_alerts) {
758
        $fallback = true;
759
        $fault_detail .= '#' . ($o + 1) . ':&nbsp;';
760
        if ($tmp_alerts['bill_id']) {
761
            $fault_detail .= '<a href="' . \LibreNMS\Util\Url::generate(['page' => 'bill', 'bill_id' => $tmp_alerts['bill_id']], []) . '">' . $tmp_alerts['bill_name'] . '</a>;&nbsp;';
762
            $fallback = false;
763
        }
764
765
        if ($tmp_alerts['port_id']) {
766
            $tmp_alerts = cleanPort($tmp_alerts);
767
            $fault_detail .= generate_port_link($tmp_alerts) . ';&nbsp;';
768
            $fallback = false;
769
        }
770
771
        if ($tmp_alerts['accesspoint_id']) {
772
            $fault_detail .= generate_ap_link($tmp_alerts, $tmp_alerts['name']) . ';&nbsp;';
773
            $fallback = false;
774
        }
775
776
        if ($tmp_alerts['sensor_id']) {
777
            if ($tmp_alerts['sensor_class'] == 'state') {
778
                // Give more details for a state (textual form)
779
                $details = 'State: ' . $tmp_alerts['state_descr'] . ' (numerical ' . $tmp_alerts['sensor_current'] . ')<br>  ';
780
            } else {
781
                // Other sensors
782
                $details = 'Value: ' . $tmp_alerts['sensor_current'] . ' (' . $tmp_alerts['sensor_class'] . ')<br>  ';
783
            }
784
            $details_a = [];
785
786
            if ($tmp_alerts['sensor_limit_low']) {
787
                $details_a[] = 'low: ' . $tmp_alerts['sensor_limit_low'];
788
            }
789
            if ($tmp_alerts['sensor_limit_low_warn']) {
790
                $details_a[] = 'low_warn: ' . $tmp_alerts['sensor_limit_low_warn'];
791
            }
792
            if ($tmp_alerts['sensor_limit_warn']) {
793
                $details_a[] = 'high_warn: ' . $tmp_alerts['sensor_limit_warn'];
794
            }
795
            if ($tmp_alerts['sensor_limit']) {
796
                $details_a[] = 'high: ' . $tmp_alerts['sensor_limit'];
797
            }
798
            $details .= implode(', ', $details_a);
799
800
            $fault_detail .= generate_sensor_link($tmp_alerts, $tmp_alerts['name']) . ';&nbsp; <br>' . $details;
801
            $fallback = false;
802
        }
803
804
        if ($tmp_alerts['bgpPeer_id']) {
805
            // If we have a bgpPeer_id, we format the data accordingly
806
            $fault_detail .= "BGP peer <a href='" .
807
                \LibreNMS\Util\Url::generate([
808
                    'page' => 'device',
809
                    'device' => $tmp_alerts['device_id'],
810
                    'tab' => 'routing',
811
                    'proto' => 'bgp',
812
                ]) .
813
                "'>" . $tmp_alerts['bgpPeerIdentifier'] . '</a>';
814
            $fault_detail .= ', AS' . $tmp_alerts['bgpPeerRemoteAs'];
815
            $fault_detail .= ', State ' . $tmp_alerts['bgpPeerState'];
816
            $fallback = false;
817
        }
818
819
        if ($tmp_alerts['type'] && $tmp_alerts['label']) {
820
            if ($tmp_alerts['error'] == '') {
821
                $fault_detail .= ' ' . $tmp_alerts['type'] . ' - ' . $tmp_alerts['label'] . ';&nbsp;';
822
            } else {
823
                $fault_detail .= ' ' . $tmp_alerts['type'] . ' - ' . $tmp_alerts['label'] . ' - ' . $tmp_alerts['error'] . ';&nbsp;';
824
            }
825
            $fallback = false;
826
        }
827
828
        if (in_array('app_id', array_keys($tmp_alerts))) {
829
            $fault_detail .= "<a href='" .
830
                \LibreNMS\Util\Url::generate([
831
                    'page' => 'device',
832
                    'device' => $tmp_alerts['device_id'],
833
                    'tab' => 'apps',
834
                    'app' => $tmp_alerts['app_type'],
835
                ]) . "'>";
836
            $fault_detail .= $tmp_alerts['app_type'];
837
            $fault_detail .= '</a>';
838
839
            if ($tmp_alerts['app_status']) {
840
                $fault_detail .= ' => ' . $tmp_alerts['app_status'];
841
            }
842
            if ($tmp_alerts['metric']) {
843
                $fault_detail .= ' : ' . $tmp_alerts['metric'] . ' => ' . $tmp_alerts['value'];
844
            }
845
            $fallback = false;
846
        }
847
848
        if ($fallback === true) {
849
            $fault_detail_data = [];
850
            foreach ($tmp_alerts as $k => $v) {
851
                if (in_array($k, ['device_id', 'sysObjectID', 'sysDescr', 'location_id'])) {
852
                    continue;
853
                }
854
                if (! empty($v) && str_i_contains($k, ['id', 'desc', 'msg', 'last'])) {
855
                    $fault_detail_data[] = "$k => '$v'";
856
                }
857
            }
858
            $fault_detail .= count($fault_detail_data) ? implode('<br>&nbsp;&nbsp;&nbsp', $fault_detail_data) : '';
859
860
            $fault_detail = rtrim($fault_detail, ', ');
861
        }
862
863
        $fault_detail .= '<br>';
864
    }//end foreach
865
866
    return $fault_detail;
867
}//end alert_details()
868
869
function dynamic_override_config($type, $name, $device)
870
{
871
    $attrib_val = get_dev_attrib($device, $name);
872
    if ($attrib_val == 'true') {
873
        $checked = 'checked';
874
    } else {
875
        $checked = '';
876
    }
877
    if ($type == 'checkbox') {
878
        return '<input type="checkbox" id="override_config" name="override_config" data-attrib="' . $name . '" data-device_id="' . $device['device_id'] . '" data-size="small" ' . $checked . '>';
879
    } elseif ($type == 'text') {
880
        return '<input type="text" id="override_config_text" name="override_config_text" data-attrib="' . $name . '" data-device_id="' . $device['device_id'] . '" value="' . $attrib_val . '">';
881
    }
882
}//end dynamic_override_config()
883
884
/**
885
 * Return the rows from 'ports' for all ports of a certain type as parsed by port_descr_parser.
886
 * One or an array of strings can be provided as an argument; if an array is passed, all ports matching
887
 * any of the types in the array are returned.
888
 *
889
 * @param $types mixed String or strings matching 'port_descr_type's.
890
 * @return array Rows from the ports table for matching ports.
891
 */
892
function get_ports_from_type($given_types)
893
{
894
    // Make the arg an array if it isn't, so subsequent steps only have to handle arrays.
895
    if (! is_array($given_types)) {
896
        $given_types = [$given_types];
897
    }
898
899
    // Check the config for a '_descr' entry for each argument. This is how a 'custom_descr' entry can
900
    //  be key/valued to some other string that's actually searched for in the DB. Merge or append the
901
    //  configured value if it's an array or a string. Or append the argument itself if there's no matching
902
    //  entry in config.
903
    $search_types = [];
904
    foreach ($given_types as $type) {
905
        if (Config::has($type . '_descr')) {
906
            $type_descr = Config::get($type . '_descr');
907
            if (is_array($type_descr)) {
908
                $search_types = array_merge($search_types, $type_descr);
909
            } else {
910
                $search_types[] = $type_descr;
911
            }
912
        } else {
913
            $search_types[] = $type;
914
        }
915
    }
916
917
    // Using the full list of strings to search the DB for, build the 'where' portion of a query that
918
    //  compares 'port_descr_type' with entry in the list. Also, since '@' is the convential wildcard,
919
    //  replace it with '%' so it functions as a wildcard in the SQL query.
920
    $type_where = ' (';
921
    $or = '';
922
    $type_param = [];
923
924
    foreach ($search_types as $type) {
925
        if (! empty($type)) {
926
            $type = strtr($type, '@', '%');
927
            $type_where .= " $or `port_descr_type` LIKE ?";
928
            $or = 'OR';
929
            $type_param[] = $type;
930
        }
931
    }
932
    $type_where .= ') ';
933
934
    // Run the query with the generated 'where' and necessary parameters, and send it back.
935
    $ports = dbFetchRows("SELECT * FROM `ports` as I, `devices` AS D WHERE $type_where AND I.device_id = D.device_id ORDER BY I.ifAlias", $type_param);
936
937
    return $ports;
938
}
939
940
/**
941
 * @param $filename
942
 * @param $content
943
 */
944
function file_download($filename, $content)
945
{
946
    $length = strlen($content);
947
    header('Content-Description: File Transfer');
948
    header('Content-Type: text/plain');
949
    header("Content-Disposition: attachment; filename=$filename");
950
    header('Content-Transfer-Encoding: binary');
951
    header('Content-Length: ' . $length);
952
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
953
    header('Expires: 0');
954
    header('Pragma: public');
955
    echo $content;
956
}
957
958
function get_rules_from_json()
959
{
960
    return json_decode(file_get_contents(Config::get('install_dir') . '/misc/alert_rules.json'), true);
961
}
962
963
function search_oxidized_config($search_in_conf_textbox)
964
{
965
    if (! Auth::user()->hasGlobalRead()) {
966
        return false;
967
    }
968
969
    $oxidized_search_url = Config::get('oxidized.url') . '/nodes/conf_search?format=json';
970
    $postdata = http_build_query(
971
        [
972
            'search_in_conf_textbox' => $search_in_conf_textbox,
973
        ]
974
    );
975
    $opts = ['http' => [
976
        'method' => 'POST',
977
        'header' => 'Content-type: application/x-www-form-urlencoded',
978
        'content' => $postdata,
979
    ],
980
    ];
981
    $context = stream_context_create($opts);
982
983
    $nodes = json_decode(file_get_contents($oxidized_search_url, false, $context), true);
984
    // Look up Oxidized node names to LibreNMS devices for a link
985
    foreach ($nodes as &$n) {
986
        $dev = device_by_name($n['node']);
987
        $n['dev_id'] = $dev ? $dev['device_id'] : false;
988
    }
989
990
    /*
991
    // Filter nodes we don't have access too
992
    $nodes = array_filter($nodes, function($device) {
993
        return \Permissions::canAccessDevice($device['dev_id'], Auth::id());
994
    });
995
    */
996
997
    return $nodes;
998
}
999
1000
/**
1001
 * @param $data
1002
 * @return bool|mixed
1003
 */
1004
function array_to_htmljson($data)
1005
{
1006
    if (is_array($data)) {
1007
        $data = htmlentities(json_encode($data));
1008
1009
        return str_replace(',', ',<br />', $data);
1010
    } else {
1011
        return false;
1012
    }
1013
}
1014
1015
/**
1016
 * @param  int  $eventlog_severity
1017
 * @return string $eventlog_severity_icon
1018
 */
1019
function eventlog_severity($eventlog_severity)
1020
{
1021
    switch ($eventlog_severity) {
1022
        case 1:
1023
            return 'label-success'; //OK
1024
        case 2:
1025
            return 'label-info'; //Informational
1026
        case 3:
1027
            return 'label-primary'; //Notice
1028
        case 4:
1029
            return 'label-warning'; //Warning
1030
        case 5:
1031
            return 'label-danger'; //Critical
1032
        default:
1033
            return 'label-default'; //Unknown
1034
    }
1035
} // end eventlog_severity
1036
1037
/**
1038
 * Get the http content type of the image
1039
 *
1040
 * @param  string  $type  svg or png
1041
 * @return string
1042
 */
1043
function get_image_type(string $type)
1044
{
1045
    return $type === 'svg' ? 'image/svg+xml' : 'image/png';
1046
}
1047
1048
function get_oxidized_nodes_list()
1049
{
1050
    $context = stream_context_create([
1051
        'http' => [
1052
            'header' => 'Accept: application/json',
1053
        ],
1054
    ]);
1055
1056
    $data = json_decode(file_get_contents(Config::get('oxidized.url') . '/nodes?format=json', false, $context), true);
1057
1058
    foreach ($data as $object) {
1059
        $device = device_by_name($object['name']);
1060
        if (! device_permitted($device['device_id'])) {
1061
            //user cannot see this device, so let's skip it.
1062
            continue;
1063
        }
1064
1065
        echo '<tr>
1066
        <td>' . $device['device_id'] . '</td>
1067
        <td>' . $object['name'] . '</td>
1068
        <td>' . $device['sysName'] . '</td>
1069
        <td>' . $object['status'] . '</td>
1070
        <td>' . $object['time'] . '</td>
1071
        <td>' . $object['model'] . '</td>
1072
        <td>' . $object['group'] . '</td>
1073
        <td></td>
1074
        </tr>';
1075
    }
1076
}
1077
1078
/**
1079
 * Get the fail2ban jails for a device... just requires the device ID
1080
 * an empty return means either no jails or fail2ban is not in use
1081
 *
1082
 * @param $device_id
1083
 * @return array
1084
 */
1085
function get_fail2ban_jails($device_id)
1086
{
1087
    $options = [
1088
        'filter' => [
1089
            'type' => ['=', 'fail2ban'],
1090
        ],
1091
    ];
1092
1093
    $component = new LibreNMS\Component();
1094
    $f2bc = $component->getComponents($device_id, $options);
1095
1096
    if (isset($f2bc[$device_id])) {
1097
        $id = $component->getFirstComponentID($f2bc, $device_id);
1098
1099
        return json_decode($f2bc[$device_id][$id]['jails']);
1100
    }
1101
1102
    return [];
1103
}
1104
1105
/**
1106
 * Get the Postgres databases for a device... just requires the device ID
1107
 * an empty return means Postres is not in use
1108
 *
1109
 * @param $device_id
1110
 * @return array
1111
 */
1112
function get_postgres_databases($device_id)
1113
{
1114
    $options = [
1115
        'filter' => [
1116
            'type' => ['=', 'postgres'],
1117
        ],
1118
    ];
1119
1120
    $component = new LibreNMS\Component();
1121
    $pgc = $component->getComponents($device_id, $options);
1122
1123
    if (isset($pgc[$device_id])) {
1124
        $id = $component->getFirstComponentID($pgc, $device_id);
1125
1126
        return json_decode($pgc[$device_id][$id]['databases']);
1127
    }
1128
1129
    return [];
1130
}
1131
1132
/**
1133
 * Return stacked graphs information
1134
 *
1135
 * @param  string  $transparency  value of desired transparency applied to rrdtool options (values 01 - 99)
1136
 * @return array containing transparency and stacked setup
1137
 */
1138
function generate_stacked_graphs($transparency = '88')
1139
{
1140
    if (Config::get('webui.graph_stacked') == true) {
1141
        return ['transparency' => $transparency, 'stacked' => '1'];
1142
    } else {
1143
        return ['transparency' => '', 'stacked' => '-1'];
1144
    }
1145
}
1146
1147
/**
1148
 * Parse AT time spec, does not handle the entire spec.
1149
 *
1150
 * @param  string|int  $time
1151
 * @return int
1152
 */
1153
function parse_at_time($time)
1154
{
1155
    if (is_numeric($time)) {
1156
        return $time < 0 ? time() + $time : intval($time);
1157
    }
1158
1159
    if (preg_match('/^[+-]\d+[hdmy]$/', $time)) {
1160
        $units = [
1161
            'm' => 60,
1162
            'h' => 3600,
1163
            'd' => 86400,
1164
            'y' => 31557600,
1165
        ];
1166
        $value = substr($time, 1, -1);
1167
        $unit = substr($time, -1);
1168
1169
        $offset = ($time[0] == '-' ? -1 : 1) * $units[$unit] * $value;
1170
1171
        return time() + $offset;
1172
    }
1173
1174
    return (int) strtotime($time);
1175
}
1176
1177
/**
1178
 * Get the ZFS pools for a device... just requires the device ID
1179
 * an empty return means ZFS is not in use or there are currently no pools
1180
 *
1181
 * @param $device_id
1182
 * @return array
1183
 */
1184
function get_zfs_pools($device_id)
1185
{
1186
    $options = [
1187
        'filter' => [
1188
            'type' => ['=', 'zfs'],
1189
        ],
1190
    ];
1191
1192
    $component = new LibreNMS\Component();
1193
    $zfsc = $component->getComponents($device_id, $options);
1194
1195
    if (isset($zfsc[$device_id])) {
1196
        $id = $component->getFirstComponentID($zfsc, $device_id);
1197
1198
        return json_decode($zfsc[$device_id][$id]['pools']);
1199
    }
1200
1201
    return [];
1202
}
1203
1204
/**
1205
 * Get the ports for a device... just requires the device ID
1206
 * an empty return means portsactivity is not in use or there are currently no ports
1207
 *
1208
 * @param $device_id
1209
 * @return array
1210
 */
1211
function get_portactivity_ports($device_id)
1212
{
1213
    $options = [
1214
        'filter' => [
1215
            'type' => ['=', 'portsactivity'],
1216
        ],
1217
    ];
1218
1219
    $component = new LibreNMS\Component();
1220
    $portsc = $component->getComponents($device_id, $options);
1221
1222
    if (isset($portsc[$device_id])) {
1223
        $id = $component->getFirstComponentID($portsc, $device_id);
1224
1225
        return json_decode($portsc[$device_id][$id]['ports']);
1226
    }
1227
1228
    return [];
1229
}
1230
1231
/**
1232
 * Returns the sysname of a device with a html line break prepended.
1233
 * if the device has an empty sysname it will return device's hostname instead
1234
 * And finally if the device has no hostname it will return an empty string
1235
 *
1236
 * @param array device
1237
 * @return string
1238
 */
1239
function get_device_name($device)
1240
{
1241
    $ret_str = '';
1242
1243
    if (format_hostname($device) !== $device['sysName']) {
1244
        $ret_str = $device['sysName'];
1245
    } elseif ($device['hostname'] !== $device['ip']) {
1246
        $ret_str = $device['hostname'];
1247
    }
1248
1249
    return $ret_str;
1250
}
1251
1252
/**
1253
 * Returns state generic label from value with optional text
1254
 */
1255
function get_state_label($sensor)
1256
{
1257
    $state_translation = dbFetchRow('SELECT * FROM state_translations as ST, sensors_to_state_indexes as SSI WHERE ST.state_index_id=SSI.state_index_id AND SSI.sensor_id = ? AND ST.state_value = ? ', [$sensor['sensor_id'], $sensor['sensor_current']]);
1258
1259
    switch ($state_translation['state_generic_value']) {
1260
        case 0:  // OK
1261
            $state_text = $state_translation['state_descr'] ?: 'OK';
1262
            $state_label = 'label-success';
1263
            break;
1264
        case 1:  // Warning
1265
            $state_text = $state_translation['state_descr'] ?: 'Warning';
1266
            $state_label = 'label-warning';
1267
            break;
1268
        case 2:  // Critical
1269
            $state_text = $state_translation['state_descr'] ?: 'Critical';
1270
            $state_label = 'label-danger';
1271
            break;
1272
        case 3:  // Unknown
1273
        default:
1274
            $state_text = $state_translation['state_descr'] ?: 'Unknown';
1275
            $state_label = 'label-default';
1276
    }
1277
1278
    return "<span class='label $state_label'>$state_text</span>";
1279
}
1280
1281
/**
1282
 * Get sensor label and state color
1283
 *
1284
 * @param  array  $sensor
1285
 * @param  string  $type  sensors or wireless
1286
 * @return string
1287
 */
1288
function get_sensor_label_color($sensor, $type = 'sensors')
1289
{
1290
    $label_style = 'label-success';
1291
    if (is_null($sensor)) {
0 ignored issues
show
The condition is_null($sensor) is always false.
Loading history...
1292
        return 'label-unknown';
1293
    }
1294
    if (! is_null($sensor['sensor_limit_warn']) && $sensor['sensor_current'] > $sensor['sensor_limit_warn']) {
1295
        $label_style = 'label-warning';
1296
    }
1297
    if (! is_null($sensor['sensor_limit_low_warn']) && $sensor['sensor_current'] < $sensor['sensor_limit_low_warn']) {
1298
        $label_style = 'label-warning';
1299
    }
1300
    if (! is_null($sensor['sensor_limit']) && $sensor['sensor_current'] > $sensor['sensor_limit']) {
1301
        $label_style = 'label-danger';
1302
    }
1303
    if (! is_null($sensor['sensor_limit_low']) && $sensor['sensor_current'] < $sensor['sensor_limit_low']) {
1304
        $label_style = 'label-danger';
1305
    }
1306
    $unit = __("$type.{$sensor['sensor_class']}.unit");
1307
    if ($sensor['sensor_class'] == 'runtime') {
1308
        $sensor['sensor_current'] = \LibreNMS\Util\Time::formatInterval($sensor['sensor_current'] * 60);
1309
1310
        return "<span class='label $label_style'>" . trim($sensor['sensor_current']) . '</span>';
1311
    }
1312
    if ($sensor['sensor_class'] == 'frequency' && $sensor['sensor_type'] == 'openwrt') {
1313
        return "<span class='label $label_style'>" . trim($sensor['sensor_current']) . ' ' . $unit . '</span>';
1314
    }
1315
1316
    return "<span class='label $label_style'>" . trim(Number::formatSi($sensor['sensor_current'], 2, 3, $unit)) . '</span>';
1317
}
1318
1319
/**
1320
 * @params int unix time
1321
 * @params int seconds
1322
 *
1323
 * @return int
1324
 *
1325
 * Rounds down to the nearest interval.
1326
 *
1327
 * The first argument is required and it is the unix time being
1328
 * rounded down.
1329
 *
1330
 * The second value is the time interval. If not specified, it
1331
 * defaults to 300, or 5 minutes.
1332
 */
1333
function lowest_time($time, $seconds = 300)
1334
{
1335
    return $time - ($time % $seconds);
1336
}
1337
1338
/**
1339
 * @params int
1340
 *
1341
 * @return string
1342
 *
1343
 * This returns the subpath for working with nfdump.
1344
 *
1345
 * 1 value is taken and that is a unix time stamp. It will be then be rounded
1346
 * off to the lowest five minutes earlier.
1347
 *
1348
 * The return string will be a path partial you can use with nfdump to tell it what
1349
 * file or range of files to use.
1350
 *
1351
 * Below ie a explanation of the layouts as taken from the NfSen config file.
1352
 *  0             no hierachy levels - flat layout - compatible with pre NfSen version
1353
 *  1 %Y/%m/%d    year/month/day
1354
 *  2 %Y/%m/%d/%H year/month/day/hour
1355
 *  3 %Y/%W/%u    year/week_of_year/day_of_week
1356
 *  4 %Y/%W/%u/%H year/week_of_year/day_of_week/hour
1357
 *  5 %Y/%j       year/day-of-year
1358
 *  6 %Y/%j/%H    year/day-of-year/hour
1359
 *  7 %Y-%m-%d    year-month-day
1360
 *  8 %Y-%m-%d/%H year-month-day/hour
1361
 */
1362
function time_to_nfsen_subpath($time)
1363
{
1364
    $time = lowest_time($time);
1365
    $layout = Config::get('nfsen_subdirlayout');
1366
1367
    if ($layout == 0) {
1368
        return 'nfcapd.' . date('YmdHi', $time);
1369
    } elseif ($layout == 1) {
1370
        return date('Y\/m\/d\/\n\f\c\a\p\d\.YmdHi', $time);
1371
    } elseif ($layout == 2) {
1372
        return date('Y\/m\/d\/H\/\n\f\c\a\p\d\.YmdHi', $time);
1373
    } elseif ($layout == 3) {
1374
        return date('Y\/W\/w\/\n\f\c\a\p\d\.YmdHi', $time);
1375
    } elseif ($layout == 4) {
1376
        return date('Y\/W\/w\/H\/\n\f\c\a\p\d\.YmdHi', $time);
1377
    } elseif ($layout == 5) {
1378
        return date('Y\/z\/\n\f\c\a\p\d\.YmdHi', $time);
1379
    } elseif ($layout == 6) {
1380
        return date('Y\/z\/H\/\n\f\c\a\p\d\.YmdHi', $time);
1381
    } elseif ($layout == 7) {
1382
        return date('Y\-m\-d\/\n\f\c\a\p\d\.YmdHi', $time);
1383
    } elseif ($layout == 8) {
1384
        return date('Y\-m\-d\/H\/\n\f\c\a\p\d\.YmdHi', $time);
1385
    }
1386
}
1387
1388
/**
1389
 * @params string hostname
1390
 *
1391
 * @return string
1392
 *
1393
 * Takes a hostname and transforms it to the name
1394
 * used by nfsen.
1395
 */
1396
function nfsen_hostname($hostname)
1397
{
1398
    $nfsen_hostname = str_replace('.', Config::get('nfsen_split_char'), $hostname);
1399
1400
    if (! is_null(Config::get('nfsen_suffix'))) {
1401
        $nfsen_hostname = str_replace(Config::get('nfsen_suffix'), '', $nfsen_hostname);
1402
    }
1403
1404
    return $nfsen_hostname;
1405
}
1406
1407
/**
1408
 * @params string hostname
1409
 *
1410
 * @return string
1411
 *
1412
 * Takes a hostname and returns the path to the nfsen
1413
 * live dir.
1414
 */
1415
function nfsen_live_dir($hostname)
1416
{
1417
    $hostname = nfsen_hostname($hostname);
1418
1419
    foreach (Config::get('nfsen_base') as $base_dir) {
1420
        if (file_exists($base_dir) && is_dir($base_dir)) {
1421
            return $base_dir . '/profiles-data/live/' . $hostname;
1422
        }
1423
    }
1424
}
1425
1426
/**
1427
 * Get the ZFS pools for a device... just requires the device ID
1428
 * an empty return means ZFS is not in use or there are currently no pools
1429
 *
1430
 * @param $device_id
1431
 * @return array
1432
 */
1433
function get_chrony_sources($device_id)
1434
{
1435
    $options = [
1436
        'filter' => [
1437
            'type' => ['=', 'chronyd'],
1438
        ],
1439
    ];
1440
1441
    $component = new LibreNMS\Component();
1442
    $chronyd_cpnt = $component->getComponents($device_id, $options);
1443
1444
    if (isset($chronyd_cpnt[$device_id])) {
1445
        $id = $component->getFirstComponentID($chronyd_cpnt, $device_id);
1446
1447
        return json_decode($chronyd_cpnt[$device_id][$id]['sources']);
1448
    }
1449
1450
    return [];
1451
}
1452