File Structure
To begin your wonderful journey into the abyss that is making a star rating system in PHP, jQuery and with a sprinkle of MySQL, you’re going to have to make/download a few files. So go on, make a few files, and call them style.css, script.js, 5star.php (or index.php) and send.php. On top of this you’re going to need 3 more files. The first one is the jQuery.js file, which you can download from the jQuery website. The next two are the star images. Now there’s nothing stopping you from making these yourself, but if you’re going to, don’t forget to make them as transparent pngs, as I’ve done for the star.png and star_blank.png files below.
star.png:
star_blank.png:
Now wait..What about IE6 Users?
Okay, I’m going to be honest, and the way I’ve coded this, well, it just ain’t gonna work for IE6 users. The fact of the matter is that IE6 is an antiquated technology. It has less than 25% market share at the minute, and that number gets lower every day. Should we as web developers really be supporting a browser which just doesn’t work for users anymore?
Now the reason it isn’t going to work for IE6 users is because IE doesn’t support Alpha Transparency in the PNG format. What that means is that transparent pngs won’t work with IE6. Now, there are ways around this, and you should consider visiting here if IE6 is such a huge problem for you. However, many big sites are beginning to not support IE6, and it feels like the right time to let it go. I will leave it up to you to implement the hacks required to get transparency to work in IE6.
A PHP Skeleton
We’re going to begin by making the PHP/HTML/CSS for the static rating system. We’ll then add some jQuery to make it dynamic.
To begin though, you’re going to have to alter your MySQL table (The table in which the items you want to be ratable are in). What you’re going to have to do is add 3 columns to the end of this table. These columns are called rating, total_rating and total_ratings. Now this is different depending on what MySQL software you have, but usually it consists of you running a query. Some clients let you add columns in a more user friendly way, such as the MySQL Query Browser. However, if you want to run the query, you go to the SQL section, and enter this:
ALTER TABLE `database`.`table` ADD COLUMN `rating` INTEGER UNSIGNED NOT NULL,
ADD COLUMN `total_rating` INTEGER UNSIGNED NOT NULL AFTER `rating`,
ADD COLUMN `total_ratings` INTEGER UNSIGNED NOT NULL AFTER `total_rating`;
See there on the first line, where it says “database” and “table”? You’re going to have to change those to the database and table names which apply to you. After you’ve ran that code, we can continue.
Connecting to a database and all that.
Connecting to a database in PHP is rather easy, and it only requires about two lines of code. Start off your document as usual with the <php sign, and then write this:
// This will connect to the MySQL server
mysql_connect("localhost", "admin", "password") or die(mysql_error());
// This will connect to a database on that server.
mysql_select_db("test") or die(mysql_error());</pre>
mysql_connect() connects to the server. The or die(mysql_error()); kills the script if the mysql_connect()bit doesn’t work and gives you a little MySQL error message to tell you what’s up. You’re going to have to change the “admin” and “password” text to whatever your username and password is. You might also have to change localhost to something, but in 99% of cases you wont. Ask your web host if localhost doesn’t work for you.
mysql_select_db() just selects the test database. Change the “text” writing to whatever your database name is. After this we’re going to run a little MySQL query inside a variable.
$query = mysql_query("SELECT * FROM table");
$query is the variable which the query is in. mysql_query() is a function in PHP which will run the query inside it. In this case we’re SELECTing data FROM the table, table. Don’t forget to change “table” to whatever the table you’re selecting from is.
Now what we’re going to is make a nice little while loop.
while($row = mysql_fetch_array($query)) {
}
Basically what we’re doing is making a variable, and then inside that, changing the query results into an array. This will then keep adding to this array, meaning we can access all the ratings and put them as a list. The while loop just moves through each row until its at the end of the table. Inside this while loop, define a variable called $rating as shown below, and clost the php code with ?>
$rating = (int)$row[rating];
?>
This is just putting the rating column for each rating into a variable called rating. The next bit is basically some HTML with bits of PHP added on top:
<div class="floatleft">
<div id="rating_<?php echo $row[id]; ?>">
<span class="star_1"><img src="star_blank.png" alt="" <?php if($rating > 0) { echo"class='hover'"; } ?> /></span>
<span class="star_2"><img src="star_blank.png" alt="" <?php if($rating > 1.5) { echo"class='hover'"; } ?> /></span>
<span class="star_3"><img src="star_blank.png" alt="" <?php if($rating > 2.5) { echo"class='hover'"; } ?> /></span>
<span class="star_4"><img src="star_blank.png" alt="" <?php if($rating > 3.5) { echo"class='hover'"; } ?> /></span>
<span class="star_5"><img src="star_blank.png" alt="" <?php if($rating > 4.5) { echo"class='hover'"; } ?> /></span>
</div>
</div>
<div class="star_rating">
(Rated <strong><?php echo $rating; ?></strong> Stars)
</div>
<div class="clearleft"> </div>
<?php
}
?>
Okay so if you have a grasp of HTML, the above code is just a few divs, with spans and images. The PHP statement inside the img code checks if the raing is above a certain amount, and if it is, it adds “class=’hover’” to the image code. This is so we can highlight certain stars depending on the rating we get from the database, as to illustrate the current star rating. I’ve also labelled the div with the id of the row in the database, and wrote a bit of text in another div, saying the rating. This is all pretty straight forward stuff, so I’m just going to go straight on to the next bit.
In the 5star.php (or index.php) file, include the CSS and Javascript files:
<link rel="stylesheet" type="text/css" href="style.css">
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="script.js"></script>
Everyone loves a bit of CSS
Put that in the head section of your html document. Now lets move on to the CSS so we can make this script look prettier. My CSS script is pretty darn simple, and I understand that not all of you might want divs to float to the left. If you wanna make seperate classes for the elements in the rating system, put these classes before the underscore (_). For instance, if you’re adding a class to the div, star_1 called “floatleft”, then write it as follows:
<span class="floatleft star_1"></span>
This is because the underscore is used to split the class into two parts, to define the star number, etc. So if we put floatleft after the underscore, the star number would become “1 floatleft”, which we don’t want. I’m not going to go into a lot of detail about how the CSS works,a s thats pretty basic stuff, so I’ll just give you the document. CSS is pretty self explanatory anyway.
/* The hover class, when the user hovers over a star */
.hover {
background: url('star.png');
z-index: 1;
}
/* This is for the span classes, that represent the seperate stars. You might want to change this to a seperate class */
span {
float: left;
cursor: pointer;
}
/* So that we can break the float left elements */
.clearleft {
clear: left;
}
/* Again, you might want to make this a seperate class. */
div {
display: block;
width: 120px;
padding-top: 10px;
height: 16px;
margin: 0;
}
/* Floats stuff to the left */
.floatleft {
float: left;
}
/* Text to display when the user presses a star */
.highlight {
font-family: Arial, sans-serif;
font-size: 14px;
position: relative;
bottom: 9px;
color: #93784b;
font-weight: bold;
}
/* The text beside the rating, displaying the rating in text, incase the user doesn't 'get it' */
.star_rating {
font-family: Arial, sans-serif;
font-size: 14px;
color: #93784b;
float: left;
width: 100px;
position: relative;
top: 10px;
}
You can go ahead and save that CSS file, and close it. We won’t be needing any more CSS for the remainder of the tutorial.
Time for Some jQuery
Okay, so now its time for some jQuery. Hopefully you can keep up. Open up script.js with notepad, or whatever editor you use. Start of the jQuery document as you usually would, like so:
$(document).ready(function() {
Now think about what we’re doing here. We’re trying to set it up so when the user hovers over a star, the stars before it all highlight with the current star. We also need to set something up so that stuff happens when the user clicks on the star. So first of all we’re going to make 2 new functions, for click and hover actions:
$("[id^=rating_]").hover(function() {
});
$("[id^=rating_]").children("[class^=star_]").click(function() {
});
That may look quite complicated if you’re new to this whole jQuery scene. Let me explain what we’re doing here. First of all, the $() tells jQuery we’re selecting something. The stuff inside the brackets is what we’re selecting. Of course, in jQuery, there are tonnes of ways to select stuff. Now what we’re selecting might be more complicated to the untrained eye. According to what I’ve said, we’re selecting [id^=rating_]. What we’re saying is to select all elements, where the id begins with rating_. That’s what the ^= means, “begins with”. The square brackets just corner all of this info off. Then we link this to the hover function in jQuery, and then bind that to a function. Finally we close off the function and hover bit, which we’ll be adding to later.
We’re doing the same with the next bit. We select the same thing as before, and then zoom in on that divs children, this time where the class begins with “star_”. Then we bind it to the click function, which we bind to another function.
Hovering
Okay, so lets start adding to these functions. Lets begin in the hover function. So on the line below where we selected the rating_ div, binded it to hover, add the following:
rid = $(this).attr("id").split("_")[1];
This gets the number after the rating_ text. First, we select this ($(this)), and select the attribute “id” with attr(“id”), and split it by the underscore. Split turns it into an array, and then we select the first part of this array with [1]. We’re going to select something more specific, using the rid variable.
$("#rating_"+rid).children("[class^=star_]").children('img').hover(function() {
In this part we’re selecting the div with the id (denoted by the hash) rating_rid, where rid is the id of the div. Then we select the children of this element until we come to the humble img div. Then we bind all of this to a hover function. Next, add this:
$("#rating_"+rid).children("[class^=star_]").children('img').removeClass("hover");
/* The hovered item number */
var hovered = $(this).parent().attr("class").split("_")[1];
while(hovered > 0) {
$("#rating_"+rid).children(".star_"+hovered).children('img').addClass("hover");
hovered--;
}
});
Okay, so lets break that bit down. First of all, we remove the hover class from all of the images, with this:
$("#rating_"+rid).children("[class^=star_]").children('img').removeClass("hover");
Then we get the number of the item that’s being hovered over, and put it in a variable.
/* The hovered item number */
var hovered = $(this).parent().attr("class").split("_")[1];
Finally, we do a simple little while loop, which adds the class ‘hover’ to the img, and then takes one away from the hovered value. Then it continues this until the value is 0. So for instance, if the user is hovering over the 3rd star, then the 3rd star will highlight, then the 2nd star and then the 1st star, but it’ll all happen so fast you wont even notice!
while(hovered > 0) {
$("#rating_"+rid).children(".star_"+hovered).children('img').addClass("hover");
hovered--;
}
});
});
Next, lets work on what happens when the person clicks on the star.
Clicking
When someone clicks on the star, we want the data to be sent somewhere. Now, to send the data to the database, we need to handle it in php, so we want to send the data to a PHP script that will handle it.
var current_star = $(this).attr("class").split("_")[1];
var rid = $(this).parent().attr("id").split("_")[1];
$('#rating_'+rid).load('send.php', {rating: current_star, id: rid});
So we get the current star that the user is clicking on, and the id of the item, so we have some way of identifying the row. Then we post all this data to a file called send.php. We then apply this data to the current rating div. The bit in the curly brackets is the data we’re posting. We can then retrieve that data in the send.php file.
The Send File
This file is going to submit all the data to the database. To start this file, we need to connect to the mysql server and database again:
<?php
mysql_connect("localhost", "admin", "") or die(mysql_error());
mysql_select_db("test") or die(mysql_error());
Then we’re going to get the post data, and put it in variables. So since we’re posting the data, we’re going to use the $_POST global variable.
$rating = (int)$_POST['rating'];
$id = (int)$_POST['id'];
I also made them into integers, seeing as the data are whole numbers. Then we run another query to the mysql database, this time singling out a row with the id we got in the id variable.
$query = mysql_query("SELECT * FROM test WHERE id = '".$id."'") or die(mysql_error());
This time we’re selecting it where the id is the $id variable, or die and post a mysql error. Then we put this in a while loop, and run a few statements.
while($row = mysql_fetch_array($query)) {
if($rating > 5 || $rating < 1) {
echo"Rating can't be below 1 or more than 5";
}
elseif(isset($_COOKIE['rated'.$id])) {
echo"<div class='highlight'>Already Voted!</div>";
}
else {
Now what we’re saying here is to run a while statement, as we did previously, to put the query into an array. Inside this we check if the rating is more than 5 or (||) less than 1, because if it is, well, something is wrong. Else if, we check if the cookie rated plus the id is set. I’m using cookies to check if the user has voted before, but you could alternatively insert the id into a column in a user table in your mysql database, and check if he id was set. Just make the column into an array and use the in_array() function. You could also insert the users IP address into a database, using the $_SERVER['REMOTE_ADDR'] variable. For simplicity though, lets stick to cookies. The else statement is a bit longer, so lets do that separately.
First thing we do in the else statement is to set the cookie, as shown below:
setcookie("rated".$id, $id, time()+60*60*60*24*365);
The first bit of the setcookie() function names the cookie. The next value is the id, and the final bit is the time it will last for. This cookie will last for a year, but you could make it longer. Next thing to do is to set the rating variables:
$total_ratings = $row['total_ratings'];
$total_rating = $row['total_rating'];
$current_rating = $row['rating'];
Okay, this is somewhat unnecessary, but it’s so you can see the variables we’re going to be using. Next we manipulate these variables, and put them in different variables.
$new_total_rating = $total_rating + $rating;
$new_total_ratings = $total_ratings + 1;
$new_rating = $new_total_rating / $new_total_ratings;
so the new total rating will be the total rating plus the current rating. Then the new total ratings (the total number of votes basically) is the old one, plus 1. The new rating is then the total rating divided by the total ratings. Finally, we update the database using MySQL:
mysql_query("UPDATE test SET total_rating = '".$new_total_rating."' WHERE id = '".$id."'") or die(mysql_error());
mysql_query("UPDATE test SET rating = '".$new_rating."' WHERE id = '".$id."'") or die(mysql_error());
mysql_query("UPDATE test SET total_ratings = '".$new_total_ratings."' WHERE id = '".$id."'") or die(mysql_error());
All we’re doing is updating the test table, and setting the fields to the new fields WHERE the id equals the id we got earlier, from the jQuery script, or else die, and show a mysql_error()
Finally, show the user they did everything right and show a little message, and close all the brackets.
echo"<div class='highlight'>Vote Recorded!</div>";
}
}
?>
And we’re done!
Comments
This doesn’t work for me… I did it myself at first and it just showed a blank page, so I downloaded the source and changed all the mySQL data to correspond with my database, and it still shows a blank page… What am I doing wrong?
Hey. Double check that you’ve got everything right. Try turning on PHP error reporting, to see if it’s a php error.
Maybe it’s down to your database connection.
nice
Great tutorial! One thing though. I have an existing table with a different name for id column (I assume the id column is the primary key). I tried changing your php script (send.php) to reflect the names of my id field (id_school) but with no luck. Am I missing something. Works fine when I tested it with a table with id field, though. Any help would be great.
Hey there, glad you enjoyed the tutorial. There’s no reason why it shouldn’t work, are you sure you did everything correctly?
I get a problem too. So far it says undefined index on line 7 and 8. rating and id are undefined. How do i fix that.
Because most every situation will be different (seeing as this script is to be used in many scenerios) it’s hard for me to diagnose what the problem might be. Have you altered the code in any way or anything like that?
Hi … any demo pls :)
thanks
This is a great tutorial and is working for me. The one thing that Im having a problem with is that when I take the mouse out it still has the same amount of stars that I left it on instead of the actual amount.
Hello! This is AWESOME!
Really good stuff man!
I’m not an expert of coding and I stuck on one point:
I noticed that the script automatically recognizes how many items are in MySql Table and gives an output of correspondig Stars ratings on a vertical line.
Say you have 5 different items in the table well you get five stars lines in the 5star.php page.
How can I place the star rating where I do exactly want them to be inside the page?
Thanx a lot!
hihi, primary key name is ” id “, it’s work ok !!
Good script, but I have a few questions:
First, I don’t have access to run those SQL queries on a remote webserver, what would the table syntax structure look like in a text file?
Is there a way to use IP Addresses instead of $_COOKIES to record the info (in case user has cookies off)? How would I do that?
Also can this be used on multiple pages and how would that work.
I haven’t really thought about how you would go about storing this in a file rather than a database, h/e it would probably be as easy as doing this sort of structure:
You would have to alter the code to explode/implode this data and then find out how the users voted though.
If you’re going to use IP addresses instead of Cookies just use the $_SERVER['REMOTE_ADDR'] variable in place of the cookies. After that it would be a case of checking for that IP Address in the file/database, rather than the cookie.
Fact is though cookies are a more reliable way of storing this kind of info: If the user has a dynamic IP it could allow them to vote numerous times on one object. Altering the code to work in a user system of sorts would probably be the best idea for this kind of script.
Using this on multiple pages is easy, and would work just how you’d expect it to. Just use the same data and same script and it’ll work fine.
Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource
line 15 of 5star.php
I’m guessing I didn’t setup my DB correctly, any help would be great.
Check your database is all right first of all. Then check you’ve entered the code properly.
The script don’t work by me, i cant vote and on the send.php page i have two errors on line 7 and 8..
Notice: Undefined index: rating in C:\wamp\www\fivestars\send.php on line 7
Notice: Undefined index: id in C:\wamp\www\fivestars\send.php on line 8
can somebody help me with it?
Thnx!!
yea, I got the same thing but that is simply because the php doesn’t know what is the id or rating, and we are using them as names of columns in the DB so just replace id and rating with ‘id’ and ‘rating’
($row['id'] and $row['rating'])
Hello! This works great! didn’t have any problems (with the functionallity).
Anywho, i think you should add some JS so that after hovering the stars (Without voting) the star field goes back to normal.
Else it is just super great :D
cheers.
This is really awesome .
All I want to know..Is there any way to make it work with wordpress ? especially the part with database and asking wordpress to make a new database table.
Can you please..
Thanks in advance
Cheers
Karar A.
I haven’t looked into wordpress integration but I’m sure it’d be possible. I think it might just be a case of adding the MySQL rows to your wordpress posts table.
Hey Johnny, great resource you’ve put here! I’m having a problem however, nomatter what the JavaScript isn’t calling the send.php – I’ve tried using Absolute URLs in the script.js file as well.
I’ve checked for definite that it’s not loading send.php by putting a function that inserts the word ‘Success’ into the database, but it still never does appear in the DB (which would imply that send.php isn’t being called).
I’m using exactly the same JS as you and the same file/folder structure, but I don’t understand why this doesn’t work?
Thank you for your help!
Jack
No worries, I solved it! :D
For everyone looking to make it make the original ratings appear when you take your mouse off:
http://stackoverflow.com/questions/2351903/jquery-javascript-ratings-making-the-rating-reappear-when-user-takes-their-curso
Can I add this rating system to a Google Maps API InfoWindow?
Yeah sure. :)
Hi, I really appreciate you effort and this great tutorial. can you please help me in setting up the database. What I want is this if it is possible. the user is reviewing a product using this kind of form:
name: his name
recommand th product: yes/no
Price: stars rate
shipping: stars rate
Quality: stars rating
Comments:
thanks in advance and really appreciate your help
all you need is to pass the value of each stars to ” SEND.php” and check if the IP and COOKIE still There! before you update your Data base! if the value is NULL! IP and cookie is clear.. post it!!
you dont need to take a while loop! dude wake up!! the purpose of this is run your star without giving a loop value!
this thing is not worth it especially to other beginners who wants to learn how Star rating works..
Just delete this TOPIC!! this is very worthless! neither you i!
I have a problem
What does this usually mean?
mysql_fetch_array(): supplied argument is not a valid MySQL result resource in /home/content/h/o/m/homepagesdfw/html/services/poolservices/tahitianpools/writereview.php on line 91
nice tutorial and easy to follow!
and its works for me!
thanks!
I was just wondering, is the rating script AJAX based, as in, does it need a page reload to show the updated rating?
Looking forward to your reply.
Greetz, Jaac
Really amazing searched allover the net but finally get satisfied here on webtint
and one request after rating show the average rating