Project

General

Profile

Download (38.8 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
	foreach($interfaces as $int) {
653
		$ipaddr = get_interface_ip($int);
654
		$ip_array[$int] = $ipaddr;
655
	}
656
	return $ip_array;
657
}
658

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

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

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

    
803
/* wrapper for exec() */
804
function mwexec($command, $mute = false) {
805

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

    
825
/* wrapper for exec() in background */
826
function mwexec_bg($command) {
827

    
828
	global $g;
829

    
830
	if ($g['debug']) {
831
		if (!$_SERVER['REMOTE_ADDR'])
832
			echo "mwexec(): $command\n";
833
	}
834

    
835
	exec("nohup $command > /dev/null 2>&1 &");
836
}
837

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

    
851
	global $aliastable;
852

    
853
	$aliastable = array();
854

    
855
	if (is_array($config['aliases']['alias'])) {
856
		foreach ($config['aliases']['alias'] as $alias) {
857
			if ($alias['name'])
858
				$aliastable[$alias['name']] = $alias['address'];
859
		}
860
	}
861
}
862
/* check if an alias exists */
863
function is_alias($name) {
864

    
865
	global $aliastable;
866

    
867
	return isset($aliastable[$name]);
868
}
869

    
870
/* expand a host or network alias, if necessary */
871
function alias_expand($name) {
872

    
873
	global $aliastable;
874

    
875
	if (isset($aliastable[$name]))
876
		return "\${$name}";
877
	else if (is_ipaddr($name) || is_subnet($name) || is_port($name))
878
		return "{$name}";
879
	else
880
		return null;
881
}
882

    
883
function alias_expand_urltable($name) {
884
	global $config;
885
	$urltable_prefix = "/var/db/aliastables/";
886
	$urltable_filename = $urltable_prefix . $name . ".txt";
887

    
888
	foreach ($config['aliases']['alias'] as $alias) {
889
		if (($alias['type'] == 'urltable') && ($alias['name'] == $name)) {
890
			if (is_URL($alias["url"]) && file_exists($urltable_filename) && filesize($urltable_filename))
891
				return $urltable_filename;
892
			else if (process_alias_urltable($name, $alias["url"], 0, true))
893
				return $urltable_filename;
894
		}
895
	}
896
	return null;
897
}
898

    
899
/* find out whether two subnets overlap */
900
function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2) {
901

    
902
	if (!is_numeric($bits1))
903
		$bits1 = 32;
904
	if (!is_numeric($bits2))
905
		$bits2 = 32;
906

    
907
	if ($bits1 < $bits2)
908
		$relbits = $bits1;
909
	else
910
		$relbits = $bits2;
911

    
912
	$sn1 = gen_subnet_mask_long($relbits) & ip2long($subnet1);
913
	$sn2 = gen_subnet_mask_long($relbits) & ip2long($subnet2);
914

    
915
	if ($sn1 == $sn2)
916
		return true;
917
	else
918
		return false;
919
}
920

    
921
/* compare two IP addresses */
922
function ipcmp($a, $b) {
923
	if (ip_less_than($a, $b))
924
		return -1;
925
	else if (ip_greater_than($a, $b))
926
		return 1;
927
	else
928
		return 0;
929
}
930

    
931
/* return true if $addr is in $subnet, false if not */
932
function ip_in_subnet($addr,$subnet) {
933
	list($ip, $mask) = explode('/', $subnet);
934
	$mask = (0xffffffff << (32 - $mask)) & 0xffffffff;
935
	return ((ip2long($addr) & $mask) == (ip2long($ip) & $mask));
936
}
937

    
938
/* verify (and remove) the digital signature on a file - returns 0 if OK */
939
function verify_digital_signature($fname) {
940
	global $g;
941

    
942
	if(!file_exists("/usr/local/sbin/gzsig"))
943
		return 4;
944

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

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

    
954
	if ($arpoutput[0]) {
955
		$arpi = explode(" ", $arpoutput[0]);
956
		$macaddr = $arpi[3];
957
		if (is_macaddr($macaddr))
958
			return $macaddr;
959
		else
960
			return false;
961
	}
962

    
963
	return false;
964
}
965

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

    
975
function mac_format($clientmac) {
976
    $mac =explode(":", $clientmac);
977

    
978
    global $config;
979

    
980
    $mac_format = $config['captiveportal']['radmac_format'] ? $config['captiveportal']['radmac_format'] : false;
981

    
982
    switch($mac_format) {
983

    
984
        case 'singledash':
985
        return "$mac[0]$mac[1]$mac[2]-$mac[3]$mac[4]$mac[5]";
986

    
987
        case 'ietf':
988
        return "$mac[0]-$mac[1]-$mac[2]-$mac[3]-$mac[4]-$mac[5]";
989

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

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

    
996
        default:
997
        return $clientmac;
998
    }
999
}
1000

    
1001
function resolve_retry($hostname, $retries = 5) {
1002

    
1003
       if (is_ipaddr($hostname))
1004
               return $hostname;
1005

    
1006
       for ($i = 0; $i < $retries; $i++) {
1007
               $ip = gethostbyname($hostname);
1008

    
1009
               if ($ip && $ip != $hostname) {
1010
                       /* success */
1011
                       return $ip;
1012
               }
1013

    
1014
               sleep(1);
1015
       }
1016

    
1017
       return false;
1018
}
1019

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

    
1032
function update_filter_reload_status($text) {
1033
        global $g;
1034

    
1035
        file_put_contents("{$g['varrun_path']}/filter_reload_status", $text);
1036
}
1037

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

    
1063
function run_plugins($directory) {
1064
        global $config, $g;
1065

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

    
1078
/*
1079
 *    safe_mkdir($path, $mode = 0755)
1080
 *    create directory if it doesn't already exist and isn't a file!
1081
 */
1082
function safe_mkdir($path, $mode=0755) {
1083
        global $g;
1084

    
1085
        if (!is_file($path) && !is_dir($path)) {
1086
                return @mkdir($path, $mode, true);
1087
        } else {
1088
                return false;
1089
        }
1090
}
1091

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

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

    
1117
	if (is_array($names)) {
1118
		$name_list = array();
1119
		foreach ($names as $name) {
1120
			$name_list[] = escapeshellarg($name);
1121
		}
1122
	} else
1123
		$name_list = array(escapeshellarg($names));
1124

    
1125
	exec("/sbin/sysctl -i " . implode(" ", $name_list), $output);
1126
	$values = array();
1127
	foreach ($output as $line) {
1128
		$line = explode(": ", $line, 2);
1129
		if (count($line) == 2)
1130
			$values[$line[0]] = $line[1];
1131
	}
1132

    
1133
	return $values;
1134
}
1135

    
1136
/*
1137
 * set_sysctl($value_list)
1138
 * Set sysctl OID's listed as key/value pairs and return
1139
 * an array with keys set for those that succeeded
1140
 */
