Sessions problem- variables not holding from page to page

Hey, I am learning from one of Sitepoint’s books PHP & MySQL Novice to Ninja by Kevin Yank and encountered a funny problem. The example itself in the book is incorrect and the source code of the book is not working either.
Here I am making a Shopping Cart. The problem is that once you put items in the shopping cart in ‘catalog.html.php’ page and store them in a variable $_SESSION[‘cart’], it becomes empty and stops holdings all its values when I go to the next page ‘cart.html.php’ where I should be able to check all the items I bought. I don’t understand fully enough how sessions work thus I have no idea how to debug it. Could you explain what is the problem?

index.html :

<?php
include_once $_SERVER['DOCUMENT_ROOT'] .
    '/includes/magicquotes.inc.php';

$items = array(
    array('id' => '1', 'desc' => 'Canadian-Australian Dictionary',
        'price' => 24.95),
    array('id' => '2', 'desc' => 'As-new parachute (never opened)',
        'price' => 1000),
    array('id' => '3', 'desc' => 'Songs of the Goldfish (2CD set)',
        'price' => 19.99),
    array('id' => '4', 'desc' => 'Simply JavaScript (SitePoint)',
        'price' => 39.95));

session_start();
if (!isset($_SESSION['cart']))
{
  $_SESSION['cart'] = array();
}

include 'catalog.html.php';

if (isset($_POST['action']) and $_POST['action'] == 'Buy')
{
  // Add item to the end of the $_SESSION['cart'] array
  $_SESSION['cart'][] = $_POST['id'];
  header('Location: .');
  exit();
}

if (isset($_POST['action']) and $_POST['action'] == 'Empty cart')
{
  // Empty the $_SESSION['cart'] array
  unset($_SESSION['cart']);
  header('Location: ?cart');
  exit();
}

if (isset($_GET['cart']))
{
  $cart = array();
  $total = 0;
  foreach ($_SESSION['cart'] as $id)
  {
    foreach ($items as $product)
    {
      if ($product['id'] == $id)
      {
        $cart[] = $product;
        $total += $product['price'];
        break;
      }
    }
  }

  include 'cart.html.php';
  exit();
}

cart.html.php :

<?php include_once $_SERVER['DOCUMENT_ROOT'] .
    '/includes/helpers.inc.php'; ?>
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Shopping Cart</title>
    <style>
    table {
      border-collapse: collapse;
    }
    td, th {
      border: 1px solid black;
    }
    </style>
  </head>
  <body>
    <h1>Your Shopping Cart</h1>
	<?php echo count($_SESSION['cart']); ?>
    <?php if (count($cart) > 0): ?>
    <table>
      <thead>
        <tr>
          <th>Item Description</th>
          <th>Price</th>
        </tr>
      </thead>
      <tfoot>
        <tr>
          <td>Total:</td>
          <td>$<?php echo number_format($total, 2); ?></td>
        </tr>
      </tfoot>
      <tbody>
        <?php foreach ($cart as $item): ?>
          <tr>
            <td><?php htmlout($item['desc']); ?></td>
            <td>
              $<?php echo number_format($item['price'], 2); ?>
            </td>
          </tr>
        <?php endforeach; ?>
      </tbody>
    </table>
    <?php else: ?>
    <p>Your cart is empty!</p>
    <?php endif; ?>
    <form action="?" method="post">
      <p>
        <a href="?">Continue shopping</a> or
        <input type="submit" name="action" value="Empty cart">
      </p>
    </form>
  </body>
</html>

catalog.html.php :

<?php include_once $_SERVER['DOCUMENT_ROOT'] .
    '/includes/helpers.inc.php'; ?>
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Product Catalog</title>
    <style>
    table {
      border-collapse: collapse;
    }
    td, th {
      border: 1px solid black;
    }
    </style>
  </head>
  <body>
    <p>Your shopping cart contains <?php
        echo count($_SESSION['cart']); ?> items.</p>
    <p><a href="?cart">View your cart</a></p>
    <table border="1">
      <thead>
        <tr>
          <th>Item Description</th>
          <th>Price</th>
        </tr>
      </thead>
      <tbody>
        <?php foreach ($items as $item): ?>
          <tr>
            <td><?php htmlout($item['desc']); ?></td>
            <td>
              $<?php echo number_format($item['price'], 2); ?>
            </td>
            <td>
              <form action="" method="post">
                <div>
                  <input type="hidden" name="id" value="<?php
                      htmlout($item['id']); ?>">
                  <input type="submit" name="action" value="Buy">
                </div>
              </form>
            </td>
          </tr>
        <?php endforeach; ?>
      </tbody>
    </table>
    <p>All prices are in imaginary dollars.</p>
  </body>
</html>

Each page which is going to be accessing SESSIONS must start with:


<?php session_start(); ?>

No, it did not work and somehow even made it worse :smiley: Now it also says “Cannot modify header information - headers already sent by…”. The code is copied straight from the source code (http://www.sitepoint.com/books/phpmysql5/code.php), Chapter 9, I’m surprised no one has spotted this mistake yet.

Without running the whole thing on a server, it’s difficult to say - but here’s a few things I noticed

Firstly, you are showing a php file with the name index.html - this should be index.php (maybe a typo on your part)

Secondly, there’s no need to repeat <?php after the first occasion, simply use <?
or echo your html instead.

HTTP headers must be invoked before any output is made. Otherwise the call fails.

what’s the content of helpers.inc.php?

If a site’s “home page” is index.php then that is the best place to have session_start(), right at the start of that then it’ll already be in place for any scripts that are included by index.php and any scripts that are included by them ones, etc

The information you’ve received here is accurate. The problem will be to do with where you’re placing session_start(). You should have no output at all before using that command (the error you got after moving session_start() is highlighting the fact that you’re trying to send output to the browser before calling the function).

Check for any whitespace at the start of your script, and check your includes to make sure nothing is output before calling the function. You should call session_start() at the very start of the first script - before any include and even before any whitespace etc.