Project

General

Profile

Download (18.1 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php /* $Id$ */ /*
2
	util.inc
3
	part of m0n0wall (http://m0n0.ch/wall)
4

    
5
	Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
6
	All rights reserved.
7

    
8
	Redistribution and use in source and binary forms, with or without
9
	modification, are permitted provided that the following conditions are met:
10

    
11
	1. Redistributions of source code must retain the above copyright notice,
12
	   this list of conditions and the following disclaimer.
13

    
14
	2. Redistributions in binary form must reproduce the above copyright
15
	   notice, this list of conditions and the following disclaimer in the
16
	   documentation and/or other materials provided with the distribution.
17

    
18
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
19
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
22
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
	POSSIBILITY OF SUCH DAMAGE.
28
*/
29

    
30
/* kill a process by pid file */
31
function killbypid($pidfile) {
32
	sigkillbypid($pidfile, "TERM");
33
}
34

    
35
function isvalidpid($pid) {
36
	$running = `ps -p $pid | wc -l`;
37
	if(intval($running) > 1)
38
		return true;
39
	else 
40
		return false;
41
}
42

    
43
function isvalidproc($proc) {
44
	$running = `ps awux | grep $proc | grep -v grep | wc -l`;
45
	if(intval($running) >= 1)
46
		return true;
47
	else 
48
		return false;
49
}
50

    
51
/* sigkill a process by pid file */
52
/* return 1 for success and 0 for a failure */
53
function sigkillbypid($pidfile, $sig) {
54
	if (is_file($pidfile)) {
55
		$pid = trim(file_get_contents($pidfile));
56
		if(isvalidpid($pid))
57
			return mwexec("/bin/kill -s $sig {$pid}", true);
58
	}
59
	return 0;
60
}
61

    
62
/* kill a process by name */
63
function sigkillbyname($procname, $sig) {
64
	if(isvalidproc($procname))
65
		return mwexec("/usr/bin/killall -{$sig} " . escapeshellarg($procname), true);
66
}
67

    
68
/* kill a process by name */
69
function killbyname($procname) {
70
	if(isvalidproc($procname))
71
		mwexec("/usr/bin/killall " . escapeshellarg($procname));
72
}
73

    
74
function is_module_loaded($module_name) {
75
	$running = `/sbin/kldstat | grep {$module_name} | /usr/bin/grep -v grep | /usr/bin/wc -l`;
76
	if (intval($running) >= 1)
77
		return true;
78
	else
79
		return false;
80
}
81

    
82
/* return the subnet address given a host address and a subnet bit count */
83
function gen_subnet($ipaddr, $bits) {
84
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
85
		return "";
86

    
87
	return long2ip(ip2long($ipaddr) & gen_subnet_mask_long($bits));
88
}
89

    
90
/* return the highest (broadcast) address in the subnet given a host address and a subnet bit count */
91
function gen_subnet_max($ipaddr, $bits) {
92
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
93
		return "";
94

    
95
	return long2ip(ip2long($ipaddr) | ~gen_subnet_mask_long($bits));
96
}
97

    
98
/* returns a subnet mask (long given a bit count) */
99
function gen_subnet_mask_long($bits) {
100
	$sm = 0;
101
	for ($i = 0; $i < $bits; $i++) {
102
		$sm >>= 1;
103
		$sm |= 0x80000000;
104
	}
105
	return $sm;
106
}
107

    
108
/* same as above but returns a string */
109
function gen_subnet_mask($bits) {
110
	return long2ip(gen_subnet_mask_long($bits));
111
}
112

    
113
function is_numericint($arg) {
114
	return (preg_match("/[^0-9]/", $arg) ? false : true);
115
}
116

    
117
/* returns true if $ipaddr is a valid dotted IPv4 address */
118
function is_ipaddr($ipaddr) {
119
	if (!is_string($ipaddr))
120
		return false;
121

    
122
	$ip_long = ip2long($ipaddr);
123
	$ip_reverse = long2ip($ip_long);
124

    
125
	if ($ipaddr == $ip_reverse)
126
		return true;
127
	else
128
		return false;
129
}
130

    
131
/* returns true if $ipaddr is a valid dotted IPv4 address or an alias thereof */
132
function is_ipaddroralias($ipaddr) {
133

    
134
	global $aliastable, $config;
135

    
136
	if(is_array($config['aliases']['alias'])) {
137
		foreach($config['aliases']['alias'] as $alias) {
138
			if($alias['name'] == $ipaddr)
139
				return true;
140
		}
141
	}
142

    
143
	if (isset($aliastable[$ipaddr]) && is_ipaddr($aliastable[$ipaddr]))
144
		return true;
145
	else
146
		return is_ipaddr($ipaddr);
147

    
148
}
149

    
150
/* returns true if $ipaddr is a valid dotted IPv4 address or any alias */
151
function is_ipaddroranyalias($ipaddr) {
152

    
153
	global $aliastable;
154

    
155
	if (isset($aliastable[$ipaddr]))
156
		return true;
157
	else
158
		return is_ipaddr($ipaddr);
159
}
160

    
161
/* returns true if $subnet is a valid subnet in CIDR format */
162
function is_subnet($subnet) {
163
	if (!is_string($subnet))
164
		return false;
165

    
166
	list($hp,$np) = explode('/', $subnet);
167

    
168
	if (!is_ipaddr($hp))
169
		return false;
170

    
171
	if (!is_numeric($np) || ($np < 1) || ($np > 32))
172
		return false;
173

    
174
	return true;
175
}
176

    
177
/* returns true if $subnet is a valid subnet in CIDR format or an alias thereof */
178
function is_subnetoralias($subnet) {
179

    
180
	global $aliastable;
181

    
182
	if (isset($aliastable[$subnet]) && is_subnet($aliastable[$subnet]))
183
		return true;
184
	else
185
		return is_subnet($subnet);
186
}
187

    
188
/* returns true if $hostname is a valid hostname */
189
function is_hostname($hostname) {
190
	if (!is_string($hostname))
191
		return false;
192

    
193
	if (preg_match("/^([_a-z0-9\-]+\.?)+$/i", $hostname))
194
		return true;
195
	else
196
		return false;
197
}
198

    
199
/* returns true if $domain is a valid domain name */
200
function is_domain($domain) {
201
	if (!is_string($domain))
202
		return false;
203

    
204
	if (preg_match("/^([a-z0-9\-]+\.?)+$/i", $domain))
205
		return true;
206
	else
207
		return false;
208
}
209

    
210
/* returns true if $uname is a valid DynDNS username */
211
function is_dyndns_username($uname) {
212
	if (!is_string($uname))
213
		return false;
214

    
215
	if (preg_match("/[^a-z0-9\-.@_]/i", $uname))
216
		return false;
217
	else
218
		return true;
219
}
220

    
221
/* returns true if $macaddr is a valid MAC address */
222
function is_macaddr($macaddr) {
223
	if (!is_string($macaddr))
224
		return false;
225

    
226
	$maca = explode(":", $macaddr);
227
	if (count($maca) != 6)
228
		return false;
229

    
230
	foreach ($maca as $macel) {
231
		if (($macel === "") || (strlen($macel) > 2))
232
			return false;
233
		if (preg_match("/[^0-9a-f]/i", $macel))
234
			return false;
235
	}
236

    
237
	return true;
238
}
239

    
240
/* returns true if $name is a valid name for an alias */
241
/* returns NULL if a reserved word is used */
242
function is_validaliasname($name) {
243
	/* Array of reserved words */
244
	$reserved = array("port", "pass");
245
	if (in_array($name, $reserved, true))
246
		return; /* return NULL */
247

    
248
	if (!preg_match("/[^a-zA-Z0-9_]/", $name))
249
		return true;
250
	else
251
		return false;
252
}
253

    
254
/* returns true if $port is a valid TCP/UDP port */
255
function is_port($port) {
256
	if (!is_numericint($port))
257
		return false;
258

    
259
	if (($port < 1) || ($port > 65535))
260
		return false;
261
	else
262
		return true;
263
}
264

    
265
/* returns true if $portrange is a valid TCP/UDP portrange ("<port>:<port>") */
266
function is_portrange($portrange) {
267
        $ports = explode(":", $portrange);
268

    
269
        if(count($ports) == 2 && is_port($ports[0]) && is_port($ports[1]))
270
                return true;
271
        else
272
                return false;
273
}
274

    
275
/* returns true if $val is a valid shaper bandwidth value */
276
function is_valid_shaperbw($val) {
277
	return (preg_match("/^(\d+(?:\.\d+)?)([MKG]?b|%)$/", $val));
278
}
279

    
280
/* return the configured interfaces list. */
281
function get_configured_interface_list($only_opt = false, $withdisabled = false) {
282
	global $config;
283

    
284
	$iflist = array();
285

    
286
	if (!$only_opt) {
287
		if (isset($config['interfaces']['wan']))
288
			$iflist['wan'] = "wan";
289
		if (isset($config['interfaces']['lan']))
290
			$iflist['lan'] = "lan";
291
	}
292

    
293
	/* if list */
294
        foreach($config['interfaces'] as $if => $ifdetail) {
295
		if ($if == "wan" || $if == "lan")
296
			continue;
297
		if (isset($ifdetail['enable']) || $withdisabled == true)
298
			$iflist[$if] = $if;
299
	}
300

    
301
	return $iflist;
302
}
303

    
304
/* return the configured interfaces list. */
305
function get_configured_interface_list_by_realif($only_opt = false, $withdisabled = false) {
306
        global $config;
307

    
308
        $iflist = array();
309

    
310
        if (!$only_opt) {
311
                if (isset($config['interfaces']['wan'])) {
312
			$tmpif = get_real_interface("wan");
313
			if (!empty($tmpif))
314
				$iflist[$tmpif] = "wan";
315
		}
316
                if (isset($config['interfaces']['lan'])) {
317
			$tmpif = get_real_interface("lan");
318
			if (!empty($tmpif))
319
				$iflist[$tmpif] = "lan";
320
		}
321
        }
322

    
323
        /* if list */
324
        foreach($config['interfaces'] as $if => $ifdetail) {
325
                if ($if == "wan" || $if == "lan")
326
                        continue;
327
                if (isset($ifdetail['enable']) || $withdisabled == true) {
328
			$tmpif = get_real_interface($if);
329
			if (!empty($tmpif))
330
				$iflist[$tmpif] = $if;
331
		}
332
        }
333

    
334
        return $iflist;
335
}
336

    
337
/* return the configured interfaces list with their description. */
338
function get_configured_interface_with_descr($only_opt = false, $withdisabled = false) {
339
        global $config;
340

    
341
        $iflist = array();
342

    
343
	if (!$only_opt) {
344
                if (isset($config['interfaces']['wan'])) {
345
			if (empty($config['interfaces']['wan']['descr']))
346
				$iflist['wan'] = "WAN";
347
			else
348
				$iflist['wan'] = $config['interfaces']['wan']['descr'];
349
		}
350
                if (isset($config['interfaces']['lan'])) {
351
			if (empty($config['interfaces']['lan']['descr']))
352
                                $iflist['lan'] = "LAN";
353
                        else
354
                                $iflist['lan'] = $config['interfaces']['lan']['descr'];
355
		}
356
        }
357

    
358
        /* if list */
359
        foreach($config['interfaces'] as $if => $ifdetail) {
360
		if (isset($ifdetail['enable']) || $withdisabled == true) {
361
			if($ifdetail['descr'] == "")
362
				$iflist[$if] = strtoupper($if);
363
                        else
364
				$iflist[$if] = strtoupper($ifdetail['descr']);
365
		}
366
	}
367

    
368
        return $iflist;
369
}
370

    
371

    
372
/*
373
 *   get_interface_list() - Return a list of all physical interfaces
374
 *   along with MAC and status.
375
 *
376
 *   $mode = "active" - use ifconfig -lu
377
 *           "media"  - use ifconfig to check physical connection
378
 *			status (much slower)
379
 */
380
function get_interface_list($mode = "active", $keyby = "physical", $vfaces = "") {
381
        global $config;
382
	$upints = array();
383
        /* get a list of virtual interface types */
384
        if(!$vfaces) {
385
		$vfaces = array (
386
				'bridge',
387
				'ppp',
388
				'sl',
389
				'gif',
390
				'gre',
391
				'faith',
392
				'lo',
393
				'ng',
394
				'vlan',
395
				'pflog',
396
				'pfsync',
397
				'enc',
398
				'tun',
399
				'carp',
400
				'lagg',
401
				'plip'
402
		);
403
	}
404
	switch($mode) {
405
	case "active":
406
                $upints = explode(" ", trim(shell_exec("/sbin/ifconfig -lu")));
407
        	break;
408
	case "media":
409
                $intlist = explode(" ", trim(shell_exec("/sbin/ifconfig -l")));
410
                $ifconfig = "";
411
                exec("/sbin/ifconfig -a", $ifconfig);
412
                $regexp = '/(' . implode('|', $intlist) . '):\s/';
413
                $ifstatus = preg_grep('/status:/', $ifconfig);
414
		foreach($ifstatus as $status) {
415
			$int = array_shift($intlist);
416
                	if(stristr($status, "active")) $upints[] = $int;
417
		}
418
		break;
419
	}
420
        /* build interface list with netstat */
421
        $linkinfo = "";
422
        exec("/usr/bin/netstat -inW -f link | awk '{ print $1, $4 }'", $linkinfo);
423
        array_shift($linkinfo);
424
	/* build ip address list with netstat */
425
	$ipinfo = "";
426
	exec("/usr/bin/netstat -inW -f inet | awk '{ print $1, $4 }'", $ipinfo);
427
	array_shift($ipinfo);
428
	foreach($linkinfo as $link) {
429
		$friendly = "";
430
                $alink = explode(" ", $link);
431
                $ifname = rtrim(trim($alink[0]), '*');
432
                /* trim out all numbers before checking for vfaces */
433
		if (!in_array(array_shift(preg_split('/\d/', $ifname)), $vfaces)) {
434
			$toput = array(
435
					"mac" => trim($alink[1]),
436
					"up" => in_array($ifname, $upints)
437
				);
438
			foreach($ipinfo as $ip) {
439
				$aip = explode(" ", $ip);
440
				if($aip[0] == $ifname) {
441
					$toput['ipaddr'] = $aip[1];
442
				}
443
			}
444
			foreach($config['interfaces'] as $name => $int) {
445
				if($int['if'] == $ifname) $friendly = $name;
446
			}
447
			switch($keyby) {
448
			case "physical":
449
				if($friendly != "") {
450
					$toput['friendly'] = $friendly;
451
				}
452
				$dmesg_arr = array();
453
				exec("/sbin/dmesg |grep $ifname | head -n1", $dmesg_arr);
454
				preg_match_all("/<(.*?)>/i", $dmesg_arr[0], $dmesg);
455
				$toput['dmesg'] = $dmesg[1][0];
456
				$iflist[$ifname] = $toput;
457
				break;
458
			case "friendly":
459
				if($friendly != "") {
460
					$toput['if'] = $ifname;
461
					$iflist[$friendly] = $toput;
462
				}
463
				break;
464
			}
465
                }
466
        }
467
        return $iflist;
468
}
469

    
470
/* wrapper for exec() */
471
function mwexec($command, $mute = false) {
472

    
473
	global $g;
474
	$oarr = array();
475
	$retval = 0;
476
	if ($g['debug']) {
477
		if (!$_SERVER['REMOTE_ADDR'])
478
			echo "mwexec(): $command\n";
479
		exec("$command 2>&1", $oarr, $retval);
480
	} else {
481
		exec("$command 2>&1", $oarr, $retval);
482
	}
483
	if(isset($config['system']['developerspew']))
484
                $mute = false;
485
	if(($retval <> 0) && ($mute === false)) {
486
		$output = implode(" ", $oarr);
487
		log_error("The command '$command' returned exit code '$retval', the output was '$output' ");
488
	}
489
	return $retval;
490
}
491

    
492
/* wrapper for exec() in background */
493
function mwexec_bg($command) {
494

    
495
	global $g;
496

    
497
	if ($g['debug']) {
498
		if (!$_SERVER['REMOTE_ADDR'])
499
			echo "mwexec(): $command\n";
500
	}
501

    
502
	exec("nohup $command > /dev/null 2>&1 &");
503
}
504

    
505
/* unlink a file, if it exists */
506
function unlink_if_exists($fn) {
507
	$to_do = glob($fn);
508
	if(is_array($to_do)) {
509
		foreach($to_do as $filename)
510
			@unlink($filename);
511
	} else {
512
		@unlink($fn);
513
	}
514
}
515
/* make a global alias table (for faster lookups) */
516
function alias_make_table($config) {
517

    
518
	global $aliastable;
519

    
520
	$aliastable = array();
521

    
522
	if (is_array($config['aliases']['alias'])) {
523
		foreach ($config['aliases']['alias'] as $alias) {
524
			if ($alias['name'])
525
				$aliastable[$alias['name']] = $alias['address'];
526
		}
527
	}
528
}
529
/* check if an alias exists */
530
function is_alias($name) {
531

    
532
	global $aliastable;
533

    
534
	return isset($aliastable[$name]);
535
}
536

    
537
function alias_expand_value($name) {
538

    
539
	global $aliastable, $config;
540
	$newaddress = "";
541
	$firstentry = true;
542
	if($config['aliases']['alias'])
543
		foreach($config['aliases']['alias'] as $alias) {
544
			if($alias['name'] == $name) {
545
				if($alias['type'] == "openvpn") {
546
					$vpn_address_split = split(" ", $alias['address']);
547
					foreach($vpn_address_split as $vpnsplit) {
548
						foreach($config['openvpn']['user'] as $openvpn) {
549
							if($openvpn['name'] == $vpnsplit) {
550
								if($firstentry == false) 
551
									$newaddress .= " ";
552
								$newaddress .= $openvpn['ip'];
553
								$firstentry = false;
554
							}
555
						}
556
					}
557
				} else {
558
					$newaddress = $alias['address'];
559
				}
560
			}
561
		}
562
		return $newaddress;
563
}
564

    
565
/* expand a host or network alias, if necessary */
566
function alias_expand($name) {
567

    
568
	global $aliastable;
569

    
570
	if (isset($aliastable[$name]))
571
		return "\${$name}";
572
	else if (is_ipaddr($name) || is_subnet($name))
573
		return "{$name}";
574
	else
575
		return null;
576
}
577

    
578
/* expand a host alias, if necessary */
579
function alias_expand_host($name) {
580
	global $aliastable;
581

    
582
	if (isset($aliastable[$name])) {
583
		$ip_arr = explode(" ", $aliastable[$name]);
584
		foreach($ip_arr as $ip) {
585
			if (!is_ipaddr($ip))
586
				return null;
587
		}
588
		return $aliastable[$name];
589
	} else if (is_ipaddr($name))
590
		return $name;
591
	else
592
		return null;
593
}
594

    
595
/* expand a network alias, if necessary */
596
function alias_expand_net($name) {
597

    
598
	global $aliastable;
599

    
600
	if (isset($aliastable[$name]) && is_subnet($aliastable[$name]))
601
		return $aliastable[$name];
602
	else if (is_subnet($name))
603
		return $name;
604
	else
605
		return null;
606
}
607

    
608
/* find out whether two subnets overlap */
609
function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2) {
610

    
611
	if (!is_numeric($bits1))
612
		$bits1 = 32;
613
	if (!is_numeric($bits2))
614
		$bits2 = 32;
615

    
616
	if ($bits1 < $bits2)
617
		$relbits = $bits1;
618
	else
619
		$relbits = $bits2;
620

    
621
	$sn1 = gen_subnet_mask_long($relbits) & ip2long($subnet1);
622
	$sn2 = gen_subnet_mask_long($relbits) & ip2long($subnet2);
623

    
624
	if ($sn1 == $sn2)
625
		return true;
626
	else
627
		return false;
628
}
629

    
630
/* compare two IP addresses */
631
function ipcmp($a, $b) {
632
	if (ip2long($a) < ip2long($b))
633
		return -1;
634
	else if (ip2long($a) > ip2long($b))
635
		return 1;
636
	else
637
		return 0;
638
}
639

    
640
/* return true if $addr is in $subnet, false if not */
641
function ip_in_subnet($addr,$subnet) {
642
	list($ip, $mask) = explode('/', $subnet);
643
	$mask = 0xffffffff << (32 - $mask);
644
	return ((ip2long($addr) & $mask) == (ip2long($ip) & $mask));
645
}
646

    
647
/* verify (and remove) the digital signature on a file - returns 0 if OK */
648
function verify_digital_signature($fname) {
649

    
650
	global $g;
651

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

    
654
}
655

    
656
/* obtain MAC address given an IP address by looking at the ARP table */
657
function arp_get_mac_by_ip($ip) {
658
	mwexec("/sbin/ping -c 1 -t 1 {$ip}");
659
	$arpoutput = "";
660
	exec("/usr/sbin/arp -n {$ip}", $arpoutput);
661

    
662
	if ($arpoutput[0]) {
663
		$arpi = explode(" ", $arpoutput[0]);
664
		$macaddr = $arpi[3];
665
		if (is_macaddr($macaddr))
666
			return $macaddr;
667
		else
668
			return false;
669
	}
670

    
671
	return false;
672
}
673

    
674
/* return a fieldname that is safe for xml usage */
675
function xml_safe_fieldname($fieldname) {
676
	$replace = array('/', '-', ' ', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
677
			 '_', '+', '=', '{', '}', '[', ']', '|', '/', '<', '>', '?',
678
			 ':', ',', '.', '\'', '\\'
679
		);
680
	return strtolower(str_replace($replace, "", $fieldname));
681
}
682

    
683
function mac_format($clientmac) {
684
    $mac =explode(":", $clientmac);
685

    
686
    global $config;
687

    
688
    $mac_format = $config['captiveportal']['radmac_format'] ? $config['captiveportal']['radmac_format'] : false;
689

    
690
    switch($mac_format) {
691

    
692
        case 'singledash':
693
        return "$mac[0]$mac[1]$mac[2]-$mac[3]$mac[4]$mac[5]";
694

    
695
        case 'ietf':
696
        return "$mac[0]-$mac[1]-$mac[2]-$mac[3]-$mac[4]-$mac[5]";
697

    
698
        case 'cisco':
699
        return "$mac[0]$mac[1].$mac[2]$mac[3].$mac[4]$mac[5]";
700

    
701
        case 'unformatted':
702
        return "$mac[0]$mac[1]$mac[2]$mac[3]$mac[4]$mac[5]";
703

    
704
        default:
705
        return $clientmac;
706
    }
707
}
708

    
709
function resolve_retry($hostname, $retries = 5) {
710

    
711
       if (is_ipaddr($hostname))
712
               return $hostname;
713

    
714
       for ($i = 0; $i < $retries; $i++) {
715
               $ip = gethostbyname($hostname);
716

    
717
               if ($ip && $ip != $hostname) {
718
                       /* success */
719
                       return $ip;
720
               }
721

    
722
               sleep(1);
723
       }
724

    
725
       return false;
726
}
727

    
728
function format_bytes($bytes) {
729
	if ($bytes >= 1073741824) {
730
		return sprintf("%.2f GB", $bytes/1073741824);
731
	} else if ($bytes >= 1048576) {
732
		return sprintf("%.2f MB", $bytes/1048576);
733
	} else if ($bytes >= 1024) {
734
		return sprintf("%.0f KB", $bytes/1024);
735
	} else {
736
		return sprintf("%d bytes", $bytes);
737
	}
738
}
739

    
740
?>
(34-34/40)