Project

General

Profile

Download (39.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
	return long2ip(ip2long($ipaddr) & gen_subnet_mask_long($bits));
223
}
224

    
225
/* return the subnet address given a host address and a subnet bit count */
226
function gen_subnetv6($ipaddr, $bits) {
227
	if (!is_ipaddrv6($ipaddr) || !is_numeric($bits))
228
		return "";
229
	return Net_IPv6::getNetmask($ipaddr, $bits);
230
}
231

    
232
/* return the highest (broadcast) address in the subnet given a host address and a subnet bit count */
233
function gen_subnet_max($ipaddr, $bits) {
234
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
235
		return "";
236

    
237
	return long2ip32(ip2long($ipaddr) | ~gen_subnet_mask_long($bits));
238
}
239

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

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

    
283
/* returns a subnet mask (long given a bit count) */
284
function gen_subnet_mask_long($bits) {
285
	$sm = 0;
286
	for ($i = 0; $i < $bits; $i++) {
287
		$sm >>= 1;
288
		$sm |= 0x80000000;
289
	}
290
	return $sm;
291
}
292

    
293
/* same as above but returns a string */
294
function gen_subnet_mask($bits) {
295
	return long2ip(gen_subnet_mask_long($bits));
296
}
297

    
298
/* Convert long int to IP address, truncating to 32-bits. */
299
function long2ip32($ip) {
300
	return long2ip($ip & 0xFFFFFFFF);
301
}
302

    
303
/* Convert IP address to long int, truncated to 32-bits to avoid sign extension on 64-bit platforms. */
304
function ip2long32($ip) {
305
	return ( ip2long($ip) & 0xFFFFFFFF );
306
}
307

    
308
/* Convert IP address to unsigned long int. */
309
function ip2ulong($ip) {
310
	return sprintf("%u", ip2long32($ip));
311
}
312

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

    
325
/* Find the smallest possible subnet mask which can contain a given number of IPs
326
 *  e.g. 512 IPs can fit in a /23, but 513 IPs need a /22
327
 */
328
function find_smallest_cidr($number) {
329
	$smallest = 1;
330
	for ($b=32; $b > 0; $b--) {
331
		$smallest = ($number <= pow(2,$b)) ? $b : $smallest;
332
	}
333
	return (32-$smallest);
334
}
335

    
336
/* Return the previous IP address before the given address */
337
function ip_before($ip) {
338
	return long2ip32(ip2long($ip)-1);
339
}
340

    
341
/* Return the next IP address after the given address */
342
function ip_after($ip) {
343
	return long2ip32(ip2long($ip)+1);
344
}
345

    
346
/* Return true if the first IP is 'before' the second */
347
function ip_less_than($ip1, $ip2) {
348
	// Compare as unsigned long because otherwise it wouldn't work when
349
	//   crossing over from 127.255.255.255 / 128.0.0.0 barrier
350
	return ip2ulong($ip1) < ip2ulong($ip2);
351
}
352

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

    
360
/* Convert a range of IPs to an array of subnets which can contain the range. */
361
function ip_range_to_subnet_array($startip, $endip) {
362
	if (!is_ipaddr($startip) || !is_ipaddr($endip)) {
363
		return array();
364
	}
365

    
366
	// Container for subnets within this range.
367
	$rangesubnets = array();
368

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

    
372
	// Loop here to reduce subnet size and retest as needed. We need to make sure
373
	//   that the target subnet is wholly contained between $startip and $endip.
374
	for ($cidr; $cidr <= 32; $cidr++) {
375
		// Find the network and broadcast addresses for the subnet being tested.
376
		$targetsub_min = gen_subnet($startip, $cidr);
377
		$targetsub_max = gen_subnet_max($startip, $cidr);
378

    
379
		// Check best case where the range is exactly one subnet.
380
		if (($targetsub_min == $startip) && ($targetsub_max == $endip)) {
381
			// Hooray, the range is exactly this subnet!
382
			return array("{$startip}/{$cidr}");
383
		}
384

    
385
		// These remaining scenarios will find a subnet that uses the largest
386
		//  chunk possible of the range being tested, and leave the rest to be
387
		//  tested recursively after the loop.
388

    
389
		// Check if the subnet begins with $startip and ends before $endip
390
		if (($targetsub_min == $startip) && ip_less_than($targetsub_max, $endip)) {
391
			break;
392
		}
393

    
394
		// Check if the subnet ends at $endip and starts after $startip
395
		if (ip_greater_than($targetsub_min, $startip) && ($targetsub_max == $endip)) {
396
			break;
397
		}
398

    
399
		// Check if the subnet is between $startip and $endip
400
		if (ip_greater_than($targetsub_min, $startip) && ip_less_than($targetsub_max, $endip)) {
401
			break;
402
		}
403
	}
404

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

    
411
	// Add in the subnet we found before, to preserve ordering
412
	$rangesubnets[] = "{$targetsub_min}/{$cidr}";
413

    
414
	// And some more logic that will search after the subnet we found to fill in to the end of the range.
415
	if ($endip != $targetsub_max) {
416
		$rangesubnets = array_merge($rangesubnets, ip_range_to_subnet_array(ip_after($targetsub_max), $endip));
417
	}
418
	return $rangesubnets;
419
}
420

    
421
function is_iprange($range) {
422
	if (substr_count($range, '-') != 1) {
423
		return false;
424
	}
425
	list($ip1, $ip2) = explode ('-', $range);
426
	return (is_ipaddr($ip1) && is_ipaddr($ip2));
427
}
428

    
429
function is_numericint($arg) {
430
	return (preg_match("/[^0-9]/", $arg) ? false : true);
431
}
432

    
433

    
434
/* returns true if $ipaddr is a valid dotted IPv4 address or a IPv6 */
435
function is_ipaddr($ipaddr) {
436
	if(is_ipaddrv4($ipaddr)) {
437
		return true;
438
	}
439
	if(is_ipaddrv6($ipaddr)) {
440
		return true;
441
	}
442
	return false;
443
}
444

    
445
/* returns true if $ipaddr is a valid IPv6 address */
446
function is_ipaddrv6($ipaddr) {
447
	$result = Net_IPv6::checkIPv6($ipaddr);
448
	return $result;
449
}
450

    
451
/* returns true if $ipaddr is a valid dotted IPv4 address */
452
function is_ipaddrv4($ipaddr) {
453
	if (!is_string($ipaddr))
454
		return false;
455

    
456
	$ip_long = ip2long($ipaddr);
457
	$ip_reverse = long2ip32($ip_long);
458

    
459
	if ($ipaddr == $ip_reverse)
460
		return true;
461
	else
462
		return false;
463
}
464

    
465
/* returns true if $ipaddr is a valid dotted IPv4 address or an alias thereof */
466
function is_ipaddroralias($ipaddr) {
467
	global $config;
468

    
469
	if (is_alias($ipaddr)) {
470
		if (is_array($config['aliases']['alias'])) {
471
			foreach ($config['aliases']['alias'] as $alias) {
472
                        	if ($alias['name'] == $ipaddr && $alias['type'] != "port")
473
					return true;
474
			}
475
                }
476
		return false;
477
	} else
478
		return is_ipaddr($ipaddr);
479

    
480
}
481

    
482
/* returns true if $subnet is a valid subnet in CIDR format */
483
function is_subnet($subnet) {
484
	if (!is_string($subnet))
485
		return false;
486

    
487
	list($hp,$np) = explode('/', $subnet);
488

    
489
	if (!is_ipaddr($hp))
490
		return false;
491

    
492
	if (!is_numeric($np) || ($np < 1) || ($np > 32))
493
		return false;
494

    
495
	return true;
496
}
497

    
498
/* returns true if $subnet is a valid subnet in CIDR format or an alias thereof */
499
function is_subnetoralias($subnet) {
500

    
501
	global $aliastable;
502

    
503
	if (isset($aliastable[$subnet]) && is_subnet($aliastable[$subnet]))
504
		return true;
505
	else
506
		return is_subnet($subnet);
507
}
508

    
509
/* returns true if $hostname is a valid hostname */
510
function is_hostname($hostname) {
511
	if (!is_string($hostname))
512
		return false;
513

    
514
	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))
