Implementing facebook-style "unlike" function - php

I've recently implemented a custom liking and disliking feature for my comics site. I'd like to give users the ability to "Take back" their selection by "unclicking" the like or dislike button.
My function works by:
1) Passing button value (id = 'like' or id = 'dislike') via Jquery to
php script
2) script will first check if an ip exists in the database against
that given comic id... if not it will insert user's IP and current
comic ID... if it does, it originally said "you've already voted"... but now to implement "unliking", I will just have it run a delete query
3) then it will get total current likes for that comic id and
increment.
The way I think it can be done is if the user presses the button again, I basically run the opposite query... delete that user's vote from the table given that comic id... then decrement total likes for that image in the comics table.
So my questions are,
1) Is doing an insert query if they press a button once, then a delete
query if they "deselect" that same choice the best way to implement
this? Couldn't a user spam and overload the database by continuously
pressing the like button, thereby constantly liking and unliking?
Should I just implement some sort of $_SESSION['count'] for that ID?
2) If I'm storing a certain IP... what happens if several uniques
users happen to use the same computer at... let's say a netcafe... it
will always store that user's IP. Is storing against the IP the best
way to go?
Code if you need a reference:
<?php
include 'dbconnect.php';
$site = $_GET['_site'];
$imgid = intval($_GET['_id']);
$input = $_GET['_choice'];
if ($site == "artwork") {
$table = "artwork";
}
else {
$table = "comics";
}
$check = "SELECT ip, tablename, imgid FROM votes WHERE ip = '".$_SERVER['REMOTE_ADDR']."' AND tablename = '$table' AND imgid = $imgid";
$result = $mysqli->query($check);
if ($result->num_rows == 0) {
//Insert voter's information into votes table
$sql = "INSERT INTO
votes (ip, tablename, imgid)
VALUES
(\"".$_SERVER['REMOTE_ADDR']."\", \"$table\", $imgid)
ON DUPLICATE KEY UPDATE
imgid = VALUES(imgid)";
if (!$mysqli->query($sql)) printf("Error: %s\n", $mysqli->error);
/*while ($row = $result->fetch_assoc()) {
echo "you've inserted: " . $row['ip'] . ", " . $row['tablename'] . ", " . $row['imgid'] . ".";
}*/
$result = $mysqli->query("SELECT like_count, dislike_count FROM $table WHERE id = $imgid");
//put the counts into a list
list($likes, $dislikes) = $result->fetch_array(MYSQLI_NUM);
if ($input == "like") {
$sql = "UPDATE $table SET like_count = like_count + 1 WHERE id = $imgid";
$mysqli->query($sql);
$likes++;
}
else if ($input == "dislike") {
$sql = "UPDATE $table SET dislike_count = dislike_count + 1 WHERE id = $imgid";
$mysqli->query($sql);
$dislikes++;
}
}
else { //"unlike" their previous like for that given image id
$sql = "DELETE FROM
votes
WHERE (ip, tablename, imgid) =
(\"".$_SERVER['REMOTE_ADDR']."\", \"$table\", $imgid)";
if (!$mysqli->query($sql)) printf("Error: %s\n", $mysqli->error);
$result = $mysqli->query("SELECT like_count, dislike_count FROM $table WHERE id = $imgid");
//put the counts into a list
list($likes, $dislikes) = $result->fetch_array(MYSQLI_NUM);
if ($input == "like") { //remove like
$sql = "UPDATE $table SET like_count = like_count - 1 WHERE id = $imgid";
$mysqli->query($sql);
$likes--;
}
else if ($input == "dislike") {
$sql = "UPDATE $table SET dislike_count = dislike_count - 1 WHERE id = $imgid";
$mysqli->query($sql);
$dislikes--;
}
}
echo "Likes: " . $likes . ", Dislikes: " . $dislikes;
mysqli_close($mysqli);
?>

1) I would say yes, use a count feature to limit the number of attempts they can hit the button in succession. Probably wouldn't have much trouble unless they hit really high numbers, I believe a simple loop would do fine.
2) I would not store just the IP. I would try and use something more than just the IP as an Identifier, like the IP and the session cookie - that way it's unique. However on the look back to the server you would have to parse the entry from the db. Or perhaps the mac address. I'm not sure if you have access to that or not. How can I get the MAC and the IP address of a connected client in PHP?
I'm sure there's another way but conceptually that's how I see it working.

