Complete Star Rating Script for PHP

Created: March 22, 2013
Last Modified: January 28, 2020
Subscribe to Internet Tips and Tools Feed

★★★★★★★★★★Star Rating Script 4.3 out of 5 stars based on 7 ratings.
5 stars
5 votes
4 stars
1 votes
1 stars
1 votes

Your Rating:

This complete 5 star rating script shows you how to make a star rating system, how to store the user ratings in a database and how to use microdata to have the ratings appear in google, bing and yahoo search results as rich snippets. Go ahead and login so you can see how the system works. Creating an account doesn't require email verification so you can use a fake email address if you desire.

A PHP login script is available here if you need one to use with the ratings script.
NEW!! 4/24/2014 - You can now use this star ratings script without requiring the user to login. The script will use the user's IP address for the user_id.


  • NEW!! 3/30/2017 - Now works with MySQL or MySQLi
  • Makes the stars without the use of images through HTML entities or you can supply images
  • Uses Javascript Ajax to submit a user rating
  • Uses PHP and MySQL
  • Automatically builds the html code for the new microdata standard so that the star ratings show up as rich snippets in google, yahoo and bing search engine results
  • Two MySQL database tables are used for faster access of star rating averages and total ratings
  • Visitors can rate without logging in or you can require users to login or create an account


Downloaded 0 times.
Please make a donation to reveal the download link.

There are two files inside of called ratings.php and db.php. Unzip both files and upload them to your server and then include the ratings.php file anywhere you want the star rating to show up in your webpage like this:

		$r['name'] = "Name of product"; // Needed for microdata and for rich snippets to appear in search engines

If your web page is an .htm or .html file instead of a .php file then you have to make sure that your server can process PHP code in html files by adding a line to the .htaccess file located in the www folder of your server. The line may look something like this:

	addhandler application/x-httpd-php .htm .html

One nice thing about having two tables with one table holding the average stars and total votes for each product is that if you have a webpage that displays many products or stores at once you may want to get the rating for each product or store without retrieving the ratings details. This can be done without doing a lot of searching through the mysql database. Here is an example:

/* multiple_ratings.php
	taken from cavesearch/cave-ajax.php
	/* You may have a webpage that displays multiple products at one time.
		On this page you may want to display the star rating average for each product
		but not the star rating details.  Here is a mysql example of getting
		stores within a certain distance and then joining the star_rating_averages for
		each store, by the being the same as the star_rating_averages page.
	$rows = array();
	// To search by kilometers instead of miles, replace 3959 with 6371. 
	$query = "SELECT markers.*, ( 3959 * acos( cos( radians($lat) ) * cos( radians( lat ) ) * cos( radians( lng ) 
				- radians($lng) ) + sin( radians($lat) ) * sin( radians( lat ) ) ) ) AS distance, 
				star_rating_averages.avg_stars, star_rating_averages.total_votes
				FROM markers
				LEFT JOIN star_rating_averages ON =
				WHERE archive = 0 AND ";
	if ($w > $e) { // If the bounds include the intl. date line
	    $query .= "(lat BETWEEN $s AND $n) AND ((lng BETWEEN -180 AND $e) OR (lng BETWEEN $w AND 180))";
	} else {
	    $query .= "(lat BETWEEN $s AND $n) AND (lng BETWEEN $w AND $e)";
	$query .= " ORDER BY distance ASC LIMIT 100";
	$result = mysql_query($query) or die($query." : ".mysql_error());
	while($r = mysql_fetch_assoc($result)) 
		$r['distance'] = round($r['distance'], 1);
		$r = array_map('utf8_encode', $r);
		$rows['marker'.$r['id']] = $r;
	// Echo $rows associate array into javascript obj
	echo '<script type="text/javascript">'.chr(13);
	print "var obj = ".json_encode($rows).';'.chr(13);
	echo '</script>';

<script type="text/javascript">
	/* Here is a javascript example of displaying the star_ratings_averages for each store
		once they have been retrieved from mysql and php.
		Taken from cavesearch\ajax.js
	// Star rating variables
	var star_image_width = 1; // 1em; Could change to 16px for image of a star that is 16 pixels wide
	var star_width_type = 'em'; // Change to 'px' for pixels if using an image instead of HTML entity
	var yellow_star = '&#9733;'; // HTML entity of a star
	//var yellow_star = "<img src='yellowstar.gif'>"; // If you want to use an image then uncomment this line
	var grey_star = '&#9733;'; // HTML entity of a star used for blank stars in ratings
	//var grey_star = "<img src='greystar.gif'>"; // If you want to use an image then uncomment this line
	var user_star = '&#9733;'; // HTML entity of a star used for the users personal rating
	//var user_star = "<img src='redstar.gif'>"; // If you want to use an image then uncomment this line
	var blank_star = '&#9734;'; // HTML entity of a star outline used for a users personal rating before rating
	//var blank_star = "<img src='blankstar.gif'>"; // If you want to use an image then uncomment this line
	var yellow = "#F99B00"; // Color used for HTML star entity
	var grey = "#999999"; // Color used for remainder of stars not in the rating value
	var red = "#FF5555"; // Color used for the stars of the users personal rating

function processMarkers(obj)
	for (var key in obj)
		if (obj.hasOwnProperty(key))
			if (key.match(/^marker\d+>/i)) // find 'marker##'
function processMarker(obj)
	// Calculate the width of the yellow stars
	//var avg_stars_width = Math.round((star_image_width * obj['avg_stars'])*10)/10; // Version 1.45 - Not used anymore; Calculating with javascript
	// Put 5 grey stars in relative span
	var stars_display = "<span class='stars_display' data-avg-stars='"+obj['avg_stars']="' style='position: relative; display:inline-block; overflow:hidden; color: "+grey+"; '>"+
	// Overlay 5 yellow stars on top of the grey stars
	stars_display += "<span style='position: absolute; top: 0; left: 0; color: "+yellow+"; overflow:hidden;'>"+
	// Close relative span
	stars_display += "</span>"+" ("+obj['total_votes']+" ratings)"; 

	document.write(obj['id']+". "+obj['name']+": "+stars_display+"<br>");

function change_avg_stars()
	/* Version 1.45 - This function gets the width of 5 stars and then
		calculates the width of the avg_stars span inside it (firstChild) */
	var all_el = document.getElementsByTagName('*');

	for (var i = 0; i < all_el.length; i++) {
	    if (all_el[i].className && all_el[i].className.match(/stars_display/i)) {
			var stars_display = all_el[i];
			var full_width = stars_display.clientWidth;
			var avg_stars = stars_display.getAttribute("data-avg-stars");
			var avg_stars_width = (avg_stars / 5) * full_width;
			for (var s = 0; s < stars_display.children.length; s++)
				if (stars_display.children[s].nodeName == "IMG" && !stars_display.children[s].complete)
					setTimeout("change_avg_stars()", 500); // if stars are images and they haven't been loaded yet then call again 
				else if (stars_display.children[s].nodeName == "SPAN")
					stars_display.children[s].style.width = avg_stars_width + "px";	



March 26, 2019 - Ver 1.5c - Fixed "warning: undefined variable" if PHP is set to display warnings.

August 9, 2017 - Ver 1.5b - Bug fix in db.php - Changed if ($server_has_mysqli) to if ($GLOBALS["server_has_mysqli"]) throughout. Also changed $db_link->affected_rows() to $db_link->affected_rows.

April 17, 2017 - Ver 1.5a - Bug Fix - When adding MySQLi support there was a function that accidentally converted the averages to an integer or round number. This has been fixed by changing db.php on line 30 to use floatval() instead of intval().

March 30, 2017 - Ver 1.5 - Added support for MySQLi database functions if your server supports it. now includes ratings.php and db.php. The script will automatically use MySQLi if your server supports it, otherwise it will use MySQL.

June 29, 2016 - Ver 1.45 - Bug fix: The width of the average stars was sometimes being miscalculated and displayed incorrectly because it was relying on font-size which does not go by width but by height. Corrected! You can also use images for the stars instead of HTML entities if desired. Also the script now uses the web page address for the id of the product in the mysql database, so that you no longer have to worry about setting an id for star ratings in each web page.

October 3, 2014 - Ver 1.4a - I don't think we need $_SESSION['refer'] = $_SERVER['REQUEST_URI']; on line 94 and 95 so I removed it. It was for a login script to change location back to referring page. But I think login scripts will have their own method.

April 24, 2014 - Ver 1.4 - Now the script does not require the user to login. However, this is not recommended. Change the $require_login variable at the beginning of the script to $require_login = 0; Then the script will use the user's IP address as a unique identifier (user_id). However, most user's have a dynamic IP address (changing address). So they could come back in a few days and put another star rating as a different user. To try and offset this the script will also set a cookie with the user's IP address. If the cookie is found then even though they have a new IP address the script will treat them as a previous user. (Of course a user could still delete their cookies)

April 9, 2014 - Ver 1.3a - Bug fix for iOS, iPhone, iPad devices. Because iOS tries to implement onmouseover (or hover) events but doesn't do it well, a user had to click on a star twice for it to register the vote. The first click just acted as an onmouseover event and the second click was an onclick event. Now detecting iOS devices on lines 295 to 324 with if (!(\"ontouchstart\" in document.documentElement)) to stop this bug.

July 29, 2013 - ver 1.3 - Bug Fix in star_ratings_averages table. Previously the averages were being stored with only 1 decimal place. Changed to 2 decimals on lines 162 and 175 with mysql ROUND because with only 1 decimal place if a user changes their vote by one star up or down multiple times then the average rating can start to be off. Changed line 203 to grab the avg_stars with 1 decimal place so that it is a pleasing visual for the user.

July 29, 2013 - ver 1.25 - Bug Fix. On line 80 changed $_SESSION['refer'] to only be set if ratings.php is not being called by ajax. This prevents login from changing location to ratings.php

May 17, 2013 - ver 1.2 - Version 1.1 no longer is used. It has been removed. Fixed the yellow stars alignment for all browsers including iPad and iPhone Safari by adding display:inline-block; to line 254 and 294 of ratings.php and to line 84 of multiple_ratings.php.

May 15, 2013 - ver 1.1 - Fixed iPhone bug around line 256 where stars are aligned 3 pixels too low. Fixed with adding top:-3px for iphone only.

March 22, 2013 - Created Complete Star Rating Script

Back to
Subscribe to Internet Tips and Tools Feed        

User Comments

There are 52 comments.

Displaying first 50 comments.

1. Posted By: Vova Feldman - - April 22, 2013, 3:49 am
Great job Jeff! Love the way you managed to squeeze the back-end and client-side in one script. It's great approach you are a web developer and know how to setup a DB etc. But if you are not savvy in computers, I suggest to use the project. It happens to be that I'm the lead developer of the project ;) which is a very user-friendly and full solution for a Rating System (client+backend). Check it here:
For the ease of use we've developed several plugins/apps for different platforms:
1. WordPress plugin -
2. Blogger gadget -
3. Shopify app -
4. WiX app -

Keep up with the awesome work!

2. Posted By: Jolle - - April 23, 2013, 7:15 am
I like your blog but the file is missing!

3. Posted By: Jeff - - April 23, 2013, 11:42 am
Hi Jolle,

I apologize for the missing file. Not sure what happened. I re-uploaded the file. Please let me know if it is working for you. I am able to download it myself with IE and Chrome. But for some reason my Firefox keeps saying 404 Not Found.


4. Posted By: JK - - May 16, 2013, 3:43 pm
Hi Jeff -

I will appreciate it if you can give us also a sample of the login.php code so that it is easier to integrate into our site.

Thanks a ton.

5. Posted By: DJ3 - - July 24, 2013, 12:44 am
Could be a very nice script but there's a lot missing, for example login.php. registrate.php and so on

I hope the maker will post it some day

6. Posted By: Jeff - - July 29, 2013, 12:17 pm

A login script that works with this star ratings script is now available at


7. Posted By: Matt - - September 19, 2013, 9:33 am
Is there a way to combine written reviews with this as well? So people can do somthing similar to what I am right now (writing a comment) based on their rating?


8. Posted By: Jeff - - October 24, 2013, 10:22 am
Hi Matt,

Yes, you can have the comments with the user's star ratings. I just created an example php file for you and attached it. It will have to be changed according to your login and comment system.


9. Posted By: danish - - November 15, 2013, 9:05 am
Hi. when i click on a star to submit rating then a java script popup open with this message

"There was a problem retrieving the XML data:404".

How to resolve this problem. is something missing?

10. Posted By: Jeff - - November 15, 2013, 10:43 am
Hello Danish,

I have not seen this problem before. It appears there might be a problem with your server. Or maybe you have ratings.php in a subfolder. Make sure it is in the same folder as the HTML or PHP file that is calling it.


11. Posted By: danish - - November 15, 2013, 11:02 am
thanks 4 your fast reply Jeff. it was sub folder problem. data is submitting now.

12. Posted By: Jeff - - November 15, 2013, 11:16 am

You are welcome. Glad it's working!

13. Posted By: shefat robin - - November 29, 2013, 10:01 am
Thanks Vova Feldman for your help ....thats great its up and running .... thanks a lot mate.. :)