515
		return true;
516
	else
517
		return false;
518
}
519

    
520
/* returns true if $domain is a valid domain name */
521
function is_domain($domain) {
522
	if (!is_string($domain))
523
		return false;
524

    
525
	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))
526
		return true;
527
	else
528
		return false;
529
}
530

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

    
536
/* returns true if $name is a valid name for an alias */
537
/* returns NULL if a reserved word is used */
538
function is_validaliasname($name) {
539
	/* Array of reserved words */
540
	$reserved = array("port", "pass");
541
	if (in_array($name, $reserved, true))
542
		return; /* return NULL */
543

    
544
	if (!preg_match("/[^a-zA-Z0-9_]/", $name))
545
		return true;
546
	else
547
		return false;
548
}
549

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

    
564
/* returns true if $portrange is a valid TCP/UDP portrange ("<port>:<port>") */
565
function is_portrange($portrange) {
566
        $ports = explode(":", $portrange);
567

    
568
        if(count($ports) == 2 && is_port($ports[0]) && is_port($ports[1]))
569
                return true;
570
        else
571
                return false;
572
}
573

    
574
/* returns true if $port is a valid port number or an alias thereof */
575
function is_portoralias($port) {
576
	global $config;
577

    
578
        if (is_alias($port)) {
579
                if (is_array($config['aliases']['alias'])) {
580
                        foreach ($config['aliases']['alias'] as $alias) {
581
                                if ($alias['name'] == $port && $alias['type'] == "port")
582
                                        return true;
583
                        }
584
                }
585
                return false;
586
        } else
587
                return is_port($port);
588
}
589

    
590
/* returns true if $val is a valid shaper bandwidth value */
591
function is_valid_shaperbw($val) {
592
	return (preg_match("/^(\d+(?:\.\d+)?)([MKG]?b|%)$/", $val));
593
}
594

    
595
/* return the configured carp interface list */
596
function get_configured_carp_interface_list() {
597
	global $config;
598

    
599
	$iflist = array();
600

    
601
	if(is_array($config['virtualip']['vip'])) {
602
                $viparr = &$config['virtualip']['vip'];
603
                foreach ($viparr as $vip) {
604
                        switch ($vip['mode']) {
605
                        case "carp":
606
                        case "carpdev-dhcp":
607
				$vipif = "vip" . $vip['vhid'];
608
                        	$iflist[$vipif] = $vip['subnet'];
609
                                break;
610
                        }
611
                }
612
        }
613

    
614
	return $iflist;
615
}
616

    
617
/* return the configured IP aliases list */
618
function get_configured_ip_aliases_list() {
619
        global $config;
620

    
621
        $alias_list=array();
622

    
623
        if(is_array($config['virtualip']['vip'])) {
624
                $viparr = &$config['virtualip']['vip'];
625
                foreach ($viparr as $vip) {
626
                        if ($vip['mode']=="ipalias") {
627
                                $alias_list[$vip['subnet']] = $vip['interface'];
628
                        }
629
                }
630
        }
631

    
632
        return $alias_list;
633
}
634

    
635

    
636
/* return the configured interfaces list. */
637
function get_configured_interface_list($only_opt = false, $withdisabled = false) {
638
	global $config;
639

    
640
	$iflist = array();
641

    
642
	/* if list */
643
	foreach($config['interfaces'] as $if => $ifdetail) {
644
		if ($only_opt && ($if == "wan" || $if == "lan"))
645
			continue;
646
		if (isset($ifdetail['enable']) || $withdisabled == true)
647
			$iflist[$if] = $if;
648
	}
649

    
650
	return $iflist;
651
}
652

    
653
/* return the configured interfaces list. */
654
function get_configured_interface_list_by_realif($only_opt = false, $withdisabled = false) {
655
	global $config;
656

    
657
	$iflist = array();
658

    
659
	/* if list */
660
	foreach($config['interfaces'] as $if => $ifdetail) {
661
		if ($only_opt && ($if == "wan" || $if == "lan"))
662
			continue;
663
		if (isset($ifdetail['enable']) || $withdisabled == true) {
664
			$tmpif = get_real_interface($if);
665
			if (!empty($tmpif))
666
				$iflist[$tmpif] = $if;
667
		}
668
	}
669

    
670
	return $iflist;
671
}
672

    
673
/* return the configured interfaces list with their description. */
674
function get_configured_interface_with_descr($only_opt = false, $withdisabled = false) {
675
	global $config;
676

    
677
	$iflist = array();
678

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

    
691
	return $iflist;
692
}
693

    
694

    
695
/*
696
 *   get_interface_list() - Return a list of all physical interfaces
697
 *   along with MAC and status.
698
 *
699
 *   $mode = "active" - use ifconfig -lu
700
 *           "media"  - use ifconfig to check physical connection
701
 *			status (much slower)
702
 */
