RatingExtension/Source Code
From PeacockWiki
(Difference between revisions)
| Revision as of 02:11, 30 July 2006 (edit) Trevorp (Talk | contribs) ← Previous diff |
Revision as of 04:34, 30 July 2006 (edit) Trevorp (Talk | contribs) Next diff → |
||
| Line 1: | Line 1: | ||
| <pre><?php | <pre><?php | ||
| - | #If html request requests file, serve file | + | ################################################################################ |
| + | # Core Code # | ||
| + | ################################################################################ | ||
| + | # This section handles the core functions of this extension # | ||
| + | # * Serving Files # | ||
| + | # * Recording Ratings # | ||
| + | # * Displaying Ratings # | ||
| + | ################################################################################ | ||
| + | |||
| + | #------------------------------------------------------------------------------- | ||
| + | # If html request requests file, serve file # | ||
| + | # Files are requested by adding the ?file= GET parameter # | ||
| + | #------------------------------------------------------------------------------- | ||
| if(isset($_GET['file'])) | if(isset($_GET['file'])) | ||
| doFile(); | doFile(); | ||
| - | #If html request contains rate information, process it | + | #------------------------------------------------------------------------------- |
| + | # If html request contains rate information, process it # | ||
| + | # Rating information indicated by ?rate= GET parameter # | ||
| + | # # | ||
| + | # MediaWiki engine is started by imitating the code in index.php # | ||
| + | # This ensures database functions are working # | ||
| + | #------------------------------------------------------------------------------- | ||
| if(isset($_GET['rate'])) | if(isset($_GET['rate'])) | ||
| { | { | ||
| Line 15: | Line 33: | ||
| $action = $wgRequest->getVal( 'action', 'view' ); | $action = $wgRequest->getVal( 'action', 'view' ); | ||
| $title = $wgRequest->getVal( 'title' ); | $title = $wgRequest->getVal( 'title' ); | ||
| - | $wgTitle = $mediaWiki->checkInitialQueries( $title,$action,$wgOut, $wgRequest, $wgContLang ); | + | $wgTitle = $mediaWiki->checkInitialQueries($title, $action, $wgOut, |
| + | $wgRequest, $wgContLang); | ||
| #Record Rating | #Record Rating | ||
| #---------------- | #---------------- | ||
| - | $sql = "REPLACE INTO `ratings` (`page_oldid`, `user_id`, `page_rating`) VALUES (".$_GET['oldid'].", '".($wgUser->getID()?$wgUser->getID():$wgUser->getName())."', ".$_GET['rate'].")"; | + | $sql = "REPLACE INTO `ratings` (`page_oldid`, `user_id`, `page_rating`) '. |
| + | 'VALUES (".$_GET['oldid'].", '". | ||
| + | ($wgUser->getID()?$wgUser->getID():$wgUser->getName()). | ||
| + | "', ".$_GET['rate'].")"; | ||
| $dbr =& wfGetDB( DB_WRITE ); | $dbr =& wfGetDB( DB_WRITE ); | ||
| $res=wfQuery($sql, DB_WRITE, ""); | $res=wfQuery($sql, DB_WRITE, ""); | ||
| Line 31: | Line 53: | ||
| } | } | ||
| - | #get oldid of current page | + | #------------------------------------------------------------------------------- |
| + | # Initialize extension # | ||
| + | # Sets up credit information, and hooks # | ||
| + | #------------------------------------------------------------------------------- | ||
| + | if(isset($wgScriptPath)) | ||
| + | { | ||
| + | $wgExtensionCredits["parserhook"][]=array( | ||
| + | 'name' => 'Rating Extension', | ||
| + | 'version' => '0.1', | ||
| + | 'url' => 'http://wiki.peacocktech.com/wiki/RatingExtension', | ||
| + | 'author' => '[http://about.peacocktech.com/trevorp/ Trevor Peacock]', | ||
| + | 'description' => 'Adds rating mechanism' ); | ||
| + | $wgHooks['OutputPageBeforeHTML'][] = 'InsertRating'; | ||
| + | $wgHooks['SkinTemplateSetupPageCss'][] = 'RatingCss'; | ||
| + | } | ||
| + | |||
| + | #------------------------------------------------------------------------------- | ||
| + | # Insert rating to top of page # | ||
| + | #------------------------------------------------------------------------------- | ||
| + | function InsertRating($parserOutput, $text) { | ||
| + | global $wgArticle; | ||
| + | $oldid=getOldID($wgArticle); | ||
| + | if($oldid) | ||
| + | $text='<div id="ratingsection">'. | ||
| + | getRatingHTML(getRating($oldid), $oldid).'</div>'.$text; | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | #------------------------------------------------------------------------------- | ||
| + | # Add CSS into skin for rating # | ||
| + | #------------------------------------------------------------------------------- | ||
| + | function RatingCss(&$css) { | ||
| + | global $wgScriptPath; | ||
| + | $css = "/*<![CDATA[*/". | ||
| + | " @import \"$wgScriptPath/?file=rating.css\"; ". | ||
| + | "/*]]>*/"; | ||
| + | return true; | ||
| + | } | ||
| + | |||
| + | ################################################################################ | ||
| + | # Supporting Functions # | ||
| + | ################################################################################ | ||
| + | # These functions support the core functions of the extension # | ||
| + | ################################################################################ | ||
| + | |||
| + | #------------------------------------------------------------------------------- | ||
| + | # Use the mediawiki engine to run the given sql code and return an object # | ||
| + | # containing the first result of the query # | ||
| + | #------------------------------------------------------------------------------- | ||
| + | #run sql code | ||
| + | function runQuery($sql) | ||
| + | { | ||
| + | $dbr =& wfGetDB( DB_SLAVE ); | ||
| + | $res=wfQuery($sql, DB_SLAVE, ""); | ||
| + | return $dbr->fetchObject( $res ); | ||
| + | } | ||
| + | |||
| + | #------------------------------------------------------------------------------- | ||
| + | # Return the oldid of the current page # | ||
| + | # If oldid=0 (most current revision) take the latest oldid from the database # | ||
| + | # for the current article # | ||
| + | #------------------------------------------------------------------------------- | ||
| function getOldID($article) | function getOldID($article) | ||
| { | { | ||
| Line 38: | Line 122: | ||
| return $oldid; | return $oldid; | ||
| $dbr =& wfGetDB( DB_SLAVE ); | $dbr =& wfGetDB( DB_SLAVE ); | ||
| - | $sql = "SELECT MAX(`rc_this_oldid`) AS `rc_this_oldid` FROM recentchanges WHERE rc_cur_id=".$article->getID().";"; | + | $sql = "SELECT MAX(`rc_this_oldid`) AS `rc_this_oldid` FROM recentchanges '. |
| - | $res=wfQuery($sql, DB_WRITE, ""); | + | 'WHERE rc_cur_id=".$article->getID().";"; |
| + | $res=wfQuery($sql, DB_SLAVE, ""); | ||
| $row=$dbr->fetchObject( $res ); | $row=$dbr->fetchObject( $res ); | ||
| if($row->rc_this_oldid) | if($row->rc_this_oldid) | ||
| Line 46: | Line 131: | ||
| } | } | ||
| - | #run sql code | + | #------------------------------------------------------------------------------- |
| - | function runQuery($sql) | + | # Performs a SQL query to fetch a rating for page oldid # |
| - | { | + | #------------------------------------------------------------------------------- |
| - | $dbr =& wfGetDB( DB_SLAVE ); | + | |
| - | $res=wfQuery($sql, DB_SLAVE, ""); | + | |
| - | return $dbr->fetchObject( $res ); | + | |
| - | } | + | |
| - | + | ||
| - | #perform sql query to fetch rating for a given oldid | + | |
| function getRatingData($oldid) | function getRatingData($oldid) | ||
| { | { | ||
| - | $sql="SELECT COUNT(*) AS `count`, AVG(`page_rating`) AS `rating` FROM ratings WHERE `page_oldid`=".$oldid." GROUP BY `page_oldid`;"; | + | $sql="SELECT COUNT(*) AS `count`, AVG(`page_rating`) AS `rating` '. |
| + | 'FROM ratings WHERE `page_oldid`=".$oldid." GROUP BY `page_oldid`;"; | ||
| return runQuery($sql); | return runQuery($sql); | ||
| } | } | ||
| - | #fetch/calculate rating from database | + | #------------------------------------------------------------------------------- |
| + | # Fetch and calculate a rating for page oldid # | ||
| + | # If there are not enough ratings for the current revivion, cycle # | ||
| + | # older revisions to gather a minimum number of ratings # | ||
| + | #------------------------------------------------------------------------------- | ||
| function getRating($oldid) | function getRating($oldid) | ||
| { | { | ||
| Line 71: | Line 155: | ||
| $finalrating='?'; | $finalrating='?'; | ||
| $currentcount=number_format($ratingdata->count, 0); | $currentcount=number_format($ratingdata->count, 0); | ||
| + | #If there are not enough ratings for the current revision | ||
| if($rating->count<$countlimit) | if($rating->count<$countlimit) | ||
| { | { | ||
| $count=$ratingdata->count; | $count=$ratingdata->count; | ||
| $rating=$count*$ratingdata->rating; | $rating=$count*$ratingdata->rating; | ||
| - | # echo "not enough data ($rating/$count)\n"; | + | #cycle older revisions looking for more ratings |
| - | while($oldid=$wgTitle->getPreviousRevisionID($oldid)) | + | while($oldid=$wgTitle->getPreviousRevisionID($oldid)) |
| { | { | ||
| - | # echo "trying previous ratings\n"; | ||
| $ratingdata=getRatingData($oldid); | $ratingdata=getRatingData($oldid); | ||
| + | #If still not enough ratings | ||
| if($count+$ratingdata->count<$countlimit) | if($count+$ratingdata->count<$countlimit) | ||
| { | { | ||
| $count+=$ratingdata->count; | $count+=$ratingdata->count; | ||
| $rating+=$ratingdata->count*$ratingdata->rating; | $rating+=$ratingdata->count*$ratingdata->rating; | ||
| - | # echo "still not enough data ($rating/$count)\n"; | ||
| } | } | ||
| - | else | + | else #found enough ratings |
| { | { | ||
| $rating+=($countlimit-$count)*$ratingdata->rating; | $rating+=($countlimit-$count)*$ratingdata->rating; | ||
| $count=$countlimit; | $count=$countlimit; | ||
| - | # echo "enough data ($rating/$count)\n"; | ||
| $finalrating=$rating/$count; | $finalrating=$rating/$count; | ||
| $oldid=false; | $oldid=false; | ||
| Line 98: | Line 181: | ||
| else | else | ||
| $finalrating=$rating/$count; | $finalrating=$rating/$count; | ||
| - | + | ||
| + | #format rating data | ||
| if(is_numeric($finalrating)) | if(is_numeric($finalrating)) | ||
| $finalrating=($finalrating-1)*1.25; | $finalrating=($finalrating-1)*1.25; | ||
| - | $ratingarray=array('display'=>(is_numeric($finalrating)?number_format($finalrating, 2):$finalrating)." ($currentcount ratings)", | + | $ratingarray=array('display'=> |
| + | (is_numeric($finalrating)?number_format($finalrating, 2):$finalrating). | ||
| + | " ($currentcount ratings)", | ||
| 'count'=>$currentcount, | 'count'=>$currentcount, | ||
| 'rating'=>(is_numeric($finalrating)?$finalrating:0)); | 'rating'=>(is_numeric($finalrating)?$finalrating:0)); | ||
| Line 107: | Line 193: | ||
| } | } | ||
| - | #Generate html code to insert into page | + | #------------------------------------------------------------------------------- |
| + | # Given the rating array and the page oldid, generate HTML code to be # | ||
| + | # displayed # | ||
| + | #------------------------------------------------------------------------------- | ||
| function getRatingHTML($rating, $oldid) | function getRatingHTML($rating, $oldid) | ||
| { | { | ||
| Line 113: | Line 202: | ||
| $countlimit=3; | $countlimit=3; | ||
| $html=''; | $html=''; | ||
| + | #generate stars | ||
| for($x=0;$x<=4;$x++) | for($x=0;$x<=4;$x++) | ||
| { | { | ||
| - | $html.='<a href="'.$wgTitle->getFullURL('oldid='.$oldid.'&rate='.($x+1)).'">'. | + | $html.='<a href="'. |
| - | '<img src="'.$wgScriptPath.'/extensions/rating/star'; | + | $wgTitle->getFullURL('oldid='.$oldid.'&rate='.($x+1)).'">'. |
| - | if($rating['rating']>=$x+1) | + | '<img src="?file=star'; |
| + | if($rating['rating']>=$x+1) #larger than current star : filled | ||
| $html.='4'.($rating['count']<$countlimit?'b':''); | $html.='4'.($rating['count']<$countlimit?'b':''); | ||
| - | elseif($rating['rating']>$x+0.75) | + | elseif($rating['rating']>$x+0.75) #3/4 current star : 3/4 filled |
| $html.='3'.($rating['count']<$countlimit?'b':''); | $html.='3'.($rating['count']<$countlimit?'b':''); | ||
| - | elseif($rating['rating']>$x+0.5) | + | elseif($rating['rating']>$x+0.5) #1/2 current star : 1/2 filled |
| $html.='2'.($rating['count']<$countlimit?'b':''); | $html.='2'.($rating['count']<$countlimit?'b':''); | ||
| - | elseif($rating['rating']>$x+0.25) | + | elseif($rating['rating']>$x+0.25) #1/4 current star : 1/4 filled |
| $html.='1'.($rating['count']<$countlimit?'b':''); | $html.='1'.($rating['count']<$countlimit?'b':''); | ||
| - | else | + | else #less than current star : empty |
| $html.='0'; | $html.='0'; | ||
| $html.='.png" align=bottom/></a>'."\n"; | $html.='.png" align=bottom/></a>'."\n"; | ||
| } | } | ||
| + | #add text rating | ||
| $html.=' '.$rating['display'].''; | $html.=' '.$rating['display'].''; | ||
| $html=($rating['count']<$countlimit?'<b>'.$html.'</b>':$html); | $html=($rating['count']<$countlimit?'<b>'.$html.'</b>':$html); | ||
| return $html; | return $html; | ||
| - | } | ||
| - | |||
| - | #Insert rating to top of page | ||
| - | function InsertRating($parserOutput, $text) { | ||
| - | global $wgArticle; | ||
| - | $oldid=getOldID($wgArticle); | ||
| - | if($oldid) | ||
| - | $text='<div id="ratingsection">'.getRatingHTML(getRating($oldid), $oldid).'</div>'.$text; | ||
| - | } | ||
| - | |||
| - | |||
| - | #set up extension info | ||
| - | if(isset($wgScriptPath)) | ||
| - | { | ||
| - | $wgExtensionCredits["parserhook"][]=array( | ||
| - | 'name' => 'Rating Extension', | ||
| - | 'version' => '0.1', | ||
| - | 'url' => 'http://wiki.peacocktech.com/wiki/RatingExtension', | ||
| - | 'author' => '[http://about.peacocktech.com/trevorp/ Trevor Peacock]', | ||
| - | 'description' => 'Adds rating mechanism' ); | ||
| - | $wgHooks['OutputPageBeforeHTML'][] = 'InsertRating'; | ||
| - | $wgHooks['SkinTemplateSetupPageCss'][] = 'RatingCss'; | ||
| - | } | ||
| - | |||
| - | #Add CSS into skin for rating | ||
| - | function RatingCss(&$css) { | ||
| - | global $wgScriptPath; | ||
| - | $css = "/*<![CDATA[*/". | ||
| - | " @import \"$wgScriptPath/?file=rating.css\"; ". | ||
| - | "/*]]>*/"; | ||
| - | return true; | ||
| } | } | ||
| - | #Return file if requested | + | #------------------------------------------------------------------------------- |
| + | # Return a file and exit. # | ||
| + | # File determined by ?file= GET parameter # | ||
| + | #------------------------------------------------------------------------------- | ||
| function doFile() | function doFile() | ||
| { | { | ||
| switch ($_GET['file']) | switch ($_GET['file']) | ||
| { | { | ||
| + | #Star .png files | ||
| + | case "star0.png": | ||
| + | case "star1.png": | ||
| + | case "star1b.png": | ||
| + | case "star2.png": | ||
| + | case "star2b.png": | ||
| + | case "star3.png": | ||
| + | case "star3b.png": | ||
| + | case "star4.png": | ||
| + | case "star4b.png": | ||
| + | header("Content-type: image/png"); | ||
| + | echo readFile('extensions/rating/'.$_GET['file']); | ||
| + | die(); | ||
| + | #extension css styling | ||
| case "rating.css": | case "rating.css": | ||
| header("Content-type: text/css"); | header("Content-type: text/css"); | ||
| Line 181: | Line 259: | ||
| #ratingsection b { | #ratingsection b { | ||
| - | // border: 1px solid black; | ||
| color: red; | color: red; | ||
| padding: 4px; | padding: 4px; | ||
Revision as of 04:34, 30 July 2006
<?php
################################################################################
# Core Code #
################################################################################
# This section handles the core functions of this extension #
# * Serving Files #
# * Recording Ratings #
# * Displaying Ratings #
################################################################################
#-------------------------------------------------------------------------------
# If html request requests file, serve file #
# Files are requested by adding the ?file= GET parameter #
#-------------------------------------------------------------------------------
if(isset($_GET['file']))
doFile();
#-------------------------------------------------------------------------------
# If html request contains rate information, process it #
# Rating information indicated by ?rate= GET parameter #
# #
# MediaWiki engine is started by imitating the code in index.php #
# This ensures database functions are working #
#-------------------------------------------------------------------------------
if(isset($_GET['rate']))
{
#Init
#----------------
require_once( 'includes/Setup.php' );
require_once( "includes/Wiki.php" );
$mediaWiki = new MediaWiki();
$action = $wgRequest->getVal( 'action', 'view' );
$title = $wgRequest->getVal( 'title' );
$wgTitle = $mediaWiki->checkInitialQueries($title, $action, $wgOut,
$wgRequest, $wgContLang);
#Record Rating
#----------------
$sql = "REPLACE INTO `ratings` (`page_oldid`, `user_id`, `page_rating`) '.
'VALUES (".$_GET['oldid'].", '".
($wgUser->getID()?$wgUser->getID():$wgUser->getName()).
"', ".$_GET['rate'].")";
$dbr =& wfGetDB( DB_WRITE );
$res=wfQuery($sql, DB_WRITE, "");
#Return to refering page and exit
#----------------
$wgTitle->invalidateCache();
header( 'Location: '.$_SERVER["HTTP_REFERER"] ) ;
die();
}
#-------------------------------------------------------------------------------
# Initialize extension #
# Sets up credit information, and hooks #
#-------------------------------------------------------------------------------
if(isset($wgScriptPath))
{
$wgExtensionCredits["parserhook"][]=array(
'name' => 'Rating Extension',
'version' => '0.1',
'url' => 'http://wiki.peacocktech.com/wiki/RatingExtension',
'author' => '[http://about.peacocktech.com/trevorp/ Trevor Peacock]',
'description' => 'Adds rating mechanism' );
$wgHooks['OutputPageBeforeHTML'][] = 'InsertRating';
$wgHooks['SkinTemplateSetupPageCss'][] = 'RatingCss';
}
#-------------------------------------------------------------------------------
# Insert rating to top of page #
#-------------------------------------------------------------------------------
function InsertRating($parserOutput, $text) {
global $wgArticle;
$oldid=getOldID($wgArticle);
if($oldid)
$text='<div id="ratingsection">'.
getRatingHTML(getRating($oldid), $oldid).'</div>'.$text;
}
#-------------------------------------------------------------------------------
# Add CSS into skin for rating #
#-------------------------------------------------------------------------------
function RatingCss(&$css) {
global $wgScriptPath;
$css = "/*<![CDATA[*/".
" @import \"$wgScriptPath/?file=rating.css\"; ".
"/*]]>*/";
return true;
}
################################################################################
# Supporting Functions #
################################################################################
# These functions support the core functions of the extension #
################################################################################
#-------------------------------------------------------------------------------
# Use the mediawiki engine to run the given sql code and return an object #
# containing the first result of the query #
#-------------------------------------------------------------------------------
#run sql code
function runQuery($sql)
{
$dbr =& wfGetDB( DB_SLAVE );
$res=wfQuery($sql, DB_SLAVE, "");
return $dbr->fetchObject( $res );
}
#-------------------------------------------------------------------------------
# Return the oldid of the current page #
# If oldid=0 (most current revision) take the latest oldid from the database #
# for the current article #
#-------------------------------------------------------------------------------
function getOldID($article)
{
$oldid=$article->getOldIDFromRequest();
if($oldid!=0)
return $oldid;
$dbr =& wfGetDB( DB_SLAVE );
$sql = "SELECT MAX(`rc_this_oldid`) AS `rc_this_oldid` FROM recentchanges '.
'WHERE rc_cur_id=".$article->getID().";";
$res=wfQuery($sql, DB_SLAVE, "");
$row=$dbr->fetchObject( $res );
if($row->rc_this_oldid)
return $row->rc_this_oldid;
return null;
}
#-------------------------------------------------------------------------------
# Performs a SQL query to fetch a rating for page oldid #
#-------------------------------------------------------------------------------
function getRatingData($oldid)
{
$sql="SELECT COUNT(*) AS `count`, AVG(`page_rating`) AS `rating` '.
'FROM ratings WHERE `page_oldid`=".$oldid." GROUP BY `page_oldid`;";
return runQuery($sql);
}
#-------------------------------------------------------------------------------
# Fetch and calculate a rating for page oldid #
# If there are not enough ratings for the current revivion, cycle #
# older revisions to gather a minimum number of ratings #
#-------------------------------------------------------------------------------
function getRating($oldid)
{
global $wgTitle;
$countlimit=3;
$ratingdata=getRatingData($oldid);
$finalrating='?';
$currentcount=number_format($ratingdata->count, 0);
#If there are not enough ratings for the current revision
if($rating->count<$countlimit)
{
$count=$ratingdata->count;
$rating=$count*$ratingdata->rating;
#cycle older revisions looking for more ratings
while($oldid=$wgTitle->getPreviousRevisionID($oldid))
{
$ratingdata=getRatingData($oldid);
#If still not enough ratings
if($count+$ratingdata->count<$countlimit)
{
$count+=$ratingdata->count;
$rating+=$ratingdata->count*$ratingdata->rating;
}
else #found enough ratings
{
$rating+=($countlimit-$count)*$ratingdata->rating;
$count=$countlimit;
$finalrating=$rating/$count;
$oldid=false;
}
}
}
else
$finalrating=$rating/$count;
#format rating data
if(is_numeric($finalrating))
$finalrating=($finalrating-1)*1.25;
$ratingarray=array('display'=>
(is_numeric($finalrating)?number_format($finalrating, 2):$finalrating).
" ($currentcount ratings)",
'count'=>$currentcount,
'rating'=>(is_numeric($finalrating)?$finalrating:0));
return $ratingarray;
}
#-------------------------------------------------------------------------------
# Given the rating array and the page oldid, generate HTML code to be #
# displayed #
#-------------------------------------------------------------------------------
function getRatingHTML($rating, $oldid)
{
global $wgTitle, $wgScriptPath;
$countlimit=3;
$html='';
#generate stars
for($x=0;$x<=4;$x++)
{
$html.='<a href="'.
$wgTitle->getFullURL('oldid='.$oldid.'&rate='.($x+1)).'">'.
'<img src="?file=star';
if($rating['rating']>=$x+1) #larger than current star : filled
$html.='4'.($rating['count']<$countlimit?'b':'');
elseif($rating['rating']>$x+0.75) #3/4 current star : 3/4 filled
$html.='3'.($rating['count']<$countlimit?'b':'');
elseif($rating['rating']>$x+0.5) #1/2 current star : 1/2 filled
$html.='2'.($rating['count']<$countlimit?'b':'');
elseif($rating['rating']>$x+0.25) #1/4 current star : 1/4 filled
$html.='1'.($rating['count']<$countlimit?'b':'');
else #less than current star : empty
$html.='0';
$html.='.png" align=bottom/></a>'."\n";
}
#add text rating
$html.=' '.$rating['display'].'';
$html=($rating['count']<$countlimit?'<b>'.$html.'</b>':$html);
return $html;
}
#-------------------------------------------------------------------------------
# Return a file and exit. #
# File determined by ?file= GET parameter #
#-------------------------------------------------------------------------------
function doFile()
{
switch ($_GET['file'])
{
#Star .png files
case "star0.png":
case "star1.png":
case "star1b.png":
case "star2.png":
case "star2b.png":
case "star3.png":
case "star3b.png":
case "star4.png":
case "star4b.png":
header("Content-type: image/png");
echo readFile('extensions/rating/'.$_GET['file']);
die();
#extension css styling
case "rating.css":
header("Content-type: text/css");
?>
#ratingsection {
float: right;
margin-top: -3.7em;
padding: 3px;
}
#ratingsection b {
color: red;
padding: 4px;
}
<?php
die();
}
}
?>
