Jump to content

[SOLVED] Kilobytes to MB with a loop


Bifter

Recommended Posts

Hi All,

 

I'm try to convert a number within a table from kilobytes into Mb's using the following code:

 

<?php
function kMGTB2($size2)
{
  $kB = 1024;
  $MB = $kB*1024;
  $GB = $MB*1024;
  $TB = $GB*1024;

  if($size2 < $MB)
    return (round($size2/$kB, 2)).' kB per Second';
  elseif($size2 < $GB)
    return (round($size2/$MB, 2)).' MB per Second';
  elseif($size2 < $TB)
    return (round($size2/$GB, 2)).' GB per Second';
  else
    return (round($size2/$TB, 2)).' TB per Second';
} 


foreach($list as $r)
{

echo "<tr>"."\n".$r[0].$r[1]."<td>".print_r(kMGTB2($size2))."</td><td>".$r[3]."</td><td>".$r[4]."</td>".$r[5].$r[6]."\n"."</tr>"."\n";
}

}
else
{
echo "<tr><td colspan='7'>No Data Found</td></tr>"."\n";
}
?>

 

But it returns:

 

0 kB per Second0 kB per Second0 kB per Second0 kB per Second0 kB per Second0 kB per Second0 kB per Second0 kB per Second0 kB per Second0 kB per Second0 kB per Second0 kB per Second0 kB per Second0 kB per Second0 kB per Second0 kB per Second0 kB per Second

above the table and 0 for every row.

 

I cannot figure this out - any help would be much appriaciated!!!

 

Thanks,

B.

Link to comment
Share on other sites

print_r() is used to "display information about a variable in a way that's readable by humans". You are using it with print_r(kMGTB2($size2)), so it is just outputting whatever is returned by your function and there is no point in using it in your posted code.

 

Where are you setting $size2 in the code before calling your kMGTB2() function each time in the loop? If you pass your function a zero value it will return a zero value, which is what you are getting as output.

Link to comment
Share on other sites

Try a bit of debugging statements on the function itself :

 

function kMGTB2($size2)
{
  $kB = 1024;
  $MB = $kB*1024;
  $GB = $MB*1024;
  $TB = $GB*1024;

  if($size2 < $MB) {
           $out = (round($size2/$kB, 2)).' kB per Second';
           echo 'we are in the first bit';
          }
  elseif($size2 < $GB) {
          $out = (round($size2/$MB, 2)).' MB per Second';
          echo 'we are in the second bit';
          }
  elseif($size2 < $TB) {
          $out = (round($size2/$GB, 2)).' GB per Second';
          echo 'we are in the third bit';
          }
  else  {
          $out = (round($size2/$TB, 2)).' TB per Second';
          echo 'we are in the last bit';
          }

return $out;
} 

Link to comment
Share on other sites

I once wrote this function that you can use:

 

<?php
/**
* Converts a size in bytes to a human readable size using appropriate units.
*
* @param int $bytes The number of bytes
* @param int $precision Floating point output precision
* @param bool $si Use SI prefixes (kB, MB, etc.) or IEC prefixes (KiB, MiB, etc.)
* @return string
* @author Daniel Egeberg <daniel.egeberg@gmail.com>
*/
function humanReadableSize($bytes, $precision = 2, $si = false)
{
if (!$si) {
	$units = array('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB');
}
else {
	$units = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
}

$unitSize = $si ? 1000 : 1024;

if ($bytes == 0) { // logarithms are only defined for positive real numbers
	$x = 0;
}
else if ($bytes < 0) {
	throw new OutOfRangeException('You cannot have negative sizes.');
}
else {
	$x = (int) log($bytes, $unitSize);
}

if (!isset($units[$x])) { // we ran out of units
	$x = sizeof($units)-1;
}

if ($x == 0 || $precision < 0) { // a float byte size isn't possible
	$precision = 0;
}

return sprintf(
	'%.' . intval($precision) . 'f %s',
	$bytes / pow($unitSize, $x),
	$units[$x]
);
}

echo humanReadableSize(123456789); // 117.74 MiB

Link to comment
Share on other sites

alternatively

<?php
    function byteConvert($bytes)
    {
        $s = array('B', 'Kb', 'MB', 'GB', 'TB', 'PB');
        $e = floor(log($bytes)/log(1024));
     
        return sprintf('%.2f '.$s[$e], ($bytes/pow(1024, floor($e))));
    }
?>

