Weird pow() php bug - php

I have this piece of php code:
$skill_amount = round(pow($rarity,1.25));
It should be noted that $rarity is derived from a query.
I am inputting values like 0,2,4,8,16,32,64 into it.
99% of the time it is working but a small amount of times my users are reporting huge values like:
13771, 77936
What could possibly be causing this?

"What could possibly be causing this?"
A large or unexpected value for $rarity.
If you can inspect all possible values of $rarity, you should do that. Otherwise, you could do some basic debugging.
if ($skill_amount > some sane value) {
// log $skill_amount & $rarity to a file or email
// maybe also some other investigative values, like stuff that assisted the derivation of $rarity
}

No trouble found in this script, so I would agree with the need for sanity checks on $rarity.
<?php // RAY_temp_amy_neville.php
error_reporting(E_ALL);
echo '<pre>';
$range = range(1, 4096);
foreach ($range as $rarity)
{
$skill_amount = round(pow($rarity,1.25));
$out[$rarity] = $skill_amount;
}
print_r($out);

Related

n factorial issue with large number

I have written the following code for finding n!. I am running this through CLI.
<?php
$handle = fopen("php://stdin", "r");
$number = (int) trim(fgets($handle));
$fact = calcFactorial($number);
echo $fact . "\n";
function calcFactorial($number) {
if ($number < 2) {
return 1;
} else {
return $number * calcFactorial($number - 1);
}
}
fclose($handle);
?>
The above code is working fine. But there are two issues with two different PHP installations.
On one PC I get,
Fatal error: Maximum function nesting level of '100' reached,
aborting!
To correct above problem I find the solution here. Is this the correct way to have a solution? Because it depends on a particular Default Value of 'xdebug.max_nesting_level' .
On other PC I get,
INF
So what is the best approach to tackle this issue?
P.S.: I have gone through various solutions throughout this website but I am not able to conclude.
UPDATE: There is one function suggested. But can it be done without using any kind of function?
Nesting limit:
if the calcFactorial() can by non-recursive then you can change it to this:
function calcFactorial($number){
if($number<2){
return 1;
}
$ret = 1;
for($i=2;$i<=$number;$i++){
$ret = $ret*$i;
}
return $ret;
}
if has to be recursive you never be able to calc factorial of number bigger then Maximum function nesting level.
INF:
That means PHP thinks number is infinitive (to big to store in memory) ... i think (not sure) that answer is bigger than PHP_INT_MAX ...
You can confirm this by echo is_infinite($number);
you can try solve this with storing numbers as strings (of digits) or arrays (of digits) and than write some function to make multiplication of this strings (arrays) but it is not easy to do

php foreach in foreach looping

