...

View Full Version : in_array bugging my code



Dubz
11-22-2011, 11:17 PM
I have this code here that i use for a chat bot. The problem is, the in_array part doesn't seem to be working correctly. I marked the lines with errors with a comment explaining the details of it.



<?php
//Details of the function:
/*
$contests stores the array of contests
$contests is stored as $contests[hostID] = details
$message is the message received
$contest[0] is the host
$contest[1] is the details

EX: $contest[test] = "This is a test contest";
"test" is the host and "This is a test contest" is the details
*/
function contestCommand($packet,$message,$type){
global $bot, $commandCode, $contest_MinRank;
$contests = $bot->getDB('contests');
$message = explode(' ',@$message[1],2);
switch($message[0]){
case 'add':
if(!$bot->minRank($packet['u'],$contest_MinRank)) return;
$contest = explode(' ',$message[1],2);
if(!$contest[0] || !$contest[1]) { $bot->respond("Usage: ".$commandCode."contest add [host] [details]",$type,$packet['u']); return;}
if(in_array($contest[0],$contests)) { $bot->respond("Only one contest per user!",$type,$packet['u']); return;}//The problem is the check to see if the contest is added or not.
$contests[$contest[0]] = $contest[1];
$bot->updateDB('contests',$contests);
$bot->respond("Contest added! (".$packet['u'].")",$type,$packet['u']);
break;
case 'remove':
if(!$bot->minRank($packet['u'],$contest_MinRank)) return;
$contest = explode(' ',$message[1],2);
if(!$contest) $bot->respond("Usage: ".$commandCode."contest remove [host]",$type,$packet['u']);
if(!in_array($contest[0],$contests)) { $bot->respond("No contest for this user!",$type,$packet['u']); return;}
$contests = array_diff($contests,array($contest[0]));//Doesn't remove properly. Plan on fixing later unless aswered here
$bot->updateDB('contests',$contests);
$bot->respond("Contest removed! (".$packet['u'].")",$type,$packet['u']);
break;
default:
foreach($contests as $host => $details){
$ua = $bot->getUserArray($host);
if($ua['registered']) $host==$ua['registered'];
$bot->sendPC($packet['u'],"[$host] - $details");
}
}
}
?>

Fou-Lu
11-23-2011, 12:55 AM
What is $message? The description leads me to believe that this is a string, but its being used as an array. Since you overwrite the $message within the function itself, its later uses would be an array potentially.

Either the in_array is wrong, or the assignment below is wrong. The assignment below indicates that $contest[0] is a key within the array with the value of $contest[1]. The in_array works for values, not for keys. If you want to detect a key existing, use either isset($array['key']) or use array_key_exists('key', $array). The former is faster, while the latter will return true for null values.
Similar issue to the array_diff, assuming its been associated. Use unset($array['key']) instead.

Dubz
11-23-2011, 01:26 AM
What is $message? The description leads me to believe that this is a string, but its being used as an array. Since you overwrite the $message within the function itself, its later uses would be an array potentially.

Either the in_array is wrong, or the assignment below is wrong. The assignment below indicates that $contest[0] is a key within the array with the value of $contest[1]. The in_array works for values, not for keys. If you want to detect a key existing, use either isset($array['key']) or use array_key_exists('key', $array). The former is faster, while the latter will return true for null values.
Similar issue to the array_diff, assuming its been associated. Use unset($array['key']) instead.

This script is for a chat bot.
before the function, $message is set to the message sent. then it is exploded into $message as $message[0] (the first word) and $message[1] (everything after). the first word indicates the command (which is the function) and runs it. while it is in the function, it takes the $message[1] of the initial message and explodes it again. now we have $message[0] as the second word of the message and $message[1] as everything else. the second word is used as a switch (to add or remove a contest or list for the default). if it hits a case, the $message[1] is exploded again into $contest which is set so the third word of the message is the host and everything else is the details of the contest.

Simplified, its like this:
First word: $message[0] -> (command)
Second word: $message[1]/$message[0](after explode) -> (switch)
Third word: $contest[0] -> (host)
Fourth+ word(s): $contest[1] -> (details)

The 'if(in_array' line for the add case is supposed to check if $contest[0] is already set in $contests and if so, do the action stated

The same for the remove case except it checks to see if it exists. If it doesn't, it tells the user that it never had one. If it does, it removes it.

