Bifter Posted June 1, 2009 Share Posted June 1, 2009 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. Quote Link to comment https://forums.phpfreaks.com/topic/160480-solved-kilobytes-to-mb-with-a-loop/ Share on other sites More sharing options...
lonewolf217 Posted June 1, 2009 Share Posted June 1, 2009 echo what you are receiving for $size2 to make sure you are getting the right information into the function Quote Link to comment https://forums.phpfreaks.com/topic/160480-solved-kilobytes-to-mb-with-a-loop/#findComment-846865 Share on other sites More sharing options...
PFMaBiSmAd Posted June 1, 2009 Share Posted June 1, 2009 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. Quote Link to comment https://forums.phpfreaks.com/topic/160480-solved-kilobytes-to-mb-with-a-loop/#findComment-846876 Share on other sites More sharing options...
grissom Posted June 1, 2009 Share Posted June 1, 2009 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; } Quote Link to comment https://forums.phpfreaks.com/topic/160480-solved-kilobytes-to-mb-with-a-loop/#findComment-846879 Share on other sites More sharing options...
Daniel0 Posted June 1, 2009 Share Posted June 1, 2009 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 <[email protected]> */ 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 Quote Link to comment https://forums.phpfreaks.com/topic/160480-solved-kilobytes-to-mb-with-a-loop/#findComment-846916 Share on other sites More sharing options...
Axeia Posted June 1, 2009 Share Posted June 1, 2009 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 ) Quote Link to comment https://forums.phpfreaks.com/topic/160480-solved-kilobytes-to-mb-with-a-loop/#findComment-846928 Share on other sites More sharing options...
gevans Posted June 1, 2009 Share Posted June 1, 2009 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)); Quote Link to comment https://forums.phpfreaks.com/topic/160480-solved-kilobytes-to-mb-with-a-loop/#findComment-846930 Share on other sites More sharing options...
Daniel0 Posted June 1, 2009 Share Posted June 1, 2009 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. Quote Link to comment https://forums.phpfreaks.com/topic/160480-solved-kilobytes-to-mb-with-a-loop/#findComment-846932 Share on other sites More sharing options...
laffin Posted June 1, 2009 Share Posted June 1, 2009 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. Quote Link to comment https://forums.phpfreaks.com/topic/160480-solved-kilobytes-to-mb-with-a-loop/#findComment-846933 Share on other sites More sharing options...
gevans Posted June 1, 2009 Share Posted June 1, 2009 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 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. Quote Link to comment https://forums.phpfreaks.com/topic/160480-solved-kilobytes-to-mb-with-a-loop/#findComment-846938 Share on other sites More sharing options...
PFMaBiSmAd Posted June 1, 2009 Share Posted June 1, 2009 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.) Quote Link to comment https://forums.phpfreaks.com/topic/160480-solved-kilobytes-to-mb-with-a-loop/#findComment-846940 Share on other sites More sharing options...
Daniel0 Posted June 1, 2009 Share Posted June 1, 2009 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 Quote Link to comment https://forums.phpfreaks.com/topic/160480-solved-kilobytes-to-mb-with-a-loop/#findComment-846944 Share on other sites More sharing options...
Bifter Posted June 1, 2009 Author Share Posted June 1, 2009 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? Quote Link to comment https://forums.phpfreaks.com/topic/160480-solved-kilobytes-to-mb-with-a-loop/#findComment-846952 Share on other sites More sharing options...
laffin Posted June 1, 2009 Share Posted June 1, 2009 '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]; } Quote Link to comment https://forums.phpfreaks.com/topic/160480-solved-kilobytes-to-mb-with-a-loop/#findComment-846954 Share on other sites More sharing options...
PFMaBiSmAd Posted June 1, 2009 Share Posted June 1, 2009 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. Quote Link to comment https://forums.phpfreaks.com/topic/160480-solved-kilobytes-to-mb-with-a-loop/#findComment-846958 Share on other sites More sharing options...
laffin Posted June 1, 2009 Share Posted June 1, 2009 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. Quote Link to comment https://forums.phpfreaks.com/topic/160480-solved-kilobytes-to-mb-with-a-loop/#findComment-846966 Share on other sites More sharing options...
Daniel0 Posted June 1, 2009 Share Posted June 1, 2009 [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. Quote Link to comment https://forums.phpfreaks.com/topic/160480-solved-kilobytes-to-mb-with-a-loop/#findComment-847029 Share on other sites More sharing options...
laffin Posted June 1, 2009 Share Posted June 1, 2009 So yer saying I should question the fuinction library of php. Than wut use is the function library of php, if I have to second guess its output? Quote Link to comment https://forums.phpfreaks.com/topic/160480-solved-kilobytes-to-mb-with-a-loop/#findComment-847041 Share on other sites More sharing options...
Daniel0 Posted June 1, 2009 Share Posted June 1, 2009 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. Quote Link to comment https://forums.phpfreaks.com/topic/160480-solved-kilobytes-to-mb-with-a-loop/#findComment-847060 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.