Ensuring users do not spam "like" button - php

My friends and I are creating a petition board and i'm adding a like/dislike function to it. I intend to make it such that only users can like/dislike it. Problem is, I do not know how to ensure that the users do not spam the button multiple times and how to register which user has liked/disliked which topic. Below is my code so far.
EDIT: Thanks I am creating the likes/dislikes table right now. But now I have to compare the users with the database to see if they have previously liked a comment. I know I have to use WHERE (to check both likes and dislikes table) but i am not sure how to combine it with IF.
<?php
include connect.php
if (isset($_POST['like']) || isset($_POST['dislike']))
{
if($_SESSION['signed_in']){
if (isset($_POST['like'])) {
$sql="UPDATE
topics
SET
likes=likes+1,
WHERE
id=topic_id";
echo "You liked it";
}
elseif (isset($_POST['dislike'])) {
$sql="UPDATE
topics
SET
dislikes=dislikes+1,
WHERE
id=topic_id";
echo "You disliked it";
}
}
else{
echo 'Please log in.'
}
?>

You should have a table of "likes" with the following columns.
"article_id", "user_id", the primary key should contain both columns
Every time a user likes an article, INSERT INTO likes VALUES($article_id, $user_id);
It will fail if someones Likes twice, thanks to the primary key.
Every time a user dislikes, DELETE FROM likes WHERE article_id = $article_id AND user_id = $user_id. That will allow the user to like again if he wants.
To get the number of Likes for an article, run a SELECT COUNT(*) as nb_of_likes FROM likes WHERE article_id = $article_id instead of storing the number in the article table.
Makes sense ?

The following solutions are possible, which can be used together:
If you use a registration/login mechanism, then you could internally setup some counting mechanism so each user can like once per petition (like Bgi suggested).
You could store a cookie, preventing him for further liking, even if he creates a new user.
Of course people can delete cookies or use other browsers, so you could hash their IP with e.g. md5 and compare the hash if that hash was already using the petition.
Of course multiple people can share the same IP, so IP hashing might not always be a good solution. Alternatively, you could use facebook API, and require that people have some amount of friends or something in order to verify their authenticy.
You will never fully be able to get rid of spammers, depends on how specific is your petition. Hence the more you want to prevent exploiting from using the petition, the less anonymous it will be.

Related

Cannot select all results from a table depending on another table (relational DB) in PHP and MySQL

I am trying to finish this website I am currently creating, but I am kind of stuck.
I want to create a table called "orders" in my DB. I want this table to be related to my users table so that when the user goes to his "orders.php" page (once logged in already) he sees all his current and previous orders.
These would be my table fields/cols:
id
username
ordernumber
description
quantity
total
This is my approach:
Whenever a new order is created, insert all the table fields/cols depending on the user's choice (selected stuff for the order), but the username would be the only value gathered from a $_SESSION or $_COOKIE variable, which holds the username. Then, once the user goes to orders.php, I will execute a query to show all the orders that only that username has ordered. Please note that I do sanitize all my input/output and I do not store sensitive data in my cookies. My system is designed so it only uses the session as the method of authentication, therefore you need to login every time you close the browser but that is fine.
1) Is this a safe approach? Do you have any suggestions/comments?
2) Could you help me construct the query?
I haven't really worked with relational databases, so I am kind of lost. How can I call all the orders from table "orders" where username = "username from the session"?
So far I have this:
"SELECT * FROM orders WHERE username = ? " //(Using PDO)
I know that this will work but my concern is in case of getting a session hijacked or something like that, then a user would be able to retrieve any users' orders, or not?
Thank you for explaining this a little bit further and helping me out!
Cheers!
Be careful! Please don't create a plain text cookie containing a human-readable user id (like user2345995 or OllieJones). It's far too easy for a badguy to fake a cookie like that just by guessing, and then your users' information leaks out.
You're working in php. Therefore you can use php's session mechanism to store your userid and other values. php uses hard-to-guess session ids (SIDs) and stores them in either a cookie or as a sid=1234abcd9875 parameter in URLs.
For the sake of your system's integrity, please read up on this. It's actually a pretty well-designed feature and it's been in the wild for fifteen years or so: it's debugged.
http://php.net/manual/en/session.idpassing.php
If you're using the session system, you basically do this in your first page, your login page.
session_start();
...
$_SESSION['username'] = $username; /* which you get by logging in */
...
On your order lookup page you do something similar to retrieve the username and use it in a query.
session_start();
...
$orderstmt = $pdoconn->prepare("SELECT * FROM orders WHERE username = :username");
$orderstmt->execute( array(':username' => $_SESSION['username']) );
...
while ($row = $orderstmt->fetch()) {
/* use the row's data */
}
$orderstmt->closeCursor();

