Project

General

Profile

Download (39.9 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php 
2
/*
3
	util.inc
4
	part of the pfSense project (http://www.pfsense.com)
5

    
6
	originally part of m0n0wall (http://m0n0.ch/wall)
7
	Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
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
/*
33
	pfSense_BUILDER_BINARIES:	/bin/ps	/bin/kill	/usr/bin/killall	/sbin/ifconfig	/usr/bin/netstat
34
	pfSense_BUILDER_BINARIES:	/usr/bin/awk	/sbin/dmesg		/sbin/ping /usr/local/sbin/gzsig	/usr/sbin/arp
35
	pfSense_BUILDER_BINARIES:	/sbin/conscontrol	/sbin/devd	/bin/ps
36
	pfSense_MODULE:	utils
37
*/
38

    
39
/* kill a process by pid file */
40
function killbypid($pidfile) {
41
	return sigkillbypid($pidfile, "TERM");
42
}
43

    
44
function isvalidpid($pid) {
45
	$output = "";
46
	exec("/bin/pgrep -F {$pid}", $output, $retval);
47

    
48
	return (intval($retval) == 0);
49
}
50

    
51
function is_process_running($process) {
52
	$output = "";
53
	exec("/bin/pgrep -ax {$process}", $output, $retval);
54

    
55
	return (intval($retval) == 0);
56
}
57

    
58
function isvalidproc($proc) {
59
	return is_process_running($proc);
60
}
61

    
62
/* sigkill a process by pid file */
63
/* return 1 for success and 0 for a failure */
64
function sigkillbypid($pidfile, $sig) {
65
	if (is_file($pidfile))
66
		return mwexec("/bin/pkill -{$sig} -F {$pidfile}", true);
67

    
68
	return 0;
69
}
70

    
71
/* kill a process by name */
72
function sigkillbyname($procname, $sig) {
73
	if(isvalidproc($procname))
74
		return mwexec("/usr/bin/killall -{$sig} " . escapeshellarg($procname), true);
75
}
76

    
77
/* kill a process by name */
78
function killbyname($procname) {
79
	if(isvalidproc($procname)) 
80
		mwexec("/usr/bin/killall " . escapeshellarg($procname));
81
}
82

    
83
function is_subsystem_dirty($subsystem = "") {
84
	global $g;
85

    
86
	if ($subsystem == "")
87
		return false;
88

    
89
	if (file_exists("{$g['varrun_path']}/{$subsystem}.dirty"))
90
		return true;
91

    
92
	return false;
93
}
94

    
95
function mark_subsystem_dirty($subsystem = "") {
96
	global $g;
97

    
98
	if (!file_put_contents("{$g['varrun_path']}/{$subsystem}.dirty", "DIRTY"))
99
		log_error(sprintf(gettext("WARNING: Could not mark subsystem: %s dirty"), $subsystem));
100
}
101

    
102
function clear_subsystem_dirty($subsystem = "") {
103
	global $g;
104

    
105
	@unlink("{$g['varrun_path']}/{$subsystem}.dirty");
106
}
107

    
108
function config_lock() {
109
	return;
110
}
111
function config_unlock() {
112
	return;
113
}
114

    
115
/* lock configuration file */
116
function lock($lock, $op = LOCK_SH) {
117
	global $g, $cfglckkeyconsumers;
118
	if (!$lock)
119
		die(gettext("WARNING: You must give a name as parameter to lock() function."));
120
	if (!file_exists("{$g['tmp_path']}/{$lock}.lock"))
121
		@touch("{$g['tmp_path']}/{$lock}.lock");
122
	$cfglckkeyconsumers++;
123
	if ($fp = fopen("{$g['tmp_path']}/{$lock}.lock", "w")) {
124
		if (flock($fp, $op))
125
			return $fp;
126
		else
127
			fclose($fp);
128
	}
129
}
130

    
131
/* unlock configuration file */
132
function unlock($cfglckkey = 0) {
133
	global $g, $cfglckkeyconsumers;
134
	flock($cfglckkey, LOCK_UN);
135
	fclose($cfglckkey);
136
	return;
137
}
138

    
139
function send_event($cmd) {
140
	global $g;
141

    
142
	if(!isset($g['event_address']))
143
		$g['event_address'] = "unix:///var/run/check_reload_status";
144
		
145
	$try = 0;
146
	while ($try < 3) {
147
		$fd = @fsockopen($g['event_address']);
148
		if ($fd) {
149
			fwrite($fd, $cmd);
150
			$resp = fread($fd, 4096);
151
			if ($resp != "OK\n")
152
				log_error("send_event: sent {$cmd} got {$resp}");
153
			fclose($fd);
154
			$try = 3;
155
		} else
156
			mwexec_bg("/usr/bin/nice -n20 /usr/local/sbin/check_reload_status");
157
		$try++;
158
	}
159
}
160

    
161
function send_multiple_events($cmds) {
162
	global $g;
163

    
164
	if(!isset($g['event_address']))
165
		$g['event_address'] = "unix:///var/run/check_reload_status";
166
			
167
	if (!is_array($cmds))
168
		return;
169
	$fd = fsockopen($g['event_address']);
170
	if ($fd) {
171
		foreach ($cmds as $cmd) {
172
			fwrite($fd, $cmd);
173
			$resp = fread($fd, 4096);
174
			if ($resp != "OK\n")
175
				log_error("send_event: sent {$cmd} got {$resp}");
176
		}
177
		fclose($fd);
178
	}
179
}
180

    
181
function refcount_init($reference) {
182
	$shmid = shmop_open($reference, "c", 0644, 10);
183
	shmop_write($shmid, 0, 0);
184
	shmop_close($shmid);
185
}
186

    
187
function refcount_reference($reference) {
188
	$shmid = @shmop_open($reference, "w", 0644, 10);
189
	if (!$shmid) {
190
		refcount_init($reference);
191
		$shmid = shmop_open($reference, "w", 0644, 10);
192
	}
193
	$shm_data = shmop_read($shmid, 0, 10);
194
	$shm_data = intval($shm_data) + 1;
195
	shmop_write($shmid, $shm_data, 0);
196
	shmop_close($shmid);
197
	
198
	return $shm_data;
199
}
200

    
201
function refcount_unreference($reference) {
202
	/* We assume that the shared memory exists. */
203
	$shmid = shmop_open($reference, "w", 0644, 10);
204
	$shm_data = shmop_read($shmid, 0, 10);
205
	$shm_data = intval($shm_data) - 1;
206
	if ($shm_data < 0) {
207
		//debug_backtrace();
208
		log_error(sprintf(gettext("Reference %s is going negative, not doing unreference."), $reference));
209
	} else
210
		shmop_write($shmid, $shm_data, 0);
211
	shmop_close($shmid);
212
	
213
	return $shm_data;
214
}
215

    
216
function is_module_loaded($module_name) {
217
	$running = `/sbin/kldstat | grep {$module_name} | /usr/bin/grep -v grep | /usr/bin/wc -l`;
218
	if (intval($running) >= 1)
219
		return true;
220
	else
221
		return false;
222
}
223

    
224
/* return the subnet address given a host address and a subnet bit count */
225
function gen_subnet($ipaddr, $bits) {
226
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
227
		return "";
228
	return long2ip(ip2long($ipaddr) & gen_subnet_mask_long($bits));
229
}
230

    
231
/* return the subnet address given a host address and a subnet bit count */
232
function gen_subnetv6($ipaddr, $bits) {
233
	if (!is_ipaddrv6($ipaddr) || !is_numeric($bits))
234
		return "";
235

    
236
	$address = Net_IPv6::getNetmask($ipaddr, $bits);
237
	return $address;
238
}
239

    
240
/* return the highest (broadcast) address in the subnet given a host address and a subnet bit count */
241
function gen_subnet_max($ipaddr, $bits) {
242
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
243
		return "";
244

    
245
	return long2ip32(ip2long($ipaddr) | ~gen_subnet_mask_long($bits));
246
}
247

    
248
/* Generate end number for a given ipv6 subnet mask
249
 * no, it does not perform math */
250
function gen_subnetv6_max($ipaddr, $bits) {
251
	if(!is_ipaddrv6($ipaddr))
252
		return false;
253
	
254
	$subnetstart = gen_subnetv6($ipaddr, $bits);
255
	/* we should have a expanded full ipv6 subnet starting at 0.
256
	 * Now split those by the semicolon so we can do 16 bit math */
257
	$parts = explode(":", $subnetstart);
258
	if(count($parts) <> 8)
259
		return false;
260

    
261
	/* reverse the array, we start with the lsb */
262
	$parts = array_reverse($parts);
263
	/* set the itteration count properly */
264
	$bitsleft = 128 - $bits;
265
	$i = 0;
266
	foreach($parts as $part) {
267
		/* foreach 16 bits we go to the next part */
268
		/* no this isn't proper hex math, neither does it overflow properly */
269
		while($bitsleft > 0) {
270
			if($part == "0") {
271
				$part = "f";
272
			} else {
273
				$part = $part . "f";
274
			}
275
			$bitsleft = $bitsleft - 4;
276
			$j++;
277
			if($j == 4) {
278
				$parts[$i] = $part;
279
				$j = 0;
280
				$i++;
281
				continue 2;
282
			}
283
		}
284
		$i++;
285
	}
286
	$parts = array_reverse($parts);
287
	$subnet_end = implode(":", $parts);
288
	return $subnet_end;
289
}
290

    
291
/* returns a subnet mask (long given a bit count) */
292
function gen_subnet_mask_long($bits) {
293
	$sm = 0;
294
	for ($i = 0; $i < $bits; $i++) {
295
		$sm >>= 1;
296
		$sm |= 0x80000000;
297
	}
298
	return $sm;
299
}
300

    
301
/* same as above but returns a string */
302
function gen_subnet_mask($bits) {
303
	return long2ip(gen_subnet_mask_long($bits));
304
}
305

    
306
/* Convert long int to IP address, truncating to 32-bits. */
307
function long2ip32($ip) {
308
	return long2ip($ip & 0xFFFFFFFF);
309
}
310

    
311
/* Convert IP address to long int, truncated to 32-bits to avoid sign extension on 64-bit platforms. */
312
function ip2long32($ip) {
313
	return ( ip2long($ip) & 0xFFFFFFFF );
314
}
315

    
316
/* Convert IP address to unsigned long int. */
317
function ip2ulong($ip) {
318
	return sprintf("%u", ip2long32($ip));
319
}
320

    
321
/* Find out how many IPs are contained within a given IP range
322
 *  e.g. 192.168.0.0 to 192.168.0.255 returns 256
323
 */
324
function ip_range_size($startip, $endip) {
325
	if (is_ipaddr($startip) && is_ipaddr($endip)) {
326
		// Operate as unsigned long because otherwise it wouldn't work
327
		//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
328
		return abs(ip2ulong($startip) - ip2ulong($endip)) + 1;
329
	}
330
	return -1;
331
}
332

    
333
/* Find the smallest possible subnet mask which can contain a given number of IPs
334
 *  e.g. 512 IPs can fit in a /23, but 513 IPs need a /22
335
 */
336
function find_smallest_cidr($number) {
337
	$smallest = 1;
338
	for ($b=32; $b > 0; $b--) {
339
		$smallest = ($number <= pow(2,$b)) ? $b : $smallest;
340
	}
341
	return (32-$smallest);
342
}
343

    
344
/* Return the previous IP address before the given address */
345
function ip_before($ip) {
346
	return long2ip32(ip2long($ip)-1);
347
}
348

    
349
/* Return the next IP address after the given address */
350
function ip_after($ip) {
351
	return long2ip32(ip2long($ip)+1);
352
}
353

    
354
/* Return true if the first IP is 'before' the second */
355
function ip_less_than($ip1, $ip2) {
356
	// Compare as unsigned long because otherwise it wouldn't work when
357
	//   crossing over from 127.255.255.255 / 128.0.0.0 barrier
358
	return ip2ulong($ip1) < ip2ulong($ip2);
359
}
360

    
361
/* Return true if the first IP is 'after' the second */
362
function ip_greater_than($ip1, $ip2) {
363
	// Compare as unsigned long because otherwise it wouldn't work
364
	//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
365
	return ip2ulong($ip1) > ip2ulong($ip2);
366
}
367

    
368
/* Convert a range of IPs to an array of subnets which can contain the range. */
369
function ip_range_to_subnet_array($startip, $endip) {
370
	if (!is_ipaddr($startip) || !is_ipaddr($endip)) {
371
		return array();
372
	}
373

    
374
	// Container for subnets within this range.
375
	$rangesubnets = array();
376

    
377
	// Figure out what the smallest subnet is that holds the number of IPs in the given range.
378
	$cidr = find_smallest_cidr(ip_range_size($startip, $endip));
379

    
380
	// Loop here to reduce subnet size and retest as needed. We need to make sure
381
	//   that the target subnet is wholly contained between $startip and $endip.
382
	for ($cidr; $cidr <= 32; $cidr++) {
383
		// Find the network and broadcast addresses for the subnet being tested.
384
		$targetsub_min = gen_subnet($startip, $cidr);
385
		$targetsub_max = gen_subnet_max($startip, $cidr);
386

    
387
		// Check best case where the range is exactly one subnet.
388
		if (($targetsub_min == $startip) && ($targetsub_max == $endip)) {
389
			// Hooray, the range is exactly this subnet!
390
			return array("{$startip}/{$cidr}");
391
		}
392

    
393
		// These remaining scenarios will find a subnet that uses the largest
394
		//  chunk possible of the range being tested, and leave the rest to be
395
		//  tested recursively after the loop.
396

    
397
		// Check if the subnet begins with $startip and ends before $endip
398
		if (($targetsub_min == $startip) && ip_less_than($targetsub_max, $endip)) {
399
			break;
400
		}
401

    
402
		// Check if the subnet ends at $endip and starts after $startip
403
		if (ip_greater_than($targetsub_min, $startip) && ($targetsub_max == $endip)) {
404
			break;
405
		}
406

    
407
		// Check if the subnet is between $startip and $endip
408
		if (ip_greater_than($targetsub_min, $startip) && ip_less_than($targetsub_max, $endip)) {
409
			break;
410
		}
411
	}
412

    
413
	// Some logic that will recursivly search from $startip to the first IP before the start of the subnet we just found.
414
	// NOTE: This may never be hit, the way the above algo turned out, but is left for completeness.
415
	if ($startip != $targetsub_min) {
416
		$rangesubnets = array_merge($rangesubnets, ip_range_to_subnet_array($startip, ip_before($targetsub_min)));
417
	}
418

    
419
	// Add in the subnet we found before, to preserve ordering
420
	$rangesubnets[] = "{$targetsub_min}/{$cidr}";
421

    
422
	// And some more logic that will search after the subnet we found to fill in to the end of the range.
423
	if ($endip != $targetsub_max) {
424
		$rangesubnets = array_merge($rangesubnets, ip_range_to_subnet_array(ip_after($targetsub_max), $endip));
425
	}
426
	return $rangesubnets;
427
}
428

    
429
function is_iprange($range) {
430
	if (substr_count($range, '-') != 1) {
431
		return false;
432
	}
433
	list($ip1, $ip2) = explode ('-', $range);
434
	return (is_ipaddr($ip1) && is_ipaddr($ip2));
435
}
436

    
437
function is_numericint($arg) {
438
	return (preg_match("/[^0-9]/", $arg) ? false : true);
439
}
440

    
441

    
442
/* returns true if $ipaddr is a valid dotted IPv4 address or a IPv6 */
443
function is_ipaddr($ipaddr) {
444
	if(is_ipaddrv4($ipaddr)) {
445
		return true;
446
	}
447
	if(is_ipaddrv6($ipaddr)) {
448
		return true;
449
	}
450
	return false;
451
}
452

    
453
/* returns true if $ipaddr is a valid IPv6 address */
454
function is_ipaddrv6($ipaddr) {
455
	$result = Net_IPv6::checkIPv6($ipaddr);
456
	return $result;
457
}
458

    
459
/* returns true if $ipaddr is a valid dotted IPv4 address */
460
function is_ipaddrv4($ipaddr) {
461
	if (!is_string($ipaddr))
462
		return false;
463

    
464
	$ip_long = ip2long($ipaddr);
465
	$ip_reverse = long2ip32($ip_long);
466

    
467
	if ($ipaddr == $ip_reverse)
468
		return true;
469
	else
470
		return false;
471
}
472

    
473
/* returns true if $ipaddr is a valid dotted IPv4 address or an alias thereof */
474
function is_ipaddroralias($ipaddr) {
475
	global $config;
476

    
477
	if (is_alias($ipaddr)) {
478
		if (is_array($config['aliases']['alias'])) {
479
			foreach ($config['aliases']['alias'] as $alias) {
480
				if ($alias['name'] == $ipaddr && $alias['type'] != "port")
481
					return true;
482
			}
483
		}
484
		return false;
485
	} else
486
		return is_ipaddr($ipaddr);
487

    
488
}
489

    
490
/* returns true if $subnet is a valid subnet in CIDR format */
491
function is_subnet($subnet) {
492
	if (!is_string($subnet))
493
		return false;
494

    
495
	list($hp,$np) = explode('/', $subnet);
496

    
497
	if (!is_ipaddr($hp))
498
		return false;
499

    
500
	if (!is_numeric($np) || ($np < 1) || ($np > 32))
501
		return false;
502

    
503
	return true;
504
}
505

    
506
/* returns true if $subnet is a valid subnet in CIDR format or an alias thereof */
507
function is_subnetoralias($subnet) {
508
	global $aliastable;
509

    
510
	if (isset($aliastable[$subnet]) && is_subnet($aliastable[$subnet]))
511
		return true;
512
	else
513
		return is_subnet($subnet);
514
}
515

    
516
/* returns true if $hostname is a valid hostname */
517
function is_hostname($hostname) {
518
	if (!is_string($hostname))
519
		return false;
520

    
521
	if (preg_match('/^(?:(?:[a-z0-9_]|[a-z0-9_][a-z0-9_\-]*[a-z0-9_])\.)*(?:[a-z0-9_]|[a-z0-9_][a-z0-9_\-]*[a-z0-9_])$/i', $hostname))
522
		return true;
523
	else
524
		return false;
525
}
526

    
527
/* returns true if $domain is a valid domain name */
528
function is_domain($domain) {
529
	if (!is_string($domain))
530
		return false;
531

    
532
	if (preg_match('/^(?:(?:[a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])\.)*(?:[a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])$/i', $domain))
533
		return true;
534
	else
535
		return false;
536
}
537

    
538
/* returns true if $macaddr is a valid MAC address */
539
function is_macaddr($macaddr) {
540
	return preg_match('/^[0-9A-F]{2}(?:[:][0-9A-F]{2}){5}$/i', $macaddr) == 1 ? true : false;
541
}
542

    
543
/* returns true if $name is a valid name for an alias */
544
/* returns NULL if a reserved word is used */
545
function is_validaliasname($name) {
546
	/* Array of reserved words */
547
	$reserved = array("port", "pass");
548
	if (in_array($name, $reserved, true))
549
		return; /* return NULL */
550
	if (!preg_match("/[^a-zA-Z0-9_]/", $name) && (strlen($name) < 32))
551
		return true;
552
	else
553
		return false;
554
}
555

    
556
/* returns true if $port is a valid TCP/UDP port */
557
function is_port($port) {
558
	$tmpports = explode(":", $port);
559
	foreach($tmpports as $tmpport) {
560
		if (getservbyname($tmpport, "tcp") || getservbyname($tmpport, "udp"))
561
			continue;
562
		if (!ctype_digit($tmpport))
563
			return false;
564
		else if ((intval($tmpport) < 1) || (intval($tmpport) > 65535))
565
			return false;
566
	}
567
	return true;
568
}
569

    
570
/* returns true if $portrange is a valid TCP/UDP portrange ("<port>:<port>") */
571
function is_portrange($portrange) {
572
	$ports = explode(":", $portrange);
573

    
574
	if(count($ports) == 2 && is_port($ports[0]) && is_port($ports[1]))
575
		return true;
576
	else
577
		return false;
578
}
579

    
580
/* returns true if $port is a valid port number or an alias thereof */
581
function is_portoralias($port) {
582
	global $config;
583

    
584
	if (is_alias($port)) {
585
		if (is_array($config['aliases']['alias'])) {
586
			foreach ($config['aliases']['alias'] as $alias) {
587
				if ($alias['name'] == $port && $alias['type'] == "port")
588
					return true;
589
				}
590
			}
591
			return false;
592
	} else
593
		return is_port($port);
594
}
595

    
596
/* returns true if $val is a valid shaper bandwidth value */
597
function is_valid_shaperbw($val) {
598
	return (preg_match("/^(\d+(?:\.\d+)?)([MKG]?b|%)$/", $val));
599
}
600

    
601
/* return the configured carp interface list */
602
function get_configured_carp_interface_list() {
603
	global $config;
604

    
605
	$iflist = array();
606

    
607
	if(is_array($config['virtualip']['vip'])) {
608
		$viparr = &$config['virtualip']['vip'];
609
		foreach ($viparr as $vip) {
610
			switch ($vip['mode']) {
611
				case "carp":
612
				case "carpdev-dhcp":
613
					$vipif = "vip" . $vip['vhid'];
614
					$iflist[$vipif] = $vip['subnet'];
615
					break;
616
			}
617
		}
618
	}
619

    
620
	return $iflist;
621
}
622

    
623
/* return the configured IP aliases list */
624
function get_configured_ip_aliases_list() {
625
	global $config;
626

    
627
	$alias_list=array();
628

    
629
	if(is_array($config['virtualip']['vip'])) {
630
		$viparr = &$config['virtualip']['vip'];
631
		foreach ($viparr as $vip) {
632
			if ($vip['mode']=="ipalias") {
633
				$alias_list[$vip['subnet']] = $vip['interface'];
634
			}
635
		}
636
	}
637

    
638
	return $alias_list;
639
}
640

    
641

    
642
/* comparison function for sorting by the order in which interfaces are normally created */
643
function compare_interface_friendly_names($a, $b) {
644
	if ($a == $b)
645
		return 0;
646
	else if ($a == 'wan')
647
		return -1;
648
	else if ($b == 'wan')
649
		return 1;
650
	else if ($a == 'lan')
651
		return -1;
652
	else if ($b == 'lan')
653
		return 1;
654

    
655
	return strnatcmp($a, $b);
656
}
657

    
658
/* return the configured interfaces list. */
659
function get_configured_interface_list($only_opt = false, $withdisabled = false) {
660
	global $config;
661

    
662
	$iflist = array();
663

    
664
	/* if list */
665
	foreach($config['interfaces'] as $if => $ifdetail) {
666
		if ($only_opt && ($if == "wan" || $if == "lan"))
667
			continue;
668
		if (isset($ifdetail['enable']) || $withdisabled == true)
669
			$iflist[$if] = $if;
670
	}
671

    
672
	return $iflist;
673
}
674

    
675
/* return the configured interfaces list. */
676
function get_configured_interface_list_by_realif($only_opt = false, $withdisabled = false) {
677
	global $config;
678

    
679
	$iflist = array();
680

    
681
	/* if list */
682
	foreach($config['interfaces'] as $if => $ifdetail) {
683
		if ($only_opt && ($if == "wan" || $if == "lan"))
684
			continue;
685
		if (isset($ifdetail['enable']) || $withdisabled == true) {
686
			$tmpif = get_real_interface($if);
687
			if (!empty($tmpif))
688
				$iflist[$tmpif] = $if;
689
		}
690
	}
691

    
692
	return $iflist;
693
}
694

    
695
/* return the configured interfaces list with their description. */
696
function get_configured_interface_with_descr($only_opt = false, $withdisabled = false) {
697
	global $config;
698

    
699
	$iflist = array();
700

    
701
	/* if list */
702
	foreach($config['interfaces'] as $if => $ifdetail) {
703
		if ($only_opt && ($if == "wan" || $if == "lan"))
704
			continue;
705
		if (isset($ifdetail['enable']) || $withdisabled == true) {
706
			if(empty($ifdetail['descr']))
707
				$iflist[$if] = strtoupper($if);
708
			else
709
				$iflist[$if] = strtoupper($ifdetail['descr']);
710
		}
711
	}
712

    
713
	return $iflist;
714
}
715

    
716
/*
717
 *   get_configured_ip_addresses() - Return a list of all configured
718
 *   interfaces IP Addresses
719
 *
720
 */
721
function get_configured_ip_addresses() {
722
	require_once("interfaces.inc");
723
	$ip_array = array();
724
	$interfaces = get_configured_interface_list();
725
	if(is_array($interfaces)) {
726
		foreach($interfaces as $int) {
727
			$ipaddr = get_interface_ip($int);
728
			$ip_array[$int] = $ipaddr;
729
		}
730
	}
731
	$interfaces = get_configured_carp_interface_list();
732
	if(is_array($interfaces)) 
733
		foreach($interfaces as $int => $ipaddr) 
734
			$ip_array[$int] = $ipaddr;
735
	return $ip_array;
736
}
737

    
738
/*
739
 *   get_interface_list() - Return a list of all physical interfaces
740
 *   along with MAC and status.
741
 *
742
 *   $mode = "active" - use ifconfig -lu
743
 *           "media"  - use ifconfig to check physical connection
744
 *			status (much slower)
745
 */
746
function get_interface_list($mode = "active", $keyby = "physical", $vfaces = "") {
747
        global $config;
748
	$upints = array();
749
        /* get a list of virtual interface types */
750
        if(!$vfaces) {
751
		$vfaces = array (
752
				'bridge',
753
				'ppp',
754
				'pppoe',
755
				'pptp',
756
				'l2tp',
757
				'sl',
758
				'gif',
759
				'gre',
760
				'faith',
761
				'lo',
762
				'ng',
763
				'_vlan',
764
				'_wlan',
765
				'pflog',
766
				'plip',
767
				'pfsync',
768
				'enc',
769
				'tun',
770
				'carp',
771
				'lagg',
772
				'vip',
773
				'ipfw'
774
		);
775
	}
776
	switch($mode) {
777
	case "active":
778
                $upints = explode(" ", trim(shell_exec("/sbin/ifconfig -lu")));
779
        	break;
780
	case "media":
781
                $intlist = explode(" ", trim(shell_exec("/sbin/ifconfig -l")));
782
                $ifconfig = "";
783
                exec("/sbin/ifconfig -a", $ifconfig);
784
                $regexp = '/(' . implode('|', $intlist) . '):\s/';
785
                $ifstatus = preg_grep('/status:/', $ifconfig);
786
		foreach($ifstatus as $status) {
787
			$int = array_shift($intlist);
788
			if(stristr($status, "active")) $upints[] = $int;
789
		}
790
		break;
791
	default:
792
		$upints = explode(" ", trim(shell_exec("/sbin/ifconfig -l")));
793
		break;
794
	}
795
        /* build interface list with netstat */
796
        $linkinfo = "";
797
        exec("/usr/bin/netstat -inW -f link | awk '{ print $1, $4 }'", $linkinfo);
798
        array_shift($linkinfo);
799
	/* build ip address list with netstat */
800
	$ipinfo = "";
801
	exec("/usr/bin/netstat -inW -f inet | awk '{ print $1, $4 }'", $ipinfo);
802
	array_shift($ipinfo);
803
	foreach($linkinfo as $link) {
804
		$friendly = "";
805
		$alink = explode(" ", $link);
806
		$ifname = rtrim(trim($alink[0]), '*');
807
		/* trim out all numbers before checking for vfaces */
808
		if (!in_array(array_shift(preg_split('/\d/', $ifname)), $vfaces) &&
809
			!stristr($ifname, "_vlan") && !stristr($ifname, "_wlan")) {
810
			$toput = array(
811
					"mac" => trim($alink[1]),
812
					"up" => in_array($ifname, $upints)
813
				);
814
			foreach($ipinfo as $ip) {
815
				$aip = explode(" ", $ip);
816
				if($aip[0] == $ifname) {
817
					$toput['ipaddr'] = $aip[1];
818
				}
819
			}
820
			if (is_array($config['interfaces'])) {
821
				foreach($config['interfaces'] as $name => $int)
822
					if($int['if'] == $ifname) $friendly = $name;
823
			}
824
			switch($keyby) {
825
			case "physical":
826
				if($friendly != "") {
827
					$toput['friendly'] = $friendly;
828
				}
829
				$dmesg_arr = array();
830
				exec("/sbin/dmesg |grep $ifname | head -n1", $dmesg_arr);
831
				preg_match_all("/<(.*?)>/i", $dmesg_arr[0], $dmesg);
832
				$toput['dmesg'] = $dmesg[1][0];
833
				$iflist[$ifname] = $toput;
834
				break;
835
			case "ppp":
836
				
837
			case "friendly":
838
				if($friendly != "") {
839
					$toput['if'] = $ifname;
840
					$iflist[$friendly] = $toput;
841
				}
842
				break;
843
			}
844
		}
845
	}
846
	return $iflist;
847
}
848

    
849
/****f* util/log_error
850
* NAME
851
*   log_error  - Sends a string to syslog.
852
* INPUTS
853
*   $error     - string containing the syslog message.
854
* RESULT
855
*   null
856
******/
857
function log_error($error) {
858
	global $g;
859
	$page = $_SERVER['SCRIPT_NAME'];
860
	syslog(LOG_WARNING, "$page: $error");
861
	if ($g['debug'])
862
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
863
	return;
864
}
865

    
866
/****f* util/log_auth
867
* NAME
868
*   log_error  - Sends a string to syslog as LOG_AUTH facility
869
* INPUTS
870
*   $error     - string containing the syslog message.
871
* RESULT
872
*   null
873
******/
874
function log_auth($error) {
875
	global $g;
876
	$page = $_SERVER['SCRIPT_NAME'];
877
	syslog(LOG_AUTH, "$page: $error");
878
	if ($g['debug'])
879
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
880
	return;
881
}
882

    
883
/****f* util/exec_command
884
 * NAME
885
 *   exec_command - Execute a command and return a string of the result.
886
 * INPUTS
887
 *   $command   - String of the command to be executed.
888
 * RESULT
889
 *   String containing the command's result.
890
 * NOTES
891
 *   This function returns the command's stdout and stderr.
892
 ******/
893
function exec_command($command) {
894
	$output = array();
895
	exec($command . ' 2>&1 ', $output);
896
	return(implode("\n", $output));
897
}
898

    
899
/* wrapper for exec() */
900
function mwexec($command, $mute = false) {
901
	global $g;
902

    
903
	if ($g['debug']) {
904
		if (!$_SERVER['REMOTE_ADDR'])
905
			echo "mwexec(): $command\n";
906
	}
907
	$oarr = array();
908
	$retval = 0;
909
	$garbage = exec("$command 2>&1", $oarr, $retval);
910

    
911
	if(isset($config['system']['developerspew']))
912
		$mute = false;
913
	if(($retval <> 0) && ($mute === false)) {
914
		$output = implode(" ", $oarr);
915
		log_error(sprintf(gettext("The command '%1\$s' returned exit code '%2\$d', the output was '%3\$s' "), $command, $retval, $output));
916
	}
917
	return $retval;
918
}
919

    
920
/* wrapper for exec() in background */
921
function mwexec_bg($command) {
922
	global $g;
923

    
924
	if ($g['debug']) {
925
		if (!$_SERVER['REMOTE_ADDR'])
926
			echo "mwexec(): $command\n";
927
	}
928

    
929
	exec("nohup $command > /dev/null 2>&1 &");
930
}
931

    
932
/* unlink a file, if it exists */
933
function unlink_if_exists($fn) {
934
	$to_do = glob($fn);
935
	if(is_array($to_do)) {
936
		foreach($to_do as $filename)
937
			@unlink($filename);
938
	} else {
939
		@unlink($fn);
940
	}
941
}
942
/* make a global alias table (for faster lookups) */
943
function alias_make_table($config) {
944
	global $aliastable;
945

    
946
	$aliastable = array();
947

    
948
	if (is_array($config['aliases']['alias'])) {
949
		foreach ($config['aliases']['alias'] as $alias) {
950
			if ($alias['name'])
951
				$aliastable[$alias['name']] = $alias['address'];
952
		}
953
	}
954
}
955

    
956
/* check if an alias exists */
957
function is_alias($name) {
958
	global $aliastable;
959

    
960
	return isset($aliastable[$name]);
961
}
962

    
963
function alias_get_type($name) {
964
        global $config;
965
        
966
	if (is_array($config['aliases']['alias'])) {
967
		foreach ($config['aliases']['alias'] as $alias) {
968
			if ($name == $alias['name'])
969
				return $alias['type'];
970
		}
971
	}
972

    
973
        return "";
974
}
975

    
976
/* expand a host or network alias, if necessary */
977
function alias_expand($name) {
978
	global $aliastable;
979

    
980
	if (isset($aliastable[$name]))
981
		return "\${$name}";
982
	else if (is_ipaddr($name) || is_subnet($name) || is_port($name))
983
		return "{$name}";
984
	else
985
		return null;
986
}
987

    
988
function alias_expand_urltable($name) {
989
	global $config;
990
	$urltable_prefix = "/var/db/aliastables/";
991
	$urltable_filename = $urltable_prefix . $name . ".txt";
992

    
993
	if (is_array($config['aliases']['alias'])) {
994
		foreach ($config['aliases']['alias'] as $alias) {
995
			if (($alias['type'] == 'urltable') && ($alias['name'] == $name)) {
996
				if (is_URL($alias["url"]) && file_exists($urltable_filename) && filesize($urltable_filename))
997
					return $urltable_filename;
998
				else if (process_alias_urltable($name, $alias["url"], 0, true))
999
					return $urltable_filename;
1000
			}
1001
		}
1002
	}
1003
	return null;
1004
}
1005

    
1006
/* find out whether two subnets overlap */
1007
function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2) {
1008

    
1009
	if (!is_numeric($bits1))
1010
		$bits1 = 32;
1011
	if (!is_numeric($bits2))
1012
		$bits2 = 32;
1013

    
1014
	if ($bits1 < $bits2)
1015
		$relbits = $bits1;
1016
	else
1017
		$relbits = $bits2;
1018

    
1019
	$sn1 = gen_subnet_mask_long($relbits) & ip2long($subnet1);
1020
	$sn2 = gen_subnet_mask_long($relbits) & ip2long($subnet2);
1021

    
1022
	if ($sn1 == $sn2)
1023
		return true;
1024
	else
1025
		return false;
1026
}
1027

    
1028
/* compare two IP addresses */
1029
function ipcmp($a, $b) {
1030
	if (ip_less_than($a, $b))
1031
		return -1;
1032
	else if (ip_greater_than($a, $b))
1033
		return 1;
1034
	else
1035
		return 0;
1036
}
1037

    
1038
/* return true if $addr is in $subnet, false if not */
1039
function ip_in_subnet($addr,$subnet) {
1040
	if(is_ipaddrv6($addr)) {
1041
		$result = Net_IPv6::IsInNetmask($addr, $subnet);
1042
		if($result)
1043
			return true;
1044
		else
1045
			return false;
1046
	}
1047
	list($ip, $mask) = explode('/', $subnet);
1048
	$mask = (0xffffffff << (32 - $mask)) & 0xffffffff;
1049
	return ((ip2long($addr) & $mask) == (ip2long($ip) & $mask));
1050
}
1051

    
1052
/* verify (and remove) the digital signature on a file - returns 0 if OK */
1053
function verify_digital_signature($fname) {
1054
	global $g;
1055

    
1056
	if(!file_exists("/usr/local/sbin/gzsig"))
1057
		return 4;
1058

    
1059
	return mwexec("/usr/local/sbin/gzsig verify {$g['etc_path']}/pubkey.pem < " . escapeshellarg($fname));
1060
}
1061

    
1062
/* obtain MAC address given an IP address by looking at the ARP table */
1063
function arp_get_mac_by_ip($ip) {
1064
	mwexec("/sbin/ping -c 1 -t 1 {$ip}", true);
1065
	$arpoutput = "";
1066
	exec("/usr/sbin/arp -n {$ip}", $arpoutput);
1067

    
1068
	if ($arpoutput[0]) {
1069
		$arpi = explode(" ", $arpoutput[0]);
1070
		$macaddr = $arpi[3];
1071
		if (is_macaddr($macaddr))
1072
			return $macaddr;
1073
		else
1074
			return false;
1075
	}
1076

    
1077
	return false;
1078
}
1079

    
1080
/* return a fieldname that is safe for xml usage */
1081
function xml_safe_fieldname($fieldname) {
1082
	$replace = array('/', '-', ' ', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
1083
			 '_', '+', '=', '{', '}', '[', ']', '|', '/', '<', '>', '?',
1084
			 ':', ',', '.', '\'', '\\'
1085
		);
1086
	return strtolower(str_replace($replace, "", $fieldname));
1087
}
1088

    
1089
function mac_format($clientmac) {
1090
    $mac =explode(":", $clientmac);
1091

    
1092
    global $config;
1093

    
1094
    $mac_format = $config['captiveportal']['radmac_format'] ? $config['captiveportal']['radmac_format'] : false;
1095

    
1096
    switch($mac_format) {
1097

    
1098
        case 'singledash':
1099
        return "$mac[0]$mac[1]$mac[2]-$mac[3]$mac[4]$mac[5]";
1100

    
1101
        case 'ietf':
1102
        return "$mac[0]-$mac[1]-$mac[2]-$mac[3]-$mac[4]-$mac[5]";
1103

    
1104
        case 'cisco':
1105
        return "$mac[0]$mac[1].$mac[2]$mac[3].$mac[4]$mac[5]";
1106

    
1107
        case 'unformatted':
1108
        return "$mac[0]$mac[1]$mac[2]$mac[3]$mac[4]$mac[5]";
1109

    
1110
        default:
1111
        return $clientmac;
1112
    }
1113
}
1114

    
1115
function resolve_retry($hostname, $retries = 5) {
1116

    
1117
	if (is_ipaddr($hostname))
1118
		return $hostname;
1119

    
1120
       for ($i = 0; $i < $retries; $i++) {
1121
		// FIXME: gethostbyname does not work for AAAA hostnames, boo, hiss
1122
               $ip = gethostbyname($hostname);
1123

    
1124
		if ($ip && $ip != $hostname) {
1125
			/* success */
1126
			return $ip;
1127
		}
1128

    
1129
		sleep(1);
1130
	}
1131

    
1132
	return false;
1133
}
1134

    
1135
function format_bytes($bytes) {
1136
	if ($bytes >= 1073741824) {
1137
		return sprintf("%.2f GB", $bytes/1073741824);
1138
	} else if ($bytes >= 1048576) {
1139
		return sprintf("%.2f MB", $bytes/1048576);
1140
	} else if ($bytes >= 1024) {
1141
		return sprintf("%.0f KB", $bytes/1024);
1142
	} else {
1143
		return sprintf("%d bytes", $bytes);
1144
	}
1145
}
1146

    
1147
function update_filter_reload_status($text) {
1148
	global $g;
1149

    
1150
	file_put_contents("{$g['varrun_path']}/filter_reload_status", $text);
1151
}
1152

    
1153
/****f* util/return_dir_as_array
1154
 * NAME
1155
 *   return_dir_as_array - Return a directory's contents as an array.
1156
 * INPUTS
1157
 *   $dir       - string containing the path to the desired directory.
1158
 * RESULT
1159
 *   $dir_array - array containing the directory's contents. This array will be empty if the path specified is invalid.
1160
 ******/
