I'm trying to write a piece of code that checks a users stats, be that their points, rank or num_friends and in turn awards them a badge similar to that used in SO. The system is set so when a task (vote up, comment, etc.) is completed by a user, their user_id is recorded and queued to be evaluated at 5 min intervals by a cron job. Is this the most efficient way of doing this? I saw the other post about badges but am not sure if this is the method that was selected as the preferred way.
Another question I have is about actually checking these variables (points, rank, num_friends) against the user. I have a number of badges and want to allow admins to add their own where they select a variable, the operator (==, >=, etc.) and the value it's set to. How do I evaluate that in an IF conditional statement? I tried using SWITCH for the operators but can't get the variables to be evaluated correctly, like:
function checkbadges($userid,$points,$rank,$friends){
global $database;
$q = $database->db_query("SELECT * FROM badges");
while($bq = $database->db_fetch_assoc($q)) {
switch($bq[badge_sign]) {
case "1":
if($bq[badge_var] == $bq[badge_value])
givebadge($userid, $bq[badge_id]);
break;
case "2":
if($bq[badge_var] >= $bq[badge_value]))
givebadge($userid, $bq[badge_id]);
break;
case "3":
if($bq[badge_var] <= $bq[badge_value]))
givebadge($userid, $bq[badge_id]);
break;
case "4":
if($bq[badge_var] != $bq[badge_value]))
givebadge($userid, $bq[badge_id]);
break;
}
}
}
I think I have to use eval() but I'm not sure how, any help would be appreciated!
If $bq['badge_var'] is a string which is a valid variable name in the current scope, you can just do this:
$value = ${ $bq['badge_var'] };
It might be safer and easier to extend if you pass an array to checkbadges() instead:
function checkbadges($userid,$userdata){
global $database;
$q = $database->db_query("SELECT * FROM badges");
while($bq = $database->db_fetch_assoc($q)) {
$currentValue = $userdata[ $db['badge_var'] ];
$requiredValue = $db['badge_value'];
$issueBadge = false;
switch($bq['badge_sign']) {
case "1":
$issueBadge = ( $currentValue == $requiredValue );
break;
case "2":
$issueBadge = ( $currentValue >= $requiredValue );
break;
case "3":
$issueBadge = ( $currentValue <= $requiredValue );
break;
case "4":
$issueBadge = ( $currentValue != $requiredValue );
break;
}
if ($issueBadge) {
givebadge($userid, $bq['badge_id']);
}
}
}
where $userdata is something like this:
array( 'points' => 1 , 'friends' => 10, 'rank' => 10 );
You can then extend the available variables without modifying the function
Which is the expected value and the observed value of the variable you are not getting the right value for?
Additionally, its better practice to use:
$arr['key']
instead of
$arr[key]
as PHP will evaluate it first as a constant which is bad practice, see PHP Reference: Arrays
Related
I've written a switch which needs to match any combinations in the predefined array but now its matching only if all the combination from the given array is succeeded. But I want to match any combination from the array.
example : if my combination consists only 'man','cisman' then also my combination needs to succeed and needs to return $result = "male.png";. But if any item otherthan the given combination needs to rejected and needs to return default case.
Working demo
$menCombo = ['man','cisman','transmasculine','transman'];
$womanCombo = ['woman','ciswoman','transfeminine','transwoman'];
switch($genderdetail) {
case count(array_intersect($menCombo, $genderdetail)) === count(($menCombo)):
case "man":
case "cisman":
case "transman":
case "transmasculine":{
$result = "male.png";
break;
}
case count(array_intersect($womanCombo, $genderdetail)) === count(($womanCombo)):
case "woman":
case "ciswoman":
case "transfeminine":
case "transwoman":{
$result = "female.png";
break;
}
default: {
$result = "others.png";
break;
}
}
As mentioned in the comments, if $genderdetail isn't an array, you make it one. Now, if array difference of 2 arrays returns empty, it sure has to belong to the haystack array in comparison.
<?php
$genderdetail = ['man','cisman'];
$menCombo = ['man','cisman','transmasculine','transman'];
$womanCombo = ['woman','ciswoman','transfeminine','transwoman'];
$result = 'others.png';
if(!is_array($genderdetail)){
$genderdetail = [ $genderdetail ];
}
if(empty(array_diff($genderdetail, $menCombo))){
$result = 'male.png';
}else if(empty(array_diff($genderdetail, $womanCombo))){
$result = 'female.png';
}
echo $result;
What about changing the count condition to
case count(array_intersect($menCombo, $genderdetail)) === count(($genderdetail)):
you count the array mayches and not the long array of poszibilities. Same for the female count.
I have the variable
$sql1 .= "Brukertype";
Which gets information set from an already-filled textbox. It can either have the value Administrator or the value Iskjører.
What is the best way to change these values before inserting them into SQL?
The Administrator value should get changed to the value 1 and Iskjører gets changed to the value 2.
I can't use a select function (dropdown list) on the question because it needs to be enabled/disabled on my command.
This is a reasonable place to use a switch statement. You want a 'marshaling' function, like this:
function marshal_input($input) {
$result = 0;
switch ($input){
case 'Administrator':
$result = 1;
break;
case 'Iskjører':
$result = 2;
break;
case 'SomethingYouHaventThoughtOfYet':
$result = 3;
break;
default:
$result = 0;
break;
}
}
However, the implementation of the marshaling function can be almost anything:
function marshal_input($input) {
$options = array("Administrator" => 1, "Iskjører" =>2);
return $options[$input];
}
The point is that you need some code that maps from the human-readable form to the numerical representation the db needs. Then you just call it like so:
$sql_version = marshal_input($sql1);//Doesn't overwrite the variable
//...or...
$sql1 = marshal_input($sql1);//Note this overwrites the variable.
Since you have stated:
It can eighter have the value "Administrator" or the value "Iskjører"...
we only check whether the value is 'Administrator' or not.
Try this:
$val = 'Administrator'; // user input variable
$sql_val = ($val == 'Administrator') ? 1 : 2;
If value is 'Administrator' set $sql_val to 1, else set $sql_val to 2
I'm working on code that takes a random value, checks if it's correct with a few checks and if it is, it'll return it. If it isn't, it's supposed to rerun the function untill one that does is found.
If the random value is correct it'll set a var to 1 like this: $chosen = 1; and then using a while loop it'll keep running the current function untill it's 0:
public function generate_chair($id, $optredenID)
{
$model = new Model_Shop;
// Get all the chairs for the given room
$chairs = $model->check_chair($id);
// Get an array of reserved chairs for a given event
$reserved = $model->get_reserved($optredenID);
do {
// If chosen = 0, all chairs are available.
// If chosen = 1, one of the chairs is not available
$chosen = 0;
// Create a new empty array
$rand_chairs = array();
// Pick a random chair
$chair = array_rand($chairs);
// Based off the amount chosen in the dorpdown, build array
switch($_POST['AantalPlaatsen']) {
case '1':
array_push($rand_chairs, $chair);
break;
case '2':
array_push($rand_chairs, $chair);
array_push($rand_chairs, $chair+1);
// Check if the chair chosen is the last chair in a row
// If it is, check for another chair
if($chair == 20 || $chair == 40 || $chair == 60 || $chair == 80 || $chair == 100 || $chair == 120 || $chair == 140 ||$chair == 160 ||
$chair == 180 || $chair == 200) {
$chosen = 1;
}
break;
case '3':
array_push($rand_chairs, $chair);
array_push($rand_chairs, $chair+1);
array_push($rand_chairs, $chair+2);
break;
case '4':
array_push($rand_chairs, $chair);
array_push($rand_chairs, $chair+1);
array_push($rand_chairs, $chair+2);
array_push($rand_chairs, $chair+3);
break;
}
// Check if one of the random generated chairs is in the reserved array
// If so, the chair is unavailable and new random must be generated
if( count(array_intersect( $rand_chairs, $reserved )) != 0 ) {
$chosen = 1;
}
} while ($chosen == 1);
return $rand_chairs;
What I wanted works now, but I'm wondering if anyone has a idea for another issue.
As shown in the switch-case, when the customer chooses 2 chairs and the first one is at the end of a row, it has to check for a new chair, because you can't spread multiple chairs over multiple rows.
The way I do this is with alot (too many) if statements. Does anyone know a better solution?
Why are you using recursion here? Why not just repeat the part of the function which you need to rerun?
do {
$chosen = 0;
// create a new empty array
$rand_chairs = array();
// Pick a random chair
$chair = array_rand($chairs);
...
foreach($rand_chairs as $key) {
if(in_array($key, $reserved)) {
$chosen = 1;
break; // oops, we need to rerun
}
}
} while( $chosen == 1 )
This uses a do-while control structure, which runs through the body at least once.
The break statement exits out of the while loop early, since the key has been found.
Additionally, instead of the foreach statement, you could use array_intersect():
if( count(array_intersect( $rand_chairs, $reserved )) != 0 ) {
$chosen = 1;
}
Faster algorithm would go something like this: you would run it one row of seats at a time, since "sitting at opposite ends of adjacent rows" isn't really "sitting together"...
Boolean seatsTaken()
int startsAt(), runLength()
For each row in seatsTaken
adjacent = 0
seat = 0
while not row(seat):
++adjacent
if adjacent > 0:
startsAt.push(seat-adjacent)
runLength.push(adjacent)
When this is done you have an array of all the blocks. Select only the blocks that are big enough (runLength() >= needed) and randomly choose one of them
I'm retrieving data from a MySQL db and creating reports from it. I need to get counts when certain conditions are met, and since db queries are rather expensive (and I will have a lot of traffic), I'm looping thru the results from a single query in order to increment a counter.
It seems like it's working (the counter is incrementing) and the results are somewhat close, but the counters are not correct.
At the moment, there are 411 records in the table, but I'm getting numbers like 934 from a ['total'] counter and 927 for ['males'], and that definitely can't be right. However, I get 4 from ['females'], which is correct…
I'm pretty sure it was working last night, but now it's not—I'm quite baffled. (there are still just 411 records)
$surveydata = mysql_query("SELECT `age`,`e_part`,`gender` FROM $db_surveydata;") or die(mysql_error());
$rowcount = mysql_num_rows($surveydata);
$age=array('18+'=>0,'<18'=>0,'total'=>0);
$e_part=array('yes'=>0,'no'=>0,'total'=>0);
$genders=array('male'=>0,'female'=>0,'trans'=>0,'don\'t know'=>0,'total'=>0);
while ($responses = mysql_fetch_assoc($surveydata)) {
foreach ($responses as $response){
switch ($response){
case $responses['age']:
if ($responses['age'] > 18) {$age['18+']++;$age['total']++;}
// i tried putting the ['total'] incrementer in the if/else
// just in case, but same result
else {$age['<18']++;$age['total']++;}
break;
case $responses['e_part']:
if ($responses['e_part']) {$e_part['yes']++;}
else {$e_part['no']++;}
$e_part['total']++;
break;
case $responses['gender']:
switch ($responses['gender']){
case 1:$genders['male']++;break;
case 2:$genders['female']++;break;
case 3:$genders['trans']++;break;
case 9:$genders['don\'t know']++;break;
default:break;
}
$genders['total']++;
break;
default:break;
} // end switch
} //end for
} // end while
thanks!
this is the problem:
foreach ($responses as $response){
switch ($response){
case $responses['age']:
switch $responses looks for match
foreach ($responses as $k=>$v){
switch ($k){
case 'age':
if ($v > 18) ....
mysql_fetch_assoc() retrieves a single row from the table. You then loop over that row, processing each individual field. Then the long set of if() checks to determine which field you're on. That entire structure could be changed to:
while($response = mysql_fetch_assoc($surveydata)) {
if ($responses['age'] > 18) {
$age['18+']++;
} else {
$age['<18']++;
$age['total']++;}
if ($responses['e_part']) {
$e_part['yes']++;
} else {
$e_part['no']++;
}
$e_part['total']++;
switch ($responses['gender']){
case 1:$genders['male']++;break;
case 2:$genders['female']++;break;
case 3:$genders['trans']++;break;
case 9:$genders['don\'t know']++;break;
default:break;
}
$genders['total']++;
}
There's no need for the switch ($response); you can't really switch on an array like that. And even if you could, the 'values' you get wouldn't make any sense -- i'm thinking if it works at all, the value you're switching on would be either 'Array' or the length of the array. (I forget how PHP handles arrays-as-scalars.)
You'll want something like this...
$total = 0;
while ($response = mysql_fetch_assoc($surveydata))
{
if (isset($response['age']))
{
++$age[($response['age'] < 18) ? '<18' : '18+'];
++$age['total'];
}
if (isset($response['e_part']))
{
++$e_part[($responses['e_part']) ? 'yes' : 'no'];
++$e_part['total'];
}
if (isset($response['gender']))
{
switch ($response['gender'])
{
case 1: ++$genders['male']; break;
case 2: ++$genders['female']; break;
case 3: ++$genders['trans']; break;
case 9: ++$genders["don't know"]; break;
}
++$genders['total'];
}
++$total;
}
The benefit of the if (isset(...)) is that if 'age', 'e_part', or 'gender' is null, the corresponding code to count it won't get activated. It does about the same thing as your code, minus the embarrassing loop -- and minus the counting of the field even though it is null, because every row will have the same fields.
function addAds($n) {
for ($i=0;$i<=$n;$i++) {
while($row=mysql_fetch_array(mysql_query("SELECT * FROM users"))) {
$aut[]=$row['name'];
}
$author=$aut[rand(0,mysql_num_rows(mysql_query("SELECT * FROM users")))];
$name="pavadinimas".rand(0,3600);
$rnd=rand(0,1);
if($rnd==0) {
$type="siulo";
} else {
$type="iesko";
}
$text="tekstas".md5("tekstas".rand(0,8000));
$time=time()-rand(3600,86400);
$catid=rand(1,9);
switch ($catid) {
case 1:
$subid=rand(1,8);
break;
case 2:
$subid=rand(9,16);
break;
case 3:
$subid=rand(17,24);
break;
case 4:
$subid=rand(25,32);
break;
case 5:
$subid=rand(33,41);
break;
case 6:
$subid=rand(42,49);
break;
case 7:
$subid=rand(50,56);
break;
case 8:
$subid=rand(57,64);
break;
case 9:
$subid=rand(65,70);
break;
}
mysql_query("INSERT INTO advert(author,name,type,text,time,catid,subid) VALUES('$author','$name','$type','$text','$time','$catid','$subid')") or die(mysql_error());
}
echo "$n adverts successfully added.";
}
The problem with this function, is that it never loads. As I noticed, my while loop causes it. If i comment it, everything is ok. It has to get random user from my db and set it to variable $author.
The problem is that the query is in the loop, so it gets run every time (so you start from the beginning every time). Just move the mysql_query() part to right before the while loop and store it in a variable:
$query = mysql_query("SELECT * FROM users");
while($row=mysql_fetch_array($query))
You can replace this mega switch with one line:
$subid = rand(($catid * 8) - 7, min($catid * 8, 70));
The condition of a while loop is executed and evaluated with each iteration. So mysql_query is called with every iteration and retunrs true.
Just execute your database query once and cache the result:
function addAds($n) {
$result = mysql_query("SELECT * FROM users");
$aut = array();
while ($row = mysql_fetch_array($result)) {
$aut[]=$row['name'];
}
$rowCount = count($aut);
for ($i=0; $i<=$n; $i++) {
$author=$aut[rand(0,$rowCount)];
// …
mysql_query("INSERT INTO advert(author,name,type,text,time,catid,subid) VALUES('$author','$name','$type','$text','$time','$catid','$subid')") or die(mysql_error());
}
echo "$n adverts successfully added.";
}
I also think the problem is your functions are way too big to understand(quickly). You should make them smaller and test them with a unit testing framework like phpunit.
It's a lot of time that I don't use PHP but I think that the assignment
$row=mysql_fetch_array(mysql_query("SELECT * FROM users"))
should always returns true, it executes the query again and again on every iteration..
You're starting a new query each time you run the loop.