Project

General

Profile

Download (39 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
	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 -x {$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("WARNING: Could not mark subsystem: {$subsytem} dirty");
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("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
	$try = 0;
143
	while ($try < 3) {
144
		$fd = @fsockopen($g['event_address']);
145
		if ($fd) {
146
			fwrite($fd, $cmd);
147
			$resp = fread($fd, 4096);
148
			if ($resp != "OK\n")
149
				log_error("send_event: sent {$cmd} got {$resp}");
150
			fclose($fd);
151
			$try = 3;
152
		} else
153
			mwexec_bg("/usr/bin/nice -n20 /usr/local/sbin/check_reload_status");
154
		$try++;
155
	}
156
}
157

    
158
function send_multiple_events($cmds) {
159
        global $g;
160

    
161
	if (!is_array($cmds))
162
		return;
163
        $fd = fsockopen($g['event_address']);
164
        if ($fd) {
165
		foreach ($cmds as $cmd) {
166
                	fwrite($fd, $cmd);
167
                	$resp = fread($fd, 4096);
168
                	if ($resp != "OK\n")
169
                        	log_error("send_event: sent {$cmd} got {$resp}");
170
		}
171
                fclose($fd);
172
        }
173
}
174

    
175
function refcount_init($reference) {
176
	$shmid = shmop_open($reference, "c", 0644, 10);
177
	shmop_write($shmid, 0, 0);
178
	shmop_close($shmid);
179
}
180

    
181
function refcount_reference($reference) {
182
	$shmid = @shmop_open($reference, "w", 0644, 10);
183
	if (!$shmid) {
184
		refcount_init($reference);
185
		$shmid = shmop_open($reference, "w", 0644, 10);
186
	}
187
	$shm_data = shmop_read($shmid, 0, 10);
188
	$shm_data = intval($shm_data) + 1;
189
	shmop_write($shmid, $shm_data, 0);
190
	shmop_close($shmid);
191
	
192
	return $shm_data;
193
}
194

    
195
function refcount_unreference($reference) {
196
	/* We assume that the shared memory exists. */
197
	$shmid = shmop_open($reference, "w", 0644, 10);
198
	$shm_data = shmop_read($shmid, 0, 10);
199
	$shm_data = intval($shm_data) - 1;
200
	if ($shm_data < 0) {
201
		//debug_backtrace();
202
		log_error("Reference {$reference} is going negative, not doing unreference.");
203
	} else
204
		shmop_write($shmid, $shm_data, 0);
205
	shmop_close($shmid);
206
	
207
	return $shm_data;
208
}
209

    
210
function is_module_loaded($module_name) {
211
	$running = `/sbin/kldstat | grep {$module_name} | /usr/bin/grep -v grep | /usr/bin/wc -l`;
212
	if (intval($running) >= 1)
213
		return true;
214
	else
215
		return false;
216
}
217

    
218
/* return the subnet address given a host address and a subnet bit count */
219
function gen_subnet($ipaddr, $bits) {
220
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
221
		return "";
222

    
223
	return long2ip(ip2long($ipaddr) & gen_subnet_mask_long($bits));
224
}
225

    
226
/* return the highest (broadcast) address in the subnet given a host address and a subnet bit count */
227
function gen_subnet_max($ipaddr, $bits) {
228
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
229
		return "";
230

    
231
	return long2ip32(ip2long($ipaddr) | ~gen_subnet_mask_long($bits));
232
}
233

    
234
/* returns a subnet mask (long given a bit count) */
235
function gen_subnet_mask_long($bits) {
236
	$sm = 0;
237
	for ($i = 0; $i < $bits; $i++) {
238
		$sm >>= 1;
239
		$sm |= 0x80000000;
240
	}
241
	return $sm;
242
}
243

    
244
/* same as above but returns a string */
245
function gen_subnet_mask($bits) {
246
	return long2ip(gen_subnet_mask_long($bits));
247
}
248

    
249
/* Convert long int to IP address, truncating to 32-bits. */
250
function long2ip32($ip) {
251
	return long2ip($ip & 0xFFFFFFFF);
252
}
253

    
254
/* Convert IP address to long int, truncated to 32-bits to avoid sign extension on 64-bit platforms. */
255
function ip2long32($ip) {
256
	return ( ip2long($ip) & 0xFFFFFFFF );
257
}
258

    
259
/* Convert IP address to unsigned long int. */
260
function ip2ulong($ip) {
261
	return sprintf("%u", ip2long32($ip));
262
}
263

    
264
/* Find out how many IPs are contained within a given IP range
265
 *  e.g. 192.168.0.0 to 192.168.0.255 returns 256
266
 */
267
function ip_range_size($startip, $endip) {
268
	if (is_ipaddr($startip) && is_ipaddr($endip)) {
269
		// Operate as unsigned long because otherwise it wouldn't work
270
		//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
271
		return abs(ip2ulong($startip) - ip2ulong($endip)) + 1;
272
	}
273
	return -1;
274
}
275

    
276
/* Find the smallest possible subnet mask which can contain a given number of IPs
277
 *  e.g. 512 IPs can fit in a /23, but 513 IPs need a /22
278
 */
279
function find_smallest_cidr($number) {
280
	$smallest = 1;
281
	for ($b=32; $b > 0; $b--) {
282
		$smallest = ($number <= pow(2,$b)) ? $b : $smallest;
283
	}
284
	return (32-$smallest);
285
}
286

    
287
/* Return the previous IP address before the given address */
288
function ip_before($ip) {
289
	return long2ip32(ip2long($ip)-1);
290
}
291

    
292
/* Return the next IP address after the given address */
293
function ip_after($ip) {
294
	return long2ip32(ip2long($ip)+1);
295
}
296

    
297
/* Return true if the first IP is 'before' the second */
298
function ip_less_than($ip1, $ip2) {
299
	// Compare as unsigned long because otherwise it wouldn't work when
300
	//   crossing over from 127.255.255.255 / 128.0.0.0 barrier
301
	return ip2ulong($ip1) < ip2ulong($ip2);
302
}
303

    
304
/* Return true if the first IP is 'after' the second */
305
function ip_greater_than($ip1, $ip2) {
306
	// Compare as unsigned long because otherwise it wouldn't work
307
	//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
308
	return ip2ulong($ip1) > ip2ulong($ip2);
309
}
310

    
311
/* Convert a range of IPs to an array of subnets which can contain the range. */
312
function ip_range_to_subnet_array($startip, $endip) {
313
	if (!is_ipaddr($startip) || !is_ipaddr($endip)) {
314
		return array();
315
	}
316

    
317
	// Container for subnets within this range.
318
	$rangesubnets = array();
319

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

    
323
	// Loop here to reduce subnet size and retest as needed. We need to make sure
324
	//   that the target subnet is wholly contained between $startip and $endip.
325
	for ($cidr; $cidr <= 32; $cidr++) {
326
		// Find the network and broadcast addresses for the subnet being tested.
327
		$targetsub_min = gen_subnet($startip, $cidr);
328
		$targetsub_max = gen_subnet_max($startip, $cidr);
329

    
330
		// Check best case where the range is exactly one subnet.
331
		if (($targetsub_min == $startip) && ($targetsub_max == $endip)) {
332
			// Hooray, the range is exactly this subnet!
333
			return array("{$startip}/{$cidr}");
334
		}
335

    
336
		// These remaining scenarios will find a subnet that uses the largest
337
		//  chunk possible of the range being tested, and leave the rest to be
338
		//  tested recursively after the loop.
339

    
340
		// Check if the subnet begins with $startip and ends before $endip
341
		if (($targetsub_min == $startip) && ip_less_than($targetsub_max, $endip)) {
342
			break;
343
		}
344

    
345
		// Check if the subnet ends at $endip and starts after $startip
346
		if (ip_greater_than($targetsub_min, $startip) && ($targetsub_max == $endip)) {
347
			break;
348
		}
349

    
350
		// Check if the subnet is between $startip and $endip
351
		if (ip_greater_than($targetsub_min, $startip) && ip_less_than($targetsub_max, $endip)) {
352
			break;
353
		}
354
	}
355

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

    
362
	// Add in the subnet we found before, to preserve ordering
363
	$rangesubnets[] = "{$targetsub_min}/{$cidr}";
364

    
365
	// And some more logic that will search after the subnet we found to fill in to the end of the range.
366
	if ($endip != $targetsub_max) {
367
		$rangesubnets = array_merge($rangesubnets, ip_range_to_subnet_array(ip_after($targetsub_max), $endip));
368
	}
369
	return $rangesubnets;
370
}
371

    
372
function is_iprange($range) {
373
	if (substr_count($range, '-') != 1) {
374
		return false;
375
	}
376
	list($ip1, $ip2) = explode ('-', $range);
377
	return (is_ipaddr($ip1) && is_ipaddr($ip2));
378
}
379

    
380
function is_numericint($arg) {
381
	return (preg_match("/[^0-9]/", $arg) ? false : true);
382
}
383

    
384
/* returns true if $ipaddr is a valid dotted IPv4 address */
385
function is_ipaddr($ipaddr) {
386
	if (!is_string($ipaddr))
387
		return false;
388

    
389
	$ip_long = ip2long($ipaddr);
390
	$ip_reverse = long2ip32($ip_long);
391

    
392
	if ($ipaddr == $ip_reverse)
393
		return true;
394
	else
395
		return false;
396
}
397

    
398
/* returns true if $ipaddr is a valid dotted IPv4 address or an alias thereof */
399
function is_ipaddroralias($ipaddr) {
400
	global $config;
401

    
402
	if (is_alias($ipaddr)) {
403
		if (is_array($config['aliases']['alias'])) {
404
			foreach ($config['aliases']['alias'] as $alias) {
405
                        	if ($alias['name'] == $ipaddr && $alias['type'] != "port")
406
					return true;
407
			}
408
                }
409
		return false;
410
	} else
411
		return is_ipaddr($ipaddr);
412

    
413
}
414

    
415
/* returns true if $subnet is a valid subnet in CIDR format */
416
function is_subnet($subnet) {
417
	if (!is_string($subnet))
418
		return false;
419

    
420
	list($hp,$np) = explode('/', $subnet);
421

    
422
	if (!is_ipaddr($hp))
423
		return false;
424

    
425
	if (!is_numeric($np) || ($np < 1) || ($np > 32))
426
		return false;
427

    
428
	return true;
429
}
430

    
431
/* returns true if $subnet is a valid subnet in CIDR format or an alias thereof */
432
function is_subnetoralias($subnet) {
433

    
434
	global $aliastable;
435

    
436
	if (isset($aliastable[$subnet]) && is_subnet($aliastable[$subnet]))
437
		return true;
438
	else
439
		return is_subnet($subnet);
440
}
441

    
442
/* returns true if $hostname is a valid hostname */
443
function is_hostname($hostname) {
444
	if (!is_string($hostname))
445
		return false;
446

    
447
	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))
448
		return true;
449
	else
450
		return false;
451
}
452

    
453
/* returns true if $domain is a valid domain name */
454
function is_domain($domain) {
455
	if (!is_string($domain))
456
		return false;
457

    
458
	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))