1141
function set_sysctl($values) {
1142
	if (empty($values))
1143
		return array();
1144

    
1145
	$value_list = array();
1146
	foreach ($values as $key => $value) {
1147
		$value_list[] = escapeshellarg($key) . "=" . escapeshellarg($value);
1148
	}
1149

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

    
1152
	/* Retry individually if failed (one or more read-only) */
1153
	if ($success <> 0 && count($value_list) > 1) {
1154
		foreach ($value_list as $value) {
1155
			exec("/sbin/sysctl -i " . $value, $output);
1156
		}
1157
	}
1158

    
1159
	$ret = array();
1160
	foreach ($output as $line) {
1161
		$line = explode(": ", $line, 2);
1162
		if (count($line) == 2)
1163
			$ret[$line[0]] = true;
1164
	}
1165

    
1166
	return $ret;
1167
}
1168

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

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

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

    
1211
function start_devd() {
1212
	global $g;
1213

    
1214
        exec("/sbin/devd");
1215
        sleep(1);
1216
}
1217

    
1218
function is_interface_mismatch() {
1219
        global $config, $g;
1220

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

    
1236
        if ($g['minimum_nic_count'] > $i) {
1237
                $do_assign = true;
1238
        } else if (file_exists("{$g['tmp_path']}/assign_complete"))
1239
                $do_assign = false;
1240

    
1241
        return $do_assign;
1242
}
1243

    
1244
/* sync carp entries to other firewalls */
1245
function carp_sync_client() {
1246
	global $g;
1247
	send_event("filter sync");
1248
}
1249

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

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

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

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

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

    
1407
function is_file_included($file = "") {
1408
	$files = get_included_files();
1409
	if (in_array($file, $files))
1410
		return true;
1411
	
1412
	return false;
1413
}
1414

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

    
1424
    // We walk through each arrays and put value in the results (without
1425
    // considering previous value).
1426
    $result = array();
1427

    
1428
    // loop available array
1429
    foreach($arrays as $array) {
1430

    
1431
        // The first remaining array is $array. We are processing it. So
1432
        // we remove it from remaing arrays.
1433
        array_shift($remains);
1434

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

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

    
1466
?>
(42-42/54)