703
function get_interface_list($mode = "active", $keyby = "physical", $vfaces = "") {
704
        global $config;
705
	$upints = array();
706
        /* get a list of virtual interface types */
707
        if(!$vfaces) {
708
		$vfaces = array (
709
				'bridge',
710
				'ppp',
711
				'pppoe',
712
				'pptp',
713
				'l2tp',
714
				'sl',
715
				'gif',
716
				'gre',
717
				'faith',
718
				'lo',
719
				'ng',
720
				'_vlan',
721
				'_wlan',
722
				'pflog',
723
				'plip',
724
				'pfsync',
725
				'enc',
726
				'tun',
727
				'carp',
728
				'lagg',
729
				'vip',
730
				'ipfw'
731
		);
732
	}
733
	switch($mode) {
734
	case "active":
735
                $upints = explode(" ", trim(shell_exec("/sbin/ifconfig -lu")));
736
        	break;
737
	case "media":
738
                $intlist = explode(" ", trim(shell_exec("/sbin/ifconfig -l")));
739
                $ifconfig = "";
740
                exec("/sbin/ifconfig -a", $ifconfig);
741
                $regexp = '/(' . implode('|', $intlist) . '):\s/';
742
                $ifstatus = preg_grep('/status:/', $ifconfig);
743
		foreach($ifstatus as $status) {
744
			$int = array_shift($intlist);
745
                	if(stristr($status, "active")) $upints[] = $int;
746
		}
747
		break;
748
	default:
749
		$upints = explode(" ", trim(shell_exec("/sbin/ifconfig -l")));
750
		break;
751
	}
752
        /* build interface list with netstat */
753
        $linkinfo = "";
754
        exec("/usr/bin/netstat -inW -f link | awk '{ print $1, $4 }'", $linkinfo);
755
        array_shift($linkinfo);
756
	/* build ip address list with netstat */
757
	$ipinfo = "";
758
	exec("/usr/bin/netstat -inW -f inet | awk '{ print $1, $4 }'", $ipinfo);
759
	array_shift($ipinfo);
760
	foreach($linkinfo as $link) {
761
		$friendly = "";
762
                $alink = explode(" ", $link);
763
                $ifname = rtrim(trim($alink[0]), '*');
764
                /* trim out all numbers before checking for vfaces */
765
		if (!in_array(array_shift(preg_split('/\d/', $ifname)), $vfaces) &&
766
			!stristr($ifname, "_vlan") && !stristr($ifname, "_wlan")) {
767
			$toput = array(
768
					"mac" => trim($alink[1]),
769
					"up" => in_array($ifname, $upints)
770
				);
771
			foreach($ipinfo as $ip) {
772
				$aip = explode(" ", $ip);
773
				if($aip[0] == $ifname) {
774
					$toput['ipaddr'] = $aip[1];
775
				}
776
			}
777
			if (is_array($config['interfaces'])) {
778
				foreach($config['interfaces'] as $name => $int)
779
					if($int['if'] == $ifname) $friendly = $name;
780
			}
781
			switch($keyby) {
782
			case "physical":
783
				if($friendly != "") {
784
					$toput['friendly'] = $friendly;
785
				}
786
				$dmesg_arr = array();
787
				exec("/sbin/dmesg |grep $ifname | head -n1", $dmesg_arr);
788
				preg_match_all("/<(.*?)>/i", $dmesg_arr[0], $dmesg);
789
				$toput['dmesg'] = $dmesg[1][0];
790
				$iflist[$ifname] = $toput;
791
				break;
792
			case "ppp":
793
				
794
			case "friendly":
795
				if($friendly != "") {
796
					$toput['if'] = $ifname;
797
					$iflist[$friendly] = $toput;
798
				}
799
				break;
800
			}
801
                }
802
        }
803
        return $iflist;
804
}
805

    
806
/****f* util/log_error
807
* NAME
808
*   log_error  - Sends a string to syslog.
809
* INPUTS
810
*   $error     - string containing the syslog message.
811
* RESULT
812
*   null
813
******/
814
function log_error($error) {
815
        global $g;
816
        $page = $_SERVER['SCRIPT_NAME'];
817
        syslog(LOG_WARNING, "$page: $error");
818
        if ($g['debug'])
819
                syslog(LOG_WARNING, var_dump(debug_backtrace()));
820
        return;
821
}
822

    
823
/****f* util/exec_command
824
 * NAME
825
 *   exec_command - Execute a command and return a string of the result.
826
 * INPUTS
827
 *   $command   - String of the command to be executed.
828
 * RESULT
829
 *   String containing the command's result.
830
 * NOTES
831
 *   This function returns the command's stdout and stderr.
832
 ******/