1161
function return_dir_as_array($dir) {
1162
	$dir_array = array();
1163
	if (is_dir($dir)) {
1164
		if ($dh = opendir($dir)) {
1165
			while (($file = readdir($dh)) !== false) {
1166
				$canadd = 0;
1167
				if($file == ".") $canadd = 1;
1168
				if($file == "..") $canadd = 1;
1169
				if($canadd == 0)
1170
					array_push($dir_array, $file);
1171
			}
1172
			closedir($dh);
1173
		}
1174
	}
1175
	return $dir_array;
1176
}
1177

    
1178
function run_plugins($directory) {
1179
	global $config, $g;
1180

    
1181
	/* process packager manager custom rules */
1182
	$files = return_dir_as_array($directory);
1183
	if (is_array($files)) {
1184
		foreach ($files as $file) {
1185
			if (stristr($file, ".sh") == true)
1186
				mwexec($directory . $file . " start");
1187
			else if (!is_dir($directory . "/" . $file) && stristr($file,".inc")) 
1188
				require_once($directory . "/" . $file);
1189
		}
1190
	}
1191
}
1192

    
1193
/*
1194
 *    safe_mkdir($path, $mode = 0755)
1195
 *    create directory if it doesn't already exist and isn't a file!
1196
 */
1197
function safe_mkdir($path, $mode=0755) {
1198
	global $g;
1199

    
1200
	if (!is_file($path) && !is_dir($path)) {
1201
		return @mkdir($path, $mode, true);
1202
	} else {
1203
		return false;
1204
	}
1205
}
1206

    
1207
/*
1208
 * make_dirs($path, $mode = 0755)
1209
 * create directory tree recursively (mkdir -p)
1210
 */
