PHP Trivia Game - Day 2-3

Here is an updated version of the trivia game code, which has multiple screens (Welcome, Question) and fully-working sessions.

You can also play the game itself on this website!

/web/www/trivia/index.php

Unchanged from the starter code!

/web/src/trivia/TriviaController.php

Our updated controller.

<?php

class TriviaController {

  private $questions = [];

  private $db;

  private $errorMessage = "";

  /**
   * Constructor
   */
  public function __construct($input) {
    // Start the session!
    session_start();

    $this->input = $input;
    $this->loadQuestions();

  }

  /**
   * Run the server
   * 
   * Given the input (usually $_GET), then it will determine
   * which command to execute based on the given "command"
   * parameter.  Default is the welcome page.
   */
  public function run() {
    // Get the command
    $command = "welcome";
    if (isset($this->input["command"]) && (
      $this->input["command"] == "login" || isset($_SESSION["name"])))
      $command = $this->input["command"];

    switch($command) {
      case "login": 
        $this->login();
        break;
      case "answer":
        $this->answerQuestion();
        break;
      case "question":
        $this->showQuestion();
        break;
      case "logout": 
        $this->logout(); // notice no break 
      case "welcome":
      default:
        $this->showWelcome();
        break;
    }
  }

  public function login() {
    if (isset($_POST["fullname"]) && isset($_POST["email"]) &&
      !empty($_POST["fullname"]) && !empty($_POST["email"])) {
      // TODO: check that email looks right!
      $_SESSION["name"] = $_POST["fullname"];
      $_SESSION["email"] = $_POST["email"];
      $_SESSION["score"] = 0;

      // call showQuestion OR ...
      // redirect with a header to the question screen
      header("Location: ?command=question");
      return;
    }

    $this->showWelcome("Name or email missing");
  }

  /**
   * Logout function.  We **need** to clear the session somehow.
   * When the user wants to start over, we should allow them to
   * reset the game.  I'll call it logout, so this function destroys
   * the session and immediately starts a new one.
   */
  public function logout() {
    // Destroy the session
    session_destroy();

    // Start a new session.  Why?  We want to show the next question.
    session_start();
    $_SESSION["score"] = 0;
  }

  /**
   * Load questions from a file, store them as an array
   * in the current object.
   */
  public function loadQuestions() {
    $this->questions = json_decode(file_get_contents("/opt/src/trivia/data/trivia-s25.json"), true);
  }

  /**
   * Our getQuestion function, now as a method!
   */
  function getQuestion($id = null) {
    // Todo: Think about how to change this function to get
    // the qid from the session rather than needing the id
    // passed in. Would this be better?

    if ($id == null) {
      $randid = array_rand($this->questions);

      // Add the question ID to the session
      $_SESSION["qid"] = $randid;

      return array_merge(["id"=>$randid], $this->questions[$randid]);
    }
    return array_merge(["id"=>$id], $this->questions[$id]);

  }

  /**
   * Show a question to the user.  This function loads a
   * template PHP file and displays it to the user based on
   * properties of this object.
   */
  public function showQuestion($message = "") {
    $question = $this->getQuestion();
    $score = $_SESSION["score"]; // score variable, make the template easier to read
    $name = $_SESSION["name"]; // name variable, make the template easier to read
    include("/opt/src/trivia/templates/question.php");
  }
  
  public function showWelcome($message = "") {
    include("/opt/src/trivia/templates/welcome.php");
  }

  /**
   * Check the user's answer to a question.
   */
  public function answerQuestion() {
    $message = "";
    if (isset($_POST["answer"]) && isset($_POST["qid"]) && is_numeric($_POST["qid"])) {

      $question = $this->getQuestion($_POST["qid"]);

      if (strtolower(trim($_POST["answer"])) == strtolower($question["answer"])) {
        $message = "<div class=\"alert alert-success\" role=\"alert\">
          Correct!
          </div>";
        // Remove the question ID from the session
        unset($_SESSION["qid"]);
        // Update the user's score
        $_SESSION["score"] += 10; // + 10 points!
      }
      else {
        $message = "<div class=\"alert alert-danger\" role=\"alert\">
          Incorrect!
          </div>";
      }
    }
    $this->showQuestion($message);
  }
}

/web/src/trivia/templates/welcome.php

The welcome template.

<!DOCTYPE html>
<html lang="en" data-bs-theme="light">
  <head>
    <meta charset="UTF-8">  
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="author" content="CS4640 Spring 2025">
    <meta name="description" content="Our Front-Controller Trivia Game">  
    <title>PHP Form Example - Trivia</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"  integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN"  crossorigin="anonymous">       
  </head>

  <body>
    <div class="container" style="margin-top: 15px;">
      <div class="row">
        <div class="col-xs-12">
          <h1>Welcome to our Trivia Game!</h1>
          <p>Please answer the questions below to begin playing</p>
        </div>
      </div>
      <?=$message?>
      <div class="row">
        <div class="col-xs-12">
          <form action="?command=login" method="post">
            <div class="mb-3">
              <label for="name" class="form-label">Name</label>
              <input type="text" class="form-control" id="name" name="fullname">
            </div>
            <div class="mb-3">
              <label for="email" class="form-label">Email address</label>
              <input type="email" class="form-control" id="email" name="email" aria-describedby="emailHelp">
              <div id="emailHelp" class="form-text">We'll never share your email with anyone else.</div>
            </div>
            <div class="mb-3">
              <label for="passwd" class="form-label">Password</label>
              <input type="password" class="form-control" id="password" name="password">
            </div>
            <button type="submit" class="btn btn-primary">Start</button>
          </form>
        </div>
      </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script>
  </body>
</html>

/web/src/trivia/templates/question.php

Our question template. Mostly unchanged! To update, simply print out the $name above the Score.

/web/src/trivia/data/trivia-s25.json

Unchanged from starter code!