creating user id's (best route)

I am looking for the best way to write out a php/mysql query to create unique user id's rather than using the autoincrement method in mysql.
Ex: Facebook gives users a long string of numbers as a user id when singing up before you can assign a username. This string of numbers can be used to view your profile OR you can use username. I want users to be able to change username in the future, so don't want to design my system based on username.
I don't know how big the site will get, so please take that into consideration with the solution. I don't want something that is going to be server intensive if there are alot of users signing up.
There isn't really a best route for something like this. Essentially you need to ask yourself what your system requires. You may be able to use an email address as the ID, an auto-incremented number, MD5 hash, or even a heavy-entropy GUID.
Keep in mind that email addresses may change, auto-incremented numbers can be leveraged in automated exploits, and there's technically some chance of hashes colliding.
If you decided to go the route of generating a high-entropy GUID using PHP, you could do so using a function like uniqid.
echo uniqid(); // 513ac40699d85
echo uniqid("_", true); // _513ac3e00bfe46.78760239
The second line shows the two arguments you can provide; a prefix, and a request for more entropy, which will result in a more unique result.
You should follow some algorithm like this:
Enter your new user into the database.
Get the record ID
Generate the userID
Insert the userID next to the name into the sql database.
Enter your new user into the database.
//get username from previous form
$user=$_POST['user'];
// login into mysql server and prepare data for writing
$connect=mysql_connect('localhost', $user, $pass);
$selectdb = mysql_select_db('mydb');
$query = "insert into users_table set
username='$user';";
$run_query=mysql_query($query);
Get the record ID
$id=mysql_insert_id();
Generate the userID
$first_chars=substr($user, 2);
$year=date('y');
$new_user_id= $first_chars.$year.$id;
Insert the UserID next to the name into the sql database
$query="update users_table set userid='$new_user_id' where id='$id';";
$run_query=mysql_query($query);
if (!$run_query) {
echo mysql_error();
}
else {
echo 'your user name is '.$user.' and user id is '.$new_user_id ; }
You can use mysql as a database. Wampserver combines everything and makes it easy. However, i'm not sure if I can help you very much because your question is very vague. Add some more detail please.
Use a hexdigest like sha or md5 to generate an id something like sha1($uname+$timestamp+$salt)
By doing this your will be storing a lot of data for each entry as sha1 takes up 40 bytes.You have already mentioned that the site is may go big,making it a huge amount of data.Decide whether its worth that lot of space.
PS:you can always slice the string,but the collision chance is more that way.

Limiting activity via PHP