14. Posted By: Manjua - - December 18, 2013, 7:43 pm

Can you post a database. please..!

15. Posted By: Faizal - - February 26, 2014, 12:12 am
Jeff, you are awesome!!. Thanks for sharing. :)

16. Posted By: ahmed - - March 6, 2014, 1:21 am
getting unknown error
please help

Warning: substr() expects parameter 1 to be string, object given in /home/content/75/11751475/html/bikes/bajaj/200ns/ratings.php on line 72
SELECT stars, sent_date FROM star_rating WHERE page='5' AND user_id='' LIMIT 1 : Unknown column 'user_id' in 'where clause'

17. Posted By: Jeff - - March 9, 2014, 5:09 pm
Hello ahmed,

Do you have a link to the server so I can test it? It appears that it is not finding a 'user_id' column in the star_rating table. Did you try to create the tables yourself in the database? Because ratings.php creates the tables itself.


18. Posted By: hj - - March 19, 2014, 5:03 am

19. Posted By: VJ - - April 10, 2014, 6:59 am
Thanks for the iOS fix. It works great.

20. Posted By: Belal - - April 21, 2014, 4:30 pm
I need helpm I a m begiiner in PHP, need shopping cart Php Mysql....thanx in advance

21. Posted By: dvorak7 - - April 23, 2014, 2:56 am
Hi Jeff,

