Project

General

Profile

Download (38.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 -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
	global $g;
812

    
813
	if ($g['debug']) {
814
		if (!$_SERVER['REMOTE_ADDR'])
815
			echo "mwexec(): $command\n";
816
	}
817
	$oarr = array();
818
	$retval = 0;
819
	$garbage = exec("$command 2>&1", $oarr, $retval);
820

    
821
	if(isset($config['system']['developerspew']))
822
                $mute = false;
823
	if(($retval <> 0) && ($mute === false)) {
824
		$output = implode(" ", $oarr);
825
		log_error("The command '$command' returned exit code '$retval', the output was '$output' ");
826
	}
827
	return $retval;
828
}
829

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

    
833
	global $g;
834

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

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

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

    
856
	global $aliastable;
857

    
858
	$aliastable = array();
859

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

    
870
	global $aliastable;
871

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

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

    
878
	global $aliastable;
879

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
968
	return false;
969
}
970

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

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

    
983
    global $config;
984

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

    
987
    switch($mac_format) {
988

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

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

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

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

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

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

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

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

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

    
1019
               sleep(1);
1020
       }
1021

    
1022
       return false;
1023
}
1024

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

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

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

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

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

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

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

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

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

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

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

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

    
1138
	return $values;
1139
}
1140

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

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

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

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

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

    
1171
	return $ret;
1172
}
1173

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

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

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

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

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

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

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

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

    
1246
        return $do_assign;
1247
}
1248

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1471
?>
(42-42/54)