1211
function make_dirs($path, $mode = 0755) {
1212
	$base = '';
1213
	foreach (explode('/', $path) as $dir) {
1214
		$base .= "/$dir";
1215
		if (!is_dir($base)) {
1216
			if (!@mkdir($base, $mode))
1217
				return false;
1218
		}
1219
	}
1220
	return true;
1221
}
1222

    
1223
/*
1224
 * get_sysctl($names)
1225
 * Get values of sysctl OID's listed in $names (accepts an array or a single
1226
 * name) and return an array of key/value pairs set for those that exist
1227
 */
1228
function get_sysctl($names) {
1229
	if (empty($names))
1230
		return array();
1231

    
1232
	if (is_array($names)) {
1233
		$name_list = array();
1234
		foreach ($names as $name) {
1235
			$name_list[] = escapeshellarg($name);
1236
		}
1237
	} else
1238
		$name_list = array(escapeshellarg($names));
1239

    
1240
	exec("/sbin/sysctl -i " . implode(" ", $name_list), $output);
1241
	$values = array();
1242
	foreach ($output as $line) {
1243
		$line = explode(": ", $line, 2);
1244
		if (count($line) == 2)
1245
			$values[$line[0]] = $line[1];
1246
	}
1247

    
1248
	return $values;
1249
}
1250

    
1251
/*
1252
 * set_sysctl($value_list)
1253
 * Set sysctl OID's listed as key/value pairs and return
1254
 * an array with keys set for those that succeeded
1255
 */