I want to extrect all usernames and passwords each from his file and output it nicely.
I wrote a code on my appserv 2.5.1 on my computer but only the last loop gave the username output.
Tested the code on other machines and it worked perfectly.
Dont know what is the problem ...
usernames.txt content :
user1
user2
user3
passwords.txt content :
pass1
pass2
pass3
script content :
$usernames = explode("\n", file_get_contents("usernames.txt"));
$passwords = explode("\n", file_get_contents("passwords.txt"));
foreach( $usernames as $username )
{
foreach( $passwords as $password )
{
echo $username.":".$password."\n";
}
}
output :
:pass1
:pass2
:pass3
:pass1
:pass2
:pass3
user3:pass1
user3:pass2
user3:pass3
for ($i=0;$i<count($usernames) && $i<count($password); $i++) {
echo $usernames[$i].':'.$passwords[$i];
}
But $password[x] must be related to $usernames[x]
There's always those that will say you don't need it (and you often don't) but I tend to use regular expressions whenever I'm parsing these kind of flat files - there's always some quirky character, extra line-break or difference that finds it's way into a text file - be it from transferring servers, restoring backups or simply user-interference. You could also make use of array_combine in this situation if you'd prefer to carrying on using a foreach loop - I know some folks prefer it for readability.
preg_match_all('/\w+/m', file_get_contents('usernames.txt'), $usernames);
preg_match_all('/\w+/m', file_get_contents('passwords.txt'), $passwords);
if(count($usernames[0]) !== count($passwords[0]))
die('Computer says: mismatch!'); // some resemblance of error handling...
$result = array_combine($usernames[0], $passwords[0]);
foreach($result as $name => $pass)
echo "{$name}:{$pass}\n";
demo
After debugging with the post author, I guessed that the problem was with the line return character. Using a \r\n fixed the problem:
$usernames = explode("\n\r", file_get_contents("usernames.txt"));
$passwords = explode("\n\r", file_get_contents("passwords.txt"));
For reference, please note that it is very important not to assume your input data is right. If you see that something is wrong and it points obviously to a mistake you made previously (in that case it is clearly not the foreach function that is buggy, but the array), then you need to swallow your pride and debug your own code. I have been programming PHP for 10 years, and I still have to remember that every single day.

Am I bloating my coding with IF statements?

I was wondering, do too many IF statements bloat coding and when is it okay not to use them?
These two examples both work the same and I'm the only one editing / using the script. Am I teaching myself bad habits by not adding the IF statement?
if ($en['mm_place']) {
$tmp = explode(",", $en['mm_place']);
$en['mm_place'] = $tmp[0].", ".$tmp[1]." ".$tmp[2];
}
is the same as...
$tmp = explode(",", $en['mm_place']);
$en['mm_place'] = $tmp[0].", ".$tmp[1]." ".$tmp[2];
EDIT: using #Francis Avila example I came up with this...
if ($en['mm_wmeet']) {
$tmp = explode(",", $en['mm_wmeet']);
for ($i = 0; $i < count($tmp); $i++) {
$en['mm_wmeet'] = $tmp[$i];
}
}
In this particular example, they are not the same.
If $en['mm_place'] is empty, then $tmp will not have three elements, so your string construction will be bogus.
Actually what you need is probably this:
if (!empty($en['mm_place'])) { // depending on whether you know if this is set and must be a string.
$tmp = explode(',', $en['mm_place'], 3);
if (count($tmp)===3) {
$en['mm_place'] = "{$tmp[0]}, {$tmp[1]} {$tmp[2]}";
}
}
Run PHP with E_NOTICE set, and code in such a way that you don't get any notices. PHP requires an extraordinary amount of discipline to use safely and properly because it has so many sloppy misfeatures. Notices will inform you of most bad practices. You will probably end up using lots of if statements.
if they don't serve any purpose then yes, you're bloating.
In this kind of situation, where you are checking if an array element exists before operating on it, you should keep the if-statement in the code. Here it will only throw a notice if the element is missing, but in the future you definitely could have similar code that will crash if the element is not set.
Edit: Actually those two code samples are not the same. if $en['mm_place'] is null or not set, the first sample will leave it as such while the second will replace it with ", "

PHP json_encode a debug_backtrace() with resource types

Currently, I have a logger which logs errors together with a backtrace.
The logger serializes the backtrace to JSON via json_encode().
Let's look at some hypothetical code...
<?php
error_reporting(-1); // show all errors
function test($b){
echo json_encode(debug_backtrace()); // take a backtrace snapshot
}
$c = imagecreate(50,50); // create a resource...
test($c); // ...and pass to function
?>
If you run the code above, we will see something like:
Warning: json_encode() [function.json-encode]: type is unsupported, encoded as null in /code/ch6gVw on line 5
[{"file":"/code/ch6gVw","line":8,"function":"test","args":[null]}]
We can notice two things going on here:
The logger itself is causing a warning! Bad bad bad!
The logged data tells us we passed a null to the function?!?!
So, my proposed solution is something like:
foreach($trace as $i=>$v)
if(is_resource($v))
$trace[$i] = (string)$v.' ('.get_resource_type($v).')';
The result would look like Resource id #1 (gd)
This, however, may cause some grave issues.
We need to somehow track which arrays we looped through so as to avoid ending up in infinite loops with arrays referencing themselves ($GLOBALS tend to cause this mess).
We would also have to convert resources of object properties, but objects, unlike arrays, are not a copy of the original thing, hence changing the property changes the live object. On the other hand, how safe is it to clone() the object?
Won't such a loop severely slow down the server (backtraces tend to be large, no)?
I ended up with the following function:
function clean_trace($branch){
if(is_object($branch)){
// object
$props = array();
$branch = clone($branch); // doesn't clone cause some issues?
foreach($props as $k=>$v)
$branch->$k = clean_trace($v);
}elseif(is_array($branch)){
// array
foreach($branch as $k=>$v)
$branch[$k] = clean_trace($v);
}elseif(is_resource($branch)){
// resource
$branch = (string)$branch.' ('.get_resource_type($branch).')';
}elseif(is_string($branch)){
// string (ensure it is UTF-8, see: https://bugs.php.net/bug.php?id=47130)
$branch = utf8_encode($branch);
}
// other (hopefully serializable) stuff
return $branch;
}
You can see it in action here. However, I'm not convinced:
It is quite slow (iterating over lots of data)
It is quite memory intensive (data needs to be copied to not mess the original)
It is not safe in case where arrays/objects reference themselves
Example: $a = array(); $a['ref'] = &$a; (PHP does this to some internal variables)
I'm concerned that cloning objects may have some serious side-effects (consider the magic method __clone(), an invitation to wreck havoc).
So you are trying to store the backtrace as a data structure that can be used to pretty-print the results later on?
If that isn't needed I'd just store $result = print_r(debug_backtrace(), true) and be done with it.
If not my first shot would be something like:
<?php
error_reporting(-1);
function test($b){
echo json_encode(clean(debug_backtrace()));
}
$c = fopen("/tmp/foo", "w");
test($c);
function clean($trace) {
array_walk_recursive($trace, function(&$element) {
if(is_object(&$element)) {
// work around unrealizable elements and preserve typing
$element = array(get_class($element), (object)$element);
} else if(is_resource($element)) {
$element = get_resource_type($element) . '#' .(int)$element;
}
});
return $trace;
}
It's just a rough sketch but I'm not aware of any project that stores backtracks for later inspection in a non textual or already processed format and looking around the mature frameworks didn't bring anything up

Script dies, I'm not sure why

I'm trying to parse a 6,000 line 500 KB file into an array so I can import the data into our system. The problem is that the script stops executing somewhere between lines 3000-4000. There are no breaks in the code, we use it on other imports. Any ideas on why this might be happening and what I can do to prevent it?
/**
* Takes a seperated value string and makes it an array
* #param $delimiter string The delimiter to be seperated by, usually a comma or tab
* #param $string string The string to seperate
* #return array The resulting array
*/
public function svToArray ($delimiter, $string) {
$x = 0;
$rowList = array();
$splitContent = preg_split("#\n+#", trim($string));
foreach ($splitContent as $key => $value) {
$newData = preg_split("#".$delimiter."#", $value);
if ($x == 0) {
$headerValues = array_values($newData);
} else {
$tempRow = array();
foreach ($newData as $rowColumnKey => $rowColumnValue) {
$tempRow[$headerValues[$rowColumnKey]] = $rowColumnValue;
}
$rowList[] = $tempRow;
}
$x++;
}
return $rowList;
}
UPDATE:
Error reporting is enabled. I've started using a file that's only 130KB at 1,500 lines and it does the same thing...
When I add debug code as in the following example nothing echoes at all unless I put an exit after the echo "test<br/>";
public function svToArray ($delimiter, $string) {
$x = 0;
$rowList = array();
$splitContent = preg_split("#\n+#", trim($string));
echo "test<br/>";
foreach ($splitContent as $key => $value) {
$newData = preg_split("#".$delimiter."#", $value);
if ($x == 0) {
$headerValues = array_values($newData);
} else {
$tempRow = array();
foreach ($newData as $rowColumnKey => $rowColumnValue) {
$tempRow[$headerValues[$rowColumnKey]] = $rowColumnValue;
}
$rowList[] = $tempRow;
}
$x++;
}
echo "test";
$this->tru->debug($rowList);
exit;
return $rowList;
}
UPDATE
If I comment out $tempRow[] = $rowColumnValue; then it echoes everything fine....
Probably it just timeouts. Does it always stop after X seconds?
Try setting the max execution time higher: set_time_limit(900) at the top of your pages.
You can check the max execution time in your phpinfo():
1. Create a new php page with
2. Search for max_execution_time
Have you looked at the files? Is there a line with too many delimiters? Also, what are all the "#" about?
My best guess is that you're hitting a line where $headerValues[$rowColumnKey] is not defined.
What about $rowColumnKey and $rowColumnValue ?
They are not defined in the function.
Make sure that you have error reporting set, put this on top of your php file:
ini_set('display_errors', true);
error_reporting(E_ALL);
Also you can extend the script's execution time:
ini_set('max_execution_time', 50000);
About the only time I've a php script die, with no output and no errors is when it runs out of memory. It doesn't look like your script would use much memory, but I would check to make sure that the memory limit for php is high enough.
Are you sure that you are iterating through the returned array instead of simply trying to print it? (The issue may be outside of the function rather than within it.)
Also...
`exit;
return $rowList;`
Try removing the 'exit;' line and see if that changes anything.
Also, $splitContent is not defined as an array before being used, but preg_split is going to return an array. (This should not impact your results, but it is safe to do so.)
Why are you using $key => $value pairs when you cannot be sure of what will be within the string? If we could see an small example of the content of $string, we might be able to adjust this function to work better.
The # should be replaced with /, but that may simply be a formatting issue.
$newData should be defined as an array before being used just to be safe even though that is not causing your issue.
If you can, increase maximum execution time in php.ini.. also increase the maximum memory amount for each instance.. checking error logs of your webserver could also help.
It appears as though there was too much output to the output buffer, causing the page to show nothing at all.

Categories