2014-01-28 3 views
0

На моем веб-сайте я отображаю 5 вопросов (MCQ) на страницу и когда пользователь запрашивает новую страницу, я вызываю скрипт score_update() со счетом этой страницы, а затем представляю его следующим стр.Создание надежной системы подсчета очков в PHP

scoreUpdate() скрипт что-то вроде

<?php 
//connect to database 
//update the score 
?> 

Проблема в том, что пользователь может обновить страницу и счет может обновляться дважды или несколько раз, он обновляет страницу или он может непосредственно вызывать сценарий путем просмотра исходного кода.

Как я могу реализовать эту систему? Мне нужна идея.

EDIT

Вот моя схема базы данных

user

------------------------------------------ 
user_id | username | password | points 
------------------------------------------ 

PS: пользователь может попытаться один и тот же вопрос еще раз в какой-то момент в будущем. На это нет никаких ограничений. Поэтому нет необходимости отслеживать поставленные им вопросы. Он должен получить отметки только в том случае, если он попытается задать вопрос и правильно его исправить. Надеюсь, я поняла.

+2

Рекомендуется использовать PRG (Post Redirect Get), чтобы (в основном) избежать этой проблемы. –

+0

@Jack: PRG не полезен в моем случае, поскольку я обновляю счет в фоновом режиме и не могу перенаправить его на страницу. Я хочу реализовать систему подсчета очков, подобную переполнению стека. –

+0

@InsaneCoder прочитал мой последний комментарий в моем ответе, если вам не нужно время, которое вы можете просто создать таблицу с идентификатором questionID и идентификатором учетной записи и получить результат с предложением WHERE, соответствующим как идентификатору accountID, так и currentQuestionID. Если возвращаемые строки> 0, вы не можете добавить счет снова, потому что пользователь уже оценил. – Steini

ответ

1

Я бы предложил использовать клавиши формы, также известные как NONCE.

Это означает, что каждый раз, когда выполняется подача, создается новый ключ формы (NONCE).

Каждый NONCE может использоваться только один раз, а NONCE должен быть действительным для представления формы для работы.

Большинство современных фреймворков имеют нечто вроде этого встроенного в стандартную комплектацию.

Смотрите эту статью для более глубокого объяснения идеи: http://net.tutsplus.com/tutorials/php/secure-your-forms-with-form-keys/

И этого раздел защиты Symfony2 CSRF на формах, которые используют ту же технику: http://symfony.com/doc/current/book/forms.html#csrf-protection

+0

: Я думаю, что это может быть решение. Я смотрю на него –

+0

После того, как я ударил головой о стену, пробовав другие методы, я, наконец, в конечном итоге использовал то, что вы предложили, и его потрясающий способ, сохраняя тяжелую работу моего сервера. +1 –

+0

рад помочь :) – edmondscommerce

0

Существуют различные возможные решения таких проблем. Это в основном то же самое с счетчиками посетителей или опросами.

По крайней мере, вы должны хранить свою информацию где-нибудь, если пользователь уже активировал этот сценарий и переназначил его при каждом вызове страницы.

  • Первый и лучший метод - это учетная запись пользователя для входа и сохранения в PHP $ _SESSION или непосредственно в базе данных, связанной с user_id/account_id. Но это, если на вашей странице нет входа прямо сейчас, это слишком много для меньшей проблемы, я думаю. Но если у вас уже одна панель входа, это, безусловно, лучшее решение.
  • Другим методом является сохранение cookie, который может быть проблемой в некоторых странах в последнее время, если пользователь не соглашается с тем, что перед рукой и файлы cookie могут быть удалены, поэтому их легко манипулировать.
  • Вы также можете сохранить IP-адрес пользователей: Сложнее манипулировать (требуется перезагрузка интернета и т. Д., И никто не сделает это десяток раз, чтобы подделать счетчик очков), но если несколько человек используют одно и то же интернет-соединение, только один из них может достигать одного балла.

Все они имеют разные преимущества и недостатки. В зависимости от того, как вы выглядите параноиком, вы также можете объединить несколько из них, если вы хотите сделать мошенничество/злоупотребление труднее, но это решение зависит от вас.

+0

: Да У меня есть система входа в систему, и первый метод кажется лучшим. При входе пользователя в систему я выбираю последний балл из базы данных и добавляю к нему значение оценки и отобразить общее количество для пользователя, чтобы он увидел последний балл. Но когда я обновил счет до базы данных? потому что возможно, что пользователь не вышел из системы. –

+0