Also with the unset part, an advanced php coding friend of mine who originally coded this bot told me to use array_diff and not unset because unset just clears the value of the memory while array_diff unallocates it after clearing it, freeing up space

tangoforce
11-23-2011, 02:42 AM
Also with the unset part, an advanced php coding friend of mine who originally coded this bot told me to use array_diff and not unset because unset just clears the value of the memory while array_diff unallocates it after clearing it, freeing up space

No, array_diff returns the difference between two arrays. It isn't intended for deleting parts of an array at all. Your advanced php friend should of pointed you to the php manual for an explanation.

Fou-Lu
11-23-2011, 03:37 AM
Also with the unset part, an advanced php coding friend of mine who originally coded this bot told me to use array_diff and not unset because unset just clears the value of the memory while array_diff unallocates it after clearing it, freeing up space

This can't be right. There is no way in PHP to force the freeing of memory at all (aside from C sourced extensions in which case we better be freeing it, but that said we emalloc anyway so PHP will kindly clean up after us :)). We can request it do so using unset or over-writing an assignment, but both of these will execute via efree from the garbage collection. Array_diff itself does nothing to free memory, and will actually consume additional pointers to the hashtable* buckets to generate a new list. PHP's copy-on-write optimizing will limit the size of the returned bucket to sizeof(zval*) * bucket size, but will certainly provide at minimum sizeof(zval). I would expect that both the assignment over top of a variable and unset effectively produce the same end result for memory freeing, but using a function like array_diff is guaranteed to consume more memory overall.

Still doesn't change what I have said. These lines conflict:


if(in_array($contest[0],$contests)) { $bot->respond("Only one contest per user!",$type,$packet['u']); return;}//The problem is the check to see if the contest is added or not.
$contests[$contest[0]] = $contest[1];


Lets say $contest[0] = 'test' and $contest[1] = 'this is a test'. $contests is an array of 'test' => 'this is a test'. Using in_array will seek the value of a result, so providing the above will return false since the only value available is 'this is a test'. The next line dictates that $contests is to be provided with a value of 'this is a test' with an associative index of 'test'. This is where the conflict is - you need to use either array_key_exists or isset instead of the in_array.
The same follows for array_diff. Either unset it instead, or use array_diff giving it the value (ie: $contest[1]) as the array to work with. Array_diff only cares about the values, not the keys (although you can force key checking as well using array_diff_assoc, but that will dictate both the key and the value must match).

Dubz
11-25-2011, 02:08 AM
This can't be right. There is no way in PHP to force the freeing of memory at all (aside from C sourced extensions in which case we better be freeing it, but that said we emalloc anyway so PHP will kindly clean up after us :)). We can request it do so using unset or over-writing an assignment, but both of these will execute via efree from the garbage collection. Array_diff itself does nothing to free memory, and will actually consume additional pointers to the hashtable* buckets to generate a new list. PHP's copy-on-write optimizing will limit the size of the returned bucket to sizeof(zval*) * bucket size, but will certainly provide at minimum sizeof(zval). I would expect that both the assignment over top of a variable and unset effectively produce the same end result for memory freeing, but using a function like array_diff is guaranteed to consume more memory overall.

Still doesn't change what I have said. These lines conflict:


if(in_array($contest[0],$contests)) { $bot->respond("Only one contest per user!",$type,$packet['u']); return;}//The problem is the check to see if the contest is added or not.
$contests[$contest[0]] = $contest[1];


Lets say $contest[0] = 'test' and $contest[1] = 'this is a test'. $contests is an array of 'test' => 'this is a test'. Using in_array will seek the value of a result, so providing the above will return false since the only value available is 'this is a test'. The next line dictates that $contests is to be provided with a value of 'this is a test' with an associative index of 'test'. This is where the conflict is - you need to use either array_key_exists or isset instead of the in_array.
The same follows for array_diff. Either unset it instead, or use array_diff giving it the value (ie: $contest[1]) as the array to work with. Array_diff only cares about the values, not the keys (although you can force key checking as well using array_diff_assoc, but that will dictate both the key and the value must match).

I used the array_key_exists instead of in_array and it works great now. i used unset too after i figured out because array_diff was just clearing the array. Thanks!

tangoforce
11-25-2011, 03:40 AM
i figured out because array_diff was just clearing the array.

No it wasn't even doing that. You still don't understand what it does. It compares TWO arrays and returns the DIFFERENCE between them as another array.

It doesn't clear or delete anything.



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum