【问题标题】:Upvote/Downvote System赞成/反对系统
【发布时间】:2012-06-17 13:54:00
【问题描述】:

我有以下 PHP 脚本:

<?php
$vote_type = $_GET['type'];
$book = $_GET['book'];
$id = $_GET['id'];


include 'pagehead.php';

$tracker_table = $book.'VoteTrack';
$username = $_SESSION['username'];

session_start();
if ($_SESSION['username'] == null) {
echo 'You must be logged in to vote';
echo '<br>';
echo '<a href="lesson.php?book='.$book.'&id='.$id.'">';
echo 'Return to lesson';
echo '</a>';
die();
}

include 'mysqlserver.php';
$con = mysql_connect($mysql_host, $mysql_username, $mysql_password);
if (!$con){
die ('Failed to connect to the database');
}

mysql_select_db("a6595899_s", $con);


$data_query = "SELECT * FROM $book WHERE id=$id";
$lesson_data = mysql_query($data_query);
$lesson_array = mysql_fetch_assoc($lesson_data);

$vote_cop_query = "SELECT * FROM $tracker_table WHERE user='$username' AND id=$id";
$vote_cop_data = mysql_query($vote_cop_query);
$vote_cop = mysql_fetch_assoc($vote_cop_data);

if (mysql_num_rows($vote_cop_data) != 0 && $vote_type == 'up' && $vote_cop['has'] == 1) {
echo 'You have already upvoted this lesson.';
echo '<br>';
echo '<a href="lesson.php?book='.$book.'&id='.$id.'">';
echo 'Return to lesson';
echo '</a>';
die();
} elseif (mysql_num_rows($vote_cop_data) != 0 && $vote_type == 'down' && $vote_cop['has'] == 2) {
echo 'You have already downvoted this lesson.';
echo '<br>';
echo '<a href="lesson.php?book='.$book.'&id='.$id.'">';
echo 'Return to lesson';
echo '</a>';
die();
}

$vote_count = $lesson_array['votes'];
if ($vote_type == 'up') {
$vote_count++;
$has_type = 1;
} elseif ($vote_type == 'down') {
$vote_count--;
$has_type = 2;
} else {
die('Vote type not specified.');
}

$new_or = mysql_num_rows($vote_cop_data);

if ($new_or == 0) {
$track_query = "INSERT INTO $tracker_table (user, id, has)
VALUES ('$username', $id, $has_type)";
} else {
$track_query = "UPDATE $tracker_table SET has=$has_type WHERE user='$username' AND id=$id";
}
mysql_query($track_query);


//actually cast vote..
$update_query = "UPDATE $book SET votes=$vote_count WHERE id=$id";
mysql_query($update_query);

echo 'Your vote has been submitted!';
echo '<br>';
echo '<a href="lesson.php?book='.$book.'&id='.$id.'">';
echo 'Return to lesson';
echo'</a>';


?>

这是一个非常简单的赞成/反对系统。不幸的是,它在某些情况下会崩溃。假设我正在阅读我认为很好的课程,所以我投了赞成票。后来,我意识到这堂课实际上很糟糕,所以我投了反对票。在我第一次投票之后,这节课有了一点。在我投反对票后,它又变成了 0。逻辑表明我应该能够再次对这节课投反对票,给它-1分。我的代码不允许这样做,因为我的脚本只是说不允许连续 2 次执行相同的操作。 我用什么数学来解决这个问题?

【问题讨论】:

  • 请不要使用mysql_* 函数编写新代码。它们不再维护,社区已经开始deprecation process。看到red box?相反,您应该了解 prepared statements 并使用 [PDO](http
  • @Geoist 作为记录,这是我的代码,它完全是从头开始编写的。我只需要有关代码的帮助,该代码允许某人在赞成某件事后两次反对某件事,反之亦然。
  • 查看amix.dk/blog/post/19588,这是对 Reddit 排名算法的非常好的分析。不是您问题的直接答案,但值得为后代发布。
  • 这段代码以及下面答案中的代码都存在 SQL 注入漏洞。建议读者不要从其中复制代码。

标签: php mysql


【解决方案1】:

问题在于,您在对他们自己的投票投了反对票后更新了用户的活动。

$track_query = "UPDATE $tracker_table SET has=$has_type WHERE user='$username' AND id=$id";

你应该做的是从表中删除记录而不是更新它,然后继续修改你已经存在的分数。这样,您进行的下一次投票将是您进行的“第一次”投票。

或者,您可以使用名为“nullify”或“revoke”的第三种 vote_cop 类型,然后相应地修改 vote cop。

请参阅下面的建议:

$hasVotedBefore = mysql_num_rows($vote_cop_data) != 0;

if ($hasVotedBefore) {

  switch ($vote_cop_data['has']) {
  case 0:
    $vote_cop_type = 'revoked'; // Not really neccessary to do this, but just here for show.
    break;    
  case 1:
    $vote_cop_type = 'up';
    break;
  case 2:
    $vote_cop_type = 'down';
    break;    
  default:
    break;

  if ($vote_type == $vote_cop_type) { // We're here because we voted before and our new vote is the same as the old one.

    if ($vote_type == 'up') {

      echo 'You have already upvoted this lesson.';
      echo '<br>';
      echo '<a href="lesson.php?book='.$book.'&id='.$id.'">';
      echo 'Return to lesson';
      echo '</a>';
      die();

    } elseif ($vote_type == 'down') {

      echo 'You have already downvoted this lesson.';
      echo '<br>';
      echo '<a href="lesson.php?book='.$book.'&id='.$id.'">';
      echo 'Return to lesson';
      echo '</a>';
      die(); 
    }

  } else { // Were here because we've voted before, and our new vote is the opposite of the old vote.

     // Update vote_cop row in the database so the 'has' column is 0 (value of a revoked vote)
     // This way, for future votes, we know the user has voted before, but revoked their vote.
     $track_query = "UPDATE $tracker_table SET has=0 WHERE user='$username' AND id=$id";
     mysql_query($track_query);
  }
} else { // We're here because we never voted before.

  $track_query = "INSERT INTO $tracker_table (user, id, has) VALUES ('$username', $id, $vote_type)";
  mysql_query($track_query);
}

// TODO: actually cast vote..

【讨论】:

  • 太棒了。非常感谢。
  • 我添加了算法大纲,以防上面的建议不够好。
  • 对不起我的白痴。我目前有这个:pastebin.com/533JSZwa。 “撤销”投票类型和更新 vote_cop 记录是什么意思?更新到您的意思是重新查询 MySQL 数据库?
  • 对不起我的懒惰。我已更新我的答案以包含 -actual- 代码。让我知道这是否有意义。
  • 非常有意义。谢谢!
猜你喜欢
  • 1970-01-01
  • 2016-06-19
  • 2019-10-30
  • 2011-05-05
  • 2015-10-21
  • 1970-01-01
  • 1970-01-01
  • 2019-03-10
  • 1970-01-01
相关资源
最近更新 更多