Complete Star Rating Script

Created: March 22, 2013
Last Modified: July 15, 2019
Subscribe to Internet Tips and Tools Feed

★★★★★★★★★★Star Rating Script 4 out of 5 stars based on 5 ratings.
5 stars
3 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

Couldn't connect to MySQL