I have a social network that allows users to post blogs, ask questions, and message. We have had a slight issue with spamming. For example, we had users sign up, and write about 6 blogs a minute trying to sell stuff.
I am looking for a quick way to limit these activities by the id of the user, let's say only allowing them to post 3 blogs a day.
I have the users stored in a $auth variable and through OOP bring them up by $auth->id for example to be more specific.
Looking for a fast,simple way to do this via php.
thanks in advance /**EDIT*****/
this is what I have so far, and I know for sure $too many is counting as it should, but for some reason my if(statement is not stopping the 4th blog from posting. HERE is the code
Something like CAPTCHA would be appropriate. However, if they're being entered manually, it will do little to stop them. Regardless, no reason you can't implement both methods.
I'm assuming you have a created field in your blogs table. Simply query the table for the number of blogs with today's date before allowing another to be posted. Not sure what database/API you're using. In MySQL, you could do:
SELECT COUNT(*)
FROM blogs
WHERE user_id = USERID
AND DATE(created) = '2011-11-30'
When the user writes and submits a post, save the date they posted on the post's table. Select and count the amount of times they posted today. If they are under their limit, allow the post or else give them the error/warning message.
When a post is made, do something like:
// Get last post time and number of posts today from database
$query = "SELECT
last_post,
posts_today
FROM
users
WHERE
id = '$auth->id'";
$result = mysql_fetch_assoc(mysql_query($query));
// See if this is the first post today
$isNewDay = date('Y-m-d') != date('Y-m-d',strtotime($result['last_post']));
$postsToday = ($isNewDay) ? 0 : (int) $result['posts_today'];
// Only add post if user is allowed
if ($isNewDay || $postsToday < 3) {
/*
Add the post to the database here
*/
// Update the number of posts today in the database
$query = "UPDATE
users
SET
last_post = '".date('Y-m-d H:i:s')."',
posts_today = '".($postsToday + 1)."'
WHERE
id = '$auth->id'";
mysql_query($query);
} else {
echo "You have already made 3 posts today!";
}
...or you could just use a CAPTCHA (as mentioned by others). That's what they're for. Really, you should have one in the signup process...
I'll admit I know next to nothing on PHP programming, but another option (or addition to the CAPTCHA) would be to use a service such as StopForumSpam
There's an example of how to use it here (no idea how good it is, as I don't code PHP (yet)) :)

new comments notification implementation for a web site

I've got a website where people can make posts and comment on them. I want to make a new comment notification system, so when a user logs in he can see number of new comments to his posts.
My idea is to add a 'read' table, where I will store user_id and comment_id (means user_id read comment_id). But this can make some performance issue, when table will grow big.
What's the best way to implement this?
One way to achieve that is just to save a created date for post and comment, and a "last visit" date for the user (or "last time the user click on the "show me new post" link).
Then, you just need to get all the post and comment that have a newer date than the one you find in the user table.
How about just storing the user and comment IDs for unread comments instead? Then when the user reads the comment, you can delete that row from the table.
Wouldn't it be better to store the post time in the notifications table and then look for the user's last activity (again storing the value in the users table). Then you could do a simple query:
$lastActivityTime = User->GetLastActivity();
$result = mysql_num_rows(mysql_query("SELECT COUNT(`id`) FROM `notifications` WHERE `postTime` > '$lastActivityTime'"));
Good luck!
You can choose a different storage than mySQL for this data (Like : MongoDB).
Or you can make pub/sub implementation for notifying users. (With using pubsub you dont need to store data. Just notify)

"viewed" system - once per user

I need to implement "viewed" system.
How it can be done, so that pressing F5 would not increase viewed number for more than 1 per user?
SO also has such system.
Cookies, sessions, db? How it is usually done?
You will need a combination of technologies here. Each user needs to be identified uniquely (using sessions, cookies, whatever works best in your scenario). From there, you will need to be maintaining a database of hits for an item with the user's unique key (stored in their cookie or session or whatever).
When the user accesses the page, check the database to see if that user's unique key already has a hit on that page. If not, add it. Regardless, once done, pull the total number of hits that the item has had from the database. Tahdah.
Just store in your database user_id, resource_id (eventually timestamp) and before you increase viewed value check whether SQL like this:
SELECT COUNT(*) FROM ... WHERE user_id = ? AND resource_id = ? (AND timestamp > NOW() - 7 DAYS or sth)
doesn't return 1.
This depends a lot on the situation. For example, if each user is logged in with a user ID, it would be very different then if you are doing a splash page where users are not expected to be logged in.
I will assume you are in the latter category, and that users are not logged in to your page. If this were the case, I would recommend setting a cookie using the setcookie command, this could be accomplished like this:
if (empty($_COOKIE['hasViewed'])) {
//increment the total number of views in the
//database or wherever we are storing it.
$viewer->incrementViews();
}
//make sure they have a cookie for next time
setcookie("hasViewed", "1", time() + 60*60*24*30);
Note that in this example, the user would be able to cause your view to increment again if they haven't seen the page in 30 days.

Categories