459
		return true;
460
	else
461
		return false;
462
}
463

    
464
/* returns true if $macaddr is a valid MAC address */
465
function is_macaddr($macaddr) {
466
	return preg_match('/^[0-9A-F]{2}(?=([:]?))(?:\\1[0-9A-F]{2}){5}$/i', $macaddr) == 1 ? true : false;
467
}
468

    
469
/* returns true if $name is a valid name for an alias */
470
/* returns NULL if a reserved word is used */
471
function is_validaliasname($name) {
472
	/* Array of reserved words */
473
	$reserved = array("port", "pass");
474
	if (in_array($name, $reserved, true))
475
		return; /* return NULL */
476

    
477
	if (!preg_match("/[^a-zA-Z0-9_]/", $name))
478
		return true;
479
	else
480
		return false;
481
}
482

    
483
/* returns true if $port is a valid TCP/UDP port */
484
function is_port($port) {
485
	$tmpports = explode(":", $port);
486
	foreach($tmpports as $tmpport) {
487
		if (getservbyname($tmpport, "tcp") || getservbyname($tmpport, "udp"))
488
                	continue;
489
		if (!ctype_digit($tmpport))
490
			return false;
491
		else if ((intval($tmpport) < 1) || (intval($tmpport) > 65535))
492
			return false;
493
	}
494
	return true;
495
}
496

    
497
/* returns true if $portrange is a valid TCP/UDP portrange ("<port>:<port>") */
498
function is_portrange($portrange) {
499
        $ports = explode(":", $portrange);
500

    
501
        if(count($ports) == 2 && is_port($ports[0]) && is_port($ports[1]))
502
                return true;
503
        else
504
                return false;
505
}
506

    
507
/* returns true if $port is a valid port number or an alias thereof */
508
function is_portoralias($port) {
509
	global $config;
510

    
511
        if (is_alias($port)) {
512
                if (is_array($config['aliases']['alias'])) {
513
                        foreach ($config['aliases']['alias'] as $alias) {
514
                                if ($alias['name'] == $port && $alias['type'] == "port")
515
                                        return true;
516
                        }
517
                }
518
                return false;
519
        } else
520
                return is_port($port);
521
}
522

    
523
/* returns true if $val is a valid shaper bandwidth value */
524
function is_valid_shaperbw($val) {
525
	return (preg_match("/^(\d+(?:\.\d+)?)([MKG]?b|%)$/", $val));
526
}
527

    
528
/* return the configured carp interface list */
529
function get_configured_carp_interface_list() {
530
	global $config;
531

    
532
	$iflist = array();
533

    
534
	if(is_array($config['virtualip']['vip'])) {
535
                $viparr = &$config['virtualip']['vip'];
536
                foreach ($viparr as $vip) {
537
                        switch ($vip['mode']) {
538
                        case "carp":
539
                        case "carpdev-dhcp":
540
				$vipif = "vip" . $vip['vhid'];
541
                        	$iflist[$vipif] = $vip['subnet'];
542
                                break;
543
                        }
544
                }
545
        }
546

    
547
	return $iflist;
548
}
549

    
550
/* return the configured IP aliases list */
551
function get_configured_ip_aliases_list() {
552
        global $config;
553

    
554
        $alias_list=array();
555

    
556
        if(is_array($config['virtualip']['vip'])) {
557
                $viparr = &$config['virtualip']['vip'];
558
                foreach ($viparr as $vip) {
559
                        if ($vip['mode']=="ipalias") {
560
                                $alias_list[$vip['subnet']] = $vip['interface'];
561
                        }
562
                }
563
        }
564

    
565
        return $alias_list;
566
}
567

    
568

    
569
/* comparison function for sorting by the order in which interfaces are normally created */
570
function compare_interface_friendly_names($a, $b) {
571
	if ($a == $b)
572
		return 0;
573
	else if ($a == 'wan')
574
		return -1;
575
	else if ($b == 'wan')
576
		return 1;
577
	else if ($a == 'lan')
578
		return -1;
579
	else if ($b == 'lan')
580
		return 1;
581

    
582
	return strnatcmp($a, $b);
583
}
584

    
585
/* return the configured interfaces list. */
586
function get_configured_interface_list($only_opt = false, $withdisabled = false) {
587
	global $config;
588

    
589
	$iflist = array();
590

    
591
	/* if list */
592
	foreach($config['interfaces'] as $if => $ifdetail) {
593
		if ($only_opt && ($if == "wan" || $if == "lan"))
594
			continue;
595
		if (isset($ifdetail['enable']) || $withdisabled == true)
596
			$iflist[$if] = $if;
597
	}
598

    
599
	return $iflist;
600
}
601

    
602
/* return the configured interfaces list. */
603
function get_configured_interface_list_by_realif($only_opt = false, $withdisabled = false) {
604
	global $config;
605

    
606
	$iflist = array();
607

    
608
	/* if list */
609
	foreach($config['interfaces'] as $if => $ifdetail) {
610
		if ($only_opt && ($if == "wan" || $if == "lan"))
611
			continue;
612
		if (isset($ifdetail['enable']) || $withdisabled == true) {
613
			$tmpif = get_real_interface($if);
614
			if (!empty($tmpif))
615
				$iflist[$tmpif] = $if;
616
		}
617
	}
618

    
619
	return $iflist;
620
}
621

    
622
/* return the configured interfaces list with their description. */
623
function get_configured_interface_with_descr($only_opt = false, $withdisabled = false) {
624
	global $config;
625

    
626
	$iflist = array();
627

    
628
	/* if list */
629
	foreach($config['interfaces'] as $if => $ifdetail) {
630
		if ($only_opt && ($if == "wan" || $if == "lan"))
631
			continue;
632
		if (isset($ifdetail['enable']) || $withdisabled == true) {
633
			if(empty($ifdetail['descr']))
634
				$iflist[$if] = strtoupper($if);
635
			else
636
				$iflist[$if] = strtoupper($ifdetail['descr']);
637
		}
638
	}
639

    
640
	return $iflist;
641
}
642

    
643
/*
644
 *   get_configured_ip_addresses() - Return a list of all configured
645
 *   interfaces IP Addresses
646
 *
647
 */
