Project

General

Profile

Bug #16930 » sqstat.class.php

patched file that fixes issue so it will show correctly - Jonathan Lee, 07/02/2026 04:06 PM

 
1
<?php
2
/*
3
 * sqstat.class.php
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2015-2023 Rubicon Communications, LLC (Netgate)
7
 * Copyright (C) 2006 Alex Samorukov <samm@os2.kiev.ua>
8
 * Copyright (c) 2011 Sergey Dvoriancev <dv_serg@mail.ru>
9
 * All rights reserved.
10
 *
11
 * Licensed under the Apache License, Version 2.0 (the "License");
12
 * you may not use this file except in compliance with the License.
13
 * You may obtain a copy of the License at
14
 *
15
 * http://www.apache.org/licenses/LICENSE-2.0
16
 *
17
 * Unless required by applicable law or agreed to in writing, software
18
 * distributed under the License is distributed on an "AS IS" BASIS,
19
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
 * See the License for the specific language governing permissions and
21
 * limitations under the License.
22
 */
23

    
24
/* Squid Proxy Server realtime stats */
25
DEFINE('SQSTAT_VERSION', '1.20');
26
DEFINE('SQSTAT_SHOWLEN', 60);
27

    
28
class squidstat {
29
	var $fp;
30

    
31
	// conection
32
	var $squidhost;
33
	var $squidport;
34

    
35
	// hosts
36
	var $hosts_file;
37
	var $hosts;
38

    
39
	// versions
40
	var $server_version;
41
	var $sqstat_version;
42

    
43
	// other
44
	var $group_by;
45
	var $resolveip;
46
	var $autorefresh;
47
	var $use_sessions = false;
48

    
49
	// cache manager
50
	var $cachemgr_passwd;
51

    
52
	// errors
53
	var $errno;
54
	var $errstr;
55

    
56
	function squidstat() {
57
		$this->sqstat_version = SQSTAT_VERSION;
58

    
59
		$this->squidhost = '127.0.0.1';
60
		$this->squidport = '3128';
61

    
62
		$this->group_by	= 'host';
63
		$this->resolveip = true;
64
		$this->hosts_file = '';
65
		$this->autorefresh = 0;
66
		$this->cachemgr_passwd = '';
67

    
68
		$errno = 0;
69
		$errstr = '';
70

    
71
		if (!function_exists("preg_match")) {
72
			$this->errorMsg(5, 'You need to install <a href="http://www.php.net/pcre/" target="_blank">PHP pcre extension</a> to run this script');
73
			$this->showError();
74
			exit(5);
75
		}
76

    
77
		// we need session support to gather avg. speed
78
		if (function_exists("session_start")) {
79
			$this->use_sessions = true;
80
		}
81
	}
82

    
83
	function formatXHTML($body, $refresh, $use_js = false) {
84
		$text = '<?xml version="1.0" encoding="UTF-8"?>' . "\n"
85
		    .'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">' . "\n"
86
		    . '<html>'
87
		    . '<head>'
88
		    . '<link href="sqstat.css" rel="stylesheet" type="text/css"/>';
89
		if ($refresh) {
90
			$text .= '<META HTTP-EQUIV=Refresh CONTENT="' . $refresh . '; URL=' . $_SERVER["PHP_SELF"] . '?refresh=' . $refresh . '&config=' . $GLOBALS["config"] . '"/>';
91
		}
92
		$text .= '<title>SqStat ' . SQSTAT_VERSION . '</title>' . ($use_js ? '<script src="zhabascript.js" type="text/javascript"></script>' : '') . '</head>'
93
		    . ($use_js ? '<body onload="jsInit();"><div id="dhtmltooltip"></div><i id="dhtmlpointer" class="fa fa-arrow-right"></i>' : '<body>')
94
		    . $body . '</body></html>';
95
		return $text;
96
	}
97

    
98
	function showError() {
99
		$text = '<h1>SqStat error</h1>' . '<h2 style="color:red">Error (' . $this->errno . ') : ' . $this->errstr . '</h2>';
100
		echo $this->formatXHTML($text, 0);
101
	}
102

    
103
	function connect($squidhost, $squidport) {
104
		$this->fp = false;
105
		// connecting to the squidhost
106
		$this->fp = @fsockopen($squidhost, $squidport, $this->errno, $this->errstr, 10);
107
		if (!$this->fp) {
108
			// failed to connect
109
			return false;
110
		}
111
		return true;
112
	}
113

    
114
	// based @ (c) moritz at barafranca dot com
115
	function duration ($seconds) {
116
		$takes_time = array(604800, 86400, 3600, 60, 0);
117
		$suffixes = array("w", "d", "h", "m", "s");
118
		$output = "";
119
		foreach ($takes_time as $key => $val) {
120
			${$suffixes[$key]} = ($val == 0) ? $seconds : floor(($seconds/$val));
121
			$seconds -= ${$suffixes[$key]} * $val;
122
			if (${$suffixes[$key]} > 0) {
123
				$output .= ${$suffixes[$key]};
124
				$output .= $suffixes[$key]." ";
125
			}
126
		}
127
		return trim($output);
128
	}
129

    
130
	/**
131
	* Format a number of bytes into a human readable format.
132
	* Optionally choose the output format and/or force a particular unit
133
	*
134
	* @param   int     $bytes      The number of bytes to format. Must be positive
135
	* @param   string  $format     Optional. The output format for the string
136
	* @param   string  $force      Optional. Force a certain unit. B|KB|MB|GB|TB
137
	* @return  string	       The formatted file size
138
	*/
139
	function filesize_format($bytes, $format = '', $force = '') {
140
		$force = strtoupper($force);
141
		$defaultFormat = '%01d %s';
142
		if (strlen($format) == 0) {
143
			$format = $defaultFormat;
144
		}
145
		$bytes = max(0, (int) $bytes);
146
		$units = array('b', 'Kb', 'Mb', 'Gb', 'Tb', 'Pb');
147
		$power = array_search($force, $units);
148
		if ($power === false) {
149
			$power = $bytes > 0 ? floor(log($bytes)/log(1024)) : 0;
150
		}
151
		return sprintf($format, $bytes / pow(1024, $power), $units[$power]);
152
	}
153

    
154
	function makeQuery($pass = "") {
155
		$raw = array();
156
		// sending request
157
		if (!$this->fp) {
158
			die("Please connect to server");
159
		}
160

    
161
		$out = "GET cache_object://localhost/active_requests HTTP/1.0\r\n";
162
		if ($pass != "") {
163
			$out .= "Authorization: Basic ". base64_encode("cachemgr:$pass") . "\r\n";
164
		}
165
		$out .= "\r\n";
166

    
167
		fwrite($this->fp, $out);
168

    
169
		while (!feof($this->fp)) {
170
			$raw[] = trim(fgets($this->fp, 2048));
171
		}
172
		fclose($this->fp);
173

    
174
		if (!preg_match("/^HTTP.* 200 OK$/", $raw[0])) {
175
			$this->errorMsg(1, "Cannot get data. Server answered: $raw[0]");
176
			return false;
177
		}
178

    
179
		// parsing output;
180
		$header = 1;
181
		$connection = 0;
182
		$parsed["server_version"] = "Unknown";
183
		foreach ($raw as $key => $v) {
184
			// cutoff http header
185
			if ($header == 1 && $v == "") {
186
				$header = 0;
187
			}
188
			if ($header) {
189
				if (substr(strtolower($v), 0, 7) == "server:") {
190
					// parsing server version
191
					$parsed["server_version"] = substr($v, 8);
192
				}
193
			} else {
194
				if (substr($v, 0, 11) == "Connection:") {
195
					// parsing connection
196
					$connection = substr($v, 12);
197
				}
198
				if ($connection) {
199
					/* username field is avaible in Squid 2.6+
200
					 * peer changed to remote in Squid 3.2+
201
					 * me changed to local in Squid 3.2+
202
					 */
203
					if (substr($v, 0, 9) == "username ") {
204
						$parsed["con"][$connection]["username"] = substr($v, 9);
205
					}
206
					if (substr($v, 0, 7) == "remote:") {
207
						$parsed["con"][$connection]["peer"] = substr($v, 8);
208
					}
209
					if (substr($v, 0, 5) == "peer:") {
210
						$parsed["con"][$connection]["peer"] = substr($v, 6);
211
					}
212
					if (substr($v, 0, 6) == "local:") {
213
						$parsed["con"][$connection]["me"] = substr($v, 7);
214
					}
215
					if (substr($v, 0, 3) == "me:") {
216
						$parsed["con"][$connection]["me"] = substr($v, 4);
217
					}
218
					if (substr($v, 0, 4) == "uri ") {
219
						$parsed["con"][$connection]["uri"] = substr($v, 4);
220
					}
221
					if (substr($v, 0, 10) == "delay_pool") {
222
						$parsed["con"][$connection]["delay_pool"] = substr($v, 11);
223
					}
224

    
225
					if (preg_match('/out.offset \d+, out.size (\d+)/', $v, $matches)) {
226
						$parsed["con"][$connection]["bytes"] = $matches[1];
227
					}
228
					if (preg_match('/start \d+\.\d+ \((\d+).\d+ seconds ago\)/', $v, $matches)) {
229
						$parsed["con"][$connection]["seconds"] = $matches[1];
230
					}
231
				}
232
			}
233
		}
234
		return $parsed;
235
	}
236

    
237
	function implode_with_keys($array, $glue) {
238
		foreach ($array as $key => $v) {
239
			$ret[] = $key . '=' . htmlspecialchars($v);
240
		}
241
		return implode($glue, $ret);
242
	}
243

    
244
	function makeHtmlReport($data, $resolveip = false, $hosts_array = array(), $use_js = true) {
245
		global $group_by;
246
		if ($this->use_sessions) {
247
			session_name('SQDATA');
248
			session_start();
249
		}
250

    
251
		$total_avg = $total_curr = 0;
252
		// resort data array
253
		$users = array();
254
		switch ($group_by) {
255
			case "host":
256
				$group_by_name="Host";
257
				$group_by_key='return $ip;';
258
				break;
259
			case "username":
260
				$group_by_name="User";
261
				$group_by_key='return $v["username"];';
262
				break;
263
			default:
264
				die("wrong group_by!");
265
		}
266
		foreach ($data["con"] as $key => $v) {
267
			if (substr($v["uri"], 0, 13) == "cache_object:") {
268
				continue; // skip myself
269
			}
270
			
271
			// Find the last colon in the string (the true port separator)
272
			$last_colon = strrpos($v["peer"], ":");
273
			if ($last_colon !== false) {
274
				$ip = substr($v["peer"], 0, $last_colon);
275
				// Strip surrounding brackets standard to IPv6 strings like [2001:...]
276
				$ip = trim($ip, '[]'); 
277
			} else {
278
				$ip = $v["peer"];
279
			}
280

    
281
			// FIX: Only apply sorting conversions if it is a valid IPv4 address
282
			if (isset($hosts_array[$ip])) {
283
				$ip = $hosts_array[$ip];
284
			} elseif ($resolveip) {
285
				$hostname = gethostbyaddr($ip);
286
				if ($hostname == $ip) {
287
					$ip = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ? ip2long($ip) : $ip; 
288
				} else {
289
					$ip = $hostname;
290
				}
291
			} else {
292
				$ip = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ? ip2long($ip) : $ip;
293
			}
294
			$v['connection'] = $key;
295
			if (!isset($v["username"])) {
296
				$v["username"] = "N/A";
297
			}
298

    
299
			$users[eval($group_by_key)][] = $v;
300
		}
301
		ksort($users);
302
		$refresh = 0;
303
		if (isset($_GET["refresh"]) && !isset($_GET["stop"])) {
304
			$refresh = (int)$_GET["refresh"];
305
		}
306
		$text = '';
307
		if (count($GLOBALS["configs"]) == 1) {
308
			$servers = $GLOBALS["squidhost"] . ':' . $GLOBALS["squidport"];
309
		} else {
310
			$servers = '<select onchange="this.form.submit();" name="config">';
311
			foreach ($GLOBALS["configs"] as $key => $v) {
312
				$servers .= '<option ' . ($GLOBALS["config"] == $key ? ' selected="selected" ' : '') . ' value="' . $key . '">' . htmlspecialchars($v) . '</option>';
313
			}
314
			$servers .= '</select>';
315
		}
316
		$text .= '<div class="header"><form method="get" action="' . $_SERVER["PHP_SELF"] . '">'
317
		    . 'Squid RealTime stat for the ' . $servers . ' proxy server (' . $data["server_version"] . ').<br/>'
318
		    . 'Auto refresh: <input name="refresh" type="text" size="4" value="' . $refresh . '"/> sec. <input type="submit" value="Update"/> <input name="stop" type="submit" value="Stop"/> Created at: <tt>' . date("h:i:s d/m/Y") . '</tt><br/>'
319
		    . '</div>'
320
		    . '<table class="result" align="center" width="100%" border="0">'
321
		    . '<tr>'
322
		    . '<th>' . $group_by_name . '</th><th>URI</th>'
323
		    . ($this->use_sessions ? '<th>Curr. Speed</th><th>Avg. Speed</th>' : '')
324
		    . '<th>Size</th><th>Time</th>'
325
		    . '</tr>';
326
		$ausers = $acon = 0;
327
		unset($session_data);
328
		if (isset($_SESSION['time']) && ((time() - $_SESSION['time']) < 3*60) && isset($_SESSION['sqdata']) && is_array($_SESSION['sqdata'])) {
329
			// only if the latest data was less than 3 minutes ago
330
			$session_data = $_SESSION['sqdata'];
331
		}
332
		$table = '';
333
		foreach ($users as $key => $v) {
334
			$ausers++;
335
			$table .= '<tr><td style="border-right:0;" colspan="2"><b>' . (is_int($key) ? long2ip($key) : $key) . '</b></td>'
336
			    . '<td style="border-left:0;" colspan="5">&nbsp;</td></tr>';
337
			$user_avg = $user_curr = $con_color = 0;
338
			foreach ($v as $con) {
339
				if (substr($con["uri"], 0, 7) == "http://" || substr($con["uri"], 0, 6) == "ftp://") {
340
					if (strlen($con["uri"]) > SQSTAT_SHOWLEN) {
341
						$uritext = htmlspecialchars(substr($con["uri"], 0, SQSTAT_SHOWLEN)) . '</a> ....';
342
					} else {
343
						$uritext = htmlspecialchars($con["uri"]) . '</a>';
344
					}
345
					$uri = '<a target="_blank" href="' . htmlspecialchars($con["uri"]) . '">' . $uritext;
346
				} else {
347
					$uri = htmlspecialchars($con["uri"]);
348
				}
349
				$acon++;
350
				// speed stuff
351
				$con_id = $con['connection'];
352
				$is_time = time();
353
				$curr_speed = 0;
354
				$avg_speed = 0;
355
				if (isset($session_data[$con_id]) && !empty($session_data[$con_id])) {
356
					// if we have info about current connection, we do analyze its data current speed
357
					$con_data = $session_data[$con_id];
358
					$was_time = $con_data['time'];
359
					$was_size = $con_data['size'];
360
					if ($was_time && $was_size) {
361
						$delta = $is_time - $was_time;
362
						if ($delta == 0) {
363
							$delta = 1;
364
						}
365
						if ($con['bytes'] >= $was_size) {
366
							$curr_speed = ($con['bytes'] - $was_size) / 1024 / $delta;
367
						}
368
					} else {
369
						$curr_speed = $con['bytes'] / 1024;
370
					}
371

    
372
					// avg speed
373
					$avg_speed = $con['bytes'] / 1024;
374
					if ($con['seconds'] > 0) {
375
						$avg_speed /= $con['seconds'];
376
					}
377
				}
378

    
379
				$new_data[$con_id]['time'] = $is_time;
380
				$new_data[$con_id]['size'] = $con['bytes'];
381

    
382
				// sum speeds
383
				$total_avg += $avg_speed;
384
				$user_avg += $avg_speed;
385
				$total_curr += $curr_speed;
386
				$user_curr += $curr_speed;
387

    
388
				if ($use_js) {
389
					$js = 'onMouseout="hideddrivetip()" onMouseover="ddrivetip(\'' . $this->implode_with_keys($con, '<br/>') . '\')"';
390
				} else {
391
					$js = '';
392
				}
393
				$table .= '<tr' . ( (++$con_color % 2 == 0) ? ' class="odd"' : '' ) . '><td id="white"></td>'
394
				    . '<td nowrap ' . $js . ' width="80%" >' . $uri . '</td>';
395
				if ($this->use_sessions) {
396
					$table .= '<td nowrap align="right">' . ( (round($curr_speed, 2) > 0) ? sprintf("%01.2f KB/s", $curr_speed) : '' ) . '</td>'
397
					    . '<td nowrap align="right">' . ( (round($avg_speed, 2) > 0) ? sprintf("%01.2f KB/s", $avg_speed) : '' ) . '</td>';
398
				}
399
				$table .= '<td nowrap align="right">' . $this->filesize_format($con["bytes"]) . '</td>'
400
				    . '<td nowrap align="right">' . $this->duration($con["seconds"], "short") . '</td>'
401
				    . '</tr>';
402
			}
403
			if ($this->use_sessions) {
404
				$table .= sprintf("<tr><td colspan=\"2\"></td><td align=\"right\" id=\"highlight\">%01.2f KB/s</td><td align=\"right\" id=\"highlight\">%01.2f KB/s</td><td colspan=\"2\"></td>", $user_curr, $user_avg);
405
			}
406

    
407
		}
408
		$_SESSION['time'] = time();
409
		if (isset($new_data)) {
410
			$_SESSION['sqdata'] = $new_data;
411
		}
412
		$stat_row = '';
413
		if ($this->use_sessions) {
414
			$stat_row .= sprintf("<tr class=\"total\"><td><b>Total:</b></td><td align=\"right\" colspan=\"5\"><b>%d</b> users and <b>%d</b> connections @ <b>%01.2f/%01.2f</b> KB/s (CURR/AVG)</td></tr>", $ausers, $acon, $total_curr, $total_avg);
415
		} else {
416
			$stat_row .= sprintf("<tr class=\"total\"><td><b>Total:</b></td><td align=\"right\" colspan=\"5\"><b>%d</b> users and <b>%d</b> connections</td></tr>",	$ausers, $acon);
417
		}
418
		if ($ausers == 0) {
419
			$text .= '<tr><td colspan=6><b>No active connections</b></td></tr>';
420
		} else {
421
			$text .= $stat_row . $table . $stat_row;
422
		}
423
		$text .= '</table>' . '<p class="copyleft">&copy; <a href="mailto:samm@os2.kiev.ua?subject=SqStat ' . SQSTAT_VERSION . '">Alex Samorukov</a>, 2006</p>';
424
		return $this->formatXHTML($text, $refresh, $use_js);
425
	}
426

    
427
	function parseRequest($data, $group_by = 'host', $resolveip = false) {
428
		$parsed = array();
429
		if ($this->use_sessions) {
430
			session_name('SQDATA');
431
			session_start();
432
		}
433

    
434
		// resort data array
435
		$users = array();
436
		switch ($group_by) {
437
			case "username":
438
				$group_by_name = "User";
439
				$group_by_key = "username";
440
				break;
441
			case "host":
442
			default:
443
				$group_by_name = "Host";
444
				$group_by_key = "peer";
445
				break;
446
		}
447

    
448
		// resolve IP & group
449
		foreach ($data["con"] as $key => $v) {
450
			// skip myself
451
			if (substr($v["uri"], 0, 13) == "cache_object:") {
452
				continue;
453
			}
454

    
455
			// FIX: Scan right-to-left for the true port separator on IPv6 addresses
456
			$last_colon = strrpos($v["peer"], ":");
457
			if ($last_colon !== false) {
458
				$ip = substr($v["peer"], 0, $last_colon);
459
				$ip = trim($ip, '[]'); // Strip surrounding brackets like [2001:...]
460
			} else {
461
				$ip = $v["peer"];
462
			}
463
			$v["peer"] = $ip;
464

    
465
			// name from hosts
466
			if (isset($this->hosts[$ip])) {
467
				$ip = $this->hosts[$ip];
468
			} elseif ($resolveip) {
469
				$hostname = gethostbyaddr($ip);
470
				if ($hostname == $ip) {
471
					$ip = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ? ip2long($ip) : $ip; 
472
				} else {
473
					$ip = $hostname;
474
				}
475
			} else {
476
				$ip = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ? ip2long($ip) : $ip;
477
			}
478
			$v['con_id'] = $key;
479
			$v["username"] = isset($v["username"]) ? $v["username"] : "N/A";
480

    
481
			// users [key => conn_array]
482
			$users[$v[$group_by_key]][] = $v;
483
		}
484
		ksort($users);
485

    
486
		unset($session_data);
487
		if (isset($_SESSION['time']) && ((time() - $_SESSION['time']) < 3*60) && isset($_SESSION['sqdata']) && is_array($_SESSION['sqdata'])) {
488
			// only if the latest data was less than 3 minutes ago
489
			$session_data = $_SESSION['sqdata'];
490
		}
491

    
492
		// users count & con count
493
		$ausers = $acon = 0;
494
		$total_avg = $total_curr = 0;
495
		foreach ($users as $key => $v) {
496
			$ausers++;
497

    
498
			$user_avg = $user_curr = $con_color = 0;
499
			foreach ($v as $con_key => $con) {
500
				$cres = array();
501
				$acon++;
502

    
503
				$uritext = $con["uri"];
504
				if (substr($con["uri"], 0, 7) == "http://" || substr($con["uri"], 0, 6) == "ftp://") {
505
					if (strlen($uritext) > SQSTAT_SHOWLEN) {
506
						$uritext = htmlspecialchars(substr($uritext, 0, SQSTAT_SHOWLEN)) . ' ....';
507
					}
508
				} else {
509
					$uritext = htmlspecialchars($uritext);
510
				}
511
				$cres['uritext'] = $uritext;
512
				$cres['uri'] = $con["uri"];
513

    
514
				// speed stuff
515
				$con_id = $con['connection'];
516
				$is_time = time();
517
				$curr_speed = $avg_speed = 0;
518
				if (isset($session_data[$con_id]) && !empty($session_data[$con_id])) {
519
					// if we have info about current connection, we do analyze its data current speed
520
					$con_data = $session_data[$con_id];
521
					$was_time = $con_data['time'];
522
					$was_size = $con_data['size'];
523
					if ($was_time && $was_size) {
524
						$delta = $is_time - $was_time;
525
						if ($delta == 0) {
526
							$delta = 1;
527
						}
528
						if ($con['bytes'] >= $was_size) {
529
							$curr_speed = ($con['bytes'] - $was_size) / 1024 / $delta;
530
						}
531
					} else {
532
						$curr_speed = $con['bytes'] / 1024;
533
					}
534

    
535
					// avg speed
536
					$avg_speed = $con['bytes'] / 1024;
537
					if ($con['seconds'] > 0) {
538
						$avg_speed /= $con['seconds'];
539
					}
540
				}
541
				$cres['cur_speed'] = $curr_speed;
542
				$cres['avg_speed'] = $avg_speed;
543
				$cres['seconds'] = $con["seconds"];
544
				$cres['bytes'] = $con["bytes"];
545

    
546
				// grouped parsed[key => conn_key]
547
				$parsed['users'][$key]['con'][$con_key] = $cres;
548

    
549
				// for sessions
550
				$new_data[$con_id]['time'] = $is_time;
551
				$new_data[$con_id]['size'] = $con['bytes'];
552

    
553
				// sum speeds
554
				$total_avg += $avg_speed;
555
				$user_avg += $avg_speed;
556
				$total_curr += $curr_speed;
557
				$user_curr += $curr_speed;
558
			}
559

    
560
			// total per user
561
			$parsed['users'][$key]['user_curr'] = $user_curr;
562
			$parsed['users'][$key]['user_avg'] = $user_avg;
563
		}
564

    
565
		// total info
566
		$parsed['ausers'] = $ausers;
567
		$parsed['acon'] = $acon;
568
		$parsed['total_avg'] = $total_avg;
569
		$parsed['total_curr'] = $total_curr;
570

    
571
		// update session info
572
		$_SESSION['time'] = time();
573
		if (isset($new_data)) {
574
			$_SESSION['sqdata'] = $new_data;
575
		}
576

    
577
		return $parsed;
578
	}
579

    
580
	function errorMsg($errno, $errstr) {
581
		$this->errno = $errno;
582
		$this->errstr = $errstr;
583
	}
584

    
585
	function load_hosts() {
586
		// loading hosts file
587
		$hosts_array = array();
588

    
589
		if (!empty($this->hosts_file)) {
590
			if (is_file($this->hosts_file)) {
591
				$handle = @fopen($this->hosts_file, "r");
592
				if ($handle) {
593
					while (!feof($handle)) {
594
						$buffer = fgets($handle, 4096);
595
						unset($matches);
596
						if (preg_match('/^([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})[ \t]+(.+)$/i', $buffer, $matches)) {
597
							$hosts_array[$matches[1]]=$matches[2];
598
						}
599
					}
600
					fclose($handle);
601
				}
602
				$this->hosts = $hosts_array;
603
			} else {
604
				// error
605
				$this->errorMsg(4, "Hosts file not found. Cant read <tt>'{$this->hosts_file}'</tt>.");
606
				return $this->errno;
607
			}
608
		}
609

    
610
		return 0;
611
	}
612

    
613
	function query_exec() {
614
		$data = "";
615

    
616
		$this->server_version = '(unknown)';
617
		if ($this->connect($this->squidhost, $this->squidport)) {
618
			$data = $this->makeQuery($this->cachemgr_passwd);
619
			if ($this->errno == 0) {
620
				$this->server_version = $data['server_version'];
621
				$data = $this->parseRequest($data, 'host', true);
622
			}
623
		}
624

    
625
		return $data;
626
	}
627

    
628
}
629
?>
(2-2/3)