Related

Create a "Secret Santa" generator using MySQL and PHP

I am trying to create a Secret Santa system using a PHP page and a MySQL database to store the details so if someone forgets their match they can re-request it.
Step 1: I created a random number generator based on the number of people in the list in the database.
Count Function:
$maxSQL = "SELECT COUNT(id) as total FROM secretsanta";
$maxRS = mysqli_query($conn, $maxSQL);
$maxQuery = mysqli_fetch_array($maxRS);
$maxpersons = $maxQuery['total'];
Then the Random Number Generator:
$assigned = rand(1,$maxpersons);
Step 2: Test if the random number matches the persons own id and regenerate a new number if true.
do {
$assigned = rand(1,$maxpersons);
} while ($assigned==$id);
Step 3: Write the paired id to the persons database record.
$assignSQL = "UPDATE secretsanta SET assigned = '".$assigned."' WHERE secretsanta.id = ".$id;
if (mysqli_query($conn, $assignSQL)) {
echo "Record updated successfully";
} else {
echo "Error updating record: " . mysqli_error($conn);
}
The Problem: Now I need to check that other people aren't assigned to that person or otherwise some could miss out and others would get more than others.
I tried to implement a function that contained a query to test each record to see if that number already existed and was hoping to add it as a condition to perhaps a while or do while statement?
if (!function_exists('checkRandom')){
function checkRandom($funcid){
$Check_SQL = "SELECT assigned FROM secretsanta ORDER BY id ASC";
$Check_RES = mysqli_query($conn, $Check_SQL);
if (Check_RES) {
while ($CheckArray = mysqli_fetch_array($Check_RES, MYSQLI_ASSOC)) {
$CheckAsgn = $CheckArray['assigned'];
if ($funcid==$CheckAsgn) {return true;}else{return false;}
}
}
}
}
Then implement it into the do while statement like this:
do {
$assigned = rand(1,$maxpersons);
} while ($assigned==$id||checkRandom($assigned));
No luck so far...HELP!.. please :)
P.S. I know there are websites that already do this, I just don't trust them to give out mine and family email address' if I can make my own private version myself.
Using your method, the first few assignments will be done with no problem, but imagine the last unassigned entry and how many times it will try a random number only to find the person with that id is already assigned..
I'm gonna give you another approach to your problem: for each user that you want to assign a santa to, make a new SELECT statement with a WHERE clause that lets you select only those users that are not assigned yet.
check out my code and see if that helps you. I just typed this and didnt test it so there could be some mistakes.
// load all unassigned users into an array
$unassignedUsers = [];
$query = "SELECT id, assigned FROM secretsanta WHERE assigned is NULL";
$res = mysqli_query($conn, $query);
while($row = mysqli_fetch_assoc($res){
$unassignedUsers[] = $row;
}
if(count($unassignedUsers) == 1){
echo 'There is only 1 unassigned user. Therefore he cannot be matched';
} else {
// for loop for each user in DB that is not assigned yet
//for ($i = 1;$i <= count($unassignedUsers); $i++){
$i = 0;
foreach($unassignedUsers as $user)
// if its the second-to-last iterations of the for-loop, check for legality of the last one
if(count($unassignedUsers) - $i == 1){
$lastUserID = $unassignedUsers[count($unassignedUsers)-1]['id'];
$query = "SELECT id FROM secretsanta WHERE assigned is NULL AND id = ".$lastUserID;
$res = mysqli_query($conn, $query);
$rowcount = mysqli_num_rows($res);
if ($rowcount){
// last user is still unassigned
$query = "UPDATE secretsanta SET assigned = '".$lastUserID."' WHERE id = ".$user['id'];
if(mysqli_query($conn, $query)){
echo "Record with id ".$user['id']." updated successfully";
} else {
echo "Error updating record: ".mysqli_error($conn);
}
}
} else {
// select all unassigned users
$unassignedIDs = [];
$query = "SELECT id FROM secretsanta WHERE assigned is NULL AND id <> ".$user['id'];
$res = mysqli_query($conn, $query);
while($row = mysqli_fetch_assoc($res){
$unassignedIDs[] = $row['id'];
}
// get a random id from $unassignedIDs
$randomIndex = rand(0, count($unassignedIDs)-1);
$randomID = $unassignedIDs[$randomIndex];
// assign $randomID to user
$query = "UPDATE secretsanta SET assigned = '".$randomID."' WHERE id = ".$user['id'];
if(mysqli_query($conn, $query)){
echo "Record with id ".$user['id']." updated successfully";
} else {
echo "Error updating record: ".mysqli_error($conn);
}
}
$i++;
}
}
last edit: refactored whole code so it is able to be run multiple times and only assigns new users who are not assigned yet.
Step 1 is dependent on have a contiguous set of ids for the people. Think what happens if '3' leaves the company and it hires 6 to replace them....1,2,4,5,6 ($maxpersons=5)
"Now I need to check" - no you are still trying to solve the problem by guessing then seeing if your guess worked. Use an algorithm which is always going to return a correct result. The method below requires the addition of a temporary field 'sequence' of type float.
mysqli_query($conn,"UPDATE secretsanta SET sequence=RAND()");
$first=false;
$prev=false;
$all=mysqli_query($conn, "SELECT * FROM secretsanta ORDER BY sequence, id");
while ($r=mysqli_fetch_assoc($all)) {
if (false===$first) {
$first=$r['id'];
} else {
save_pair($prev, $r['id']);
}
$prev=$r['id'];
}
save_pair($prev, $first);
(but with better error checking)

Hide/Show button, also when refreshed

I am making an application that displays "activities". Each activity has his own button. When you click on that button, you add that specific activity to your "guide". The idea is that you can add one specific activity only once, so the button of that activity must disapear when it's added to the guide. I can use a simple $(this).hide() in my javascript but that obviously doesn't work when I refresh the page. So I guess i should make a check if the activity exists in de guide.
in the database I have 3 tables, 1: activity (with an ActivityID), 2: user (with a UserID) and 3: user_activity (with ActivityID and UserID, a linktable).
So the check must check if the ActivityID exists in the user_activity table, and that the UserID that belongs to that ActivityID in the user_activity table is the sames as the current users' ID.
At this moment, I know how to check the current users UserID:
//userid
$sql = "SELECT * FROM user WHERE Username = '".$_SESSION['Username']."' ";
$stm = $db->prepare($sql);
$result = $stm->execute(array());
while($row = $stm->fetch(PDO::FETCH_ASSOC)) {
$userid = $row['UserID'];
}
But I don't know how to check if the ActivityID already exists, and how I should make this
if else statement.
Ay the moment I use this script to display the activity (incl. the button)
$sql = "SELECT * FROM activity";
$stm = $db->prepare($sql);
$result = $stm->execute(array());
while($row = $stm->fetch(PDO::FETCH_ASSOC))
{
echo '<div id="activity'.$row['ActivityID'].'">';
echo '<img src="data:image/jpeg;base64,' . base64_encode( $row['ActivityIMG'] ) . '" >', '<br>';
$instantguide = $row['ActivityID'];
echo '<input type="button" class="addActivity" onclick="MakeRequest(' . $instantguide . ')" value="Activiteit toevoegen" data-activity="' . $row['ActivityID'] . '">';
echo '</div>';
}
You need a LEFT JOIN to see what activities are already on
SELECT a.*, ua.ActivityID as added
FROM activities a LEFT JOIN user_activity ua
ON a.ActivityID=ua.ActivityID AND UserID=:userid
So you'll have an additional added field in the resultset, filled with an id if it is already chosen or empty otherwise
// First you need to get all the activityIDs from the table where you want to search and put them into an array
$sql2 = "SELECT * FROM user_activity";
$stm2 = $db->prepare($sql2);
$result2 = $stm2->execute(array());
$user_activityID = array();
while($row2 = $stm->fetch(PDO::FETCH_ASSOC))
{
// if in the table user_activity the column you are trying to compare has the same name as in activity -- $row2['ActivityID']
array_push($row2['ActivityID'], $user_activityID);
}
// Then you use in_array to compare while you go through the user_activity table
$sql = "SELECT * FROM activity";
$stm = $db->prepare($sql);
$result = $stm->execute(array());
while($row = $stm->fetch(PDO::FETCH_ASSOC))
{
if (in_array($row['ActivityID'], $user_activityID))
{
// yes the current $row['ActivityID'] from the activity table, exists in the user_activity table
// you can choose whether or not to add this to your array
array_push($row['ActivityID'], $activityID);
}
}
I'm sure there's other more efficient ways to do this, using some pdo stuff that I don't know, but this is how I would have done it.

If nothing is found for field, create new field

PHP newbie here
I have a mysql table called "topics", and i'm pulling information from the table for a page based on a result from a form (in the URL through GET)
If the URL doesn't exist, i'd like to be able for the table to create a new entry with the topic name from the URL filled in
$topic_name would be what i'd be putting in the new topicname field
My code so far:
$topic_name = strtolower(mysql_real_escape_string($_GET['t']));
//look for info
$topic_info = mysql_query("SELECT * FROM topics WHERE topicname = '$topic_name' LIMIT 1");
if (mysql_numrows($topic_info)<=0) {
//insert record
$SQL='insert into topics (topicname) values ("'.$topic_name.'")';
mysql_query($SQL);
$t_desc='NEW TOPIC : '.$topic_name;
}
else {
//do as normal (without unnessecary loop)
$g=mysql_fetch_array($topic_info);
$t_desc = $g['desc'];
}
EDIT: Sorry, I don't think i explained well, the result is from a GET from a form, so url.com/topic?=BLAH
blah would be the name of the field i'd want to create if it doesn't exist.
The table has an Auto incrementing 'ID' (primary key)
If i understand you correct :
$topic_name = (isset($_GET['t'])) ? strtolower(mysql_real_escape_string($_GET['t'])) : '';
//look for info
$topic_info = mysql_query("SELECT * FROM topics WHERE topicname = '$topic_name' LIMIT 1");
if (mysql_num_rows($topic_info)<=0) {
//insert record
//UPDATE
//$SQL='insert into topics (topicname) values ("'.$topic_name.'")';
$SQL='insert into topics (topicname, `desc`) values '.
'("'.$topic_name.'", "NEW TOPIC DESC")';
mysql_query($SQL);
$t_desc='NEW TOPIC : '.$topic_name;
} else {
//do as normal (without unnessecary loop)
$g=mysql_fetch_array($topic_info);
$t_desc = $g['desc'];
}
Try as below
$topic_info = mysql_query("SELECT * FROM topics WHERE topicname = '$topic_name' LIMIT 1");
$count = mysql_num_rows($topic_info);
if($count <= 0){
// do insert query
}
else {
// loop through you result and display record
while($g = mysql_fetch_array($topic_info)){
$t_desc = $g['desc'];
}
}
Note: Better to use PDO or Mysqli lib for new development and prevent mysql injection attack

Updating records If ipAddress and playerName match

At the moment im sending scores and data to my database from my flash game, though every level completed is a new record.
feilds are set out like l1Score,l2Score,l3Score
im trying to figure out how to update records if the field ipAddress and playerName match the current $varibles.
UPDATE highscores SET l2Score = '$l2Score' WHERE ipAddress = "$ipAddress" && playerName = '$playerName'
I was thinking somthing along these lines, but could someone point me in the right direction please!
First you want to perform a query to check if there is already a score in place for that user & IP.
$sql = "SELECT * FROM highscores WHERE ipAdress = '$ipAdress' AND playerName = '$playerName'";
$result = mysql_query($sql, $con);
$row = mysql_fetch_assoc($result);
Now, if $row is empty then you want to insert a new record, else you want to update a previous record.
if($row == "")
{
$query = "INSERT INTO highscores (l2score, ipAdress, playerName) VALUES ('$l2score', '$ipAdress', '$playerName'";
} else {
$query = "UPDATE highscores SET l2Score = '$l2Score' WHERE ipAdress = '$ipAdress' AND playerName = '$playerName'";
You may need to edit this to fit with the specific query that you need.

Keeping a counter

*Here is what I am trying to acheive: *
Basically I have a form where people can submit events to our database. In the CMS I have a page which displays a record of the number of events.
*Here is what I have: *
After the button is clicked, this script is called:
if($subject_type == 'Event') {
$query = "SELECT town, update_id, event_validex ";
$query .= "FROM dev_town ";
$query .= "LEFT JOIN updates ON dev_town.town_id = updates.town ";
$query .= " WHERE sitename = '".SITENAME."'";
$query .= " AND month = " .date('m')." AND year =" .date('Y');
$querys = $this->tep_db_query($query);
$rows = $this->tep_db_fetch_array($querys);
extract($rows); //extract rows, so you don't need to use array
$eventid = $event_validex + 1;
$sql_data_array = array('event_validex' => $eventid);
$submit_to_database = $this->tep_db_perform('updates', $sql_data_array, 'update', "town='".$town."'");
This works fine, however I cant seem to solve the next bit
This is the Problem
As you can see, it checks the database for the current month and adds it, this is providing that the sitename and that month are there, not a site and another month.
How would I get it to add the row in IF the sitename and month are not there?
I have been manually adding the months in now so that it works, and I am sure you can agree that's a ball ache.
Cheers peeps
if you want to check if site A + Month 11 exists do a select query against it and store the number of rows returned in a variable. ( $exists = mysql_num_rows("your query here"); )
then do an if statement against the $exists variable and proceed as you wish
if($exists) {
// update
} else {
// add
}
$insert = "INSERT INTO updates ('town','month','year','event_validex') VALUES ('".$town."','". date('m')."','". date('Y')."','1')";
$eventid = 1;
$sql_data_array = array('event_validex' => $eventid);
$submit_to_database = $this->tep_db_perform('updates', $sql_data_array, 'update', "town='".$town."'");
}
}
this is what I have for the else statement there, however it will add one to the value if its there but will not add a new entry if its isnt.. ?
I don't see exactly how your method "checks the database for the current month and adds it "; I'll just assume that the tep_db_perform() method of your class handles this somehow.
(uhk! n00bed it; rest of the post was somehow chopped off?) Since you're already hitting the database with the select with the intent of using the data if a record is found, then you could use the resultset assigned to $rows as a means of checking if a record exists with SITENAME and Month.
See below:
if($subject_type == 'Event') {
// build query to check the database for sitename, month and year.
$query = "SELECT town, update_id, event_validex ";
$query .= "FROM dev_town ";
$query .= "LEFT JOIN updates ON dev_town.town_id = updates.town ";
$query .= " WHERE sitename = '".SITENAME."'";
$query .= " AND month = " .date('m')." AND year =" .date('Y');
// Execute Query(wrapper for $result = mysql_query I guess?)
$querys = $this->tep_db_query($query);
// Get a resultset from database. --> you could merge this into one method with $this->tep_db_query
$rows = $this->tep_db_fetch_array($querys);
if(count($rows) > 0) {
extract($rows); //extract rows, so you don't need to use array --> I try to stay away from extract() as it makes for random variables being created.
$eventid = $event_validex + 1;
$sql_data_array = array('event_validex' => $eventid);
$submit_to_database = $this->tep_db_perform('updates', $sql_data_array, 'update', "town='".$town."'");
} else {
// insert new record into database
// updated with code to execute insert SQL query.
$insert = "INSERT INTO updates ('town','month','year','event_validex') VALUES ('".$town."','". date('m')."','". date('Y')."','1')";
$result = $this->tep_db_query($query);
}
....
}
If I've misunderstood something, please let me know, happy to work through it with you.
Hope this helps. :)

Categories