648
function get_configured_ip_addresses() {
649
	require_once("interfaces.inc");
650
	$ip_array = array();
651
	$interfaces = get_configured_interface_list();
652
	if(is_array($interfaces)) {
653
		foreach($interfaces as $int) {
654
			$ipaddr = get_interface_ip($int);
655
			$ip_array[$int] = $ipaddr;
656
		}
657
	}
658
	$interfaces = get_configured_carp_interface_list();
659
	if(is_array($interfaces)) 
660
		foreach($interfaces as $int => $ipaddr) 
661
			$ip_array[$int] = $ipaddr;
662
	return $ip_array;
663
}
664

    
665
/*
666
 *   get_interface_list() - Return a list of all physical interfaces
667
 *   along with MAC and status.
668
 *
669
 *   $mode = "active" - use ifconfig -lu
670
 *           "media"  - use ifconfig to check physical connection
671
 *			status (much slower)
672
 */
673
function get_interface_list($mode = "active", $keyby = "physical", $vfaces = "") {
674
        global $config;
675
	$upints = array();
676
        /* get a list of virtual interface types */
677
        if(!$vfaces) {
678
		$vfaces = array (
679
				'bridge',
680
				'ppp',
681
				'pppoe',
682
				'pptp',
683
				'l2tp',
684
				'sl',
685
				'gif',
686
				'gre',
687
				'faith',
688
				'lo',
689
				'ng',
690
				'_vlan',
691
				'_wlan',
692
				'pflog',
693
				'plip',
694
				'pfsync',
695
				'enc',
696
				'tun',
697
				'carp',
698
				'lagg',
699
				'vip',
700
				'ipfw'
701
		);
702
	}
703
	switch($mode) {
704
	case "active":
705
                $upints = explode(" ", trim(shell_exec("/sbin/ifconfig -lu")));
706
        	break;
707
	case "media":
708
                $intlist = explode(" ", trim(shell_exec("/sbin/ifconfig -l")));
709
                $ifconfig = "";
710
                exec("/sbin/ifconfig -a", $ifconfig);
711
                $regexp = '/(' . implode('|', $intlist) . '):\s/';
712
                $ifstatus = preg_grep('/status:/', $ifconfig);
713
		foreach($ifstatus as $status) {
714
			$int = array_shift($intlist);
715
                	if(stristr($status, "active")) $upints[] = $int;
716
		}
717
		break;
718
	default:
719
		$upints = explode(" ", trim(shell_exec("/sbin/ifconfig -l")));
720
		break;
721
	}
722
        /* build interface list with netstat */
723
        $linkinfo = "";
724
        exec("/usr/bin/netstat -inW -f link | awk '{ print $1, $4 }'", $linkinfo);
725
        array_shift($linkinfo);
726
	/* build ip address list with netstat */
727
	$ipinfo = "";
728
	exec("/usr/bin/netstat -inW -f inet | awk '{ print $1, $4 }'", $ipinfo);
729
	array_shift($ipinfo);
730
	foreach($linkinfo as $link) {
731
		$friendly = "";
732
                $alink = explode(" ", $link);
733
                $ifname = rtrim(trim($alink[0]), '*');
734
                /* trim out all numbers before checking for vfaces */
735
		if (!in_array(array_shift(preg_split('/\d/', $ifname)), $vfaces) &&
736
			!stristr($ifname, "_vlan") && !stristr($ifname, "_wlan")) {
737
			$toput = array(
738
					"mac" => trim($alink[1]),
739
					"up" => in_array($ifname, $upints)
740
				);
741
			foreach($ipinfo as $ip) {
742
				$aip = explode(" ", $ip);
743
				if($aip[0] == $ifname) {
744
					$toput['ipaddr'] = $aip[1];
745
				}
746
			}
747
			if (is_array($config['interfaces'])) {
748
				foreach($config['interfaces'] as $name => $int)
749
					if($int['if'] == $ifname) $friendly = $name;
750
			}
751
			switch($keyby) {
752
			case "physical":
753
				if($friendly != "") {
754
					$toput['friendly'] = $friendly;
755
				}
756
				$dmesg_arr = array();
757
				exec("/sbin/dmesg |grep $ifname | head -n1", $dmesg_arr);
758
				preg_match_all("/<(.*?)>/i", $dmesg_arr[0], $dmesg);
759
				$toput['dmesg'] = $dmesg[1][0];
760
				$iflist[$ifname] = $toput;
761
				break;
762
			case "ppp":
763
				
764
			case "friendly":
765
				if($friendly != "") {
766
					$toput['if'] = $ifname;
767
					$iflist[$friendly] = $toput;
768
				}
769
				break;
770
			}
771
                }
772
        }
773
        return $iflist;
774
}
775

    
776
/****f* util/log_error
777
* NAME
778
*   log_error  - Sends a string to syslog.
779
* INPUTS
780
*   $error     - string containing the syslog message.
781
* RESULT
782
*   null
783
******/
784
function log_error($error) {
785
        global $g;
786
        $page = $_SERVER['SCRIPT_NAME'];
787
        syslog(LOG_WARNING, "$page: $error");
788
        if ($g['debug'])
789
                syslog(LOG_WARNING, var_dump(debug_backtrace()));
790
        return;
791
}
792

    
793
/****f* util/exec_command
794
 * NAME
795
 *   exec_command - Execute a command and return a string of the result.
796
 * INPUTS
797
 *   $command   - String of the command to be executed.
798
 * RESULT
799
 *   String containing the command's result.
800
 * NOTES
801
 *   This function returns the command's stdout and stderr.
802
 ******/