1256
function set_sysctl($values) {
1257
	if (empty($values))
1258
		return array();
1259

    
1260
	$value_list = array();
1261
	foreach ($values as $key => $value) {
1262
		$value_list[] = escapeshellarg($key) . "=" . escapeshellarg($value);
1263
	}
1264

    
1265
	exec("/sbin/sysctl -i " . implode(" ", $value_list), $output, $success);
1266

    
1267
	/* Retry individually if failed (one or more read-only) */
1268
	if ($success <> 0 && count($value_list) > 1) {
1269
		foreach ($value_list as $value) {
1270
			exec("/sbin/sysctl -i " . $value, $output);
1271
		}
1272
	}
1273

    
1274
	$ret = array();
1275
	foreach ($output as $line) {
1276
		$line = explode(": ", $line, 2);
1277
		if (count($line) == 2)
1278
			$ret[$line[0]] = true;
1279
	}
1280

    
1281
	return $ret;
1282
}
1283

    
1284
/*
1285
 *     get_memory()
1286
 *     returns an array listing the amount of
1287
 *     memory installed in the hardware
1288
 *     [0]real and [1]available
1289
 */
1290
function get_memory() {
1291
	$matches = "";
1292
	if(file_exists("/var/log/dmesg.boot"))
1293
		$mem = `cat /var/log/dmesg.boot | grep memory`;
1294
	else
1295
		$mem = `dmesg -a | grep memory`;			
1296
	if (preg_match_all("/avail memory.* \((.*)MB\)/", $mem, $matches)) 
1297
		return array($matches[1][0], $matches[1][0]);
1298
	if(!$real && !$avail) {
1299
		$real = trim(`sysctl hw.physmem | cut -d' ' -f2`);
1300
		$avail = trim(`sysctl hw.realmem | cut -d' ' -f2`);
1301
		/* convert from bytes to megabytes */
1302
		return array(($real/1048576),($avail/1048576));
1303
	}
1304
}
1305

    
1306
function mute_kernel_msgs() {
1307
	global $config;
1308
	// Do not mute serial console.  The kernel gets very very cranky
1309
	// and will start dishing you cannot control tty errors.
1310
	if(trim(file_get_contents("/etc/platform")) == "nanobsd") 
1311
		return;
1312
	if($config['system']['enableserial']) 
1313
		return;			
1314
	exec("/sbin/conscontrol mute on");
1315
}
1316

    
1317
function unmute_kernel_msgs() {
1318
	global $config;
1319
	// Do not mute serial console.  The kernel gets very very cranky
1320
	// and will start dishing you cannot control tty errors.
1321
	if(trim(file_get_contents("/etc/platform")) == "nanobsd") 
1322
		return;
1323
	exec("/sbin/conscontrol mute off");
1324
}
1325

    
1326
function start_devd() {
1327
	global $g;
1328

    
1329
	exec("/sbin/devd");
1330
	sleep(1);
1331
}
1332

    
1333
function is_interface_vlan_mismatch() {
1334
	global $config, $g;
1335

    
1336
	if (is_array($config['vlans']['vlan'])) {
1337
		foreach ($config['vlans']['vlan'] as $vlan) {
1338
			if (does_interface_exist($vlan['if']) == false)
1339
				return true;
1340
		}
1341
	}
1342

    
1343
	return false;
1344
}
1345

    
1346
function is_interface_mismatch() {
1347
	global $config, $g;
1348

    
1349
	$do_assign = false;
1350
	$i = 0;
1351
	if (is_array($config['interfaces'])) {
1352
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
1353
			if (preg_match("/^enc|^cua|^tun|^l2tp|^pptp|^ppp|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_wlan/i", $ifcfg['if'])) {
1354
				// Do not check these interfaces.
1355
				$i++;
1356
				continue;
1357
			}
1358
			else if (does_interface_exist($ifcfg['if']) == false) {
1359
				$do_assign = true;
1360
			} else
1361
				$i++;
1362
		}
1363
	}