Вы должны сохранить его немедленно. Все это зависит от структуры базы данных. Например: таблица Score (account_id, timestamp, question_id, оценка); может выглядеть так. Затем вы выбираете просто SELECT * FROM 'score' WHERE' question_id' = $ currentQuestionID, 'account_id' = $ user_id И' timestamp' + 86400 0, то пользователь не может быть сохранен снова. Это всего лишь каракули с одной возможностью сказать, что пользователь может делать это один раз в день. Вам нужно сделать так, чтобы он соответствовал вашему сценарию. – Steini

+0

: Моя структура базы данных похожа на ** user ** (id, name, points), и вопросы берутся из таблицы ** вопросов ** (id, title, option_a, option_b, option_c, option_d, answer) –

0

Проверьте значение $_SERVER['HTTP_REFERER'].

  • Если это та же страница: перезагружается.(Ничего не делать)
  • Если предыдущий: обновление базы
  • Если другой домен: незаконный доступ (перенаправление на первый вопрос)
+0

: Я думаю, что для обработки последнего случая я также могу использовать другой подход, например, установить параметр «temp_score» на страницу до 0 после обновления, чтобы даже если он из другого домена добавлен 0. Но ваш подход сохраняет этот запрос. умный ответ. Надеюсь, у него нет ни малейшего запаса. Поощряйте других, прежде чем я награду вас за награду –

+0

: И еще одна вещь, так как оценка рассчитывается на стороне клиента, используя javascript для страницы. Есть вероятность, что пользователь может изменить код или сдать счет вручную. Я могу запутать код с помощью компрессора, но есть ли лучшее решение или совет с вашей стороны. –

+0

, используя комбинацию AJAX и $ _SESSION, я полагаю, сделал бы трюк. отправьте оценку через AJAX на сервер, а затем вычислите общий балл и сохраните его в сеансе. –

0

Рассмотрим следующую установку;

users 
+------------+-------------+------+-----+---------+----------------+ 
| Field  | Type  | Null | Key | Default | Extra   | 
+------------+-------------+------+-----+---------+----------------+ 
| user_id | smallint(5) | NO | PRI | NULL | auto_increment | 
| username | varchar(10) | NO |  | NULL |    | 
+------------+-------------+------+-----+---------+----------------+ 
... You'll have more columns, but you get the idea 

-

questions 
+----------+--------------+------+-----+---------+----------------+ 
| Field | Type   | Null | Key | Default | Extra   | 
+----------+--------------+------+-----+---------+----------------+ 
| qid  | smallint(5) | NO | PRI | NULL | auto_increment | 
| question | varchar(10) | NO |  | NULL |    | 
| votes | smallint(5) | NO |  | 0  |    | 
+----------+--------------+------+-----+---------+----------------+ 

-

votes 
+--------+-------------+------+-----+---------+-------+ 
| Field | Type  | Null | Key | Default | Extra | 
+--------+-------------+------+-----+---------+-------+ 
| qid | smallint(5) | NO |  | NULL |  | 
| user_id| smallint(5) | NO |  | NULL |  | 
+--------+-------------+------+-----+---------+-------+ 

В этой установке, я Идентификатор_пользователя 1 и голосование за вопрос ид 1

Когда пользователь голосов, их голосование помещается в пределах votes

INSERT INTO `votes` (`qid`,`user_id`) VALUES (1, 1); 

Чтобы проверить, что они уже голосовали, просто выполните;

SELECT `user_id` FROM `votes` WHERE (`user_id`=1) AND (`qid`=1); 

Если запрос возвращает все строки, мы знаем, что пользователь уже проголосовал, и мы не должны обрабатывать дублированный голос.

Конечно, это ограничивает нас только одним типом голосования - положительным или отрицательным - в зависимости от того, что вы решите отслеживать. Мы можем адаптировать votes, чтобы сохранить тип голосования;

ALTER TABLE votes ADD type ENUM('up', 'down') NOT NULL DEFAULT 'up'; 

Который сделает нашу структуру таблицы следующей:

+---------+-------------------+------+-----+---------+-------+ 
| Field | Type    | Null | Key | Default | Extra | 
+---------+-------------------+------+-----+---------+-------+ 
| qid  | smallint(5)  | NO |  | NULL |  | 
| user_id | smallint(5)  | NO |  | NULL |  | 
| type | enum('up','down') | NO |  | up  |  | 
+---------+-------------------+------+-----+---------+-------+ 

И, опять же, адаптируйте запрос поиска;