803
function exec_command($command) {
804
        $output = array();
805
        exec($command . ' 2>&1 ', $output);
806
        return(implode("\n", $output));
807
}
808

    
809
/* wrapper for exec() */
810
function mwexec($command, $mute = false) {
811

    
812
	global $g;
813
	$oarr = array();
814
	$retval = 0;
815
	if ($g['debug']) {
816
		if (!$_SERVER['REMOTE_ADDR'])
817
			echo "mwexec(): $command\n";
818
		exec("$command 2>&1", $oarr, $retval);
819
	} else {
820
		exec("$command 2>&1", $oarr, $retval);
821
	}
822
	if(isset($config['system']['developerspew']))
823
                $mute = false;
824
	if(($retval <> 0) && ($mute === false)) {
825
		$output = implode(" ", $oarr);
826
		log_error("The command '$command' returned exit code '$retval', the output was '$output' ");
827
	}
828
	return $retval;
829
}
830

    
831
/* wrapper for exec() in background */
832
function mwexec_bg($command) {
833

    
834
	global $g;
835

    
836
	if ($g['debug']) {
837
		if (!$_SERVER['REMOTE_ADDR'])
838
			echo "mwexec(): $command\n";
839
	}
840

    
841
	exec("nohup $command > /dev/null 2>&1 &");
842
}
843

    
844
/* unlink a file, if it exists */
845
function unlink_if_exists($fn) {
846
	$to_do = glob($fn);
847
	if(is_array($to_do)) {
848
		foreach($to_do as $filename)
849
			@unlink($filename);
850
	} else {
851
		@unlink($fn);
852
	}
853
}
854
/* make a global alias table (for faster lookups) */
855
function alias_make_table($config) {
856

    
857
	global $aliastable;
858

    
859
	$aliastable = array();
860

    
861
	if (is_array($config['aliases']['alias'])) {
862
		foreach ($config['aliases']['alias'] as $alias) {
863
			if ($alias['name'])
864
				$aliastable[$alias['name']] = $alias['address'];
865
		}
866
	}
867
}
868
/* check if an alias exists */
869
function is_alias($name) {
870

    
871
	global $aliastable;
872

    
873
	return isset($aliastable[$name]);
874
}
875

    
876
/* expand a host or network alias, if necessary */
877
function alias_expand($name) {
878

    
879
	global $aliastable;
880

    
881
	if (isset($aliastable[$name]))
882
		return "\${$name}";
883
	else if (is_ipaddr($name) || is_subnet($name) || is_port($name))
884
		return "{$name}";
885
	else
886
		return null;
887
}
888

    
889
function alias_expand_urltable($name) {
890
	global $config;
891
	$urltable_prefix = "/var/db/aliastables/";
892
	$urltable_filename = $urltable_prefix . $name . ".txt";
893

    
894
	foreach ($config['aliases']['alias'] as $alias) {
895
		if (($alias['type'] == 'urltable') && ($alias['name'] == $name)) {
896
			if (is_URL($alias["url"]) && file_exists($urltable_filename) && filesize($urltable_filename))
897
				return $urltable_filename;
898
			else if (process_alias_urltable($name, $alias["url"], 0, true))
899
				return $urltable_filename;
900
		}
901
	}
902
	return null;
903
}
904

    
905
/* find out whether two subnets overlap */
906
function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2) {
907

    
908
	if (!is_numeric($bits1))
909
		$bits1 = 32;
910
	if (!is_numeric($bits2))
911
		$bits2 = 32;
912

    
913
	if ($bits1 < $bits2)
914
		$relbits = $bits1;
915
	else
916
		$relbits = $bits2;
917

    
918
	$sn1 = gen_subnet_mask_long($relbits) & ip2long($subnet1);
919
	$sn2 = gen_subnet_mask_long($relbits) & ip2long($subnet2);
920

    
921
	if ($sn1 == $sn2)
922
		return true;
923
	else
924
		return false;
925
}
926

    
927
/* compare two IP addresses */
928
function ipcmp($a, $b) {
929
	if (ip_less_than($a, $b))
930
		return -1;
931
	else if (ip_greater_than($a, $b))
932
		return 1;
933
	else
934
		return 0;
935
}
936

    
937
/* return true if $addr is in $subnet, false if not */
938
function ip_in_subnet($addr,$subnet) {
939
	list($ip, $mask) = explode('/', $subnet);
940
	$mask = (0xffffffff << (32 - $mask)) & 0xffffffff;
941
	return ((ip2long($addr) & $mask) == (ip2long($ip) & $mask));
942
}
943

    
944
/* verify (and remove) the digital signature on a file - returns 0 if OK */
945
function verify_digital_signature($fname) {
946
	global $g;
947

    
948
	if(!file_exists("/usr/local/sbin/gzsig"))
949
		return 4;
950

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

    
954
/* obtain MAC address given an IP address by looking at the ARP table */
955
function arp_get_mac_by_ip($ip) {
956
	mwexec("/sbin/ping -c 1 -t 1 {$ip}", true);
957
	$arpoutput = "";
958
	exec("/usr/sbin/arp -n {$ip}", $arpoutput);
959

    
960
	if ($arpoutput[0]) {
961
		$arpi = explode(" ", $arpoutput[0]);
962
		$macaddr = $arpi[3];
963
		if (is_macaddr($macaddr))
964
			return $macaddr;
965
		else
966
			return false;
967
	}
968

    
969
	return false;
970
}
971

    
972
/* return a fieldname that is safe for xml usage */
973
function xml_safe_fieldname($fieldname) {
974
	$replace = array('/', '-', ' ', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
975
			 '_', '+', '=', '{', '}', '[', ']', '|', '/', '<', '>', '?',
976
			 ':', ',', '.', '\'', '\\'
977
		);
978
	return strtolower(str_replace($replace, "", $fieldname));
979
}
980

    
981
function mac_format($clientmac) {
982
    $mac =explode(":", $clientmac);
983

    
984
    global $config;
985

    
986
    $mac_format = $config['captiveportal']['radmac_format'] ? $config['captiveportal']['radmac_format'] : false;
987

    
988
    switch($mac_format) {
989

    
990
        case 'singledash':
991
        return "$mac[0]$mac[1]$mac[2]-$mac[3]$mac[4]$mac[5]";
992

    
993
        case 'ietf':
994
        return "$mac[0]-$mac[1]-$mac[2]-$mac[3]-$mac[4]-$mac[5]";
995

    
996
        case 'cisco':
997
        return "$mac[0]$mac[1].$mac[2]$mac[3].$mac[4]$mac[5]";
998

    
999
        case 'unformatted':
1000
        return "$mac[0]$mac[1]$mac[2]$mac[3]$mac[4]$mac[5]";
1001

    
1002
        default:
1003
        return $clientmac;
1004
    }
1005
}
1006

    
1007
function resolve_retry($hostname, $retries = 5) {
1008

    
1009
       if (is_ipaddr($hostname))
1010
               return $hostname;
1011

    
1012
       for ($i = 0; $i < $retries; $i++) {
1013
               $ip = gethostbyname($hostname);
1014

    
1015
               if ($ip && $ip != $hostname) {
1016
                       /* success */
1017
                       return $ip;
1018
               }
1019

    
1020
               sleep(1);
1021
       }
1022

    
1023
       return false;
1024
}
1025

    
1026
function format_bytes($bytes) {
1027
	if ($bytes >= 1073741824) {
1028
		return sprintf("%.2f GB", $bytes/1073741824);
1029
	} else if ($bytes >= 1048576) {
1030
		return sprintf("%.2f MB", $bytes/1048576);
1031
	} else if ($bytes >= 1024) {
1032
		return sprintf("%.0f KB", $bytes/1024);
1033
	} else {
1034
		return sprintf("%d bytes", $bytes);
1035
	}
1036
}
1037

    
1038
function update_filter_reload_status($text) {
1039
        global $g;
1040

    
1041
        file_put_contents("{$g['varrun_path']}/filter_reload_status", $text);
1042
}
1043

    
1044
/****f* util/return_dir_as_array
1045
 * NAME
1046
 *   return_dir_as_array - Return a directory's contents as an array.
1047
 * INPUTS
1048
 *   $dir       - string containing the path to the desired directory.
1049
 * RESULT
1050
 *   $dir_array - array containing the directory's contents. This array will be empty if the path specified is invalid.
1051
 ******/
1052
function return_dir_as_array($dir) {
1053
        $dir_array = array();
1054
        if (is_dir($dir)) {
1055
                if ($dh = opendir($dir)) {
1056
                        while (($file = readdir($dh)) !== false) {
1057
                                $canadd = 0;
1058
                                if($file == ".") $canadd = 1;
1059
                                if($file == "..") $canadd = 1;
1060
                                if($canadd == 0)
1061
                                        array_push($dir_array, $file);
1062
                        }
1063
                        closedir($dh);
1064
                }
1065
        }
1066
        return $dir_array;
1067
}
1068

    
1069
function run_plugins($directory) {
1070
        global $config, $g;
1071

    
1072
		/* process packager manager custom rules */
1073
		$files = return_dir_as_array($directory);
1074
		if (is_array($files)) {
1075
			foreach ($files as $file) {
1076
				if (stristr($file, ".sh") == true)
1077
					mwexec($directory . $file . " start");
1078
				else if (!is_dir($directory . "/" . $file) && stristr($file,".inc")) 
1079
					require_once($directory . "/" . $file);
1080
			}
1081
		}
1082
}
1083

    
1084
/*
1085
 *    safe_mkdir($path, $mode = 0755)
1086
 *    create directory if it doesn't already exist and isn't a file!
1087
 */
1088
function safe_mkdir($path, $mode=0755) {
1089
        global $g;
1090

    
1091
        if (!is_file($path) && !is_dir($path)) {
1092
                return @mkdir($path, $mode, true);
1093
        } else {
1094
                return false;
1095
        }
1096
}
1097

    
1098
/*
1099
 * make_dirs($path, $mode = 0755)
1100
 * create directory tree recursively (mkdir -p)
1101
 */
1102
function make_dirs($path, $mode = 0755) {
1103
        $base = '';
1104
        foreach (explode('/', $path) as $dir) {
1105
                $base .= "/$dir";
1106
                if (!is_dir($base)) {
1107
                        if (!@mkdir($base, $mode))
1108
                                return false;
1109
                }
1110
        }
1111
        return true;
1112
}
1113

    
1114
/*
1115
 * get_sysctl($names)
1116
 * Get values of sysctl OID's listed in $names (accepts an array or a single
1117
 * name) and return an array of key/value pairs set for those that exist
1118
 */
1119
function get_sysctl($names) {
1120
	if (empty($names))
1121
		return array();
1122

    
1123
	if (is_array($names)) {
1124
		$name_list = array();
1125
		foreach ($names as $name) {
1126
			$name_list[] = escapeshellarg($name);
1127
		}
1128
	} else
1129
		$name_list = array(escapeshellarg($names));
1130

    
1131
	exec("/sbin/sysctl -i " . implode(" ", $name_list), $output);
1132
	$values = array();
1133
	foreach ($output as $line) {
1134
		$line = explode(": ", $line, 2);
1135
		if (count($line) == 2)
1136
			$values[$line[0]] = $line[1];
1137
	}
1138

    
1139
	return $values;
1140
}
1141

    
1142
/*
1143
 * set_sysctl($value_list)
1144
 * Set sysctl OID's listed as key/value pairs and return
1145
 * an array with keys set for those that succeeded
1146
 */
1147
function set_sysctl($values) {
1148
	if (empty($values))
1149
		return array();
1150

    
1151
	$value_list = array();
1152
	foreach ($values as $key => $value) {
1153
		$value_list[] = escapeshellarg($key) . "=" . escapeshellarg($value);
1154
	}
1155

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

    
1158
	/* Retry individually if failed (one or more read-only) */
1159
	if ($success <> 0 && count($value_list) > 1) {
1160
		foreach ($value_list as $value) {
1161
			exec("/sbin/sysctl -i " . $value, $output);
1162
		}
1163
	}
1164

    
1165
	$ret = array();
1166
	foreach ($output as $line) {
1167
		$line = explode(": ", $line, 2);
1168
		if (count($line) == 2)
1169
			$ret[$line[0]] = true;
1170
	}
1171

    
1172
	return $ret;
1173
}
1174

    
1175
/*
1176
 *     get_memory()
1177
 *     returns an array listing the amount of
1178
 *     memory installed in the hardware
1179
 *     [0]real and [1]available
1180
 */
1181
function get_memory() {
1182
		$matches = "";
1183
        if(file_exists("/var/log/dmesg.boot"))
1184
			$mem = `cat /var/log/dmesg.boot | grep memory`;
1185
		else
1186
			$mem = `dmesg -a | grep memory`;			
1187
		if (preg_match_all("/avail memory.* \((.*)MB\)/", $mem, $matches)) 
1188
			return array($matches[1][0], $matches[1][0]);
1189
		if(!$real && !$avail) {
1190
			$real = trim(`sysctl hw.physmem | cut -d' ' -f2`);
1191
			$avail = trim(`sysctl hw.realmem | cut -d' ' -f2`);
1192
			/* convert from bytes to megabytes */
1193
			return array(($real/1048576),($avail/1048576));
1194
		}
1195
}
1196

    
1197
function mute_kernel_msgs() {
1198
		global $config;
1199
		// Do not mute serial console.  The kernel gets very very cranky
1200
		// and will start dishing you cannot control tty errors.
1201
		if(trim(file_get_contents("/etc/platform")) == "nanobsd") 
1202
			return;
1203
		if($config['system']['enableserial']) 
1204
			return;			
1205
		exec("/sbin/conscontrol mute on");
1206
}
1207

    
1208
function unmute_kernel_msgs() {
1209
		global $config;
1210
		// Do not mute serial console.  The kernel gets very very cranky
1211
		// and will start dishing you cannot control tty errors.
1212
		if(trim(file_get_contents("/etc/platform")) == "nanobsd") 
1213
			return;
1214
		exec("/sbin/conscontrol mute off");
1215
}
1216

    
1217
function start_devd() {
1218
	global $g;
1219

    
1220
        exec("/sbin/devd");
1221
        sleep(1);
1222
}
1223

    
1224
function is_interface_mismatch() {
1225
        global $config, $g;
1226

    
1227
        /* XXX: Should we process only enabled interfaces?! */
1228
        $do_assign = false;
1229
        $i = 0;
1230
	if (is_array($config['interfaces'])) {
1231
        	foreach ($config['interfaces'] as $ifname => $ifcfg) {
1232
                	if (preg_match("/^enc|^cua|^tun|^l2tp|^pptp|^ppp|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_wlan/i", $ifcfg['if'])) {
1233
                        	$i++;
1234
                	}
1235
                	else if (does_interface_exist($ifcfg['if']) == false) {
1236
				$do_assign = true;
1237
                	} else
1238
                        	$i++;
1239
        	}
1240
	}
1241

    
1242
        if ($g['minimum_nic_count'] > $i) {
1243
                $do_assign = true;
1244
        } else if (file_exists("{$g['tmp_path']}/assign_complete"))
1245
                $do_assign = false;
1246

    
1247
        return $do_assign;
1248
}
1249

    
1250
/* sync carp entries to other firewalls */
1251
function carp_sync_client() {
1252
	global $g;
1253
	send_event("filter sync");
1254
}
1255

    
1256
/****f* util/isAjax
1257
 * NAME
1258
 *   isAjax - reports if the request is driven from prototype
1259
 * INPUTS
1260
 *   none
1261
 * RESULT
1262
 *   true/false
1263
 ******/
1264
function isAjax() {
1265
        return isset ($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';
1266
}
1267

    
1268
/****f* util/timeout
1269
 * NAME
1270
 *   timeout - console input with timeout countdown. Note: erases 2 char of screen for timer. Leave space.
1271
 * INPUTS
1272
 *   optional, seconds to wait before timeout. Default 9 seconds.
1273
 * RESULT
1274
 *   returns 1 char of user input or null if no input.
1275
 ******/
1276
function timeout($timer = 9) {
1277
	while(!isset($key)) {
1278
		if ($timer >= 9) { echo chr(8) . chr(8) . ($timer==9 ? chr(32) : null)  . "{$timer}";  }
1279
		else { echo chr(8). "{$timer}"; }
1280
		`/bin/stty -icanon min 0 time 25`;
1281
		$key = trim(`KEY=\`dd count=1 2>/dev/null\`; echo \$KEY`);
1282
		`/bin/stty icanon`;
1283
		if ($key == '')
1284
			unset($key);
1285
		$timer--;
1286
		if ($timer == 0)
1287
			break;
1288
	}
1289
	return $key;	
1290
}
1291

    
1292
/****f* util/msort
1293
 * NAME
1294
 *   msort - sort array
1295
 * INPUTS
1296
 *   $array to be sorted, field to sort by, direction of sort
1297
 * RESULT
1298
 *   returns newly sorted array
1299
 ******/
1300
function msort($array, $id="id", $sort_ascending=true) {
1301
	$temp_array = array();
1302
	while(count($array)>0) {
1303
		$lowest_id = 0;
1304
		$index=0;
1305
		foreach ($array as $item) {
1306
			if (isset($item[$id])) {
1307
				if ($array[$lowest_id][$id]) {
1308
					if (strtolower($item[$id]) < strtolower($array[$lowest_id][$id])) {
1309
						$lowest_id = $index;
1310
					}
1311
				}
1312
			}
1313
			$index++;
1314
		}
1315
		$temp_array[] = $array[$lowest_id];
1316
		$array = array_merge(array_slice($array, 0,$lowest_id), array_slice($array, $lowest_id+1));
1317
	}
1318
	if ($sort_ascending) {
1319
		return $temp_array;
1320
	} else {
1321
    	return array_reverse($temp_array);
1322
	}
1323
}
1324

    
1325
/****f* util/color
1326
 * NAME
1327
 *   color - outputs a color code to the ansi terminal if supported
1328
 * INPUTS
1329
 *   color code or color name
1330
 * RESULT
1331
 *   Outputs the ansi color sequence for the color specified.  Default resets terminal.
1332
 ******/
1333
function color($color = "0m") {
1334
	/*
1335
		Color codes available:
1336
		 0m reset; clears all colors and styles (to white on black)
1337
		 1m bold on (see below)
1338
		 3m italics on
1339
		 4m underline on
1340
		 7m inverse on; reverses foreground & background colors
1341
		 9m strikethrough on
1342
		 22m bold off (see below)
1343
		 23m italics off
1344
		 24m underline off
1345
		 27m inverse off
1346
		 29m strikethrough off
1347
		 30m set foreground color to black
1348
		 31m set foreground color to red
1349
		 32m set foreground color to green
1350
		 33m set foreground color to yellow
1351
		 34m set foreground color to blue
1352
		 35m set foreground color to magenta (purple)
1353
		 36m set foreground color to cyan
1354
		 37m set foreground color to white
1355
		 40m  set background color to black
1356
		 41m set background color to red
1357
		 42m set background color to green
1358
		 43m set background color to yellow
1359
		 44m set background color to blue
1360
		 45m set background color to magenta (purple)
1361
		 46m set background color to cyan
1362
		 47m set background color to white
1363
		 49m set background color to default (black)
1364
	*/	
1365
	// Allow caching of TERM to 
1366
	// speedup subequence requests.
1367
	global $TERM;
1368
	if(!$TERM) 
1369
		$TERM=`/usr/bin/env | grep color`;
1370
	if(!$TERM)
1371
		$TERM=`/usr/bin/env | grep cons25`;
1372
	if($TERM) {
1373
		$ESCAPE=chr(27);
1374
		switch ($color) {
1375
			case "black":
1376
				return "{$ESCAPE}[30m"; 
1377
			case "red":
1378
				return "{$ESCAPE}[31m"; 
1379
			case "green":
1380
				return "{$ESCAPE}[32m"; 
1381
			case "yellow":
1382
				return "{$ESCAPE}[33m"; 
1383
			case "blue":
1384
				return "{$ESCAPE}[34m"; 
1385
			case "magenta":
1386
				return "{$ESCAPE}[35m"; 
1387
			case "cyan":
1388
				return "{$ESCAPE}[36m"; 
1389
			case "white":
1390
				return "{$ESCAPE}[37m"; 
1391
			case "default":
1392
				return "{$ESCAPE}[39m"; 
1393
		}
1394
		return "{$ESCAPE}[{$color}";
1395
	}
1396
}
1397

    
1398
/****f* util/is_URL
1399
 * NAME
1400
 *   is_URL
1401
 * INPUTS
1402
 *   string to check
1403
 * RESULT
1404
 *   Returns true if item is a URL
1405
 ******/
1406
function is_URL($url) {
1407
	$match = preg_match("'\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))'", $url);
1408
	if($match)
1409
		return true;	
1410
	return false;
1411
}
1412

    
1413
function is_file_included($file = "") {
1414
	$files = get_included_files();
1415
	if (in_array($file, $files))
1416
		return true;
1417
	
1418
	return false;
1419
}
1420

    
1421
/*
1422
	This function was borrowed from a comment on PHP.net at the following URL:
1423
	http://www.php.net/manual/en/function.array-merge-recursive.php#73843
1424
 */
1425
function array_merge_recursive_unique($array0, $array1)
1426
{
1427
    $arrays = func_get_args();
1428
    $remains = $arrays;
1429

    
1430
    // We walk through each arrays and put value in the results (without
1431
    // considering previous value).
1432
    $result = array();
1433

    
1434
    // loop available array
1435
    foreach($arrays as $array) {
1436

    
1437
        // The first remaining array is $array. We are processing it. So
1438
        // we remove it from remaing arrays.
1439
        array_shift($remains);
1440

    
1441
        // We don't care non array param, like array_merge since PHP 5.0.
1442
        if(is_array($array)) {
1443
            // Loop values
1444
            foreach($array as $key => $value) {
1445
                if(is_array($value)) {
1446
                    // we gather all remaining arrays that have such key available
1447
                    $args = array();
1448
                    foreach($remains as $remain) {
1449
                        if(array_key_exists($key, $remain)) {
1450
                            array_push($args, $remain[$key]);
1451
                        }
1452
                    }
1453

    
1454
                    if(count($args) > 2) {
1455
                        // put the recursion
1456
                        $result[$key] = call_user_func_array(__FUNCTION__, $args);
1457
                    } else {
1458
                        foreach($value as $vkey => $vval) {
1459
                            $result[$key][$vkey] = $vval;
1460
                        }
1461
                    }
1462
                } else {
1463
                    // simply put the value
1464
                    $result[$key] = $value;
1465
                }
1466
            }
1467
        }
1468
    }
1469
    return $result;
1470
}
1471

    
1472
?>
(42-42/54)