• home
  • forum
  • my
  • kt
  • download
  • AJAX Voting in PHP - Cast a Vote Without Reloading the Page

    Author: 2009-03-09 16:33:48 From:

    A simple feature that many may over look is the ability to cast a vote without having to reload a page. It can be inconvient for the user, depending on what they are voting on. Maybe they are watching a video or listening to a song, in which case, they wouldn't want to reload the page because it would cause them to lose their position in the video or song.

    So with the magic of some Javascript, PHP, and MySQL we will be able to let the user cast a vote and show them the updated states without interrupting whatever they may be doing on the page. In this tutorial, we will be pretending that the user is casting votes on movies.

    To begin, we will need to set up a MySQL database to hold the movies and their ratings from the users. Additionally, we will also be tracking the user's IP, so they can't vote more than once for the same movie. Note: If you are integrating this script into a user system, you may want to track it based on their User ID or Username, instead of IP.

    First create a database, if you haven't done so already. (or use an existing one)

    Now run this script, then delete the script.

     <?php
    mysql_connect 
    ('localhost''USERNAME''PASSWORD'
    );
    mysql_select_db('DATABASE'
    );

    // holds the movie information
    mysql_query(
    "CREATE TABLE IF NOT EXISTS `movies` (
      `id` int(11) NOT NULL auto_increment,
      `title` varchar(50) NOT NULL,
      `votes` int(11) NOT NULL,
      `rating` int(11) NOT NULL,
      PRIMARY KEY  (`id`)
    ) ENGINE=MyISAM  DEFAULT CHARSET=latin1;
    "
    );

    // holds the voter information
    mysql_query(
    "CREATE TABLE IF NOT EXISTS `voters` (
      `id` int(11) NOT NULL,
      `ip` varchar(20) NOT NULL
    ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
    "
    );
    ?> 
     

    Note: Be sure to change the log in information to yours. (Username, password, and database name)
    Now we will need to create [i]ajax.php[i], this script will not be seen viewed by the user. The job of this script is to actually execute the PHP code required to cast a vote. Such as updating the rating, checking if they have already voted, etc. It returns in an XML format which will become clear later on.

    Save this file as ajax.php

     

    <?php
    mysql_connect 
    ("localhost""USERNAME""PASSWORD"
    );
    mysql_select_db("DATABASE"
    );

    if(
    is_numeric($_GET['id']) && is_numeric($_GET['rating'
    ])) {
        
    $vote_cast $_GET['rating'
    ];
        
    $id $_GET['id'
    ];
        if(!(
    $vote_cast >= 1  && $vote_cast <= 10
    )) {
            echo 
    $vote_cast
    ;
            die(
    "Invalid vote"
    );
        }
        if(
    mysql_num_rows(mysql_query("SELECT * FROM `movies` WHERE `id`='".$id."'")) == 0
    ) {
            die(
    "Invalid movie"
    );
        }
        
    $ip $_SERVER['REMOTE_ADDR'
    ];
        if(
    mysql_num_rows(mysql_query("SELECT * FROM `voters` WHERE `id`='".$id."' && `ip`='".$ip."'")) == 0
    ) {
            
    mysql_query("INSERT INTO `voters`(`id`, `ip`) VALUES('".$id."', '".$ip."')"
    );
            
    mysql_query("UPDATE `movies` SET `votes`=votes+1, `rating`=rating+".$vote_cast." WHERE `id`='".$id."'") or die(mysql_error
    ());
            
            
    $data mysql_fetch_array(mysql_query("SELECT * FROM `movies` WHERE `id`='".$id."'"
    ));
            
    $rating round($data['rating']/$data['votes'], 1
    );
            
    $votes $data['votes'
    ];
        
            
    header('Content-Type: text/xml'
    );
            
    header('Pragma: no-cache'
    );
            echo 
    '<?xml version="1.0" encoding="UTF-8"?>'."n"
    ;
            echo 
    "<result id='".$id."' rating='".$rating."' votes='".$votes."'>Vote cast and saved.</result>n"
    ;
        }else{
            
    header('Content-Type: text/xml'
    );
            
    header('Pragma: no-cache'
    );
            echo 
    '<?xml version="1.0" encoding="UTF-8"?>'."n"
    ;
            echo 
    "<result id='".$id."' rating='-1' votes='-1'>You have already voted.</result>n"
    ;
        }
    }else{
        echo 
    "Invalid input"
    ;
    }
    ?>


    Note: Again, change your log in information to yours.

    Code Breakdown:

    if(is_numeric($_GET['id']) && is_numeric($_GET['rating'])) { - This will check that our input is set and that it is valid. (a number)
    if(!($vote_cast >= 1 && $vote_cast <= 10)) { - Although the script will only call ajax.php within the limits, a person could attempt to cast it manually with a higher or lower vote.
    if(mysql_num_rows(mysql_query("SELECT * FROM `movies` WHERE `id`='".$id."'")) == 0) { - This will check if the movie exists, based on its ID. It will return 0 or 1.
    $ip = $_SERVER['REMOTE_ADDR']; - This variable will retrieve the user's IP and set it to $ip.
    if(mysql_num_rows(mysql_query("SELECT * FROM `voters` WHERE `id`='".$id."' && `ip`='".$ip."'")) == 0) { - This will check if the user has already voted, it will return 0 if they have not.
    mysql_query("INSERT INTO `voters`(`id`, `ip`) VALUES('".$id."', '".$ip."')"); - This will insert the information about the user, so they can't vote for the same movie again.
    mysql_query("UPDATE `movies` SET `votes`=votes+1, `rating`=rating+".$vote_cast." WHERE `id`='".$id."'"); - This will add one more vote and add the rating to the total rating.
    $data = mysql_fetch_array(mysql_query("SELECT * FROM `movies` WHERE `id`='".$id."'")); - This will retrieve the newly updated data about the movie.
    $rating = round($data['rating']/$data['votes'], 1); - This will get the average rating and round it to one decimal place.
    header('Content-Type: text/xml'); - This will change the output type to XML, instead of HTML.
    echo '<?xml version="1.0" encoding="UTF-8"?>'."n"; - Required header in valid XML files
    echo "<result id='".$id."' rating='".$rating."' votes='".$votes."'>Vote cast and saved.</result>n"; - This will output the movie id, new rating, new votes, and a message.
    echo "<result id='".$id."' rating='-1' votes='-1'>You have already voted.</result>n"; - This message will be shown if they have already voted,

    Now we have all the backend coding complete but we still have nothing to show for it, so we will need to create something for the user to interact with, which will list the movies and allow them to vote.

    Save this file as movies.php

     

    <script type="text/javascript">
        function vote(id, rating) {
            if (window.XMLHttpRequest) {
                http = new XMLHttpRequest();
            } else if (window.ActiveXObject) {
                http = new ActiveXObject("Microsoft.XMLHTTP");
            }
            var url = 'ajax.php?';
            var fullurl = url + 'id=' + id + '&rating=' + rating;
            http.open("GET", fullurl, true);
            http.send(null);
            http.onreadystatechange = statechange_rate;
        }
        
        function statechange_rate() {
            if (http.readyState == 4) {
                var xmlObj = http.responseXML;
                var html = xmlObj.getElementsByTagName('result').item(0).firstChild.data;
                var id = xmlObj.getElementsByTagName('result').item(0).getAttribute("id");
                var votes = xmlObj.getElementsByTagName('result').item(0).getAttribute("votes");
                var rating = xmlObj.getElementsByTagName('result').item(0).getAttribute("rating");
                if(votes != -1) {
                       document.getElementsByName('output_' + id).item(0).innerHTML = "<br />" + html;
                    window.setTimeout("document.getElementsByName('output_" + id + "').item(0).innerHTML = '';", 5000);
                    document.getElementsByName('rating_' + id).item(0).innerHTML = rating;
                    document.getElementsByName('votes_' + id).item(0).innerHTML = votes;
                }else{
                    document.getElementsByName('output_' + id).item(0).innerHTML = "<br />" + html;
                    window.setTimeout("document.getElementsByName('output_" + id + "').item(0).innerHTML = '';", 5000);
                }
            }
        }
    </script>
    <?php
    mysql_connect 
    ("localhost""USERNAME""PASSWORD"
    );
    mysql_select_db("DATABASE"
    );

    $result mysql_query("SELECT * FROM `movies` ORDER BY `title`"
    );

    while(
    $data mysql_fetch_array($result
    )) {
        if(
    $data['votes'] > 0
    ) {
            echo 
    $data['title'].' - <span name="rating_'.$data['id'].'">'.round($data['rating']/$data['votes'], 1).'</span> out of 10 (<span name="votes_'.$data['id'].'">'.$data['votes'].'</span> votes)<br />'
    ;
        }else{
            echo 
    $data['title'].' - 0 out of 10<br />'
    ;
        }
        echo 
    'Vote: '
    ;
        for(
    $i 1;$i 11;$i
    ++) {
            echo 
    '<a href="javascript:vote('.$data['id'].', '.$i.')">'.$i.'</a> '
    ;
        }
        echo 
    ' <span name="output_'.$data['id'].'"></span>'
    ;
        echo 
    '<br /><br />'
    ;
    }
    ?>


    Note: Again, change your log in information to yours.

    Code Breakdown:

    http.open("GET", fullurl, true); - This will create the request to our ajax.php file, with the information about the vote.
    if(votes != -1) { - Before, you may have noticed we set votes="-1" if they had already voted, this was just to provide an easy way to check the return of our ajax.php script.
    document.getElementsByName('output_' + id).item(0).innerHTML = "<br />" + html; - This will inform the user about the vote they have cast.
    window.setTimeout("document.getElementsByName('output_" + id + "').item(0).innerHTML = '';", 5000); - This will set a delay to make that message go away in 5000 miliseconds (5 seconds).
    document.getElementsByName('rating_' + id).item(0).innerHTML = rating; - This will update the rating on the page to the new one.
    $result = mysql_query("SELECT * FROM `movies` ORDER BY `title`"); - This will return every movie we have ordered by name.
    while($data = mysql_fetch_array($result)) { - Loop through every movie we have and execute the code below.
    if($data['votes'] > 0) { - This will make sure we have atleast 1 vote, to avoid a division by 0.
    for($i = 1;$i < 11;$i++) { - This will list the numbers 1 through 10, allowing the users to click on it to vote.

    My result with some random movies and ratings.



    It may not be pretty but, it is easy to integrate. It should be very easy to change the numbers to images, such as stars or any image you have in mind. The same concept can be seen on the right (the 5 stars), feel free to try it out.

    discuss this topic to forum

    relation tutorial

    No information

    Category

      Ad Management (6)
      Calendars (3)
      Chat Systems (8)
      Content Management (41)
      Cookies and Sessions (12)
      Counters (15)
      Database Related (34)
      Date and Time (15)
      Development (22)
      Discussion Boards (8)
      E Commerce (8)
      Email Systems (14)
      Error Handling (8)
      File Manipulation (36)
      Flash and PHP (6)
      Form Processing (22)
      Guestbooks (12)
      Image Manipulation (26)
      Installing PHP (7)
      Introduction to PHP (29)
      Link Indexing (8)
      Mailing List Management (9)
      Miscellaneous (60)
      Networking (9)
      News Publishing (9)
      OOP (28)
      PEAR (6)
      PHP vs Other Languages (2)
      Polls and Voting (7)
      Postcards (1)
      Randomizing (14)
      Redirection (11)
      Searching (9)
      Security (29)
      Site Navigation (16)
      User Authentication (14)
      WAP and WML (7)
      Web Fetching (8)
      Web Traffic Analysis (15)
      XML and PHP (16)

    New

    Hot