@Paltinik

Система голосования на файла, как защититься от накрутки ??

Нашёл какой то скрипт рейтинга, решил его переделать.. Что бы выводились данные сразу в индексный файл и обновлялась инфа при ajax запросе... там ещё были id рейтингов, я вроде бы их убрал так как мне для 1 страницы нужно. В общем часть кода перенёс в Index.php другую в отдельный rate.php для обработки запросов.
Index.php:
<?php
$rating = new ratings();
$rating->get_ratings();
class ratings {
    var $data_file = './ratings.data.txt';
    private $data = array();

function __construct() {
    $all = file_get_contents($this->data_file);
    if($all) {
        $this->data = unserialize($all);
    }
}

    public function get_ratings() {
        $lol = $this->data;
        $rate = $lol['rate'];
        $votes = $lol['votes'];
         $stars = $lol['stars'];
?>

    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script>

$(document).ready(function() {
var widget = this;
$(widget).find('.star_<?php echo $stars; ?>').prevAll().andSelf().addClass('ratings_vote');
$(widget).find('.star_<?php echo $stars; ?>').nextAll().removeClass('ratings_vote');   

        $('.ratings_stars').hover(
            // Handles the mouseover
            function() {
                $(this).prevAll().andSelf().addClass('ratings_over');
                $(this).nextAll().removeClass('ratings_vote'); 
            },
            // Handles the mouseout
            function() {
                $(this).prevAll().andSelf().removeClass('ratings_over');
                // can't use 'this' because it wont contain the updated data
                set_votes($(this).parent());
            }
        );
        
        
        $('.ratings_stars').bind('click', function() {
            var star = this;
            var widget = $(this).parent();
            $.post(
                'rate.php',
                {
                clicked_on : $(star).attr('class')
            },
                function(INFO) {
                    widget.data( 'fsr', INFO );
                    set_votes(widget);
                },
                'json'
            ); 
        });
        
        
        
    });

    function set_votes(widget) {
        var avg = $(widget).data('fsr').stars;
        var votes = $(widget).data('fsr').votes;
        var exact = $(widget).data('fsr').rate;
        $(widget).find('.star_' + avg).prevAll().andSelf().addClass('ratings_vote');
        $(widget).find('.star_' + avg).nextAll().removeClass('ratings_vote'); 
 $('#total').text('голосов '+votes);
 $('#rate').text('рейтинг '+exact);
    }

    
    </script>
    
<div id="total">Голосов <?php echo $votes; ?></div>
<hr>
<div id="rate">Рейтинг  <?php  echo $rate; ?> </div>

<hr>

    <div id="r1" class="rate_widget">
        <div class="star_1 ratings_stars"></div>
        <div class="star_2 ratings_stars"></div>
        <div class="star_3 ratings_stars"></div>
        <div class="star_4 ratings_stars"></div>
        <div class="star_5 ratings_stars"></div>
    </div>

    <style>
        .rate_widget {
            border:     1px solid #CCC;
            overflow:   visible;
            padding:    10px;
            position:   relative;
            width:      180px;
            height:     32px;
        }
        .ratings_stars {
            background: url('star_empty.png') no-repeat;
            float:      left;
            height:     28px;
            padding:    2px;
            width:      32px;
        }
        .ratings_vote {
            background: url('star_full.png') no-repeat;
        }
        .ratings_over {
            background: url('star_highlight.png') no-repeat;
        }
        .total_votes {
            background: #eaeaea;
            top: 58px;
            left: 0;
            padding: 5px;
            position:   absolute;  
        } 
        .movie_choice {
            font: 10px verdana, sans-serif;
            margin: 0 auto 40px auto;
            width: 180px;
        }
        h1 {
            text-align: center;
            width: 400px;
            margin: 20px auto;
        }

    </style>

<?php } } ?>


rate.php
<?php
$rating = new ratings();
isset($_POST['fetch']) ?  $rating->get_ratings() : $rating->vote();
class ratings {
    var $data_file = './ratings.data.txt';
    private $data = array();
function __construct() {
    $all = file_get_contents($this->data_file);
    if($all) {
        $this->data = unserialize($all);
    }
}
public function get_ratings() {
        echo json_encode($this->data);
}

public function vote() {
    preg_match('/star_([1-5]{1})/', $_POST['clicked_on'], $match);
    $vote = $match[1];
    $this->data['votes'] += 1;
    $this->data['total_points'] += $vote;
    $this->data['rate'] = round( $this->data['total_points'] / $this->data['votes'], 1 );
    $this->data['stars'] = round( $this->data['rate'] );
    file_put_contents($this->data_file, serialize($this->data));
    $this->get_ratings();
}

}
?>


