Project

General

Profile

Download (13.9 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	graph.php
4
	part of m0n0wall (http://m0n0.ch/wall)
5
	
6
	Copyright (C) 2004-2006 T. Lechat <dev@lechat.org>, Manuel Kasper <mk@neon1.net>
7
	and Jonathan Watt <jwatt@jwatt.org>.
8
	All rights reserved.
9
	
10
	Redistribution and use in source and binary forms, with or without
11
	modification, are permitted provided that the following conditions are met:
12
	
13
	1. Redistributions of source code must retain the above copyright notice,
14
	   this list of conditions and the following disclaimer.
15
	
16
	2. Redistributions in binary form must reproduce the above copyright
17
	   notice, this list of conditions and the following disclaimer in the
18
	   documentation and/or other materials provided with the distribution.
19
	
20
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
21
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
22
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
24
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
	POSSIBILITY OF SUCH DAMAGE.
30
*/
31

    
32
if(!$_SERVER['PHP_AUTH_USER']) {
33
	Header("Location: /");
34
	exit;
35
}
36

    
37
header("Last-Modified: " . gmdate( "D, j M Y H:i:s" ) . " GMT" );
38
header("Expires: " . gmdate( "D, j M Y H:i:s", time() ) . " GMT" );
39
header("Cache-Control: no-store, no-cache, must-revalidate" ); // HTTP/1.1
40
header("Cache-Control: post-check=0, pre-check=0", FALSE );
41
header("Pragma: no-cache"); // HTTP/1.0
42
header("Content-type: image/svg+xml");
43

    
44
/********** HTTP GET Based Conf ***********/
45
$ifnum=@$_GET["ifnum"];  // BSD / SNMP interface name / number
46
$ifname=@$_GET["ifname"]?$_GET["ifname"]:"Interface $ifnum";  //Interface name that will be showed on top right of graph
47

    
48
/********* Other conf *******/
49
$scale_type="up";               //Autoscale default setup : "up" = only increase scale; "follow" = increase and decrease scale according to current graphed datas
50
$nb_plot=120;                   //NB plot in graph
51
if ($_GET["timeint"])
52
	$time_interval = $_GET["timeint"];		//Refresh time Interval
53
else
54
	$time_interval = 3;
55

    
56
$fetch_link = "ifstats.php?if={$ifnum}";
57

    
58
//SVG attributes
59
$attribs['axis']='fill="black" stroke="black"';
60
$attribs['in']='fill="#FF0000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="7"';
61
$attribs['out']='fill="#000000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="7"';
62
$attribs['graph_in']='fill="none" stroke="#FF0000" stroke-opacity="0.8"';
63
$attribs['graph_out']='fill="none" stroke="#000000" stroke-opacity="0.8"';
64
$attribs['legend']='fill="black" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="4"';
65
$attribs['graphname']='fill="#FF0000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="8"';
66
$attribs['grid_txt']='fill="gray" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="6"';
67
$attribs['grid']='stroke="gray" stroke-opacity="0.5"';
68
$attribs['switch_unit']='fill="#FF0000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="4" text-decoration="underline"';
69
$attribs['switch_scale']='fill="#FF0000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="4" text-decoration="underline"';
70
$attribs['error']='fill="blue" font-family="Arial" font-size="4"';
71
$attribs['collect_initial']='fill="gray" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="4"';
72

    
73
//Error text if we cannot fetch data : depends on which method is used
74
$error_text = "Cannot get data about interface $ifnum";
75

    
76
$height=100;            //SVG internal height : do not modify
77
$width=200;             //SVG internal width : do not modify
78

    
79
/********* Graph DATA **************/
80
print('<?xml version="1.0" encoding="iso-8859-1"?>' . "\n");?>
81
<svg width="100%" height="100%" viewBox="0 0 <?=$width?> <?=$height?>" preserveAspectRatio="none" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" onload="init(evt)">
82
  <g id="graph">
83
    <rect id="bg" x1="0" y1="0" width="100%" height="100%" fill="white"/>
84
    <line id="axis_x" x1="0" y1="0" x2="0" y2="100%" <?=$attribs['axis']?>/>
85
    <line id="axis_y" x1="0" y1="100%" x2="100%" y2="100%" <?=$attribs['axis']?>/>
86
    <path id="graph_out" d="M0 <?=$height?> L 0 <?=$height?>" <?=$attribs['graph_out']?>/>
87
    <path id="graph_in"  d="M0 <?=$height?> L 0 <?=$height?>" <?=$attribs['graph_in']?>/>
88
    <path id="grid"  d="M0 <?=$height/4*1?> L <?=$width?> <?=$height/4*1?> M0 <?=$height/4*2?> L <?=$width?> <?=$height/4*2?> M0 <?=$height/4*3?> L <?=$width?> <?=$height/4*3?>" <?=$attribs['grid']?>/>
89
    <text id="grid_txt1" x="<?=$width?>" y="<?=$height/4*1?>" <?=$attribs['grid_txt']?> text-anchor="end"> </text>
90
    <text id="grid_txt2" x="<?=$width?>" y="<?=$height/4*2?>" <?=$attribs['grid_txt']?> text-anchor="end"> </text>
91
    <text id="grid_txt3" x="<?=$width?>" y="<?=$height/4*3?>" <?=$attribs['grid_txt']?> text-anchor="end"> </text>
92
    <text id="graph_in_lbl" x="5" y="8" <?=$attribs['in']?>>In</text>
93
    <text id="graph_out_lbl" x="5" y="16" <?=$attribs['out']?>>Out</text>
94
    <text id="graph_in_txt" x="20" y="8" <?=$attribs['in']?>> </text>
95
    <text id="graph_out_txt" x="20" y="16" <?=$attribs['out']?>> </text>
96
    <text id="ifname" x="<?=$width?>" y="8" <?=$attribs['graphname']?> text-anchor="end"><?=$ifname?></text>
97
    <text id="switch_unit" x="<?=$width*0.55?>" y="5" <?=$attribs['switch_unit']?>>Switch to bytes/s</text>
98
    <text id="switch_scale" x="<?=$width*0.55?>" y="11" <?=$attribs['switch_scale']?>>AutoScale (<?=$scale_type?>)</text>
99
    <text id="datetime" x="<?=$width*0.33?>" y="5" <?=$attribs['legend']?>> </text>
100
    <text id="graphlast" x="<?=$width*0.55?>" y="17" <?=$attribs['legend']?>>Graph shows last <?=$time_interval*$nb_plot?> seconds</text>
101
    <polygon id="axis_arrow_x" <?=$attribs['axis']?> points="<?=($width) . "," . ($height)?> <?=($width-2) . "," . ($height-2)?> <?=($width-2) . "," . $height?>"/>
102
    <text id="error" x="<?=$width*0.5?>" y="<?=$height*0.5?>"  visibility="hidden" <?=$attribs['error']?> text-anchor="middle"><?=$error_text?></text>
103
    <text id="collect_initial" x="<?=$width*0.5?>" y="<?=$height*0.5?>"  visibility="hidden" <?=$attribs['collect_initial']?> text-anchor="middle">Collecting initial data, please wait...</text>
104
  </g>
105
  <script type="text/ecmascript">
106
    <![CDATA[
107

    
108
/**
109
 * getURL is a proprietary Adobe function, but it's simplicity has made it very
110
 * popular. If getURL is undefined we spin our own by wrapping XMLHttpRequest.
111
 */
112
if (typeof getURL == 'undefined') {
113
  getURL = function(url, callback) {
114
    if (!url)
115
      throw 'No URL for getURL';
116

    
117
    try {
118
      if (typeof callback.operationComplete == 'function')
119
        callback = callback.operationComplete;
120
    } catch (e) {}
121
    if (typeof callback != 'function')
122
      throw 'No callback function for getURL';
123

    
124
    var http_request = null;
125
    if (typeof XMLHttpRequest != 'undefined') {
126
      http_request = new XMLHttpRequest();
127
    }
128
    else if (typeof ActiveXObject != 'undefined') {
129
      try {
130
        http_request = new ActiveXObject('Msxml2.XMLHTTP');
131
      } catch (e) {
132
        try {
133
          http_request = new ActiveXObject('Microsoft.XMLHTTP');
134
        } catch (e) {}
135
      }
136
    }
137
    if (!http_request)
138
      throw 'Both getURL and XMLHttpRequest are undefined';
139

    
140
    http_request.onreadystatechange = function() {
141
      if (http_request.readyState == 4) {
142
        callback( { success : true,
143
                    content : http_request.responseText,
144
                    contentType : http_request.getResponseHeader("Content-Type") } );
145
      }
146
    }
147
    http_request.open('GET', url, true);
148
    http_request.send(null);
149
  }
150
}
151

    
152
var SVGDoc = null;
153
var last_ifin = 0;
154
var last_ifout = 0;
155
var last_ugmt = 0;
156
var max = 0;
157
var plot_in = new Array();
158
var plot_out = new Array();
159

    
160
var max_num_points = <?=$nb_plot?>;  // maximum number of plot data points
161
var step = <?=$width?> / max_num_points ;
162
var unit = 'bits';
163
var scale_type = '<?=$scale_type?>';
164

    
165
function init(evt) {
166
  SVGDoc = evt.target.ownerDocument;
167
  SVGDoc.getElementById("switch_unit").addEventListener("mousedown", switch_unit, false);
168
  SVGDoc.getElementById("switch_scale").addEventListener("mousedown", switch_scale, false);
169

    
170
  fetch_data();
171
}
172

    
173
function switch_unit(event)
174
{
175
  SVGDoc.getElementById('switch_unit').firstChild.data = 'Switch to ' + unit + '/s';
176
  unit = (unit == 'bits') ? 'bytes' : 'bits';
177
}
178

    
179
function switch_scale(event)
180
{
181
  scale_type = (scale_type == 'up') ? 'follow' : 'up';
182
  SVGDoc.getElementById('switch_scale').firstChild.data = 'AutoScale (' + scale_type + ')';
183
}
184

    
185
function fetch_data() {
186
  getURL('<?=$fetch_link?>', plot_data);
187
}
188

    
189
function plot_data(obj) {
190
  // Show datetimelegend
191
  var now = new Date();
192
  var datetime = (now.getMonth()+1) + "/" + now.getDate() + "/" + now.getFullYear() + ' ' + 
193
    LZ(now.getHours()) + ":" + LZ(now.getMinutes()) + ":" + LZ(now.getSeconds());
194
  SVGDoc.getElementById('datetime').firstChild.data = datetime;
195

    
196
  if (!obj.success)
197
    return handle_error();  // getURL failed to get data
198

    
199
  var t = obj.content.split("|");
200
  var ugmt = parseFloat(t[0]);  // ugmt is an unixtimestamp style
201
  var ifin = parseInt(t[1]);    // number of bytes received by the interface
202
  var ifout = parseInt(t[2]);   // number of bytes sent by the interface
203
  var scale;
204

    
205
  if (!isNumber(ifin) || !isNumber(ifout))
206
    return handle_error();
207

    
208
  var diff_ugmt  = ugmt - last_ugmt;
209
  var diff_ifin  = ifin - last_ifin;
210
  var diff_ifout = ifout - last_ifout;
211

    
212
  if (diff_ugmt == 0)
213
    diff_ugmt = 1;  /* avoid division by zero */
214

    
215
  last_ugmt = ugmt;
216
  last_ifin = ifin;
217
  last_ifout = ifout;
218
  
219
  switch (plot_in.length) {
220
  	case 0:
221
  		SVGDoc.getElementById("collect_initial").setAttributeNS(null, 'visibility', 'visible');
222
		plot_in[0] = diff_ifin / diff_ugmt;
223
		plot_out[0] = diff_ifout / diff_ugmt;
224
		setTimeout('fetch_data()',<?=1000*$time_interval?>);
225
		return;
226
	case 1:
227
    	SVGDoc.getElementById("collect_initial").setAttributeNS(null, 'visibility', 'hidden');
228
    	break;
229
    case max_num_points:
230
		// shift plot to left if the maximum number of plot points has been reached
231
		var i = 0;
232
		while (i < max_num_points) {
233
		  plot_in[i] = plot_in[i+1];
234
		  plot_out[i] = plot_out[++i];
235
		}
236
		plot_in.length--;
237
		plot_out.length--;
238
  }
239

    
240
  plot_in[plot_in.length] = diff_ifin / diff_ugmt;
241
  plot_out[plot_out.length]= diff_ifout / diff_ugmt;
242
  var index_plot = plot_in.length - 1;
243

    
244
  SVGDoc.getElementById('graph_in_txt').firstChild.data = formatSpeed(plot_in[index_plot], unit);
245
  SVGDoc.getElementById('graph_out_txt').firstChild.data = formatSpeed(plot_out[index_plot], unit);
246

    
247
  /* determine peak for sensible scaling */
248
  if (scale_type == 'up') {
249
    if (plot_in[index_plot] > max)
250
      max = plot_in[index_plot];
251
    if (plot_out[index_plot] > max)
252
      max = plot_out[index_plot];
253
  }
254
  else if (scale_type == 'follow') {
255
    i = 0;
256
    max = 0;
257
    while (i < plot_in.length) {
258
      if (plot_in[i] > max)
259
        max = plot_in[i];
260
      if (plot_out[i] > max)
261
        max = plot_out[i];
262
      i++;
263
    }
264
  }
265

    
266
  var rmax;  // max, rounded up
267

    
268
  if (unit == 'bits') {
269
    /* round up max, such that
270
         100 kbps -> 200 kbps -> 400 kbps -> 800 kbps -> 1 Mbps -> 2 Mbps -> ... */
271
    rmax = 12500;
272
    i = 0;
273
    while (max > rmax) {
274
      i++;
275
      if (i && (i % 4 == 0))
276
        rmax *= 1.25;
277
      else
278
        rmax *= 2;
279
    }
280
  } else {
281
    /* round up max, such that
282
         10 KB/s -> 20 KB/s -> 40 KB/s -> 80 KB/s -> 100 KB/s -> 200 KB/s -> 400 KB/s -> 800 KB/s -> 1 MB/s ... */
283
    rmax = 10240;
284
    i = 0;
285
    while (max > rmax) {
286
      i++;
287
      if (i && (i % 4 == 0))
288
        rmax *= 1.25;
289
      else
290
        rmax *= 2;
291
      
292
      if (i == 8)
293
        rmax *= 1.024;
294
    }
295
  }
296

    
297
  scale = <?=$height?> / rmax;
298

    
299
  /* change labels accordingly */
300
  SVGDoc.getElementById('grid_txt1').firstChild.data = formatSpeed(3*rmax/4,unit);
301
  SVGDoc.getElementById('grid_txt2').firstChild.data = formatSpeed(2*rmax/4,unit);
302
  SVGDoc.getElementById('grid_txt3').firstChild.data = formatSpeed(rmax/4,unit);
303

    
304
  var path_in = "M 0 " + (<?=$height?> - (plot_in[0] * scale));
305
  var path_out = "M 0 " + (<?=$height?> - (plot_out[0] * scale));
306
  for (i = 1; i < plot_in.length; i++)
307
  {
308
    var x = step * i;
309
    var y_in = <?=$height?> - (plot_in[i] * scale);
310
    var y_out = <?=$height?> - (plot_out[i] * scale);
311
    path_in += " L" + x + " " + y_in;
312
    path_out += " L" + x + " " + y_out;
313
  }
314

    
315
  SVGDoc.getElementById('error').setAttributeNS(null, 'visibility', 'hidden');
316
  SVGDoc.getElementById('graph_in').setAttributeNS(null, 'd', path_in);
317
  SVGDoc.getElementById('graph_out').setAttributeNS(null, 'd', path_out);
318

    
319
  setTimeout('fetch_data()',<?=1000*$time_interval?>);
320
}
321

    
322
function handle_error() {
323
  SVGDoc.getElementById("error").setAttributeNS(null, 'visibility', 'visible');
324
  setTimeout('fetch_data()',<?=1000*$time_interval?>);
325
}
326

    
327
function isNumber(a) {
328
  return typeof a == 'number' && isFinite(a);
329
}
330

    
331
function formatSpeed(speed, unit) {
332
  if (unit == 'bits')
333
    return formatSpeedBits(speed);
334
  if (unit == 'bytes')
335
    return formatSpeedBytes(speed);
336
}
337

    
338
function formatSpeedBits(speed) {
339
  // format speed in bits/sec, input: bytes/sec
340
  if (speed < 125000)
341
    return Math.round(speed / 125) + " Kbps";
342
  if (speed < 125000000)
343
    return Math.round(speed / 1250)/100 + " Mbps";
344
  // else
345
  return Math.round(speed / 1250000)/100 + " Gbps";  /* wow! */
346
}
347

    
348
function formatSpeedBytes(speed) {
349
  // format speed in bytes/sec, input:  bytes/sec
350
  if (speed < 1048576)
351
    return Math.round(speed / 10.24)/100 + " KB/s";
352
  if (speed < 1073741824)
353
    return Math.round(speed / 10485.76)/100 + " MB/s";
354
  // else
355
  return Math.round(speed / 10737418.24)/100 + " GB/s";  /* wow! */
356
}
357

    
358
function LZ(x) {
359
  return (x < 0 || x > 9 ? "" : "0") + x;
360
}
361

    
362
    ]]>
363
  </script>
364
</svg>
365

    
(60-60/173)