First, thanks for this script. Great stuff.
I'd like to allow visitors to rate without having to register or login. Is it possible ?

Thanks a lot !


22. Posted By: Jeff - - April 24, 2014, 2:36 pm
Hi Chris,

Good question! The should be a unique identifier for the user so that they don't add a new rating every time they click a star. So I thought of one way to do this with their IP address. So they can click on the stars any number of times and it will be just one users rating. However, most Internet users have a changing IP address every day. So they could come back the next day and it would be like a second person adding a rating. But that is the problem with a rating system without a login.

Change line 72 to this:

You should also change 92 to

user_id INT unsigned,

The first line above changes the user_id to a long integer of their IP Address. The next line changes user_id in the SQL database to unsigned INT, because a regular INT will not be enough room to hold all types of IP addresses.


23. Posted By: Ravi - - May 2, 2014, 12:58 am

24. Posted By: Ian - - August 10, 2014, 5:57 am
Is there a way to change $id to be the page url instead of an id number? As my site where I intend to use the script doesn't them.

25. Posted By: Jeff - - August 11, 2014, 6:49 pm
Hello Ian,

I believe you could use the page url for $id, but you would have to change at least four lines in ratings.php

Change line 50 to:

Change line 102 to:
page VARCHAR(120),

Change line 114 to:
page VARCHAR(120),

Change line 437 to:


26. Posted By: Denis - - August 13, 2014, 8:47 am
Hello. Tell me how to display the form results page if no one voted?

27. Posted By: James - - October 21, 2014, 12:10 pm
Very cool. Is this an open source project that can be used on commercial websites or would I need to obtain a license from you?

28. Posted By: Jeff - - October 24, 2014, 9:55 am
Hello Denis,

The script does not display the ratings details unless there is at least 1 rating.


29. Posted By: Jeff - - October 24, 2014, 9:56 am
Hi James,

