ExpressionEngine CMS
Open, Free, Amazing

Thread

This is an archived forum and the content is probably no longer relevant, but is provided here for posterity.

The active forums are here.

Ajax star rating bar

February 14, 2008 2:12am

Subscribe [21]
  • #1 / Feb 14, 2008 2:12am

    wiredesignz

    2882 posts

    Here’s the completed port as discussed.

    Please read page 2 of this thread for the BUG fix.

    Original files can be found here: http://www.masugadesign.com/the-lab/scripts/unobtrusive-ajax-star-rating-bar/

    You only need the assets (css, js, images) from the download and nothing needs to be altered in the original files.

    Enable query strings and set uri_protocol in application/config/config.php

    $config['uri_protocol']    = "PATH_INFO";
    
    $config['enable_query_strings'] = TRUE;
    $config['directory_trigger']    = 'd';
    $config['controller_trigger']   = 'x';   //remove the `c` conflict
    $config['function_trigger']     = 'm';

    Create application/config/ratings.php

    $config['rating_unitwidth'] = 30;
    $config['nojspage'] = 'welcome';     //redirects here if javascript is disabled

    Modify application/config/autoload.php

    $autoload['config'] = array('ratings');

    Modify application/config/routes.php

    $route['rpc.php'] = 'ratings_rpc/index';
  • #2 / Feb 14, 2008 2:14am

    wiredesignz

    2882 posts

    Create application/controllers/ratings_rpc.php

    <?php if (!defined('BASEPATH')) exit('No direct script access allowed');
    
    class Ratings_rpc extends Controller
    {
        function Ratings_rpc()
        {
            parent::Controller();
            $this->load->model('ratings_model');
            
            $this->output->set_header("Cache-Control: no-cache");
            $this->output->set_header("Pragma: nocache");
        }
        
        function index()
        {
            //get the values
            $vote_sent  = preg_replace("/[^0-9]/", "", $this->input->get('j'));
            $id_sent    = preg_replace("/[^0-9a-zA-Z]/", "", $this->input->get('q'));
            $ip_num     = preg_replace("/(^0-9\.)/", "", $this->input->get('t'));
            $units      = preg_replace("/(^0-9)/", "", $this->input->get('c'));
            $ip         = $this->input->ip_address();
            
            //added detection for javascript being disabled
            $nojs = preg_replace("/(^0-1)/", "", $this->input->get('r'));
    
            // kill the script because normal users will never see this.
            if ($vote_sent > $units) die("Sorry, vote appears to be invalid."); 
            
            //default values
            $checkIP = NULL;
            $count = 0;
            $current_rating = 0;
            $sum = 0;
            $tense = "votes"; // 0 votes
            
            //get the current values!
            if ($numbers = $this->ratings_model->findBy_id($id_sent))
            {
                $checkIP = unserialize($numbers['used_ips']);
                $count = $numbers['total_votes']; //how many votes total
                $current_rating = $numbers['total_value']; //total number of rating 
                $sum = $vote_sent + $current_rating; // add together the current vote value and the total vote value
                $tense = ($count == 1) ? "vote" : "votes"; //plural form votes/vote
            }
            
            // checking to see if the first vote has been tallied or increment the current number of votes
            ($sum == 0 ? $added = 0 : $added = $count + 1);
            
            // if it is an array i.e. already has entries the push in another value
            (is_array($checkIP) ? array_push($checkIP, $ip_num) : $checkIP = array($ip_num));
            
            //if the user hasn't yet voted, then vote normally…
            if ($this->ratings_model->countBy_ip($ip, $id_sent) == 0)
            {            
                //make sure vote is valid and IP matches - no monkey business!
                if ($vote_sent > 0 && $ip == $ip_num) 
                { 
                    $this->ratings_model->updateBy_id($id_sent, array(
                        'total_votes' => $added,
                        'total_value' => $sum,
                        'used_ips'    => serialize($checkIP),
                    ));
                } 
            } 
            
            //get the new values!
            if ($numbers = $this->ratings_model->findBy_id($id_sent))
            {
                $checkIP = unserialize($numbers['used_ips']);
                $count = $numbers['total_votes']; //how many votes total
                $current_rating = $numbers['total_value']; //total number of rating
                $tense = ($count == 1) ? "vote" : "votes"; //plural form votes/vote
            }    
            
            $data = array(
                'id_sent' => $id_sent,
                'current_rating' => $current_rating,
                'count' => $count,
                'sum'   => $sum,
                'added' => $added,
                'units' => $units,
                'tense' => $tense,
                'rating_unitwidth' => $this->config->item('rating_unitwidth'),
            );
            
            if($nojs) //javascript is disabled
            {
                //set $nojspage value in config
                redirect($this->config->item('nojspage'));
            }
    
            $this->load->view('newback_view', $data);
        }
    }
  • #3 / Feb 14, 2008 2:16am

    wiredesignz

    2882 posts

    Create application/models/ratings_model.php

    <?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
    
    class Ratings_model extends Model 
    {
        function Ratings_model()
        {
            parent::Model();
        }
        
        function bar($id, $units = '', $static = '')
        {
            //set some variables
            ($units)  OR $units = 10;
            ($static) OR $static = FALSE;
            
            $ip = $this->input->ip_address();
            $rating_unitwidth = $this->config->item('rating_unitwidth');
            
            //default values
            $count = 0;
            $current_rating = 0;
            $tense = "votes"; // 0 votes
            
            // get votes, values, ips for the current rating bar
            if (!$numbers = $this->findBy_id($id))
            {
                // insert the id in the DB if it doesn't exist already
                $data = array(
                    'id' => $id,
                    'total_votes' => $count, 
                    'total_value' => $current_rating, 
                    'used_ips' => '',
                );
                $this->insert($data);
            }
            else
            {
                $count = $numbers['total_votes']; //how many votes total        
                $current_rating = $numbers['total_value']; //total number of rating
                $tense = ($count == 1) ? "vote" : "votes"; //plural form votes/vote
            }
            
            $voted = (bool)$this->countBy_ip($ip, $id);
    
            //more default values
            $rating_width = 0;
            $rating1 = 0;
            $rating2 = 0;
            
            // now draw the rating bar
            if ($count > 0)
            {
                $rating_width = number_format($current_rating/$count,2) * $rating_unitwidth;
                $rating1 = number_format($current_rating/$count,1);
                $rating2 = number_format($current_rating/$count,2);
            }
            
            $data = array(
                'id' => $id,
                'current_rating' => $current_rating,
                'count' => $count,
                'units' => $units,
                'tense' => $tense,
                'voted' => $voted,
                'rating_width' => $rating_width,
                'rating1' => $rating1,
                'rating2' => $rating2,
                'rating_unitwidth' => $rating_unitwidth,
                'ip' => $ip,
            );
            
            if ($static == 'static')
            {
                return $this->load->view('static_rating_view', $data, TRUE);
            }
            else
            {
                return $this->load->view('dynamic_rating_view', $data, TRUE);
            }
        }
        
        function findBy_id($id)
        {
            $this->db->select('total_votes, total_value, used_ips');
            $query = $this->db->getwhere('ratings', "id = '{$id}'");
            return $query->row_array();
        }
        
        function countBy_ip($ip, $id)
        {
            $this->db->select('used_ips');
            $query = $this->db->getwhere('ratings', "used_ips LIKE '%{$ip}%' AND id = '{$id}'");
            return count($query->result());        
        }
        
        function updateBy_id($id, $data)
        {
            $this->db->where('id', $id);
            $this->db->update('ratings', $data);
        }
        
        function insert($data)
        {
            $this->db->insert('ratings', $data);
        }
    }
  • #4 / Feb 14, 2008 2:20am

    wiredesignz

    2882 posts

    Create Views:

    application/views/newback_view.php

    
    
    

    static_rating_view.php

    
    
    

    dynamic_rating_view.php

    
    									
  • #5 / Feb 14, 2008 2:32am

    wiredesignz

    2882 posts

    Usage:

    Create your page controller: application/controllers/welcome.php (`welcome` for this demo)

    class Welcome extends Controller 
    {    
        function Welcome()
        {
            parent::Controller();
            $this->load->model('ratings_model', 'ratings');
        }
        
        function index()
        {                
            $this->load->view('welcome_view');
        }
    }

    Create application/views/welcome_view.php (css, js, images dirs are in webroot)

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html lang="en" xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
    <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <title>Multiple Ajax Star Rating Bars</title>
    
    <script type="text/javascript" language="javascript" src="js/behavior.js">
    <script type="text/javascript" language="javascript" src="js/rating.js">
    
    <link rel="stylesheet" type="text/css" href="css/default.css" />
    <link rel="stylesheet" type="text/css" href="css/rating.css" />
    </head>
    
    <body>
    
    <div id="container">
    <h1>Unobtrusive AJAX Star Rating Bar</h1>
    
    <h2>v 1.2.2, March 18, 2007</h2>
    
    <p>CodeIgniter port by Wiredesignz, 2008-02-14</p>
    
    <p><br />
        <br />
    <?php echo $this->ratings->bar('id21',''); ?><br />
    <?php echo $this->ratings->bar('id22',''); ?><br />
    <?php echo $this->ratings->bar('id1',''); ?><br />
    <?php echo $this->ratings->bar('2id',5); ?><br />
    <?php echo $this->ratings->bar('3xx',6); ?><br />
    <?php echo $this->ratings->bar('4test',8); ?><br />
    <?php echo $this->ratings->bar('5560'); ?><br />
    <?php echo $this->ratings->bar('66234','','static'); ?><br />
    <?php echo $this->ratings->bar('66334',''); ?><br />
    <?php echo $this->ratings->bar('63334',''); ?></p>
    
    <p> </p>
    
    <p><br />
    <a href="http://www.masugadesign.com/the-lab/scripts/unobtrusive-ajax-star-rating-bar/">(Unobtrusive) AJAX Star Rating Bar Homepage</a></p>
    
    <p></div></p>
    
    <p></body><br />
    </html>

    And you’re good to go!

  • #6 / Feb 14, 2008 2:51am

    wiredesignz

    2882 posts

    Almost forgot:

    Create the ratings table:

    -- Table structure for table `ratings`
    
    CREATE TABLE `ratings` (
      `id` varchar(11) NOT NULL,
      `total_votes` int(11) NOT NULL default '0',
      `total_value` int(11) NOT NULL default '0',
      `used_ips` longtext,
      PRIMARY KEY  (`id`)
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8;

    And don’t forget to set up your database connection.

    application/config/database.php

  • #7 / Feb 15, 2008 2:13am

    wiredesignz

    2882 posts

    The demo can be found here: [Removed]

  • #8 / Feb 16, 2008 9:20am

    Isern Palaus

    148 posts

    Hey wiredesignz,

    A very nice tutorial. I’ll include on my new project for testing how it work 😉. I recently coded a “AJAX Tutorial” to, for a simple login in CI.

    http://ellislab.com/forums/viewthread/71636/

    Regards,
    —Isern Palaus

  • #9 / Feb 16, 2008 9:36am

    wiredesignz

    2882 posts

    Yes thanks, I saw your tutorial, very nice.

  • #10 / Feb 16, 2008 1:49pm

    taewoo

    212 posts

    wiredesignz: I bask in your super awesome gloriness.

  • #11 / Feb 16, 2008 5:34pm

    wiredesignz

    2882 posts

    Thanks taewoo, I just noticed that the forums had deleted the javascript tags from the welcome_view.

    It is fixed now.  Tip:(use & lt; script ...)

  • #12 / Feb 16, 2008 8:06pm

    wiredesignz

    2882 posts

    It appears someone (who shall remain nameless, but has a Bear avatar), was able to send 1000 votes to the rating system. :lol:

    I really didn’t bother to improve the security from the original script. But now I would suggest adding a limit field to the table with which to compare the submitted vote.

    Modified ratings table

    -- Table structure for table `ratings`
    
    CREATE TABLE `ratings` (
      `id` varchar(11) NOT NULL,
      `total_votes` int(11) NOT NULL default '0',
      `total_value` int(11) NOT NULL default '0',
      `vote_limit`  int(11) NOT NULL default '0',    //added vote limit
      `used_ips` longtext,
      PRIMARY KEY  (`id`)
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8;


    Modify application/controllers/ratings_rpc.php

    //get the current values!
    if ($numbers = $this->ratings_model->findBy_id($id_sent))
    {
        // kill the script if vote limit is exceeded.
        if ($vote_sent > $numbers['vote_limit']) die("Sorry, your vote appears to be invalid."); 
        
        $checkIP = unserialize($numbers['used_ips']);
        $count = $numbers['total_votes']; //how many votes total
        $current_rating = $numbers['total_value']; //total number of rating 
        $sum = $vote_sent + $current_rating; // add together the current vote value and the total vote value
        $tense = ($count == 1) ? "vote" : "votes"; //plural form votes/vote
    }
    
    ...
    
    //get the new values!
    if ($numbers = $this->ratings_model->findBy_id($id_sent))
    {
        $checkIP = unserialize($numbers['used_ips']);
        $count = $numbers['total_votes']; //how many votes total
        $current_rating = $numbers['total_value']; //total number of rating
        $tense = ($count == 1) ? "vote" : "votes"; //plural form votes/vote
        $units = $numbers['vote_limit']; //get the vote limit
    }


    Modify application/models/ratings_model.php

    // get votes, values, ips for the current rating bar
    if (!$numbers = $this->findBy_id($id))
    {
        // insert the id in the DB if it doesn't exist already
        $data = array(
            'id' => $id,
            'total_votes' => $count, 
            'total_value' => $current_rating,
            'vote_limit'  => $units,        //set the vote limit
            'used_ips' => '',
        );
        $this->insert($data);
    }
    
    ...
    
    function findBy_id($id)
    {
        $this->db->select('total_votes, total_value, vote_limit, used_ips');
        $query = $this->db->getwhere('ratings', "id = '{$id}'");
        return $query->row_array();
    }
  • #13 / Feb 16, 2008 9:26pm

    CI Lee

    343 posts

    Darn them! Darn them all!

    Hey that voting system prior to the bug fix worked much like the voting system of a Country in North America that happens to be in between Canada and Mexico yet shall remain nameless….

  • #14 / Feb 18, 2008 2:11am

    taewoo

    212 posts

    Hey wiredesignz…

    I’ve done it EXACTLY the way you described (including the bug fix). All the icons show up and everything seems dandy.. except when I click on one of the stars, I just get that “working.gif” (the icon that shows up when ajax is working) and nothing happens.

    I checked the DB. When the page loads, all the IDS appear as rows with total_votes = 0 and total_value = 0. WHen I click on the stars, “working.gif” shows up but nothing happens to database.

    What am I doing wrong or what am i missing?

  • #15 / Feb 18, 2008 5:25am

    wiredesignz

    2882 posts

    @taewoo: Try calling the script like

    rpc.php?j=2&q=id21&t=xxx.xxx.xxx.xxx&c=10&r=1

    from the address bar, see what output you get. (where xxx.xxx.xxx.xxx = your IP Address)

    Note: any errors in the rating_rpc controller will kill it silently when you use Ajax.

.(JavaScript must be enabled to view this email address)

ExpressionEngine News!

#eecms, #events, #releases