1364

    
1365
	if ($g['minimum_nic_count'] > $i) {
1366
		$do_assign = true;
1367
	} else if (file_exists("{$g['tmp_path']}/assign_complete"))
1368
	$do_assign = false;
1369

    
1370
	return $do_assign;
1371
}
1372

    
1373
/* sync carp entries to other firewalls */
1374
function carp_sync_client() {
1375
	global $g;
1376
	send_event("filter sync");
1377
}
1378

    
1379
/****f* util/isAjax
1380
 * NAME
1381
 *   isAjax - reports if the request is driven from prototype
1382
 * INPUTS
1383
 *   none
1384
 * RESULT
1385
 *   true/false
1386
 ******/
1387
function isAjax() {
1388
	return isset ($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';
1389
}
1390

    
1391
/****f* util/timeout
1392
 * NAME
1393
 *   timeout - console input with timeout countdown. Note: erases 2 char of screen for timer. Leave space.
1394
 * INPUTS
1395
 *   optional, seconds to wait before timeout. Default 9 seconds.
1396
 * RESULT
1397
 *   returns 1 char of user input or null if no input.
1398
 ******/
1399
function timeout($timer = 9) {
1400
	while(!isset($key)) {
1401
		if ($timer >= 9) { echo chr(8) . chr(8) . ($timer==9 ? chr(32) : null)  . "{$timer}";  }
1402
		else { echo chr(8). "{$timer}"; }
1403
		`/bin/stty -icanon min 0 time 25`;
1404
		$key = trim(`KEY=\`dd count=1 2>/dev/null\`; echo \$KEY`);
1405
		`/bin/stty icanon`;
1406
		if ($key == '')
1407
			unset($key);
1408
		$timer--;
1409
		if ($timer == 0)
1410
			break;
1411
	}
1412
	return $key;	
1413
}
1414

    
1415
/****f* util/msort
1416
 * NAME
1417
 *   msort - sort array
1418
 * INPUTS
1419
 *   $array to be sorted, field to sort by, direction of sort
1420
 * RESULT
1421
 *   returns newly sorted array
1422
 ******/
1423
function msort($array, $id="id", $sort_ascending=true) {
1424
	$temp_array = array();
1425
	while(count($array)>0) {
1426
		$lowest_id = 0;
1427
		$index=0;
1428
		foreach ($array as $item) {
1429
			if (isset($item[$id])) {
1430
				if ($array[$lowest_id][$id]) {
1431
					if (strtolower($item[$id]) < strtolower($array[$lowest_id][$id])) {
1432
						$lowest_id = $index;
1433
					}
1434
				}
1435
			}
1436
			$index++;
1437
		}
1438
		$temp_array[] = $array[$lowest_id];
1439
		$array = array_merge(array_slice($array, 0,$lowest_id), array_slice($array, $lowest_id+1));
1440
	}
1441
	if ($sort_ascending) {
1442
		return $temp_array;
1443
	} else {
1444
    	return array_reverse($temp_array);
1445
	}
1446
}
1447

    
1448
/****f* util/color
1449
 * NAME
1450
 *   color - outputs a color code to the ansi terminal if supported
1451
 * INPUTS
1452
 *   color code or color name
1453
 * RESULT
1454
 *   Outputs the ansi color sequence for the color specified.  Default resets terminal.
1455
 ******/
1456
function color($color = "0m") {
1457
	/*
1458
		Color codes available:
1459
		 0m reset; clears all colors and styles (to white on black)
1460
		 1m bold on (see below)
1461
		 3m italics on
1462
		 4m underline on
1463
		 7m inverse on; reverses foreground & background colors
1464
		 9m strikethrough on
1465
		 22m bold off (see below)
1466
		 23m italics off
1467
		 24m underline off
1468
		 27m inverse off
1469
		 29m strikethrough off
1470
		 30m set foreground color to black
1471
		 31m set foreground color to red
1472
		 32m set foreground color to green
1473
		 33m set foreground color to yellow
1474
		 34m set foreground color to blue
1475
		 35m set foreground color to magenta (purple)
1476
		 36m set foreground color to cyan
1477
		 37m set foreground color to white
1478
		 40m  set background color to black
1479
		 41m set background color to red
1480
		 42m set background color to green
1481
		 43m set background color to yellow
1482
		 44m set background color to blue
1483
		 45m set background color to magenta (purple)
1484
		 46m set background color to cyan
1485
		 47m set background color to white
1486
		 49m set background color to default (black)
1487
	*/	
1488
	// Allow caching of TERM to 
1489
	// speedup subequence requests.
1490
	global $TERM;
1491
	if(!$TERM) 
1492
		$TERM=`/usr/bin/env | grep color`;
1493
	if(!$TERM)
1494
		$TERM=`/usr/bin/env | grep cons25`;
1495
	if($TERM) {
1496
		$ESCAPE=chr(27);
1497
		switch ($color) {
1498
			case "black":
1499
				return "{$ESCAPE}[30m"; 
1500
			case "red":
1501
				return "{$ESCAPE}[31m"; 
1502
			case "green":
1503
				return "{$ESCAPE}[32m"; 
1504
			case "yellow":
1505
				return "{$ESCAPE}[33m"; 
1506
			case "blue":
1507
				return "{$ESCAPE}[34m"; 
1508
			case "magenta":
1509
				return "{$ESCAPE}[35m"; 
1510
			case "cyan":
1511
				return "{$ESCAPE}[36m"; 
1512
			case "white":
1513
				return "{$ESCAPE}[37m"; 
1514
			case "default":
1515
				return "{$ESCAPE}[39m"; 
1516
		}
1517
		return "{$ESCAPE}[{$color}";
1518
	}
1519
}
1520

    
1521
/****f* util/is_URL
1522
 * NAME
1523
 *   is_URL
1524
 * INPUTS
1525
 *   string to check
1526
 * RESULT
1527
 *   Returns true if item is a URL
1528
 ******/
1529
function is_URL($url) {
1530
	$match = preg_match("'\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))'", $url);
1531
	if($match)
1532
		return true;	
1533
	return false;
1534
}
1535

    
1536
function is_file_included($file = "") {
1537
	$files = get_included_files();
1538
	if (in_array($file, $files))
1539
		return true;
1540
	
1541
	return false;
1542
}
1543

    
1544
/*
1545
	This function was borrowed from a comment on PHP.net at the following URL:
1546
	http://www.php.net/manual/en/function.array-merge-recursive.php#73843
1547
 */
1548
function array_merge_recursive_unique($array0, $array1) {
1549

    
1550
	$arrays = func_get_args();
1551
	$remains = $arrays;
1552

    
1553
	// We walk through each arrays and put value in the results (without
1554
	// considering previous value).
1555
	$result = array();
1556

    
1557
	// loop available array
1558
	foreach($arrays as $array) {
1559

    
1560
		// The first remaining array is $array. We are processing it. So
1561
		// we remove it from remaing arrays.
1562
        array_shift($remains);
1563

    
1564
		// We don't care non array param, like array_merge since PHP 5.0.
1565
		if(is_array($array)) {
1566
			// Loop values
1567
			foreach($array as $key => $value) {
1568
				if(is_array($value)) {
1569
					// we gather all remaining arrays that have such key available
1570
					$args = array();
1571
					foreach($remains as $remain) {
1572
						if(array_key_exists($key, $remain)) {
1573
							array_push($args, $remain[$key]);
1574
						}
1575
					}
1576

    
1577
					if(count($args) > 2) {
1578
						// put the recursion
1579
						$result[$key] = call_user_func_array(__FUNCTION__, $args);
1580
					} else {
1581
						foreach($value as $vkey => $vval) {
1582
							$result[$key][$vkey] = $vval;
1583
						}
1584
					}
1585
				} else {
1586
					// simply put the value
1587
					$result[$key] = $value;
1588
				}
1589
			}
1590
		}
1591
	}
1592
	return $result;
1593
}
1594

    
1595
?>
(49-49/61)