Thank you for inquiring. At the moment you can freely use the script for a personal or commercial project.


30. Posted By: kaps - - September 30, 2015, 6:45 am
Thanks for the script.
I only have to update $ID and $Name with appropriate values, right?

which I did but nothing is appearing on the webpage where I have included ratings.php. Infact tables are also not getting created automatically.(I have correctly set up database credentials), can you please help.
i am trying to set it up e.g. here below existing star ratings which I want to replace with this one as it has rich snippet code

31. Posted By: Jeff - - September 30, 2015, 1:22 pm
Hello kaps,

I looked at the source of your page and it is not processing the line:
<?PHP require_once('ratings.php'); ?>

as PHP. It is just reading it as text. Either your server is not supporting PHP or you are using an .html file and your server is not setup to process PHP in an .html file. You may need to add a .htaccess file with the following line in it:

addhandler application/x-httpd-php .htm .html

Also, if you are not using a login script you may want to change line 18 of the ratings.php to:



32. Posted By: Kaps - - October 1, 2015, 1:02 am
Thanks Jeff for your quick response.

I am using this code in .tpl file which is ultimately processed as .php and not html, extention become file.tpl.php.

Do I need to add addhandler application/x-httpd-php .htm .html in my sites .htaccess (one available in public folder) or servers .htaccess (one available in root folder)

I added it to one available in public folder but it did not work, I tried with addhandler application/x-httpd-php .htm .html .tpl and addhandler application/x-httpd-php .htm .html .tpl.php also.

Thank for your help

33. Posted By: Jeff - - October 1, 2015, 11:17 am
Hi Kaps,

Unfortunately I do not have experience with .tpl files. I did some research and according to this page: you can do something like this:

{php} require("ratings.php"); {/php}

I have no idea if it will work though.


34. Posted By: Bek - - April 2, 2016, 5:51 am
Hi, thanks so much for this. very grateful.

I'm getting following errors though;

Notice: Undefined variable: stars_display in...
Notice: Undefined variable: your_rating_display in...

Please help!

Many Thanks in advance

35. Posted By: Jeff - - April 2, 2016, 11:27 am
Hi Bek,

I apologize for this error. The PHP in your server is set to display notices and not just errors. There are three things you can do to try and stop this notice. Just do ONE of these things and then try the next if it doesn't work:

1. Near the top of ratings.php where the variables are being defined. Add these two lines:

2. Near the top of ratings.php add this line:
error_reporting(E_ALL & ~E_NOTICE);

3. On your server there should be a php.ini file. Edit the file and look for a line that starts with error_reporting and change it to:
error_reporting=E_ALL & ~E_NOTICE


36. Posted By: Bek - - April 3, 2016, 3:42 pm
Thanks Jeff for the quick response. All sorted now.

Thanks mate...much appreciated

37. Posted By: Grietje Goedkoop - - March 30, 2017, 2:17 am
Do you have a mysqli version?
Our server just updated to php 7.1 and now the plugin doesn't work anymore. According to the developer it is caused by the new PHP version that requires mysqli.
Any suggestions are welcome, cause we like your tool!
Best Regards, Grietje Goedkoop

38. Posted By: Jeff - - March 30, 2017, 11:45 am
Hi Grietje,

Unfortunately I do not have a mysqli version of the ratings script yet. But that is a good idea! I will start working on it and let you know when it is available.


39. Posted By: Jeff - - March 30, 2017, 12:55 pm
Hello Grietje,

I believe I have the script ready with MySQLi support. It will automatically use MySQLi functions if your server supports it. Download again at:

The zip file now has two files: ratings.php and db.php. Upload both of them to your server after making the needed changes in ratings.php. The file db.php will automatically be loaded by ratings.php and it includes all the database functions.


40. Posted By: Felix - - April 15, 2017, 2:38 pm

I must say that I really like your rating script and that it works very well for both MySQL and MySQLi.

However I'm curious to why the avg_stars are rounded up to whole numbers and not to 1 decimal.

I have 1 vote for 5 stars and 1 vote for 4 stars. The average is 4.5 but it's displaying 4 stars.