SELECT `user_id` FROM `votes` WHERE (`user_id`=1) AND (`qid`=1) AND (`type`='up'); 
+0

@h: Я думаю, что вы неправильно прочитали вопрос. Даже если я посмотрю систему голосования, которую вы предложили, в моем случае она ограничивает пользователя попыткой вопроса только один раз в жизни. Но, как я уже цитировал, он может попытаться ответить на вопрос в любое время, но единственное, что я хочу, это остановить обновления при обновлении страницы. –

+0

Ах, мои плохие, извинения! –

2

Я бы рекомендовал спасение пользователь в вашей базе данных. Для этого вам нужно добавить другую таблицу.

----------------------------------- 
user_id | question_id | answer 
----------------------------------- 

Когда пользователь отвечает на вопрос, вы можете проверить, ответил ли пользователь на этот вопрос. Если да, обновите его ответ, и если это правильный ответ, обновите его. Этот метод работает, если вы не представите тот же вопрос снова, если пользователь уже ответил на него правильно.

Если вы хотите использовать вопросы несколько раз, я рекомендую другой метод. Используйте 2 таблицы:

---------------------------- 
user_id | questionnaire_id 
---------------------------- 

и

------------------------------------------ 
questionnaire_id | question_id | answer 
------------------------------------------ 

Каждый опросник уникален и содержит несколько вопросов - ответ на каждый вопрос пуст в начале. Создавайте новую анкету каждый раз, когда пользователь получает новый вопросник и сохраняет ответы на вопросник. Таким образом, вы можете удостовериться, что пользователь не может представить те же самые результаты опроса дважды (или более). Если пользователь впервые отправил эту анкету, вы можете обновить счет, если нет, ничего не делайте.

Чтобы убедиться, что пользователь не изменил свой вопросник_источник вручную, вы можете сохранить его в сеансе на сервере, чтобы пользователь не имел к нему доступа.

+0

Для его вопроса достаточно простого решения для таблицы 1 ... Просто используйте «INSERT ИЛИ UPDATE ANSWER =: ответ WHERE user_id =: user AND answer =: answer» - если вы хотите еще больше тривиально, вы можете заменить поле «ответ» на «оценка» и просто сохранить 1 или 0 там, если вопрос был прав или не прав - если вы хотите отобразить счет для пользователя, просто введите сумму запроса («оценка») где user_id =: user – Falco

0

Самая надежная система, которую я вижу, основана на отслеживании всей жизни заданной викторины.

Если вы сохраняете «текущий номер вопроса», связанный с пользователем и этой конкретной Quizz, вы можете легко отфильтровать повторяющиеся ответы:

update_score ($question_number, $choice) 
    if current question for this quizz and user is not set to $question_number 
    ignore request 
    else 
    set choice for this specific question and update score 
    increment current question (possibly reaching the end of the quizz) 

Когда последний вопрос ответил, отображается окончательная оценка/и «текущий вопрос» сбрасывается на 0.

Если пользователь хочет повторить тест, текущий вопрос задается равным 1, и весь процесс перезапускается.

Если пользователь хочет отменить текущий тест и перезапустить его, он может сделать это, вернувшись к стартовой странице опроса.

Таким образом, любая попытка представить второй ответ на этот же вопрос не удастся (будь то от случайного обновления или злонамеренных попыток), до тех пор пока Quizz не будет завершена, и вы можете начать снова с вопросом 1.

0

Вы можете использовать подход к переключению сеанса переключения (назовите его как флаг), который является самым простым и имеет хороший уровень защиты от повторяющихся запросов.

Сделать скрипт updateScore.php .При Логин пользователя установить flag=1, что означает, когда следующий запрос приходит Updation, обрабатывать его в updateScore.php и в конце тыс скрипта сделать flag=0. Когда следующая страница появится снова, сделайте flag=1. Таким образом вы чередуете значения, а также устанавливаете максимальный предел обновления в своем скрипте, скажем, в вашем случае у вас есть 5 вопросов, поэтому вы можете установить его на 50 (+10 на вопрос). Вы можете использовать более сложные значения флага, чтобы уменьшить шансы на угадывание.

+0

Ваше решение работает только для невинных пользователей, которые пытаются отправить форму дважды случайно. Пользователь может отправить одну и ту же форму один раз, затем дождаться окончания сеанса на сервере, а затем снова отправить ту же форму. В этом решении есть несколько сценариев, которые позволяют пользователю злоупотреблять сайтом и обманывать систему подсчета очков. Я бы посоветовал создать надежную систему и не использовать это решение. –

Смежные вопросы