Здравствуйте, делаю страничку голосования. Сложность заключается в том, что ни как не могу понять, как сделать запрет на повторное голосование. По ip запрет работает, это если за один и тот же пункт, голосовать в тот же день, не получится, а вот в тот же день но за второй пункт, голосование происходит. Я где-то читал, что такое можно сделать используя сессию или куки, но что-то я их не могу победить.
Код (Text): <?php include("config.php"); $teacher_id = $_POST["teacher"]; $teacher_id = strip_tags($teacher_id); $teacher_id = mysqli_real_escape_string($link, $teacher_id); $teacher_id = trim($teacher_id); $ip_address = $_SERVER["REMOTE_ADDR"]; $ip_address = strip_tags($ip_address); $ip_address = mysqli_real_escape_string($link, $ip_address); $ip_address = trim($ip_address); $data = date("Ymd"); $data = strip_tags($data); $data = mysqli_real_escape_string($link, $data); $data = trim($data); $sql = "SELECT * FROM teachers WHERE id='".$teacher_id."'"; if($result = mysqli_query($link, $sql)) { if(!$result) { echo "Запись пуста".mysqli_error(); } else { $row = mysqli_fetch_assoc($result); //var_dump($row); if($row['data'] == $data || $row['ip_address'] == $ip_address) { include("ok.php"); } else { $new_vote = $row["vote"] + 1; $sql = "UPDATE teachers SET vote='".$new_vote."', data='".$data."', ip_address='".$ip_address."' WHERE id='".$teacher_id."'"; $result = mysqli_query($link, $sql); if(!$result) { echo "Запись не произошла ".mysqli_error(); } else { include("ok2.php"); } } } } ?>
Если у учителя айдишник - цифра, то достаточно кастовать тип переменной вместо вот этого полового извращения с обрезанием и экранированием. Данные, которые ты генерируешь внутри скрипта иногда могут не представлять угрозы, в отличии от присылаемых пользователем. Вот это извращение с обрезанием и экранированием даты - лишнее. Для компактного хранения айпишника его можно конвертировать в число из четырех байт. Потому что айпишник это число из четырех байт. Просто для удобочтения его записывают отдельными октетами. Защиты собственно тут не особо видно. Расскажи задумку-то.
Айдишник учителя цифра, а как конвертировать айпи? И тогда вопрос, как тогда сделать, запрет на голосование, не только по айпи, но и чтобы пользователь мог голосовать, всего лишь один раз в сутки, не зависимо от количества предлогаемых пуктов голосования. Потому как на данный момент, запрет работает, только по айпи, и только для конкретно выбранного айдишника учителя. Но таких айдишников около 30, как запретить, пользователю голосовать за все остальные оставшиеся. Не знаю понятно ли я выражаюсь...
Берёшь при голосовании, когда ты пишешь обработчик его типа вот такого-во вида. PHP: if(isset($_POST['submit'])) { session_start() ; if(!empty($_SESSION['session'])) { echo 'Пошёл нахер отседа ты уже голосовал!'; } else { /// Тут делаешь что тебе надо и в конце Присваиваешь сессию $_SESSION['session'] = 1; } } Только почитай про сессии, как например увеличть жизнь сессии, и как сделать чтобы сессия не закрывалась когда браузер закрываешь. А можно это всё сделать ещё в бд. Например создать колонку, имя id пользователя, и колонку проголосова. в boolen 1 значит да, и 0 значит нет. При голосовании ставишь её в 1 и при повторном голосовании проверяешь, в базу у этого пользователя, там 1 или 0 если 1 значит голосовал. Если 0 значит ещё не голосовал. Если голосование доступно в течении суток, можешь поставить планировщик задач на очистку таблицы, но надо тебе про cron почитать. На самом деле не чего в этой задаче сложного нет, просто у тебя не хватает знаний, кстате такую задачу наверно лучше не через сессии реализовывать. а через базу всё таки, я бы наверно через базу решил этот вопрос. Хотя можешь ещё куками, но куки можно взять и поменять в браузере, в итоге смысл что ты будешь записывать в куки
Я где-то читал, что можно использовать такую вот функцию Код (Text): setcookie("done","yes",time()+1800); Но, как потом это значение впихнуть в переменную и записать ее в бд? Потому как у меня не получалось. И еще вопрос, для этого надо создавать отдельную таблицу или можно создать поле в таблице с учителями? Сейчас у меня всего две таблицы teachers, где хранятся ФИО учителей и названия их предметов, а вторая таблица type_teacher, там хранятся данные к какой категории они принадлежат, но с этим проблем нет. там все нормально работает. Вот структура таблицы teachers Код (Text): CREATE TABLE IF NOT EXISTS `teachers` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `name_teachers` text NOT NULL, `title_themes` text NOT NULL, `vote` int(11) NOT NULL DEFAULT '0', `data` date NOT NULL, `ip_address` varchar(15) NOT NULL, `id_type` int(11) NOT NULL, `session_id` varchar(255) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=39 ;
@kvadim тебе @askanim правильно про базу написал. В базе делаешь таблицу id, date, ip и перед тем как показать пользователю форму голосования и принять его голос, ты делаешь запрос в эту таблицу с его where ip = $ip and `date` = NOW() и если ты получил запись, значит пользователь голосовал. Если нет такой ещё записи то пусть голосует и после голосования создавай такую запись. Тут уникальная запись выйдет ip пользователя и дата голосования.
Собственно у меня и так проверяется существует ли запись с определенным ip и датой, я ж код предоставил, там вроде бы понятно. Я же писал, что по айпи аноним не может больше одного раза в сутки проголосовать за один конкретный пункт. Проблема в том, что анониму предоставляется 30 пунктов, если он один раз проголосовал в день за 1 пункт, то как запретить ему голосовать и за второй пункт в тот же день. Подскажите, сколько тогда должно быть у меня таблиц?
Ты за любой пункт перед тем как разрешать голосовать смотри есть ли в базе ip и дата на сегодня, если есть то за любой пункт не давай голосовать
Вот просмотрите пожалуйста мой код который я писал выше, подскажите что в нем надо переделать, потому как я что-то не совсем понимаю...что именно надо там поменять
@kvadim там нету запроса в таблицу в которой храниться IP и дата когда голосовали. Перед голосованием надо проверить голосовал человек или нет при этом не учитывать пункт за который он голосовал, учитывать только IP и дату, и если такая запись найдётся, не давать ему голосовать.
Ну, как нет а это? Код (Text): // тут меня берут данные из таблицы в которой хранятся не только ФИО, количество голосов за конкретного человека, а так же айпи и дата голосования $sql = "SELECT * FROM teachers WHERE id='".$teacher_id."'"; if($result = mysqli_query($link, $sql)) { if(!$result) { echo "Запись пуста".mysqli_error(); } else { $row = mysqli_fetch_assoc($result); //var_dump($row); /// тут у меня проверяется если человек голосовал, и если совпадают айпи и дата, то вывести сообщение о то, что уже голосовали, просто я это сообщение в отдельный файл запихнул ok.php if($row['data'] == $data || $row['ip_address'] == $ip_address) { include("ok.php"); } else { // А тут если айпи и дата не совпадают, то обновлять данные $new_vote = $row["vote"] + 1; $sql = "UPDATE teachers SET vote='".$new_vote."', data='".$data."', ip_address='".$ip_address."' WHERE id='".$teacher_id."'"; $result = mysqli_query($link, $sql); if(!$result) { echo "Запись не произошла ".mysqli_error(); } else { include("ok2.php"); } } } } Что тогда в этом случае надо поменять?
Так вот же из общего запроса Код (Text): $sql = "SELECT * FROM teachers WHERE id='".$teacher_id."'"; в этой таблице teachers хранятся и дата и айпи, а вот условие Код (Text): if($row['data'] == $data || $row['ip_address'] == $ip_address) которое проверяет данные взятые из бд и которые были получены в этих строках Код (Text): //тут переменная $ip_address получает айпи из глобального массива $_SERVER["REMOTE_ADDR"]; $ip_address = $_SERVER["REMOTE_ADDR"]; $ip_address = strip_tags($ip_address); $ip_address = mysqli_real_escape_string($link, $ip_address); $ip_address = trim($ip_address); //а тут получает переменная $data текущую новую дату $data = date("Ymd"); $data = strip_tags($data); $data = mysqli_real_escape_string($link, $data); $data = trim($data);
где тут условие WHERE для IP and date? Я же об этом писал и давал псевдокод SQL выполнив который нужно проверить есть результат или нету
Так этого что не достаточно Код (Text): if($row['data'] == $data || $row['ip_address'] == $ip_address) ? Не ужели надо обязательно еще и в запрос это пропихивать? Что-то я вообще ничего не пойму. Вы можете хотя бы схематично показать, что надо поменять? Вернее даже не так, а что за чем должно идти. А то у меня уже каша в голове...Если конечно Вам не трудно.
@kvadim у тебя запрос "выбрать всё где учитель такой-то" может вернуть не только одну строку, верно? ГОЛОСУЮЩИХ ЖЕ МНОГО. А ты потом проверяешь только первый кортеж в результирующей таблице. С какой вероятностью это будет запись именно этого голосующего? С маленькой. Поэтому тебе и говорят что нужно дергать строку по учитель-дата-айпишник. Тогда либо строка будет, либо её не будет. Одна или ноль. Понимаешь?
А тут тоже надо будет изменять условие или оставлять такое же? Код (Text): if($row['data'] == $data || $row['ip_address'] == $ip_address)
А ты как сам думаешь? Ты спрашиваешь у СУБД "Дай мне строку где учитель такой-то, айпишник такой-то и дата такая-то". Она тебе отвечает нулем или одной строкой. Вот если там одна строка в ответе - нужно ли, мать её, на стороне пхп проверять на соответствие даты и айпишника? А УЧИТЕЛЯ ПОЧЕМУ ВДОГОНКУ НЕ ПРОВЕРИТЬ? Кол-во строк в результате достаточно. И выбирать можно псевдокортеж с 1.
Значит как я понимаю, запрос должен быть такой Код (Text): $sql = "SELECT * FROM teachers WHERE id='".$teacher_id."'AND ip_address="'.$ip_address.'" AND data="'.$data.'" "; и условие проверки Код (Text): if($row['data'] == $data || $row['ip_address'] == $ip_address || $row['id'] == $teacher_id) , правильно ли я все понял? Если нет, то поправьте пожалуйста.
С первым понял правильно. Только можно выбирать не * а 1. Тебе же не нужен кортеж. Тебе нужно только знать, есть ли он в базе. А вот со вторым понял не правильно. Нужно проверять только кол-во строк в результате запроса.