833
function exec_command($command) {
834
        $output = array();
835
        exec($command . ' 2>&1 ', $output);
836
        return(implode("\n", $output));
837
}
838

    
839
/* wrapper for exec() */
840
function mwexec($command, $mute = false) {
841

    
842
	global $g;
843
	$oarr = array();
844
	$retval = 0;
845
	if ($g['debug']) {
846
		if (!$_SERVER['REMOTE_ADDR'])
847
			echo "mwexec(): $command\n";
848
		exec("$command 2>&1", $oarr, $retval);
849
	} else {
850
		exec("$command 2>&1", $oarr, $retval);
851
	}
852
	if(isset($config['system']['developerspew']))
853
                $mute = false;
854
	if(($retval <> 0) && ($mute === false)) {
855
		$output = implode(" ", $oarr);
856
		log_error("The command '$command' returned exit code '$retval', the output was '$output' ");
857
	}
858
	return $retval;
859
}
860

    
861
/* wrapper for exec() in background */
862
function mwexec_bg($command) {
863

    
864
	global $g;
865

    
866
	if ($g['debug']) {
867
		if (!$_SERVER['REMOTE_ADDR'])
868
			echo "mwexec(): $command\n";
869
	}
870

    
871
	exec("nohup $command > /dev/null 2>&1 &");
872
}
873

    
874
/* unlink a file, if it exists */
875
function unlink_if_exists($fn) {
876
	$to_do = glob($fn);
877
	if(is_array($to_do)) {
878
		foreach($to_do as $filename)
879
			@unlink($filename);
880
	} else {
881
		@unlink($fn);
882
	}
883
}
884
/* make a global alias table (for faster lookups) */
885
function alias_make_table($config) {
886

    
887
	global $aliastable;
888

    
889
	$aliastable = array();
890

    
891
	if (is_array($config['aliases']['alias'])) {
892
		foreach ($config['aliases']['alias'] as $alias) {
893
			if ($alias['name'])
894
				$aliastable[$alias['name']] = $alias['address'];
895
		}
896
	}
897
}
898
/* check if an alias exists */
899
function is_alias($name) {
900

    
901
	global $aliastable;
902

    
903
	return isset($aliastable[$name]);
904
}
905

    
906
/* expand a host or network alias, if necessary */
907
function alias_expand($name) {
908

    
909
	global $aliastable;
910

    
911
	if (isset($aliastable[$name]))
912
		return "\${$name}";
913
	else if (is_ipaddr($name) || is_subnet($name) || is_port($name))
914
		return "{$name}";
915
	else
916
		return null;
917
}
918

    
919
function alias_expand_urltable($name) {
920
	global $config;
921
	$urltable_prefix = "/var/db/aliastables/";
922
	$urltable_filename = $urltable_prefix . $name . ".txt";
923

    
924
	foreach ($config['aliases']['alias'] as $alias) {
925
		if (($alias['type'] == 'urltable') && ($alias['name'] == $name)) {
926
			if (is_URL($alias["url"]) && file_exists($urltable_filename) && filesize($urltable_filename))
927
				return $urltable_filename;
928
			else if (process_alias_urltable($name, $alias["url"], 0, true))
929
				return $urltable_filename;
930
		}
931
	}
932
	return null;
933
}
934

    
935
/* find out whether two subnets overlap */
936
function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2) {
937

    
938
	if (!is_numeric($bits1))
939
		$bits1 = 32;
940
	if (!is_numeric($bits2))
941
		$bits2 = 32;
942

    
943
	if ($bits1 < $bits2)
944
		$relbits = $bits1;
945
	else
946
		$relbits = $bits2;
947

    
948
	$sn1 = gen_subnet_mask_long($relbits) & ip2long($subnet1);
949
	$sn2 = gen_subnet_mask_long($relbits) & ip2long($subnet2);
950

    
951
	if ($sn1 == $sn2)
952
		return true;
953
	else
954
		return false;
955
}
956

    
957
/* compare two IP addresses */
958
function ipcmp($a, $b) {
959
	if (ip_less_than($a, $b))
960
		return -1;
961
	else if (ip_greater_than($a, $b))
962
		return 1;
963
	else
964
		return 0;
965
}
966

    
967
/* return true if $addr is in $subnet, false if not */
968
function ip_in_subnet($addr,$subnet) {
969
	if(is_ipaddrv6($addr)) {
970
		$result = Net_IPv6::IsInNetmask($addr, $subnet);
971
		if($result)
972
			return true;
973
		else
974
			return false;
975
	}
976
	list($ip, $mask) = explode('/', $subnet);
977
	$mask = (0xffffffff << (32 - $mask)) & 0xffffffff;
978
	return ((ip2long($addr) & $mask) == (ip2long($ip) & $mask));
979
}
980

    
981
/* verify (and remove) the digital signature on a file - returns 0 if OK */
982
function verify_digital_signature($fname) {
983
	global $g;
984

    
985
	if(!file_exists("/usr/local/sbin/gzsig"))
986
		return 4;
987

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

    
991
/* obtain MAC address given an IP address by looking at the ARP table */
992
function arp_get_mac_by_ip($ip) {
993
	mwexec("/sbin/ping -c 1 -t 1 {$ip}", true);
994
	$arpoutput = "";
995
	exec("/usr/sbin/arp -n {$ip}", $arpoutput);
996

    
997
	if ($arpoutput[0]) {
998
		$arpi = explode(" ", $arpoutput[0]);
999
		$macaddr = $arpi[3];
1000
		if (is_macaddr($macaddr))
1001
			return $macaddr;
1002
		else
1003
			return false;
1004
	}
1005

    
1006
	return false;
1007
}
1008

    
1009
/* return a fieldname that is safe for xml usage */
1010
function xml_safe_fieldname($fieldname) {
1011
	$replace = array('/', '-', ' ', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
1012
			 '_', '+', '=', '{', '}', '[', ']', '|', '/', '<', '>', '?',
1013
			 ':', ',', '.', '\'', '\\'
1014
		);
1015
	return strtolower(str_replace($replace, "", $fieldname));
1016
}
1017

    
1018
function mac_format($clientmac) {
1019
    $mac =explode(":", $clientmac);
1020

    
1021
    global $config;
1022

    
1023
    $mac_format = $config['captiveportal']['radmac_format'] ? $config['captiveportal']['radmac_format'] : false;
1024

    
1025
    switch($mac_format) {
1026

    
1027
        case 'singledash':
1028
        return "$mac[0]$mac[1]$mac[2]-$mac[3]$mac[4]$mac[5]";
1029

    
1030
        case 'ietf':
1031
        return "$mac[0]-$mac[1]-$mac[2]-$mac[3]-$mac[4]-$mac[5]";
1032

    
1033
        case 'cisco':
1034
        return "$mac[0]$mac[1].$mac[2]$mac[3].$mac[4]$mac[5]";
1035

    
1036
        case 'unformatted':
1037
        return "$mac[0]$mac[1]$mac[2]$mac[3]$mac[4]$mac[5]";
1038

    
1039
        default:
1040
        return $clientmac;
1041
    }
1042
}
1043

    
1044
function resolve_retry($hostname, $retries = 5) {
1045

    
1046
       if (is_ipaddr($hostname))
1047
               return $hostname;
1048

    
1049
       for ($i = 0; $i < $retries; $i++) {
1050
               $ip = gethostbyname($hostname);
1051

    
1052
               if ($ip && $ip != $hostname) {
1053
                       /* success */
1054
                       return $ip;
1055
               }
1056

    
1057
               sleep(1);
1058
       }
1059

    
1060
       return false;
1061
}
1062

    
1063
function format_bytes($bytes) {
1064
	if ($bytes >= 1073741824) {
1065
		return sprintf("%.2f GB", $bytes/1073741824);
1066
	} else if ($bytes >= 1048576) {
1067
		return sprintf("%.2f MB", $bytes/1048576);
1068
	} else if ($bytes >= 1024) {
1069
		return sprintf("%.0f KB", $bytes/1024);
1070
	} else {
1071
		return sprintf("%d bytes", $bytes);
1072
	}
1073
}
1074

    
1075
function update_filter_reload_status($text) {
1076
        global $g;
1077

    
1078
        file_put_contents("{$g['varrun_path']}/filter_reload_status", $text);
1079
}
1080

    
1081
/****f* util/return_dir_as_array
1082
 * NAME
1083
 *   return_dir_as_array - Return a directory's contents as an array.
1084
 * INPUTS
1085
 *   $dir       - string containing the path to the desired directory.
1086
 * RESULT
1087
 *   $dir_array - array containing the directory's contents. This array will be empty if the path specified is invalid.
1088
 ******/
1089
function return_dir_as_array($dir) {
1090
        $dir_array = array();
1091
        if (is_dir($dir)) {
1092
                if ($dh = opendir($dir)) {
1093
                        while (($file = readdir($dh)) !== false) {
1094
                                $canadd = 0;
1095
                                if($file == ".") $canadd = 1;
1096
                                if($file == "..") $canadd = 1;
1097
                                if($canadd == 0)
1098
                                        array_push($dir_array, $file);
1099
                        }
1100
                        closedir($dh);
1101
                }
1102
        }
1103
        return $dir_array;
1104
}
1105

    
1106
function run_plugins($directory) {
1107
        global $config, $g;
1108

    
1109
		/* process packager manager custom rules */
1110
		$files = return_dir_as_array($directory);
1111
		if (is_array($files)) {
1112
			foreach ($files as $file) {
1113
				if (stristr($file, ".sh") == true)
1114
					mwexec($directory . $file . " start");
1115
				else if (!is_dir($directory . "/" . $file) && stristr($file,".inc")) 
1116
					require_once($directory . "/" . $file);
1117
			}
1118
		}
1119
}
1120

    
1121
/*
1122
 *    safe_mkdir($path, $mode = 0755)
1123
 *    create directory if it doesn't already exist and isn't a file!
1124
 */
1125
function safe_mkdir($path, $mode=0755) {
1126
        global $g;
1127

    
1128
        if (!is_file($path) && !is_dir($path)) {
1129
                return @mkdir($path, $mode, true);
1130
        } else {
1131
                return false;
1132
        }
1133
}
1134

    
1135
/*
1136
 * make_dirs($path, $mode = 0755)
1137
 * create directory tree recursively (mkdir -p)
1138
 */
1139
function make_dirs($path, $mode = 0755) {
1140
        $base = '';
1141
        foreach (explode('/', $path) as $dir) {
1142
                $base .= "/$dir";
1143
                if (!is_dir($base)) {
1144
                        if (!@mkdir($base, $mode))
1145
                                return false;
1146
                }
1147
        }
1148
        return true;
1149
}
1150

    
1151
/*
1152
 * get_sysctl($names)
1153
 * Get values of sysctl OID's listed in $names (accepts an array or a single
1154
 * name) and return an array of key/value pairs set for those that exist
1155
 */
1156
function get_sysctl($names) {
1157
	if (empty($names))
1158
		return array();
1159

    
1160
	if (is_array($names)) {
1161
		$name_list = array();
1162
		foreach ($names as $name) {
1163
			$name_list[] = escapeshellarg($name);
1164
		}
1165
	} else
1166
		$name_list = array(escapeshellarg($names));
1167

    
1168
	exec("/sbin/sysctl -i " . implode(" ", $name_list), $output);
1169
	$values = array();
1170
	foreach ($output as $line) {
1171
		$line = explode(": ", $line, 2);
1172
		if (count($line) == 2)
1173
			$values[$line[0]] = $line[1];
1174
	}
1175

    
1176
	return $values;
1177
}
1178

    
1179
/*
1180
 * set_sysctl($value_list)
1181
 * Set sysctl OID's listed as key/value pairs and return
1182
 * an array with keys set for those that succeeded
1183
 */
1184
function set_sysctl($values) {
1185
	if (empty($values))
1186
		return array();
1187

    
1188
	$value_list = array();
1189
	foreach ($values as $key => $value) {
1190
		$value_list[] = escapeshellarg($key) . "=" . escapeshellarg($value);
1191
	}
1192

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

    
1195
	/* Retry individually if failed (one or more read-only) */
1196
	if ($success <> 0 && count($value_list) > 1) {
1197
		foreach ($value_list as $value) {
1198
			exec("/sbin/sysctl -i " . $value, $output);
1199
		}
1200
	}
1201

    
1202
	$ret = array();
1203
	foreach ($output as $line) {
1204
		$line = explode(": ", $line, 2);
1205
		if (count($line) == 2)
1206
			$ret[$line[0]] = true;
1207
	}
1208

    
1209
	return $ret;
1210
}
1211

    
1212
/*
1213
 *     get_memory()
1214
 *     returns an array listing the amount of
1215
 *     memory installed in the hardware
1216
 *     [0]real and [1]available
1217
 */
1218
function get_memory() {
1219
		$matches = "";
1220
        if(file_exists("/var/log/dmesg.boot"))
1221
			$mem = `cat /var/log/dmesg.boot | grep memory`;
1222
		else
1223
			$mem = `dmesg -a | grep memory`;			
1224
		if (preg_match_all("/avail memory.* \((.*)MB\)/", $mem, $matches)) 
1225
			return array($matches[1][0], $matches[1][0]);
1226
		if(!$real && !$avail) {
1227
			$real = trim(`sysctl hw.physmem | cut -d' ' -f2`);
1228
			$avail = trim(`sysctl hw.realmem | cut -d' ' -f2`);
1229
			/* convert from bytes to megabytes */
1230
			return array(($real/1048576),($avail/1048576));
1231
		}
1232
}
1233

    
1234
function mute_kernel_msgs() {
1235
		global $config;
1236
		// Do not mute serial console.  The kernel gets very very cranky
1237
		// and will start dishing you cannot control tty errors.
1238
		if(trim(file_get_contents("/etc/platform")) == "nanobsd") 
1239
			return;
1240
		if($config['system']['enableserial']) 
1241
			return;			
1242
		exec("/sbin/conscontrol mute on");
1243
}
1244

    
1245
function unmute_kernel_msgs() {
1246
		global $config;
1247
		// Do not mute serial console.  The kernel gets very very cranky
1248
		// and will start dishing you cannot control tty errors.
1249
		if(trim(file_get_contents("/etc/platform")) == "nanobsd") 
1250
			return;
1251
		exec("/sbin/conscontrol mute off");
1252
}
1253

    
1254
function start_devd() {
1255
	global $g;
1256

    
1257
        exec("/sbin/devd");
1258
        sleep(1);
1259
}
1260

    
1261
function is_interface_mismatch() {
1262
        global $config, $g;
1263

    
1264
        /* XXX: Should we process only enabled interfaces?! */
1265
        $do_assign = false;
1266
        $i = 0;
1267
	if (is_array($config['interfaces'])) {
1268
        	foreach ($config['interfaces'] as $ifname => $ifcfg) {
1269
                	if (preg_match("/^enc|^cua|^tun|^l2tp|^pptp|^ppp|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_wlan/i", $ifcfg['if'])) {
1270
                        	$i++;
1271
                	}
1272
                	else if (does_interface_exist($ifcfg['if']) == false) {
1273
				$do_assign = true;
1274
                	} else
1275
                        	$i++;
1276
        	}
1277
	}
1278

    
1279
        if ($g['minimum_nic_count'] > $i) {
1280
                $do_assign = true;
1281
        } else if (file_exists("{$g['tmp_path']}/assign_complete"))
1282
                $do_assign = false;
1283

    
1284
        return $do_assign;
1285
}
1286

    
1287
/* sync carp entries to other firewalls */
1288
function carp_sync_client() {
1289
	global $g;
1290
	send_event("filter sync");
1291
}
1292

    
1293
/****f* util/isAjax
1294
 * NAME
1295
 *   isAjax - reports if the request is driven from prototype
1296
 * INPUTS
1297
 *   none
1298
 * RESULT
1299
 *   true/false
1300
 ******/
1301
function isAjax() {
1302
        return isset ($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';
1303
}
1304

    
1305
/****f* util/timeout
1306
 * NAME
1307
 *   timeout - console input with timeout countdown. Note: erases 2 char of screen for timer. Leave space.
1308
 * INPUTS
1309
 *   optional, seconds to wait before timeout. Default 9 seconds.
1310
 * RESULT
1311
 *   returns 1 char of user input or null if no input.
1312
 ******/
1313
function timeout($timer = 9) {
1314
	while(!isset($key)) {
1315
		if ($timer >= 9) { echo chr(8) . chr(8) . ($timer==9 ? chr(32) : null)  . "{$timer}";  }
1316
		else { echo chr(8). "{$timer}"; }
1317
		`/bin/stty -icanon min 0 time 25`;
1318
		$key = trim(`KEY=\`dd count=1 2>/dev/null\`; echo \$KEY`);
1319
		`/bin/stty icanon`;
1320
		if ($key == '')
1321
			unset($key);
1322
		$timer--;
1323
		if ($timer == 0)
1324
			break;
1325
	}
1326
	return $key;	
1327
}
1328

    
1329
/****f* util/msort
1330
 * NAME
1331
 *   msort - sort array
1332
 * INPUTS
1333
 *   $array to be sorted, field to sort by, direction of sort
1334
 * RESULT
1335
 *   returns newly sorted array
1336
 ******/
1337
function msort($array, $id="id", $sort_ascending=true) {
1338
	$temp_array = array();
1339
	while(count($array)>0) {
1340
		$lowest_id = 0;
1341
		$index=0;
1342
		foreach ($array as $item) {
1343
			if (isset($item[$id])) {
1344
				if ($array[$lowest_id][$id]) {
1345
					if (strtolower($item[$id]) < strtolower($array[$lowest_id][$id])) {
1346
						$lowest_id = $index;
1347
					}
1348
				}
1349
			}
1350
			$index++;
1351
		}
1352
		$temp_array[] = $array[$lowest_id];
1353
		$array = array_merge(array_slice($array, 0,$lowest_id), array_slice($array, $lowest_id+1));
1354
	}
1355
	if ($sort_ascending) {
1356
		return $temp_array;
1357
	} else {
1358
    	return array_reverse($temp_array);
1359
	}
1360
}
1361

    
1362
/****f* util/color
1363
 * NAME
1364
 *   color - outputs a color code to the ansi terminal if supported
1365
 * INPUTS
1366
 *   color code or color name
1367
 * RESULT
1368
 *   Outputs the ansi color sequence for the color specified.  Default resets terminal.
1369
 ******/
1370
function color($color = "0m") {
1371
	/*
1372
		Color codes available:
1373
		 0m reset; clears all colors and styles (to white on black)
1374
		 1m bold on (see below)
1375
		 3m italics on
1376
		 4m underline on
1377
		 7m inverse on; reverses foreground & background colors
1378
		 9m strikethrough on
1379
		 22m bold off (see below)
1380
		 23m italics off
1381
		 24m underline off
1382
		 27m inverse off
1383
		 29m strikethrough off
1384
		 30m set foreground color to black
1385
		 31m set foreground color to red
1386
		 32m set foreground color to green
1387
		 33m set foreground color to yellow
1388
		 34m set foreground color to blue
1389
		 35m set foreground color to magenta (purple)
1390
		 36m set foreground color to cyan
1391
		 37m set foreground color to white
1392
		 40m  set background color to black
1393
		 41m set background color to red
1394
		 42m set background color to green
1395
		 43m set background color to yellow
1396
		 44m set background color to blue
1397
		 45m set background color to magenta (purple)
1398
		 46m set background color to cyan
1399
		 47m set background color to white
1400
		 49m set background color to default (black)
1401
	*/	
1402
	// Allow caching of TERM to 
1403
	// speedup subequence requests.
1404
	global $TERM;
1405
	if(!$TERM) 
1406
		$TERM=`/usr/bin/env | grep color`;
1407
	if(!$TERM)
1408
		$TERM=`/usr/bin/env | grep cons25`;
1409
	if($TERM) {
1410
		$ESCAPE=chr(27);
1411
		switch ($color) {
1412
			case "black":
1413
				return "{$ESCAPE}[30m"; 
1414
			case "red":
1415
				return "{$ESCAPE}[31m"; 
1416
			case "green":
1417
				return "{$ESCAPE}[32m"; 
1418
			case "yellow":
1419
				return "{$ESCAPE}[33m"; 
1420
			case "blue":
1421
				return "{$ESCAPE}[34m"; 
1422
			case "magenta":
1423
				return "{$ESCAPE}[35m"; 
1424
			case "cyan":
1425
				return "{$ESCAPE}[36m"; 
1426
			case "white":
1427
				return "{$ESCAPE}[37m"; 
1428
			case "default":
1429
				return "{$ESCAPE}[39m"; 
1430
		}
1431
		return "{$ESCAPE}[{$color}";
1432
	}
1433
}
1434

    
1435
/****f* util/is_URL
1436
 * NAME
1437
 *   is_URL
1438
 * INPUTS
1439
 *   string to check
1440
 * RESULT
1441
 *   Returns true if item is a URL
1442
 ******/
1443
function is_URL($url) {
1444
	$match = preg_match("'\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))'", $url);
1445
	if($match)
1446
		return true;	
1447
	return false;
1448
}
1449

    
1450
function is_file_included($file = "") {
1451
	$files = get_included_files();
1452
	if (in_array($file, $files))
1453
		return true;
1454
	
1455
	return false;
1456
}
1457

    
1458
/*
1459
	This function was borrowed from a comment on PHP.net at the following URL:
1460
	http://www.php.net/manual/en/function.array-merge-recursive.php#73843
1461
 */
1462
function array_merge_recursive_unique($array0, $array1)
1463
{
1464
    $arrays = func_get_args();
1465
    $remains = $arrays;
1466

    
1467
    // We walk through each arrays and put value in the results (without
1468
    // considering previous value).
1469
    $result = array();
1470

    
1471
    // loop available array
1472
    foreach($arrays as $array) {
1473

    
1474
        // The first remaining array is $array. We are processing it. So
1475
        // we remove it from remaing arrays.
1476
        array_shift($remains);
1477

    
1478
        // We don't care non array param, like array_merge since PHP 5.0.
1479
        if(is_array($array)) {
1480
            // Loop values
1481
            foreach($array as $key => $value) {
1482
                if(is_array($value)) {
1483
                    // we gather all remaining arrays that have such key available
1484
                    $args = array();
1485
                    foreach($remains as $remain) {
1486
                        if(array_key_exists($key, $remain)) {
1487
                            array_push($args, $remain[$key]);
1488
                        }
1489
                    }
1490

    
1491
                    if(count($args) > 2) {
1492
                        // put the recursion
1493
                        $result[$key] = call_user_func_array(__FUNCTION__, $args);
1494
                    } else {
1495
                        foreach($value as $vkey => $vval) {
1496
                            $result[$key][$vkey] = $vval;
1497
                        }
1498
                    }
1499
                } else {
1500
                    // simply put the value
1501
                    $result[$key] = $value;
1502
                }
1503
            }
1504
        }
1505
    }
1506
    return $result;
1507
}
1508

    
1509
?>
(42-42/54)