I am building a exam report module which consists of three sections i.e. section 1 for 1 marks and 10 questions, section 2 for 2 marks and 5 questions and section 3 for 4 marks and 5 questions. Total number of questions are 20 and the total marks are 40. Now when a user finishes exam I am trying to display his result in a report showing section wise report. The issue emerging here is if a user attempts one section only and suppose he has secured 3 correct answers so the report must show 3 in section1 and 0 in other two sections but the report each time is fetching 3 for all the section or we can say all the sections has value of one section. What i need to show is number of "correct answers" 3-0-0 as the user has attempted only one section. Although currently it takes 3 for all the sections.
Here is my code for the frontend,
<tr><td>3</td>
<td>Correct Answers</td>
<td><?php echo $rep->sectionwiseMockReport($id, $chapterId,1); ?></td>
<td><?php echo $rep->sectionwiseMockReport($id, $chapterId,2); ?></td>
<td><?php echo $rep->sectionwiseMockReport($id, $chapterId,3); ?></td>
<td><?php echo ($rep->sectionwiseMockReport($id, $chapterId,1)+$rep->sectionwiseMockReport($id, $chapterId,2)+$rep->sectionwiseMockReport($id, $chapterId,3)) ; ?></td>
</tr>
And the function that is being called is into a class,
function sectionwiseMockReport($userId, $chapterId,$section)
{
$counter1 = 0 ;
$counter2 = 0 ;
$counter3 = 0 ;
$total = 0 ;
$result = mysql_query("SELECT question_id, option_id from tbl_result_chapter WHERE user_id = $userId AND chapter_id = $chapterId");
while($row = mysql_fetch_array($result))
{
if($this->getRightOptionChapter($row['question_id']) == $row['option_id'])
{
$section = $this->idToField("tbl_question_chapter","section",$row['question_id']);
if($section == 1)
{
$counter1 = $counter1 + 1 ;
}
if($section == 2)
{
$counter2 = $counter2 + 1 ;
}
if($section == 3)
{
$counter3 = $counter3 + 1 ;
}
}
}
if($section == 1)
{
return $counter1;
}
if($section == 2)
{
return $counter2;
}
if($section == 3)
{
return $counter3;
}
}
And lastly the function,
function getRightOptionChapter($questionId)
{
$result = mysql_query("SELECT * from tbl_chapter_answer a INNER JOIN tbl_chapter_options o on a.options_id = o.id WHERE a.question_id = $questionId");
$row = mysql_fetch_array($result);
return $row['options_id'];
}
Any suggestion or help will be a lifesaver. Had been looking for this for couple of days but no success at all.
Finally got the issue. The variable $section was creating the conflict inside while loop and outside of while loop. Changed the variable name inside the while loop and working swiftly.
Related
Im learning PHP by working on a personal project. Ive spend the last 2-hours trying to figure out why my IF statment is getting skipped inside my loop, Im a more experienced coder could provide me with a bit of help here, as I am currently at a stalemate.
What Im Trying To do
User makes picks for a round in sports tournament, when round is completed calculate the user standings based on number of correct picks.
Everything works as expected except Im having an (extremely) hard time calculating the number of correct picks.
IMAGE1: THE CODE SHOULD PUT OUT THE FOLLOWING
IMAGE2: THE CODE CURRENTLY PUTS OUT THE FOLLOWING (WRONG)
MY Code
$sql ="SELECT picks.*, results.*, users.*
FROM picks
inner join results on picks.gameID = results.gameID
inner join users on picks.userID = users.userID
WHERE picks.tournament = 'SixNations' AND picks.weekNum = '3'
order by users.lastname, users.firstname";
$stmnt = $db->prepare($sql);
//JUST DISABLING FOR DEBUGING PURPOSES
/*
$stmnt->bindValue(':tournament', $tournament);
$stmnt->bindValue(':weekNum', $round);*/
$stmnt->execute()
$picks = $stmnt->fetchAll();
$totalCorrectPicks = 0;
echo'<table class="table table-responsive table-striped">';
echo'<thead>';
echo'
<tr>
<th>FirstName</th>
<th>Picked Team</th>
<th>Winning Team</th>
<th>Margin</th>
<th>TOTAL CORRECT PICKS</th>
</tr>
</thead>
<tbody>';
$i = 1; //USED TO COUNT NR GAMES
foreach($picks as $pick){
$user = $pick['firstname'];
$picked = $pick['selectedTeam'];
$result = $pick['won'];
$nrGames = $i;
echo '<tr>';
echo'<td>';
echo $user;
echo'</td>';
echo'<td>';
echo $pick['selectedTeam'];
echo'</td>';
echo'<td>';
echo $pick['won'];
echo'</td>';
if($picked == $result){
//USER PICKED CORRECT TEAM
$totalCorrectPicks = $totalCorrectPicks +1;
echo'<td>';
$margin = abs($pick['pts'] - $pick['points']);
echo $margin;
echo'</td>';
}//if
else if($picked != $result){
//user PICKED INCORRECT TEAM
echo'<td>';
$totalCorrectPicks += 0;
$margin = '<span style="color:red">WRONG PICK</span>';
echo $margin;
echo'</td>';
}//else if
##THIS IF STATMENT IS GETTING IGNORED##
if($user != $pick['firstname']){
echo'<td>';
echo $output = 'Total Correct Picks'. $totalCorrectPicks.' / '.$i;
echo'</td>';
echo'</tr>';
}//if
$i++; //keep track of number games
}//foreach
echo'</tbody>';
echo'</table>';
As can be seen on image 2, and the code above the IF statement which should print the total correct games picked by each user is getting skipped / ignored. Any advise / help on why and / how I can fix this very welcome.
Hope this might help:
CODE 1
// Assign Variable
$user = $pick['firstname'];
$nrGame = 1;
// Check user are the same from previous row or not
if($tempUser <> $user){
$points = 0;
$nrGame = 1;
}
// Pick correct team
if ($picked == $result){
$points += 1;
}
// Last Column
echo "<td>".$points." / " .$nrGame."</td>";
// Assign temporary user
$tempUser = $user;
$nrGame++;
CODE 2 (Display Points on the last row only)
// Assign variable
$maxGame = 3;
// Last Column
if ($nrGame == $maxGame)
echo "<td>".$points." / " .$nrGame."</td>";
else
echo "<td></td>";
You have:
foreach($picks as $pick){
$user = $pick['firstname'];
Then later on - in the same foreach you check for this (which you say is the problem):
if($user != $pick['firstname']){
But at no point do you update $user between the first assignment of $user = $pick['firstname']; and the if($user != $pick['firstname']) statement.
This means that the if($user != $pick['firstname']) will always be skipped because you assigned $user = $pick['firstname'] at the start of the loop.
Edit:
In answer to your question - if I understand it correctly. You can simply do something like:
Get the first user name.
// Before the foreach call, need the 'first' user name.
$previousUser = $picks[0]['firstname'];
foreach($picks as $pick){
Check for mis-match:
// For the statement check, where the "problem" is
if($previousUser != $pick['firstname'])
And place this at the end of the loop.
// At the end of the loop
$previousUser = $user;
$i++; //keep track of number games
I'm trying to improve a php script that prints a list with db values and I need to make some complex (for me) operations to achieve what I want:
A list that prints the months and if they are paid or not, a bonus value with an extra bonus value for the first 3 ids and if the user already received it.
if ($stmt = $mysqli->prepare(" SELECT members.*, account_type.*, friends.*, friendsCount.friendID,
COUNT(friendsCount.friendID) AS num_f
FROM members
INNER JOIN account_type ON account_type.id = ?
INNER JOIN friends ON friends.friendID = ?
INNER JOIN friends AS friendsCount ON friendsCount.userID = ?
WHERE members.id = ?")) {
$stmt->bind_param('iiii', $_SESSION['acc_type'], $_GET['id'], $_SESSION['user_id'], $_GET['id']);
$stmt->execute();
$result = $stmt->get_result();
$row = $result->fetch_array();
$monthNames = array("Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre");
$paid = array(); //Placeholder for paid months.
for ($i = 1; $i < 13; $i++) {
$month = 'month' . $i;
$bonus_month = 'bonus_month' . $i;
// check if the user received the monthly bonus
if ($row[$bonus_month] == 0) {
// check if the friend's member account is active
if ($row['status'] == 1) {
// check if the friend paid the month
if ($row[$month] == 1) {
$paid[] = 'Pagado';
// check the user account type
if ($row['type'] == 'Base') {
// TODO: check if the friend is one of the three first (special promotion)
// (user gets double bonus for the first three invited friends)
if ($row['extra'] == 1) {
$extra = $row['bonus'] + 5;
$bonus[] = $extra . '€';
}
else {
$bonus[] = $row['bonus'] . '€';
}
}
else {
$bonus[] = $row['bonus'] . '€';
}
$cashed[] = 'No';
$non_cashed[] = $bonus[];
}
else {
$paid[] = 'No Pagado';
$bonus[] = 'n/a';
$cashed[] = 'n/a';
}
}
else {
$paid[] = 'n/a';
$bonus[] = 'n/a';
$cashed[] = 'n/a';
}
}
else {
$paid[] = 'Pagado';
$bonus[] = $row[$bonus_month] . '€';
// TODO: find a way to check if user already received the bonus
// 12 new columns? (bonus_received_month1-12)
if (1 == 0) {
$cashed[] = 'Si';
$total_cashed[] = $row[$bonus_month];
}
else {
$cashed[] = 'No';
$non_cashed[] = $row[$bonus_month];
}
}
}
//Now make the HTML list
foreach ($monthNames as $key => $month) {
echo '
<div class="list">
<ul>
<li><a class="month">' . $month . '</a></li>
<li><a class="status">' . $paid[$key] .'</a></li>
<li><a class="bonus">' . $bonus[$key] . '</a></li>
<li><a class="cashed">' . $cashed[$key] . '</a></li>
</ul>
</div>';
}
} else echo $mysqli->error;
Actually it's working quite well but somethings are not implemented yet:
1º The extra bonus value for the first 3 ids (not including the status 0 accounts).
2º A way to check if the user already received the bonus so can be displayed the balance and the total received:
First of, I'd like to improve the method that adds the extra bonus:
// this column contains 1 for the first 3 friendIDs
if ($row['extra'] == 1) {
$extra = $row['bonus'] + 5;
$bonus[] = $extra . '€';
} else $bonus[] = $row['bonus'] . '€';
To achieve this: I have to check for the first 3 friendIDs (where userID = $_SESSION[user_id]) and compare if one of those match the current $_GET['id'].
// the number of friends
$count = $row['num_f'];
// the current friendID
$f_id = $_GET['id'];
$match = 'the first 3 ids (with acc status 1)';
if ($count > 2 && $f_id == $match) {
$extra = $row['bonus'] + 5;
$bonus[] = $extra . '€';
} else $bonus[] = $row['bonus'] . '€';
And statistics info:
// not received
echo '<p>Total acumulado: ' . array_sum($non_cashed[]) . '€</p>';
// total received
echo '<p>Total recibido: ' . array_sum($total_cashed[]) . '€</p>';
The big problem that I'm facing here is: If one of the three first accounts is inactive (status 0) how to "take" the next one that is active...
If account 1 is inactive but 2 and 3 are not, the account number 4 should be eligible for the extra bonus. The numbers are just the order that come from "select friendID from friends where userID = ?"
I presume that I can use array_key_exists to check if the $f_id exist inside the array that contains the first 3 ids...
How can I make that? Sorry if I made some mistakes, I'm working for several hours.
The tables are:
1º members: get the friend info -> "id", "status" (0 or 1; inactive/active), "name" and "month1-12" (12 columns: 0 or 1; not paid / paid month)
2º account_type: get the user acc type and the bonus value -> "id" (members.acc_type), "type" (the type name) and "bonus" (5, 10, 15 etc...)
3º friends: get the user info related to his friend -> "friendID" (members.id, the invited user), "userID" (members.id, the user that invited a friend), "extra" (1 for the first 3 invited users and 0 for the rest; 1 is double bonus, 0 is normal bonus. This column is going to be deleted), "bonus_month1-12" (12 columns; 0 is for the current month or a future month, 1+ is the bonus the user gained this month)
And to check if the user already received the bonus, I'm thinking to add 12 more columns to know it. It'll be 0 for non-received and 1 for received, unless a better method is suggested :)
I echo results in DESC order from MySQL table with while loop. I've pagination system implemented already and its size is 9 records per page. The problem is, that if I do:
// ECHO CSS BREAK
if($row['id'] % 3 == 0){
echo '<li class="clear"></li>';
}
// SHOW VIDEOS
while($row = mysql_fetch_array($result)){
echo '<li>...echo code...</li>';
// problem = implement that echo css break in ASC order
}
Use a loop variable, e.g.
$i = 0;
Then instead of
if ($row['id'] % 3 == 0) {
do
if (++$i % 3 === 0) {
This makes sure it always happens are the third [sixth, ninth, ...] time.
You may want to get arbitrary rows from the database at another point in time, or shuffle the results -- relying on row IDs is not a good idea.
Is this what you are looking to implement?
// SHOW VIDEOS
while($row = mysql_fetch_array($result)){
if($row['id'] % 3 == 0){
echo '<li>...echo code...</li>';
echo '<li class="clear"></li>';
} else {
echo '<li>...echo code...</li>';
}
}
I'm trying to get a value to be inserted into a table on a webpage if the value equals $i.
$i starts at a number and decreases every loop. i can get it to work but it outputs multiple lines for each $i equivalent to the results in the table
I've reworked the code using everyones feedback to get this.
Echo "<tr><th colspan='3'><center>$rackname</th> </tr>" ;
for ($i=$RUtotal; $i > 0; $i--)
{
echo" <tr class='rackbg'><td class='i'><center>$i</td>" ;
$sql1 = "SELECT racks.rackID, racks.rackname, devices.deviceID, devices.deviceName, racks.rackRU, devices.deviceRU, devices.RUcount
FROM racks LEFT JOIN devices ON racks.rackID = devices.rackID
WHERE devices.rackID = '$rackID'";
$query1 = mysql_query($sql1);
while ($row = mysql_fetch_assoc($query1))
{
$deviceru = $row['deviceRU'];
$deviceID = $row['deviceID'];
$device = $row['deviceName'];
$deviceRUC = $row['RUcount'];
if ($deviceru == $i)
{
echo '<td class="device" rowspan='.$deviceRUC.'><a onclick=window.location="/devices.php?id='.$deviceID.'">'.$device.'</a></td><td rowspan='.$deviceRUC.'></td></tr>';
}
else
{
;
}
}
}
Echo "<tr class='rackb'><th colspan='3'>a</th></tr> " ;
This works to a degree (picture1) but when i add echo "" to the else statement it displays all wrong. (picture 2)
Any help would be greatly appreciated
Picture1 - http://imageshack.us/photo/my-images/263/examplewq.png/
Picture2 - http://imageshack.us/photo/my-images/269/example2jp.png/
I can't quite see what you're trying to do but what it looks like to me is that you want all the items from racks joined with their relevant device and displayed in order of deviceRU. Does this help:
echo "<tr><th colspan='3'><center><b>$rackname</th></tr>" ;
$sql1 = "SELECT racks.rackID, racks.rackname, devices.deviceID, devices.deviceName, racks.rackRU, devices.deviceRU, devices.RUcount
FROM racks LEFT JOIN devices ON racks.rackID = devices.rackID
WHERE racks.rackID = '$rackID' AND devices.deviceRU <= ".intval($RUtotal)."
ORDER BY devices.deviceRU;"
$query1 = mysql_query($sql1);
while ($row = mysql_fetch_array($query1))
{
$deviceru = $row['deviceRU'];
$deviceID = $row['deviceID'];
$device = $row['deviceName'];
$deviceRUC = $row['RUcount'];
echo'<tr class="rackbg"><td class="i">'.$i.'</td><td class="device">'.$device.'</td><td></td></tr>';
}
I've used a LEFT (inner) JOIN in the SQL instead of the outer join that was there before as it'll return less results and might solve your problem. I've ordered the results by deviceRU and only returned results which have deviceRU less than or equal to $RUtotal (as I think the example was showing).
I've also removed the tags, these should be replaced by using CSS to centre either all td elements or centering class="device" and class="i" e.g.:
.device, .i {
text-align: center;
}
I've also swapped your abc to abc which is the correct format for a link.
Could you describe more of the context as it's difficult to see your intention from your post.
Mat
As Peetz said, you don't need nested loop. You need something like:
$i = $RUtotal;
// ...
while ($row = mysql_fetch_array($query1)) {
// ...
if ($deviceru == $i) {
// ...
} else {
// ...
}
// ...
$i--;
}
This is looping $i times, within the outer while loop. This means you are getting the table repeated over and over again.
I suggest you remove the outer while loop.
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.