Rating System Won't Average Correctly - php

I have a rating system that uses the following equation to generate the rating average:
((Old Rating*Old Times Amount)+New Rating)/New Rating amount
However, if the current rating is 3, and it's been rated once, when I rate it three, it says the new rating is 2.5
What is the error here? Here's the full code.
<?php
session_start();
include("lib/db.php");
$db = new DBConnect;
if(isset($_POST['rating']) && is_numeric($_POST['rating']) && is_numeric($_POST['story']))
{
if($_POST['rating'] > 5 || $_POST['rating'] < 1){die("INVALID RATING");}
$rating = mysql_real_escape_string($_POST['rating']);
$story = mysql_real_escape_string($_POST['story']);
$c = $db->query("SELECT * FROM cdb_stories WHERE id=$story");
$c = mysql_fetch_array($c);
$u_name = mysql_real_escape_string($_SESSION['logged_in']);
$uid = $db->query("SELECT id FROM cdb_users WHERE username='{$u_name}'");
if(mysql_num_rows($uid) < 1){die("NOT LOGGED IN");}
$uid = mysql_fetch_array($uid);
$ratingd = $db->query("SELECT * FROM cdb_ratings WHERE userid='{$uid['id']}'");
if(mysql_num_rows($ratingd) > 0)
{
$ratingd = mysql_fetch_array($ratingd);
$new_rate = (($c['rating']*$c['rating_amt'])-$ratingd['rating']+$rating)/$c['rating_amt'];
$db->query("UPDATE cdb_stories SET rating={$new_rate} WHERE id={$story}");
$db->query("UPDATE cdb_ratings SET rating={$rating} WHERE userid='{$uid['id']}'");
die();
}
$new_num = $c['rating_amt']+1;
$new_rate = (($c['rating']*$c['rating_amt'])+$rating)/$new_num;
$db->query("UPDATE cdb_stories SET rating_amt={$new_num}, rating={$new_rate} WHERE id={$story}");
$db->query("INSERT INTO cdb_ratings VALUES({$uid['id']},{$rating},{$story})");
}
else
{
die("INVALID FIELDS");
}
?>

((Rating * Times) + New) / (Times + 1)
For your values:
((3 * 1) + 3) / (1 + 1)
= ( 3 + 3) / 2
= 6 / 2
= 3
So the procedure looks mathematically correct.
I suggest you put the calculation into a function of it's own with parameters, so you don't get irritated so much by the rest of the code you have in that batch. This will make it easier to debug for you:
function new_rate($rating, $times, $new)
{
return (($rating * $times) + $new) / ($times + 1);
}
You can then use that more easily within your code. Additionally if something else is the cause of the error, you can simply find out by testing the bare function. If it acts correct, you know that the error is placed somewhere else.
Hope this helps.

Related

PHP Recursion -- Increment query variables

I have a database where each row contains a unique userid number, and a referralid number that links them to the person that referred them to the site. I am trying to create a recursive function that will search the database as long as it continues to find users, and perform several calculations as it goes. Below is what I have so far - I am getting stuck on trying to create incrementing query variables - PLEASE HELP!
function findrepsloop($refidnum, $num){
echo "FINDREPSLOOP STARTED<br><br>";
if(strlen($refidnum) > 0){
echo "FIRST STRLEN IF LOOP PASSED: $refidnum<br><br>";
$totalreps++;
$query{$num} = "SELECT * FROM user WHERE (refidnum = '$refidnum' && active = 'YES') ";
$result{$num} = mysql_query($query{$num});
$line{$num} = mysql_fetch_array($result{$num}, MYSQL_NUM);
$total{$num} = mysql_num_rows($result{$num});
echo "QUERY $num found $total{$num} rows in the database. LINE 0: '$line{$num}[0]<br><br>";
$totaltemp = 0;
if($total{$num} > 2){ $totaltemp = $total{$num} / 3; $totaltemp = floor($totaltemp); }else{}
$numberofthrees = $numberofthrees + $totaltemp;
while(strlen($line{$num}[0]) > 0){
$refidnum = $line{$num}[0];
$num++;
findrepsloop($refidnum, $num);
$line{$num} = mysql_fetch_array($result{$num}, MYSQL_NUM);
}
}else{
}
}