(and as anyone who knows my awesome math skills knows as well.. I didn't write that, last comment on http://php.net/log ;))

Link to comment
Share on other sites

alternatively

...

(and as anyone who knows my awesome math skills knows as well.. I didn't write that, last comment on http://php.net/log ;))

 

echo byteConvert(-1);
// Warning: Division by zero in file.php on line 7
// 0.00 B

echo byteConvert(0);
// Warning: Division by zero in file.php on line 7
// 0.00 B

echo byteConvert(pow(1024,10));
// Notice: Undefined offset: 10 in file.php on line 7
// 1.00 

 

echo humanReadableSize(-1);
// Fatal error: Uncaught exception 'OutOfRangeException' with message 'You cannot have negative sizes.'

echo humanReadableSize(0);
// 0 B

echo humanReadableSize(pow(1024,10));
// 1048576.00 YiB

 

Mine is better. It does bounds checks and throws exceptions on invalid values.

 

 

 

As long as PHP version 4.3 or higher is being used the following can be used;

 

$e = floor(log($bytes, 1024);

 

instead of;

 

$e = floor(log($bytes)/log(1024));

 

See my function two posts up.

Link to comment
Share on other sites

I prefer something quite a bit smaller

<?php
function ByteSize($size)
{
static $unit = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
$idx=0;
$mult=1;
while($size>$mult*1024) { $idx++;$mult*=1024; }
return number_format(($size/$mult),2).$unit[$idx];
}

$val=123456789;
echo "{$val} = ".ByteSize($val);
?>

 

Although yers has a lot of validation, I rarely ever use validation in these routines just because they are delegated by other routines, filesize/speed.

 

Note: I do love that routine by Axeia though, but rarely use sprintf in my coding as string expressions are already built into php. So a mix of that and this would work well.

 

Link to comment
Share on other sites

As long as PHP version 4.3 or higher is being used the following can be used;

 

$e = floor(log($bytes, 1024);

 

instead of;

 

$e = floor(log($bytes)/log(1024));

 

See my function two posts up.

 

See, just like that, told you it could be done  :P

 

Although yers has a lot of validation, I rarely ever use validation in these routines just because they are delegated by other routines, filesize/speed.

 

I'd have to agree with Daniel. What you've just said is that you're relying on the validation of one process so that you can ignore the validation of another. Surely it would be a more robust and adaptable system if you validated both processes (whatever they may be), which will in future allow them to be executed seperate from each other without the risk of uncaught failure.

Link to comment
Share on other sites

As long as the OP feeds a nonexistent value into any function, he will get a zero out. Garbage out = garbage in. The issue is not necessarily what the function code is but what data it is being given when it is called (assuming the original function code does something.)

Link to comment
Share on other sites

I prefer something quite a bit smaller

...

 

Although yers has a lot of validation, I rarely ever use validation in these routines just because they are delegated by other routines, filesize/speed.

 

Note: I do love that routine by Axeia though, but rarely use sprintf in my coding as string expressions are already built into php. So a mix of that and this would work well.

 

 

Though of course you forget to do a bounds check and will result in incorrect output with too large values.

 

It also does 1,024MB instead of 1GB. I suppose that's just a matter of preference though...

 

Do note that fewer lines != better code. I could cut off many lines from my code if I removed comments, used ternary operators, reduced the return sprintf to 1 line instead of 5 lines, etc.

 

function humanReadableSize($bytes, $precision = 2, $si = false)
{
$units = $si ? array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB') : array('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB');
$unitSize = $si ? 1000 : 1024;
if ($bytes < 0) throw new OutOfRangeException('You cannot have negative sizes.');
$x = $bytes == 0 ? 0 : (int) log($bytes, $unitSize);
if (!isset($units[$x])) $x = sizeof($units)-1;
if ($x == 0 || $precision < 0) $precision = 0;
return sprintf('%.' . intval($precision) . 'f %s', $bytes / pow($unitSize, $x), $units[$x]);
}

I find the former version much more readable though.

 

As long as the OP feeds a nonexistent value into any function, he will get a zero out. Garbage out = garbage in. The issue is not necessarily what the function code is but what data it is being given when it is called (assuming the original function code does something.)

 

Indeed. I'm sorry I hijacked the thread :P

Link to comment
Share on other sites

Thanks for the responses.

 

If

<?php echo $r[2] ."<br />"; ?> 

is used then the following is outputed:

 

524288

1048576

2097152

524288

1048576

2097152

6656000

6656000

6656000

6656000

524288

6656000

6656000

6656000

6656000

6656000

6656000

 

If im not to use print_r what should it be?

Link to comment
Share on other sites

'd have to agree with Daniel. What you've just said is that you're relying on the validation of one process so that you can ignore the validation of another. Surely it would be a more robust and adaptable system if you validated both processes (whatever they may be), which will in future allow them to be executed seperate from each other without the risk of uncaught failure.

Report to moderator  Logged

 

Yes, I rely on filesize to always return a positive whole number, Otherwise I wud write my own instead of using the php function

or that in speed calculations also return a whole positive number.

 

Validation isnt necessary when u already know the bounds of a function.

U know that filesize will never return < 0 or a float for a bytesize count, so u go with that.

 

It wud be silly to write code like

if(($fsize=filesize('about.txt'))==NULL || $fsize<0 || $fsize!=abs($fsize))
  die('error');

 

because u want to validate the value first.

 

anyways, a mix of my routine and one posted by Aexia results in this, its nice and does the job

function ByteSize($size)
{
    static $unit = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
    $size/=(pow(1024,($idx=floor(log($size)/log(1024)))));
    return number_format($size,2).$unit[$idx];
}

Link to comment
Share on other sites

If $r[2] contains the value you want to pass through your function, shouldn't that be the variable you put into the function call? You have kMGTB2($size2) now.

 

As to the use of print_r(). Your function returns the string you want to display, just use your function call without print_r in your echo statement.

Link to comment
Share on other sites

echo "<tr>"."\n".$r[0].$r[1]."<td>".kMGTB2($size2)."</td><td>".$r[3]."</td><td>".$r[4]."</td>".$r[5].$r[6]."\n"."</tr>"."\n";

 

print_r returns a string of the string/array sent to it. primarily for debugging.

the use of print_r is redundant in this situation, as u know u are dealing with only strings from yer function.

 

Link to comment
Share on other sites

[snip]

 

That's not what I meant with bounds checking. Try to do e.g. ByteSize(pow(1024, 10)) to see what I mean. Moreover, try to do ByteSize(0), which is a valid size that could be returned by e.g. filesize. As I documented in the first function I posted, logarithms are only defined for positive real numbers. Good code will never

 

Again, fewer lines != better code. As a matter of fact, if you use unit testing and code coverage you will artificially increase the code coverage percentage if you cram as much as possible into one line, which makes it more difficult to determine the quality of your testing. That's not to say that more lines leads to better code though. Another important factor is readability and maintainability. If more lines and/or whitespace leads to more readable code then it is much better.

 

It wud be silly to write code like

if(($fsize=filesize('about.txt'))==NULL || $fsize<0 || $fsize!=abs($fsize))
  die('error');

 

because u want to validate the value first.

 

Maybe, maybe not. This:

filesize('T:\os_images\windows7_7100.0.090421-1700_x64fre_client_en-us_retail_ultimate-grc1culxfrer_en_dvd.iso')

outputs -1024139264 on my computer. This is because it overflows the range of a signed integer which is what PHP by default operates with.

 

Another issue is portability. The system you've written may well have checked the size before passing it to a function, but that makes a stronger coupling with that function and your other code, which makes it less portable. By making it do its own job of validating input you're making it more portable and secure.

 

This isn't a concept that should be foreign to you. If you ask the user for his phone number, don't you check that it only contains digits and return an error if not? How about checking if the birth day they enter is a valid date? Surely your users are smart enough to only pass the input you expect, so things like protecting yourself again SQL injections is completely redundant.

 

A function should always be self-contained and not assume anything about its input.

Link to comment
Share on other sites

It's documented in the manual:

Note:  Because PHP's integer type is signed and many platforms use 32bit integers, filesize() may return unexpected results for files which are larger than 2GB. For files between 2GB and 4GB in size this can usually be overcome by using sprintf("%u", filesize($file)).

 

On this very cool place called the manual there are also some nice people who have researched stuff for you, and you would find out that you can get the size like this:

 

function getSize($file)
{
$size = filesize($file);

if ($size < 0) {
	if (strtoupper(substr(PHP_OS, 0, 3)) != 'WIN') {
		return trim(exec('stat -c%s ' . escapeshellarg($file)));
	}
	else {
		return exec('FOR %A IN (' . escapeshellarg($file) . ') DO @ECHO %~zA');
	}
}

return $size;
}

 

But this is entirely not the point. The point is that you shouldn't make any assumptions about the input and just blindly use it that way.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.