Make Your Own PHP Quiz (final part)
You can download the entire source code for this series here PHP Quiz (11.21 KB)
The first part of this post will concentrate on adding new users/scores to the leaderboard (leaders.xml). We only want to add this information to the xml file when the user has completed the quiz(obviously) so, on ‘test.php’, we check for the presence of the $last variable. We are already checking for $last to see whether or not to display the user’s score and add a witty remark. Just before we output that information, we’ll add the following code to insert username/score into ‘leader.xml’.
if (!$last) { // output question/answers as before } else { $file = "leaders.xml"; $xml = simplexml_load_file($file); $user = $xml->addChild('user'); $uname = $user->addChild('name',$_SESSION['user']); $uscore = $user->addChild('score',$_SESSION['score']); $xml->asXML("leaders.xml"); // print out user's score etc }
Once again, SimpleXML makes working with xml files ..er… simple! The code above loads the xml file, adds a new <user> along with <name> and <score> elements. The values for <name> and <score> are pulled from the respective $_SESSION variables. The file is then resaved using asXML().
OK, the next thing to do is stop duplicate usernames from being registered. Let’s return to the if/else statements at the top of ‘test.php’. Amend the ‘if (isset($_POST’register’]))’ conditional to look like the following:
if(isset($_POST['register'])) { $username = trim(strip_tags(stripslashes($_POST['username']))); $file = "leaders.xml"; $xml = simplexml_load_file($file); foreach($xml->user as $user) { if ($user->name == $username) { $_SESSION['error'] = 'That name is already registered, please choose another.'; header('Location: index.php'); exit(); } } if (isset($_SESSION['error'])) unset($_SESSION['error']); }
This loops through all of the existing <name> elements and checks them against the submitted username. If there is a match, it creates a $_SESSION['error'] variable, redirects the user back to ‘index.php’ and exits the script. The last part destroys $_SESSION['error'] when a unique username is registered.
On ‘index.php’ we can check for $_SESSION['error'] and print it out. Place the following at the end of the #quiz div on ‘index.php’
<p id="helper"><?php if($_SESSION['error']) echo $_SESSION['error']; ?></p> </div><!--quiz-->
Ok, next, we’re going to create a function to display the correct/incorrect answers on ‘results.php’ I’ve originally called it showAnswers()! It starts by taking 2 parameters, $answers and $questions.
function showAnswers($answers,$questions) {
We create a counter ($x) and loop through the answers array creating a <div> for each one. We also use the modulus operator again to give every other <div> a class of ‘clear’. This helps us to style the divs later.
function showAnswers($answers,$questions) { for($x = 0; $x< count($answers); $x++) { if ($x % 2 == 0) { $output = "<div class=\"qanda clear\">\n"; } else { $output = "<div class=\"qanda\">"; }
We continue adding to the $output variable by adding a level 4 heading and starting an ordered list
function showAnswers($answers,$questions) { for($x = 0; $x< count($answers); $x++) { if ($x % 2 == 0) { $output = "<div class=\"qanda clear\">\n"; } else { $output = "<div class=\"qanda\">"; } $output .= '<h4>Anacronym' . ($x+1) . ': ' . $questions[$x] . '</h4>'; $output .= "<ol>\n";
Things start to get a bit trickier here. Because $answers is a multi-dimensional array, we need another ‘nested’ loop to access each of the individual answers. So still inside the first ‘for’ loop, we create another one:
function showAnswers($answers,$questions) { for($x = 0; $x< count($answers); $x++) { if ($x % 2 == 0) { $output = "<div class=\"qanda clear\">\n"; } else { $output = "<div class=\"qanda\">"; } $output .= '<h4>Anacronym' . ($x+1) . ': ' . $questions[$x] . '</h4>'; $output .= "<ol>\n"; for ($y = 0;$y< count($answers[$x]); $y++) {
Remember, we are going to highlight the correct/incorrect answers. We could do this easily by just highlighting the first answer in each array (the correct answer is always the [0] index) but we also need to see if the user answered correctly. If so, we’ll add ‘Correct!’ , if not, we’ll add ‘Wrong!’.
Therefore there are 4 possible combinations to consider. First, we check if the answer we are iterating over is the correct one (index[0]) and is also present in the $_SESSION['correct'] array (meaning the user answered correctly). If so, we create a list-item with a class of ‘correctuser’ and place the text ‘(Correct!)’ after the answer.
function showAnswers($answers,$questions) { for($x = 0; $x< count($answers); $x++) { if ($x % 2 == 0) { $output = "<div class=\"qanda clear\">\n"; } else { $output = "<div class=\"qanda\">"; } $output .= '<h4>Anacronym' . ($x+1) . ': ' . $questions[$x] . '</h4>'; $output .= "<ol>\n"; for ($y = 0;$y< count($answers[$x]); $y++) { if (($answers[$x][$y] === $answers[$x][0]) && (in_array($answers[$x][$y],$_SESSION['correct']))) { $output .= "<li class=\"correctuser\">{$answers[$x][$y]} (Correct!)</li>\n";
If that was unsuccessful, we perform another check. This one simply checks if the answer we are iterating over is the correct one (index[0]) and gives the list-item a class of ‘correct’.
function showAnswers($answers,$questions) { for($x = 0; $x< count($answers); $x++) { if ($x % 2 == 0) { $output = "<div class=\"qanda clear\">\n"; } else { $output = "<div class=\"qanda\">"; } $output .= '<h4>Anacronym' . ($x+1) . ': ' . $questions[$x] . '</h4>'; $output .= "<ol>\n"; for ($y = 0;$y< count($answers[$x]); $y++) { if (($answers[$x][$y] === $answers[$x][0]) && (in_array($answers[$x][$y],$_SESSION['correct']))) { $output .= "<li class=\"correctuser\">{$answers[$x][$y]} (Correct!)</li>\n"; } else if ($answers[$x][$y] === $answers[$x][0]) { $output .= "<li class=\"correct\">{$answers[$x][$y]}</li>\n";
If that was also unsuccessful, we check if the current answer is in the $_SESSION['wrong'] array (the user answered incorrectly). If it is, we give the list-item a class of ‘wrong’ and place the text ‘(Wrong!)’ after the answer.
function showAnswers($answers,$questions) { for($x = 0; $x< count($answers); $x++) { if ($x % 2 == 0) { $output = "<div class=\"qanda clear\">\n"; } else { $output = "<div class=\"qanda\">"; } $output .= '<h4>Anacronym' . ($x+1) . ': ' . $questions[$x] . '</h4>'; $output .= "<ol>\n"; for ($y = 0;$y< count($answers[$x]); $y++) { if (($answers[$x][$y] === $answers[$x][0]) && (in_array($answers[$x][$y],$_SESSION['correct']))) { $output .= "<li class=\"correctuser\">{$answers[$x][$y]} (Correct!)</li>\n"; } else if ($answers[$x][$y] === $answers[$x][0]) { $output .= "<li class=\"correct\">{$answers[$x][$y]}</li>\n"; } else if (in_array($answers[$x][$y],$_SESSION['wrong'])) { $output .= "<li class=\"wrong\">{$answers[$x][$y]} (Woops!)</li>\n";
Finally, if none of the above conditions are met, we just print out a standard list-item:
function showAnswers($answers,$questions) { for($x = 0; $x< count($answers); $x++) { if ($x % 2 == 0) { $output = "<div class=\"qanda clear\">\n"; } else { $output = "<div class=\"qanda\">"; } $output .= '<h4>Anacronym' . ($x+1) . ': ' . $questions[$x] . '</h4>'; $output .= "<ol>\n"; for ($y = 0;$y< count($answers[$x]); $y++) { if (($answers[$x][$y] === $answers[$x][0]) && (in_array($answers[$x][$y],$_SESSION['correct']))) { $output .= "<li class=\"correctuser\">{$answers[$x][$y]} (Correct!)</li>\n"; } else if ($answers[$x][$y] === $answers[$x][0]) { $output .= "<li class=\"correct\">{$answers[$x][$y]}</li>\n"; } else if (in_array($answers[$x][$y],$_SESSION['wrong'])) { $output .= "<li class=\"wrong\">{$answers[$x][$y]} (Woops!)</li>\n"; } else { $output .= "<li>{$answers[$x][$y]}</li>\n"; }
We then close the nested ‘for’ loop, add the closing </ol> and <div> tags to $output, echo the $output and close both the first ‘for’ loop and the function. Go ahead and save this inside ‘functions.php’.
function showAnswers($answers,$questions) { for($x = 0; $x< count($answers); $x++) { if ($x % 2 == 0) { $output = "<div class=\"qanda clear\">\n"; } else { $output = "<div class=\"qanda\">"; } $output .= '<h4>Anacronym' . ($x+1) . ': ' . $questions[$x] . '</h4>'; $output .= "<ol>\n"; for ($y = 0;$y< count($answers[$x]); $y++) { if (($answers[$x][$y] === $answers[$x][0]) && (in_array($answers[$x][$y],$_SESSION['correct']))) { $output .= "<li class=\"correctuser\">{$answers[$x][$y]} (Correct!)</li>\n"; } else if ($answers[$x][$y] === $answers[$x][0]) { $output .= "<li class=\"correct\">{$answers[$x][$y]}</li>\n"; } else if (in_array($answers[$x][$y],$_SESSION['wrong'])) { $output .= "<li class=\"wrong\">{$answers[$x][$y]} (Woops!)</li>\n"; } else { $output .= "<li>{$answers[$x][$y]}</li>\n"; } } $output .= "</ol></div>\n"; echo $output; } }
To call this function, place the following inside the #quiz div in ‘results.php’
<div id="quiz"> <?php showAnswers($answers,$questions); ?> </div><!--quiz-->
The final thing we need to do is stop users from viewing the results page until they’ve completed the quiz. If you remember, on ‘test.php’, we check if this is the last question and set $last to true. We also create a session variable:
if ($num < count($questions)-1) { $num++; } else { $last = true; $_SESSION['finished'] = 'yes'; }
We can check for the presence of $_SESSION['finished'] on ‘results.php’. If it exists, show the results page, if not, redirect the user to ‘index.php’.
session_name("Acronym_Test"); session_start(); if($_SESSION['finished'] != 'yes') { header('Location: index.php'); } include_once('qandas.php'); include_once('functions.php');
And that, as they say, is that. Hopefully I haven’t forgotten anything! I’d love to hear any comments about this mini-series. Was it easy/hard to follow? Did it go into enough detail? Was it indeed helpful at all? All comments are welcomed ![]()
I’ll put up a zip file of the entire code for you to download asap.


nice man
Wow amazing . This really is a great piece of code and very helpful. I was just wondering though do you or anyone know any way that the end result can be shown as a percentage rather than an /20 score? If it did that it would be perfect as thats what I am looking for.