Displaying tagged images across multiple pages fails

I feel this is a more logic problem than anything. A database has pictures saved via a source reference and booleans for tags e.g. isLandscape=1. I had made a system to traverse pages of results based on types asked. The following is an example of what I'm facing. I only see the same 12 pictures from page 0 -> page 22. Then I start to see new ones. I think I have just been overlooking this bug since I had not noticed it until now. One thing I noticed was page22*12pictures = 264 which is the same as the first new picture id that is seen. You can see the error here (just change the p to different pages).
<?php
$pictureid = -1;
$startpage = 0;
$viewsection = -1;
$uid = -1; //user id
$amntperrow = 4; //how many pictures per row, must correlate with doThumb()'s switch case amounts
$maxrows = 3; //how many rows of pictures to drop
if(isset($_GET['pid']) && is_int(intval($_GET['pid']))) $pictureid = clean($_GET['pid']);
if(isset($_GET['sec']) && is_int(intval($_GET['sec']))) $viewsection = clean($_GET['sec']);
if(isset($_GET['p']) && is_int(intval($_GET['p']))) $startpage = clean($_GET['p']);
$result = generateResult(array("isFlowers"), $startpage);
//**snip** -- drawing thumbnails would happen here
function generateResult($types, $page) {
global $amntperrow;
global $maxrows;
$sqlWheres = "";
$idAmnt = ($amntperrow*$maxrows)*$page;
if(isset($types) && !empty($types)) {
if(count($types) >= 1) {
for($i = 0; $i<count($types); $i++) {
$sqlWheres .= $types[$i] . "='1'";
if($i < count($types)-1) $sqlWheres .= " AND ";
}
}
}
$result = "SELECT * FROM pictures WHERE ";
if(!empty($sqlWheres)) $result .= $sqlWheres . " AND " ;
$result .= " private='0' AND id >='" . $idAmnt . "' LIMIT " . ($amntperrow*$maxrows);
return $result;
}
?>
This seems like a glaring bug that I am overlooking. Thanks for the help.
What is the difference between these two queries?
SELECT *
FROM pictures
WHERE private = '0' AND id >= '24'
LIMIT 12;
and
SELECT *
FROM pictures
WHERE private = '0' AND id >= '36'
LIMIT 12;
Answer: potentially no difference at all. The database engine can decide in either case that it wants to return pictures with ids 100 through 111 - that result set meets all of the conditions of either query.
Try a query like this instead:
"SELECT *
FROM pictures
WHERE private = '0'
ORDER BY id
LIMIT " . $idAmnt . ", " . ($amntperrow * $maxrows)
The ORDER BY id is really the key. Paging through database results is generally done with a combination of ORDER BY and LIMIT.

Why does my if statement ignore my conditions?

I'm programming a random event system that happens to users when logged in and I put the below piece of code into my include file.
$tehchance = mt_rand(1,15);
if ($tehchance == "1"){
$thewin = 10;
mysql_query("UPDATE members SET Points = Points + $thewin WHERE Handle = '$members[Handle]'");
}
I also have this for another event:
if ($tehchance == "2"){
$thekhwin = 5;
$thexpwin = 10;
mysql_query("UPDATE members SET Points = Points - $thekhwin WHERE Handle = '$members[Handle]'");
mysql_query("UPDATE members SET XP = XP + $thexpwin WHERE Handle = '$members[Handle]'");
}
The code will work but sometimes when $tehchance is equal to something else other than 1 or 2, it'll just ignore my conditions and update the members table without satisfying the if statement. From testing, it'll randomly add points or subtract points. I printed the random number from $tehchance and it still adds points even when it isn't equal to 1 or 2. Then sometimes it doesn't do anything to the members table. Really confused here.
Any ideas?
Try using an if-then-else and debug that.
$tehchance = mt_rand(1,15);
if ($tehchance === 1){
echo 'doing 1';
$thewin = 10;
mysql_query("UPDATE members SET Points = Points + $thewin WHERE Handle = '$members[Handle]'");
} else if ($tehchance === 2){
echo 'doing 2';
$thekhwin = 5;
$thexpwin = 10;
mysql_query("UPDATE members SET Points = Points - $thekhwin WHERE Handle = '$members[Handle]'");
mysql_query("UPDATE members SET XP = XP + $thexpwin WHERE Handle = '$members[Handle]'");
} else {
echo 'doing nothing';
}
because you are comparing to a string : "1" instead of the number 1 (without quotes)

How to split search results into pages?

How to split the search results into pages? (like page 1, page 2, page 3...)
When the user searches for products on my e-commerce website, I want results to be split into several pages showing around 20 products per page. The search results are the outcome of database query.
For example: If the user searches for Samsung mobiles so my query will be:
SELECT * FROM PRODUCTS WHERE BRAND='SAMSUNG';
Suppose the above query returns 55 results, how to show them into pages (1,2 and 3)?
I am using PHP, MySQL, Apache on Windows machine.
The appropriate SQL would be adding:
LIMIT start, amount
You can navigate like
search.php?start=20
and then code like:
LIMIT $start, $amount
with
$start = intval($_GET['start']);
and
$amount = 20;
That will result in max 20 records a page.
Use SQL's LIMIT keyword to limit the amount of results from your query; for example:
SELECT * FROM PRODUCTS WHERE BRAND='SAMSUNG' LIMIT 20, 40;
This would select 20 elements, starting at the 40th
Here is the complete code:
<?php
// Requested page
$requested_page = isset($_GET['page']) ? intval($_GET['page']) : 1;
// Get the product count
$r = mysql_query("SELECT COUNT(*) FROM PRODUCTS WHERE BRAND='SAMSUNG'");
$d = mysql_fetch_row($r);
$product_count = $d[0];
$products_per_page = 20;
// 55 products => $page_count = 3
$page_count = ceil($product_count / $products_per_page);
// You can check if $requested_page is > to $page_count OR < 1,
// and redirect to the page one.
$first_product_shown = ($requested_page - 1) * $products_per_page;
// Ok, we write the page links
echo '<p>';
for($i=1; $i<=$page_count; $i++) {
if($i == $requested_page) {
echo $i;
} else {
echo ''.$i.' ';
}
}
echo '</p>';
// Then we retrieve the data for this requested page
$r = mysql_query("SELECT * FROM PRODUCTS WHERE BRAND='SAMSUNG' LIMIT $first_product_shown, $products_per_page");
while($d = mysql_fetch_assoc($r)) {
var_dump($d);
}
?>
Hope its help.
Yes you can run a query to get total record count and than use query using limit
exampe:
select count(id) from table_name
This will return total record count in database
In my php learning books, it provides a solution using a PHP class
it looks like this
<!-- language: php -->
<?php
error_reporting(0); // disable the annoying error report
class page_class
{
// Properties
var $current_page;
var $amount_of_data;
var $page_total;
var $row_per_page;
// Constructor
function page_class($rows_per_page)
{
$this->row_per_page = $rows_per_page;
$this->current_page = $_GET['page'];
if (empty($this->current_page))
$this->current_page = 1;
}
function specify_row_counts($amount)
{
$this->amount_of_data = $amount;
$this->page_total=
ceil($amount / $this->row_per_page);
}
function get_starting_record()
{
$starting_record = ($this->current_page - 1) *
$this->row_per_page;
return $starting_record;
}
function show_pages_link()
{
if ($this->page_total > 1)
{
print("<center><div class=\"notice\"><span class=\"note\">Halaman: ");
for ($hal = 1; $hal <= $this->page_total; $hal++)
{
if ($hal == $this->current_page)
echo "$hal | ";
else
{
$script_name = $_SERVER['PHP_SELF'];
echo "$hal |\n";
}
}
}
}
}
?>
then we call it on the script that require paging
<!-- language: php -->
<?php $per_page = 5;
$page = new Page_class($per_page);
error_reporting(0); // disable the annoying error report
$sql="SELECT * FROM table WHERE condition GROUP BY group";
$result=mysql_query($sql) or die('error'.mysql_error());
// paging start
$row_counts = mysql_num_rows($result);
$page->specify_row_counts($row_counts);
$starting_record = $page->get_starting_record();
$sql="SELECT * FROM table WHERE condition GROUP BY group LIMIT $starting_record, $per_page";
$result=mysql_query($sql) or die('error'.mysql_error());
$number = $starting_record; //numbering
$num_rows = mysql_num_rows($result);
if ($num_rows == 0 )
{ // if no result is found
echo "<div class=\"notice\">
<center><span class=note>NO DATA</span></center>
</div>";
}
else {
// while goes here ...
}
?>
// call the page link
<?php
$page->show_pages_link();
?>
hope it helps, just tried it hours ago to my search script page (learning from books)

Pagenav. By clicking next get next lets say "20" records (php/mysql)

I've already created a query to mysql that will give 20 results from mysql table etc. "cat"
heres the calling:
if(isset($_GET['cat']))
{
$query = "SELECT game_title,game_desc,....
FROM games WHERE cat_id='".validate_input($_GET['cat'])."' LIMIT 20";
}
...
by this I manage to get the results I wanted. What I am asking here is how can I create a "button" that will load the next "20" records from table "cat" (something like Buttons).
<?
$cn=mysql_connect("localhost","root","root") or die(mysql_error());
mysql_select_db("db56") or die(mysql_error());
$sql="select count(*) from emp";
$result=mysql_query($sql);
$r=mysql_fetch_row($result);
$record=$r[0];
$pagesize=20;
$totalpages=$record/$pagesize;
$currpage=$_GET["pg"];
if(!isset($currpage))
$start=0;
else {
$currpage--;
$start= $currpage * $pagesize;
}
$end=$start+$pagesize;
$sql="select * from emp limit $start,$pagesize";
$result=mysql_query($sql);
if($result){
print "<table border='1'>";
print "<tr><th>No</th><th>Name</th><th>Date</th></tr>";
while($r=mysql_fetch_row($result))
{
print "<tr><td>$r[0]</td><td>$r[1]</td><td>$r[2]</td></tr>";
}
print "</table>";
}
for($i=1;$i<=$totalpages;$i++){
print "<a href='listemp.php?pg=$i'> $i </a>";
}
?>
If you keep track of what page you're on, in the URL or a hidden field or session variable, you can use that to work out the limit. For example, page 2 should show limit 20 from row 20 (20 times the page offset).
You can pass two SQL parameters to LIMIT (put a comma between them) If you do, the first tells SQL how many records to skip (ie the offset of the first record) and the 2nd parameter is the one you're already using (how many records to return).
So just put a variable in your "next" link that says what page to display. You can pass the offset in this link, but it's pretty common to pass the "page number" instead, and multiply by the number of records per page before sticking it in the sql.
next page
With a bit more work, you can make a "previous page" link, and make the correct links non-clickable when you're at the first/last page.
Pass along a parameter that tells the script that you want another chunk of the results and not just the first batch.
So for the link it could be like this:
example.com/results.php?cat=1&page=2
Where page= will tell the script what page you want to return.
Then you want to turn that LIMIT number you have so that you can work out some simple maths
$results_cnt = 20; //--rows you want per page of results
Now in your script you'll check to see if the page variable has been set. If not, default the start row to return from the first. But as you want to return different pages/sets of results, a little math is needed in order to start at the proper row.
if(isset($_GET["page"]) //--see if the variable is even there
{
$page_num = (int)$_GET["page"]; //--forcing it to always be an integer
$start_row = $results_cnt * ($page_num - 1);
/* --
what happens:
($results_cnt currently at 20)
on page one (page=1), start at row 0
math: 20 * (1 - 1) = 0
on page two (page=2), start at row 20
math: 20 * (2 - 1) = 20
on page three (page=3), start at row 40
math: 20 * (3 - 1) = 40
etc.
*/
}
else
$start_row = 0;
Now, having set the correct starting row, adjust the SQL query to use the variables like so:
if(isset($_GET['cat']))
{
$query = "SELECT game_title,game_desc,....
FROM games
WHERE cat_id='".validate_input($_GET['cat'])."'
LIMIT $start_row, $results_cnt";
}
OK I got it fixed I guess...
in index.php:
<?php
$games = array();
$count = 1;
$total = 0;
if(isset($_GET['cat']))
{
$query = "SELECT game_title,game_desc,.... FROM games WHERE cat_id='".validate_input($_GET['cat'])."' LIMIT 20";
$total = mysql_num_rows(mysql_query("SELECT 1 FROM games WHERE cat_id='".validate_input($_GET['cat'])."'"));
}
$query_result = #mysql_query ($query) OR error(mysql_error(), __LINE__, __FILE__, 0, '', '');
while ($info = #mysql_fetch_array($query_result))
{
/* -- here goes the infos.. */
$games[$info['game_title']]['game_title'] = $info['game_title'];
etc..
if(isset($_GET['cat']))
{
/* -- for template engine */
$page->SetLoop ('PAGES', pagenav($total,$_GET['page'],20,$config['site_url'].'?cat='.$_GET['cat'],1,$lang));
}
--end php
and in funct.php
--start php
function pagenav($total,$page,$perpage,$url,$posts=0)
{
$page_arr = array();
$arr_count = 0;
if($posts)
{
$symb='&';
}
else
{
$symb='?';
}
$total_pages = ceil($total/$perpage);
$llimit = 1;
$rlimit = $total_pages;
$window = 5;
$html = '';
if ($page<1 || !$page)
{
$page=1;
}
if(($page - floor($window/5)) <= 0)
{
$llimit = 1;
if($window > $total_pages)
{
$rlimit = $total_pages;
}
else
{
$rlimit = $window;
}
}
else
{
if(($page + floor($window/2)) > $total_pages)
{
if ($total_pages - $window < 0)
{
$llimit = 1;
}
else
{
$llimit = $total_pages - $window + 1;
}
$rlimit = $total_pages;
}
else
{
$llimit = $page - floor($window/2);
$rlimit = $page + floor($window/2);
}
}
if ($page>1)
{
$page_arr[$arr_count]['title'] = 'Prev';
$page_arr[$arr_count]['link'] = $url.$symb.'page='.($page-1);
$page_arr[$arr_count]['current'] = 0;
$arr_count++;
}
for ($x=$llimit;$x <= $rlimit;$x++)
{
if ($x <> $page)
{
$page_arr[$arr_count]['title'] = $x;
$page_arr[$arr_count]['link'] = $url.$symb.'page='.($x);
$page_arr[$arr_count]['current'] = 0;
}
else
{
$page_arr[$arr_count]['title'] = $x;
$page_arr[$arr_count]['link'] = $url.$symb.'page='.($x);
$page_arr[$arr_count]['current'] = 1;
}
$arr_count++;
}
if($page < $total_pages)
{
$page_arr[$arr_count]['title'] = 'Next';
$page_arr[$arr_count]['link'] = $url.$symb.'page='.($page+1);
$page_arr[$arr_count]['current'] = 0;
$arr_count++;
}
return $page_arr;
}
?>
and call it by
{LOOP: PAGES}{PAGES.title} {/LOOP: PAGES}
in an .html file..
it works perfectly but when I press the number 2 or next to get the next 20 records it jumps back to the first 20...
on the browser it reads http://siteurl/?cat=1&page=2
I can't figure out why.

Categories