title: How to prevent people from spamming an ajax form
body: <p>My problem is I have a vote system similar to the one of Stack Overflow. My problem is that a person can spam the vote up button which makes it glitch and make it submit more times than it’s supposed to. For example, if there are 10 up votes on a post, I could repeatedly click the vote up button and the it would add two or three up votes instead of one. Similarly I could do this with the down vote button. How do I prevent this?</p>
  
  <p>Index.php:</p>
  
  <pre><code>&lt;?php
  session_start();
  require('db.php');
  $pid = 2;
  $uid = $_SESSION['id'];
  $sql = mysqli_query($con, "SELECT * FROM posts WHERE pid = '$pid'"); //check to see how many likes the post has
  $r = mysqli_fetch_assoc($sql);
  $body = $r['body'];
  $likes = $r['likes'];
  $sql2 = mysqli_query($con, "SELECT * FROM likes WHERE pid = '$pid' AND uid = '$uid'");      //check to see if user has voted
  $n = mysqli_num_rows($sql2);
  if ($n == 0) {
      //user hasn't liked or down vote anything yet
      $liked = "no";
  } else {
      if ($n &gt; 1) {
          //like scammed
          echo "&lt;script&gt;alert('Stop spamming for votes. You are banned for spam.')&lt;/script&gt;";
          exit("You have been banned for spam");
          //This isn't fool proof though, and I don't want to ban people for this. It would be best if I could just prevent the vote scam in the first place
      }
  $r = mysqli_fetch_assoc($sql2);
  $type = $r['like_type'];
  if ($type == '0') {
      $liked = "liked";
  } else {
      $liked = "disliked";
  }
  }
  ?&gt;
  &lt;!DOCTYPE html&gt;
  &lt;html&gt;
  &lt;head&gt;
      &lt;title&gt;Test&lt;/title&gt;
      &lt;script src="//code.jquery.com/jquery-latest.min.js"&gt;&lt;/script&gt;
      &lt;style&gt;
          .selected {
              color: red;
          }
      &lt;/style&gt;
  &lt;/head&gt;
  &lt;body&gt;
  &lt;div class="post"&gt;
      &lt;p&gt;&lt;?php echo $body; ?&gt;&lt;/p&gt;
  &lt;/div&gt;
  &lt;div class="likes"&gt;
      &lt;a href="javascript:;" class="upvote &lt;?php if ($liked == 'liked') {echo "selected";} ?&gt;" id='up-&lt;?php echo $pid; ?&gt;' onclick="vote('up', '&lt;?php echo $pid; ?&gt;', '&lt;?php echo $uid; ?&gt;', 'up-&lt;?php echo $pid; ?&gt;', 'votes-&lt;?php echo $pid; ?&gt;')"&gt;Upvote&lt;/a&gt;
      &lt;span id="votes-&lt;?php echo $pid; ?&gt;"&gt;&lt;?php echo $likes; ?&gt;&lt;/span&gt;
      &lt;a href="javascript:;" class="downvote &lt;?php if ($liked == 'disliked') {echo "selected";} ?&gt;" id='down-&lt;?php echo $pid; ?&gt;' onclick="vote('down', '&lt;?php echo $pid; ?&gt;', '&lt;?php echo $uid; ?&gt;', 'down-&lt;?php echo $pid; ?&gt;', 'votes-&lt;?php echo $pid; ?&gt;')"&gt;Downvote&lt;/a&gt;
  &lt;/div&gt;
  &lt;/body&gt;
  </code></pre>
  
  <p>Javascript vote() function </p>
  
  <pre><code>function vote(type, pid, uid, id, voteId) {
  var vote = $('#'+ id);
  if (vote.hasClass('selected')) {
      //user voted for this
      $.post("vote.php", {pid: pid, uid: uid, type: type, vote: 'reset'}, function(d) {
          if (d == '0' || d == '1') {
              vote.removeClass('selected');
              var votes = $('#' + voteId);
              var num = votes.text();
              if (d == '1') {
                  votes.text(++num);  
              } else {
                  votes.text(--num);
              }
          } else {
              alert('An error occurred')
          }
      });
  } else {
      var upVoteId = $('#up-' + pid);
      var downVoteId = $('#down-' + pid);
      if (upVoteId.hasClass('selected') || downVoteId.hasClass('selected')) {
          //user wants to switch votes
          $.post('vote.php', {pid: pid, uid: uid, type: type, vote: 'switch'}, function(data) {
              var votes = $('#' + voteId);
              var num = votes.text();
              if (data == '1') {
                  //downvote successful
                  votes.text(parseInt(num) - 2);
                  vote.addClass('selected');
                  upVoteId.removeClass('selected');
              }
              if (data == '0') {
                  //upvote successful
                  votes.text(parseInt(num) + 2);
                  vote.addClass('selected');
                  downVoteId.removeClass('selected');
              }
              if (d == 'error') {
                  alert('error');
              }
          });
      } else {
          $.post('test2.php', {type: type, pid: pid, uid: uid}, function(d) {
              if (d == "1") {
                  //everything good
                  $('#' + type + '-&lt;?php echo $pid; ?&gt;').addClass('selected');
                  var votes = $("#" + voteId).text();
                  if (type == 'down') {
                      //downvote
                      votes = --votes;
                      $('#' + voteId).text(votes);
                  } else {
                      votes = ++votes;
                      $('#' + voteId).text(votes);
                  }
              } else {
                  alert('failed');
              }
          });
      }
  }
  }
  }
  </code></pre>
  
  <p>Vote.php</p>
  
  <pre><code>&lt;?php
  session_start();
  require('db.php');
  
  if (!isset($_SESSION['id'], $_SESSION['un'])) {
      //not logged in
      header('Location: index.php');
      exit;
  } else {
      if (!isset($_POST['uid'], $_POST['pid'], $_POST['type'], $_POST['vote'])) {
          //form not submitted
          header('Location: home.php');
          exit;
      } else {
          $uid = (int)$_SESSION['id'];
          $pid = (int)$_POST['pid'];
          $type = preg_replace('#[^a-z]#', '', $_POST['type']);
          $vote = preg_replace('#[^a-z]#', '',$_POST['vote']); //vote type
  
          if ($vote == 'reset') {
              //initiate vote reset
              if ($type == 'down') {
                  //downvote
                  $sql = mysqli_query($con, "DELETE FROM likes WHERE like_type = '1' AND pid = '$pid' AND uid = '$uid'"); //delete the downvote
                  $sql2 = mysqli_query($con, "UPDATE posts SET likes = likes + 1 WHERE pid = '$pid'");
                  if ($sql) {
                      echo "1"; // 1
                      exit;
                  } else {
                      echo "error";
                      exit;
                  }
              } else {
                  //upvote
                  $sql = mysqli_query($con, "DELETE FROM likes WHERE like_type = '0' AND pid = '$pid' AND uid = '$uid'"); //delete upvote
                  $sql2 = mysqli_query($con, "UPDATE posts SET likes = likes - 1 WHERE pid = '$pid'");
                  if ($sql) {
                      echo "0"; // 0
                      exit;
                  } else {
                      echo "error";
                      exit;
                  }
              }
          }
  
          if ($vote == 'switch') {
              //user wanted to switch vote
              if ($type == 'down') {
                  //user had voted up but wants to vote down now
                  $sql = mysqli_query($con, "DELETE FROM likes WHERE like_type = '0' AND pid = '$pid' AND uid = '$uid'"); //delete the previous vote
                  $sql2 = mysqli_query($con, "INSERT INTO likes (pid, uid, like_type, date_liked) VALUES ('$pid', '$uid', '1', now())"); //insert new vote
                  $sql3 = mysqli_query($con, "UPDATE posts SET likes = likes - 2 WHERE pid = '$pid'");
                  if ($sql AND $sql2 AND $sql3) {
                      //all three queries were successful
                      echo "1";
                      exit;
                  } else {
                      echo "error";
                      exit;
                  }
              } else {
                  //user had voted down but wants to vote up now
                  $sql = mysqli_query($con, "DELETE FROM likes WHERE like_type = '1' AND pid = '$pid' AND uid = '$uid'") or die(mysqli_error($con)); //delete the previous vote
                  $sql2 = mysqli_query($con, "INSERT INTO likes (pid, uid, like_type, date_liked) VALUES ('$pid', '$uid', '0', now())"); //insert new vote
                  $sql3 = mysqli_query($con, "UPDATE posts SET likes = likes + 2 WHERE pid = '$pid'");
                  if ($sql AND $sql2 AND $sql3) {
                      //all three queries were successful
                      echo "0";
                      exit;
                  } else {
                      echo "error";
                      exit;
                  }
              }
          }
      }
  }
  </code></pre>
  
  <p>Test2.php </p>
  
  <pre><code>&lt;?php
  require('db.php');
  
  $pid = $_POST['pid'];
  $uid = $_POST['uid'];
  $type = $_POST['type'];
  
  if ($type == "down") {
      //downvote
      $type = 1;
      $sql = mysqli_query($con, "INSERT INTO likes (uid, pid, like_type, date_liked) VALUES ('$uid', '$pid', '$type', now())");
      $sql2 = mysqli_query($con, "UPDATE posts SET likes = likes - 1 WHERE pid = '$pid'");
      if ($sql) {
          echo '1';
          exit;
      }
  } else {
      //upvote
      $type = 0;
      $sql = mysqli_query($con, "INSERT INTO likes (uid, pid, like_type, date_liked) VALUES ('$uid', '$pid', '$type', now())");
      $sql2 = mysqli_query($con, "UPDATE posts SET likes = likes + 1 WHERE pid = '$pid'");
      if ($sql) {
          echo '1';
          exit;
      }
  }
  </code></pre>
  
  <p>These are my pages that are currently used. I plan on moving <code>test2.php</code> to <code>vote.php</code>.</p>
  
  <p>In my database I have two tables, one to store all the post details including the number of votes. The second table is to store who voted for what post and if it was an upvote or down.</p>
  
  <p>If I could make my system more efficient, please give me tips or recommendations.</p>