Данные хранятся в файле ratings.data.txt в таком виде (a:4:{s:5:"votes";i:2;s:12:"total_points";i:8;s:4:"rate";d:4;s:5:"stars";d:4;})
так это выглядит )
59ddb92c01f64781260178.png

Попозже найду плагин JQ и уберу значение stars картинка по значению rate будет выводиться.

Есть пару проблем когда обращаюсь напрямую qwe.ru/rate.php то, что то он меняет значения в файле каким то левым образом ) и вопрос по правильности подсчёта общего рейтинга, как предотвратить накрутку ? что на счёт безопасности ? так как мне всего для 1 страницы нужно, сайт статичный лэндинг без mysql на html) по этому на файлах хочу сделать это дело, или лучше mysql ? что то мне кажется тут что то много лишнего и дырявого, можно же как то лучше с делать )))
  • Вопрос задан
  • 166 просмотров
Решения вопроса 1
@Paltinik Автор вопроса
В общем сделал что смог, + защита от голосования 2 раза на LocalStogare
Как и сказал, сделал на чистом css+js
Скрипт минимальный, с 1 картинкой, 4кб ничего лишнего, осталось только стилизовать под себя )
Если вдруг кому надо, качайте : тыц

сам код:
index.php

<?php
$data = array();
$data = unserialize(file_get_contents('./ratings.data.txt'));
$rate = $data['rate'];
$votes = $data['votes'];
?>
 
<div id="total">Голосов <?php echo $votes; ?></div>
<div id="rate">Рейтинг  <?php  echo $rate; ?> </div>
<div class="stars-contanet"></div>
<div class="stars-you"></div>

<style>
    .star-proc {
        background: #000;
        height: 100%;
        -webkit-transition: 0.5s;
        -o-transition: 0.5s;
        transition: 0.5s;
    }
        .stars-contanet {
            position: relative;
            width:      150px;
            height:     30px;
        }
        .stars {
            background: url('star.png') no-repeat;
            float:      left;
            height:     30px;
            width:      30px;
        }
        .star-active {
            height: 100%;
           background-color: yellow;
           cursor:pointer;
        }
    </style>




<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
var star = '<div class="stars"></div>';
$('.stars-contanet').html(star+star+star+star+star+'<div class="star-proc"></div>');
$('.star-proc').width($('#rate').text().replace('Рейтинг', '')*20+'%');

if (!localStorage.getItem('rate')){
$('.stars').bind('click', getrate); 
        $('.stars').hover(
            function() {
                $(this).prevAll('.stars').andSelf().addClass('star-active').attr('title',$('.star-active').length);
            },
            function() {
                $(this).prevAll('.stars').andSelf().removeClass('star-active');
            }
        );
} else {
$('.stars-you').text('Ваша оценка: '+localStorage.getItem('rate'));
}

function getrate() {
$('.stars').unbind(); 
var val = $('.star-active').length;
$('.stars').removeClass('star-active');
localStorage.setItem('rate', val);
            $.post('rate.php',
                {val : val},
                function(d) {
 $('.star-proc').width(d.rate*20+'%');
 $('#total').text('голосов '+d.votes);
 $('#rate').text('рейтинг '+d.rate);
                },
                'json'
            ).complete(function(){
             $('.stars-you').text('Ваша оценка: '+val);
            });
}
    </script>


И обработчик запросов rate.php
<?php
    $data = array();
    $data = unserialize(file_get_contents('./ratings.data.txt'));
    preg_match('/([1-5]{1})/', $_POST['val'], $match);
    $vote = $match[0];
    $data['votes'] += 1;
    $data['total_points'] += $vote;
    $data['rate'] = round( $data['total_points'] / $data['votes'], 1 );
    file_put_contents('./ratings.data.txt', serialize($data));
    echo json_encode($data);
?>


Волнует вопрос, что на счёт дыр и производительности в этом коде??
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
SerafimArts
@SerafimArts
Senior Notepad Reader
Для однозначной идентификации аккаунта - нжна система регистрации + аутентификации, для не совсем однозначной - можно воспользоваться: https://github.com/samyk/evercookie - эта шняга пролезает во все хранилища, даже кеш браузера и восстанавливает состояние, даже если человек попытается открыть браузер в инкогнито (как раз за счёт кеша). Так что это лучшим решением будет за неимением аутентификации.

PS
1) Помимо mysql есть и другие БД, sqlite более чем подойдёт.
2) Код - не пахнет, а аж воняет. Уж простите =)))))
3) Этот рейтинг делается на чистом html+css без всяких плагинов, звёздочки вкладываются друг в друга и на обычный ховер просто подсвечивайте родителей.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы