Source Code for /public/inc/potion-finder.php

<?php
/**
 * Potion Finder!
 *
 * A "find it" game spread throughout Dan Q's PHP Cookery Class.
 * Four potions (blue, green, red, and yellow) are hidden on different pages of the site.
 * The player must find them all by clicking on them.
 */

// Start the session and set up an array to keep the "found" potions
session_start();

// $_SESSION['found_potions'] will be an array of the colors of the potions that have been found.
// We'll load it into a variable (or an empty array if no potions have been found yet).
$found_potions = isset( $_SESSION['found_potions'] ) ? $_SESSION['found_potions'] : [];

// Keep a list of potions and their passwords (the passwords ensure that visitors have to find
// the links, which contain the passwords: they can't just go to e.g. ?potion=blue!)
$potion_passwords = [
  'blue'   => 'JNEvDcic',
  'green'  => '9PoqhPpV',
  'red'    => 'bzfUfuQV',
  'yellow' => 'zbPADf4r',
];

 /**
  * Creates a potion link on the current page. Takes the following parameters:
  * - $color: The color of the potion.
  * The link is only shown if the user HASN'T already found the potion.
  */
function draw_potion( $color ){
  // Get access to the $found_potions variable:
  global $found_potions, $potion_passwords;

  // Check if the potion has already been found:
  if( in_array( $color, $found_potions ) ){
    return; // This potion has already been found - return without drawing anything!
  }

  // Determine the password to acttach to this potion (this stops users just going to e.g.
  // ?potion=blue to claim a potion; they need the password which only appears with the link,
  // although of course YOU know the passwords because you're reading the source code!)
  $password = $potion_passwords[ $color ];

  // Draw the potion:
  ?>
  <p class="potion">
    <a href="/?potion=<?php echo $color; ?>&potion_password=<?php echo $password; ?>"><img class="potion-img" src="/img/potions/<?php echo $color; ?>.png" alt="<?php echo ucfirst($color); ?> potion"></a>
    <span>
      You found the <?php echo $color ?> potion! Click on it to collect it!
      (<a href="/?show_potions=true">What is this?</a>)
    </span>
  </p>
  <?php
}

// Captue requests to reset the game (discard all potions):
if( isset( $_GET['reset_potions'] ) && $_GET['reset_potions'] === 'true' ){
  // Reset the game:
  $found_potions = [];
  $_SESSION['found_potions'] = $found_potions;
  // Redirect the user to the potions collection page:
  header( 'Location: /?show_potions=true' );
  die();
}

// Capture requests to collect potions:
if( isset( $_GET['potion'] ) && isset( $_GET['potion_password'] ) ){
  // Check if the password is correct:
  if( $_GET['potion_password'] !== $potion_passwords[ $_GET['potion'] ] ){
    // It's not correct! Show a HTTP 403 error and stop:
    header( 'HTTP/1.1 403 Forbidden' );
    die( 'Invalid potion. The potion you tried to collect was not authorised.' );
  }

  // Add the potion to the user's collection, unless it's already been found:
  if( ! in_array( $_GET['potion'], $found_potions ) ){
    $found_potions[] = $_GET['potion'];
  }

  // Save the updated collection back to the session:
  $_SESSION['found_potions'] = $found_potions;

  // Redirect the user to the potions collection page:
  header( 'Location: /?show_potions=true' );
  die();
}

// Capture requests to show the potions collection:
if( isset( $_GET['show_potions'] ) && $_GET['show_potions'] === 'true' ){
  // Show the potions collection:
  add_header( 'Potions Collection' );
  ?>
  <h2>Your Potions</h2>
  <p>
    <a href="/06-retaining-state/">Lesson 6</a> of Dan Q's PHP Cookery Class is all about <em>sessions</em> and <em>cookies</em>.
    One of the demonstrations it gives is a game where you must explore the site and find hidden potions.
  </p>
  <p>
    You have found <?php echo count( $found_potions ); ?> potions!
  </p>
  <?php if( count( $found_potions ) > 0 ){ ?>
    <p>You have found:</p>
    <ul class="potion-list">
      <?php foreach( $found_potions as $potion ){ ?>
        <li>
          <img class="potion-img" src="/img/potions/<?php echo $potion; ?>.png" alt="">
          <span>The <?php echo $potion; ?> potion</span>
        </li>
      <?php } ?>
    </ul>
    <?php if( count( $found_potions ) === count( $potion_passwords ) ){ ?>
      <p>
        That's all four potions! Congratulations!
      </p>
      <p>
        If you want to play again, you'll need to
        <a href="/?reset_potions=true">discard all of your potions</a>.
      </p>
    <?php } ?>
  <?php } ?>

  <h2>Where to find potions?</h2>
  <p>
    The potions are hidden on different pages of the site. Here are some clues about where you might find them:
  </p>
  <ul>
    <li <?php echo in_array( 'blue', $found_potions ) ? 'style="text-decoration: line-through;"' : ''; ?>>
      <img src="/img/potions/blue.png" alt="">
      The blue potion is found <a href="/06-retaining-state/#potion-finder">where the Potion Finder game was invented</a>.
    </li>
    <li <?php echo in_array( 'green', $found_potions ) ? 'style="text-decoration: line-through;"' : ''; ?>>
      <img src="/img/potions/green.png" alt="">
      The green potion is found amongst some tips on security.
    </li>
    <li <?php echo in_array( 'red', $found_potions ) ? 'style="text-decoration: line-through;"' : ''; ?>>
      <img src="/img/potions/red.png" alt="">
      The red potion can be found in the navigation menu. No... not the one on the side of the page... the <em>other</em> one!
    </li>
    <li <?php echo in_array( 'yellow', $found_potions ) ? 'style="text-decoration: line-through;"' : ''; ?>>
      <img src="/img/potions/yellow.png" alt="">
      The yellow potion can only be found... if you get completely lost!
    </li>
  </ul>

  <h2>Or if you'd rather cheat...</h2>
  <p>
    <a href="/source-viewer.php?file=public/inc/potion-finder.php">View the source code of this game</a>
  </p>

  <?php
  add_footer();

  die(); // Don't go on to render the normal page content!
}