Is this because it's not possible to display half a star using your method?


41. Posted By: Jeff - - April 17, 2017, 9:32 am
Hi Felix,

I apologize for that. The rating script does correctly show the averages with a decimal, but I recently added MySQLi support to the script and accidentally left a function that turned it into an integer or round number.

I fixed the bug. You can re-download or just change db.php at around line 28 to this:



42. Posted By: Felix - - April 17, 2017, 11:03 am

Thanks for fixing that Jeff! :)


43. Posted By: Grietje Goedkoop - - May 9, 2017, 4:52 am
Hi Jeff,
It took a while but I finally got round trying the new rating stars script. Unfortunately it doesn't work on the site it was on before.
I tested it on one of my sites that is however not PHP 7.1
Please have a look at both testpages:
This is my testpage:

This is the testpage of the site which runs php 7.1:

Any suggestions?

44. Posted By: Jeff - - May 9, 2017, 11:02 am
Hi Grietje,

It is difficult to tell why it is not working on PHP 7.1 because it is not displaying any errors. Let's see if we can turn on all error reporting. On line 9 of ratings.php can you add this:



45. Posted By: Grietje Goedkoop - - May 22, 2017, 6:11 am
Hi Jeff,
I have added the errorscript but nothing happens.
Did I added it correctly: @error_reporting(E_ALL);

Meanwhile I have added a simple echo at the very beginning of ratings.php, so you can see the file is loaded.
To find out where things go wrong, I have added several other echos. See:

It appears to go wrong after:
// connect to mysql
$db_link=db_connect($server, $db_username, $db_pw, $database);

I have checked db username, password, db name and server over and over. Copied and pasted them from the config file that is used by the site in general.

Any other idea what I can do?

Best Regards, Grietje

46. Posted By: Jeff - - May 22, 2017, 12:05 pm
Hi Grietje,

That is correct but don't put the @ in front of it. Just this:


Do you have any other scripts that are using mysql databases on the server? I wonder if mysqli is setup correctly on the server. Maybe we can try to get mysqli to display more errors. In db.php on line 18 can you add this:


Also in db.php can you uncomment lines 40-44 by removing the /* and the */


47. Posted By: Rehan Ansari - - October 3, 2017, 5:44 am
Dear Sir very Nice script iam install But please tell me my website HTML page base ".$stars_display.$schema.$ratings_detail.$your_rating_display."

var page_id='';
var req=false;

function change_avg_stars()
/* Version 1.45 - This function gets the width of 5 stars and then
calculates the width of the avg_stars span inside it (firstChild) */
var all_el=document.getElementsByTagName('*');

for (var i=0; i < all_el.length; i++) {
if (all_el[i].className && all_el[i].className.match(/stars_display/i)) {
var stars_display=all_el[i];
var full_width=stars_display.clientWidth;
var avg_stars=stars_display.getAttribute("data-avg-stars");
var avg_stars_width=(avg_stars / 5) * full_width;
for (var s=0; s < stars_display.children.length; s++)
if (stars_display.children[s].nodeName=="IMG" && !stars_display.children[s].complete)

48. Posted By: Jeff - - October 3, 2017, 10:11 am
Hello Rehan Ansari,

I'm sorry, I don't think I understand your question. If you are seeing the javascript code below on the html page then it looks like your server is not processing php in .html pages. You need to add a line to a .htaccess file. It could be different for different versions of php. You can try:

addhandler application/x-httpd-php .htm .html


AddHandler application/x-httpd-php5 .html .htm

Or try renaming your page to have .php ending instead of .html


49. Posted By: Thilak - - January 3, 2018, 6:22 pm
I want the voting should be based on IP not with user session.So i want to completely remove user session part in the can i do this.

50. Posted By: Jeff - - January 3, 2018, 11:26 pm
Hi Thilak,

If you have $require_login=0; on line 19 then it will not use the session user_id. It should work fine that way without requiring login. But to actually remove all the session variables from the script requires a lot of customizing:

You would have to comment out line 8 by adding // in front of it so it looks like:
// @session_start();

You would need to remove $_SESSION['user_id']= from line 75 and 78.

And change line 143 and 292 to:
if (isset($user_id))