Jump to content

Error fetching booked seats: SyntaxError: Unexpected token '<', "<br />


Go to solution Solved by mac_gyver,

Recommended Posts

Hi Guys,

Been at this for over a week now. I am making a cinema ticket booking system. Everything is fine apart from one thing - showing unavailable seats (seats already booked) in red on the cinema seat map. I am getting this error:
 

map2.php?screen=7&sgid=59:108  Error fetching booked seats: SyntaxError: Unexpected token '<', "<br />
<b>"... is not valid JSON
(anonymous) @ map2.php?screen=7&sgid=59:108
Promise.catch (async)
(anonymous) @ map2.php?screen=7&sgid=59:108
Promise.then (async)
(anonymous) @ map2.php?screen=7&sgid=59:59

The booked seats are going into a table like this:

booking (table name)

booking_id       seat_id        screening_id

57                      399             2
58                      400             2   
59                      751              96
60                      752             96
127                     668            59
128                    669             59
129                    623             59
130                    624             59
 

 

Now when I go to that screening: map2.php?screen=7&sgid=59   (note: sgid is screening_id) and screen=7 means screen 7, and it will generate the layout for screen 7. There are 10 screens, and each one has a different layout.

All of that is fine, it generates the correct layout for any of the screens.

Then I can successfully book tickets, by clicking on the Javascript seat map, each seat can be clicked on. It goes something like this: A-2 (which is the seat number) -> Click Book -> seat books and enters into db. 

Then the part which is not working. Say if I went to map2.php?screen=7&sgid=59, it should know that seat_id = 669, 668, 623 and 624 are already booked and should show up as red on the seat map - it does not do that. When the seats are initially booked, it shows a JS alert which says "Seats booked successfully" and turns red, stays red until it refreshes, then goes back to its default state. 

I have print_r the array and echo the json data. Here is a sample for getBookedSeats.php?sgid=59:  (this page has the php/sql for getting booked seats.)

<pre>Array
(
    [0] => 623
    [1] => 624
    [2] => 668
    [3] => 669
)
</pre>




[623,624,668,669]

Here is the php for the file that gets the booked seats:

getBookedSeats.php:
 

try {
    // Create a PDO connection
    $pdo = new PDO("mysql:host=$host;dbname=$dbname", $username, $password);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    // Assume you have a database connection established

    $screeningId = $_GET['sgid']; // Get screening_id from URL

    // Fetch booked seat IDs
    $query = "SELECT seat_id FROM booking WHERE screening_id = :screeningId";
    $statement = $pdo->prepare($query);
    $statement->bindParam(':screeningId', $screeningId, PDO::PARAM_INT);
    $statement->execute();
    $bookedSeatIds = $statement->fetchAll(PDO::FETCH_COLUMN);

        echo '<pre>',print_r($bookedSeatIds,1),'</pre>';



    header('Content-Type: application/json');

    echo json_encode($bookedSeatIds);
} catch (PDOException $e) {
    // Handle database connection errors
    echo json_encode(['error' => 'Database connection error']);
    // Log or display the actual error for debugging
    // echo 'Error: ' . $e->getMessage();
}

and here is the full javascript from map2.php:

<div id="seat-map"></div>
  <div id="selected-seat"></div>
  <div id="total-price">Total Price: £0.00</div>


  let screeningId;
document.addEventListener("DOMContentLoaded", function () {
  const seatMap = document.getElementById("seat-map");
  const selectedSeat = document.getElementById("selected-seat");
  const totalPriceDisplay = document.getElementById("total-price");

  let seatPrice; // Declare seatPrice as a global variable

  // Use PHP data in JavaScript
  const seatData = <?php echo json_encode($seatData); ?>;
  const uniqueRows = <?php echo json_encode($uniqueRows); ?>;
  const screeningId = <?php echo $_GET['sgid']; ?>; // Get screening_id from URL

  // Fetch the price for the current year
  fetch('getPrice.php')
    .then(response => response.json())
    .then(data => {
      seatPrice = data.price; // Assign the value to the global variable seatPrice

      // Create the seat map
      uniqueRows.forEach(row => {
        const rowContainer = document.createElement("div");
        rowContainer.className = "row";

        const rowSeats = seatData.filter(seat => seat.row === row);

        rowSeats.forEach(seat => {
          const seatElement = document.createElement("div");
          seatElement.className = "seat";
          seatElement.setAttribute("data-seat-id", seat.seat_id);

          const seatNumber = document.createElement("span");
          seatNumber.className = "seat-number";
          seatNumber.innerText = `${row}-${seat.seat_number}`;
          seatElement.appendChild(seatNumber);

          seatElement.addEventListener("click", () => {
            seatElement.classList.toggle("selected");
            updateSelectedSeat();
          });

          rowContainer.appendChild(seatElement);
        });

        seatMap.appendChild(rowContainer);
      });

      // Fetch booked seat IDs and update seat map
      fetch('getBookedSeats.php', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ screeningId }),
      })
      .then(response => {
        console.log(response); // Log the entire response
        return response.json();
      })
      .then(bookedSeats => {
        console.log(bookedSeats); // Log the booked seats data
        // Mark booked seats as occupied
        bookedSeats.forEach(bookedSeatId => {
          const bookedSeatElement = document.querySelector(`.seat[data-seat-id="${bookedSeatId}"]`);
          if (bookedSeatElement) {
            bookedSeatElement.classList.add("occupied");
          }
        });
      })
      .catch(error => console.error('Error fetching booked seats:', error));
    })
    .catch(error => console.error('Error fetching price:', error));

  function updateSelectedSeat() {
    const selectedSeats = document.querySelectorAll(".seat.selected");
    const seatNumbers = Array.from(selectedSeats).map(seat => {
      const seatId = seat.getAttribute("data-seat-id");
      const selectedSeatData = seatData.find(seat => seat.seat_id == seatId);
      return `${selectedSeatData.row}-${selectedSeatData.seat_number}`;
    });
    selectedSeat.innerText = `Selected Seats: ${seatNumbers.join(", ")}`;

    // Calculate and display the total price
    const totalPrice = seatNumbers.length * seatPrice;
    totalPriceDisplay.innerText = `Total Price: £${totalPrice.toFixed(2)}`;
  }

  function bookSeats() {
    const selectedSeats = document.querySelectorAll(".seat.selected");

    // Check if seats are selected
    if (selectedSeats.length === 0) {
      alert("Please select at least one seat.");
      return;
    }

    // Get seat IDs and insert into the database
    const seatIds = Array.from(selectedSeats).map(seat => seat.getAttribute("data-seat-id"));

    // Make an AJAX request to insert data into the database
    fetch('bookSeats.php', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ seatIds, screeningId }),
    })
    .then(response => response.json())
    .then(data => {
      console.log('Booking successful:', data);
      // You can update the UI or perform other actions here
    })
    .catch(error => console.error('Error booking seats:', error));

    // Simulate booking with a delay for visual effect
    selectedSeats.forEach(seat => {
      seat.classList.remove("selected");
      seat.classList.add("occupied");
    });

    // Move the updateSelectedSeat function call inside the setTimeout function
    setTimeout(() => {
      updateSelectedSeat();
      alert("Seats booked successfully!");
    }, 500);
  }

  // Attach click event listener to the "Book Selected Seats" button
  const bookSeatsButton = document.getElementById("book-seats-btn");
  if (bookSeatsButton) {
    bookSeatsButton.addEventListener("click", bookSeats);
  }
});

I logged the response to the console.log and this is what I get:
 

Response {type: 'basic', url: 'https://xxx.xxx.com/cinemav2/getBookedSeats.php', redirected: false, status: 200, ok: true, …}
body
: 
(...)
bodyUsed
: 
true
headers
: 
Headers {}
ok
: 
true
redirected
: 
false
status
: 
200
statusText
: 
""
type
: 
"basic"
url
: 
"https://xxx.xxx.com/cinemav2/getBookedSeats.php"
[[Prototype]]
: 
Response

I tried to do this as well:
 

 console.log(bookedSeats); 

To log the seats booked data, but its not working.

Apparently it might be that html is getting into my JSON

Can someone please help?

Thanks

Edited by webdeveloper123

Hey Barand,

Yes I removed it. It wasn't there earlier, but I was having real problems for days so I put it in there to see if everything is ok.

This may or may not help, but I have this line in the same file:

      <p class="title"><?= htmlspecialchars($listing['title']) ?></p></br>

And as the error suggested, there is a "</br>" element involved. But the HTML is valid and the php is fine. I was just trying everything I could think of, so I removed htmlspecialchars just to see if it had any effect- but still nothing. It just comes from a select sql query, then I foreach around it and output each element

Edited by webdeveloper123
2 minutes ago, Barand said:

Remember that all output from a script called by AJAX or fetch becomes part of the response that is returned.

ok, I didn't know that. Thanks

But in the getBookedSeats.php the only output (now) is the:

 $bookedSeatIds = $statement->fetchAll(PDO::FETCH_COLUMN);

    header('Content-Type: application/json');

    echo json_encode($bookedSeatIds);

So, I can't see why i'm getting this error

look at the actual response in the browser's developer tools, network tab.

the page you make the ajax request to, must only return the json encoded data. there can be nothing else output with that request.

if you are not already doing so, the code for any page should be laid out in this general order -

  1. initialization
  2. post method form processing
  3. get method business logic - get/produce data needed to display the page
  4. html document

for a page that produces a json response, you would output the response at the end of item #3 on this list, then there would either be no actual html document section or you you would exit/die to stop the php code execution on the page.

if none of the replies help solve the problem, just post all the code needed to reproduce the problem, since you have a misunderstanding of what the code should be doing. snippets of the problem don't tell us things like - 

10 minutes ago, webdeveloper123 said:

but I have this line in the same file:

 

10 minutes ago, mac_gyver said:

just post all the code needed to reproduce the problem,

Here is the full code from map2.php:
 

try {
    // Create a PDO instance
    $pdo = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    // Fetch screen data from the database
    $screenQuery = "SELECT * FROM screen";
    $screenStatement = $pdo->query($screenQuery);
    $screens = $screenStatement->fetchAll(PDO::FETCH_ASSOC);

    // Check if at least one screen is available
    if (empty($screens)) {
        die("No screens available in the database.");
    }

    // Get the first screen_id to use for fetching seat data

    $firstScreenId = $_GET['screen'] ?? '';
    $screeningId = $_GET['sgid'] ?? '';


    // Fetch seat data based on the first screen_id
    $seatQuery = "SELECT * FROM seat WHERE screen_id = :screen_id";
    $seatStatement = $pdo->prepare($seatQuery);
    $seatStatement->bindParam(':screen_id', $firstScreenId);
    $seatStatement->execute();
    $seatData = $seatStatement->fetchAll(PDO::FETCH_ASSOC);

    // Fetch unique rows
    $uniqueRows = array_unique(array_column($seatData, 'row'));
    sort($uniqueRows);

    // Close the PDO connection


    $listingsQuery = "SELECT m.image, m.title, s.screen_num, 
                      date_format(sg.screen_on, '%W, %D %b') as date, 
                      TIME_FORMAT(sg.screen_at, '%H:%i') as start_time, 
                      CONCAT(m.running_time DIV 60, ' hrs ', m.running_time % 60, ' mins') as running_time
                      FROM screening sg
                      JOIN screen s ON sg.screen_id = s.screen_id
                      JOIN movie m ON sg.movie_id = m.movie_id
                      WHERE sg.screening_id = :screening_id;";

    $listingStatement = $pdo->prepare($listingsQuery);
    $listingStatement->execute(['screening_id' => $screeningId]);
    $listings  = $listingStatement->fetchAll();




    $pdo = null;
} catch (PDOException $e) {
    die("Connection failed: " . $e->getMessage());
}
?>

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="css/styles.css">


  <title>Cinema Seat Map</title>

</head>
<body id="home">

<header id='map-header'>
      
    </header>

    <div class="listingbook">
  <div class="listings">
    <?php
    foreach ($listings as $listing) { ?>

      <p class="title"><?= htmlspecialchars($listing['title']) ?></p></br>
      <img class="image" src="images/<?= htmlspecialchars($listing['image']) ?>"><br>
      <p class="screenNum">Screen <?= htmlspecialchars($listing['screen_num']) ?></p><br>
      <p class="date"><?= htmlspecialchars($listing['date']) ?>, <?= htmlspecialchars($listing['start_time']) ?></p><br>
      <p class="running"><?= htmlspecialchars($listing['running_time']) ?></p>   
   

<?php }  ?>

</div> 

    </div>
 

   

  <div id="seat-map"></div>
  <div id="selected-seat"></div>
  <div id="total-price">Total Price: £0.00</div>

   <script>
     // Declare screeningId as a global variable
 


 

let screeningId;
document.addEventListener("DOMContentLoaded", function () {
  const seatMap = document.getElementById("seat-map");
  const selectedSeat = document.getElementById("selected-seat");
  const totalPriceDisplay = document.getElementById("total-price");

  let seatPrice; // Declare seatPrice as a global variable

  // Use PHP data in JavaScript
  const seatData = <?php echo json_encode($seatData); ?>;
  const uniqueRows = <?php echo json_encode($uniqueRows); ?>;
  const screeningId = <?php echo $_GET['sgid']; ?>; // Get screening_id from URL

  // Fetch the price for the current year
  fetch('getPrice.php')
    .then(response => response.json())
    .then(data => {
      seatPrice = data.price; // Assign the value to the global variable seatPrice

      // Create the seat map
      uniqueRows.forEach(row => {
        const rowContainer = document.createElement("div");
        rowContainer.className = "row";

        const rowSeats = seatData.filter(seat => seat.row === row);

        rowSeats.forEach(seat => {
          const seatElement = document.createElement("div");
          seatElement.className = "seat";
          seatElement.setAttribute("data-seat-id", seat.seat_id);

          const seatNumber = document.createElement("span");
          seatNumber.className = "seat-number";
          seatNumber.innerText = `${row}-${seat.seat_number}`;
          seatElement.appendChild(seatNumber);

          seatElement.addEventListener("click", () => {
            seatElement.classList.toggle("selected");
            updateSelectedSeat();
          });

          rowContainer.appendChild(seatElement);
        });

        seatMap.appendChild(rowContainer);
      });

      // Fetch booked seat IDs and update seat map
      fetch('getBookedSeats.php', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ screeningId }),
      })
      .then(response => {
        console.log(response); // Log the entire response
        return response.json();
      })
      .then(bookedSeats => {
        console.log(bookedSeats); // Log the booked seats data
        // Mark booked seats as occupied
        bookedSeats.forEach(bookedSeatId => {
          const bookedSeatElement = document.querySelector(`.seat[data-seat-id="${bookedSeatId}"]`);
          if (bookedSeatElement) {
            bookedSeatElement.classList.add("occupied");
          }
        });
      })
      .catch(error => console.error('Error fetching booked seats:', error));
    })
    .catch(error => console.error('Error fetching price:', error));

  function updateSelectedSeat() {
    const selectedSeats = document.querySelectorAll(".seat.selected");
    const seatNumbers = Array.from(selectedSeats).map(seat => {
      const seatId = seat.getAttribute("data-seat-id");
      const selectedSeatData = seatData.find(seat => seat.seat_id == seatId);
      return `${selectedSeatData.row}-${selectedSeatData.seat_number}`;
    });
    selectedSeat.innerText = `Selected Seats: ${seatNumbers.join(", ")}`;

    // Calculate and display the total price
    const totalPrice = seatNumbers.length * seatPrice;
    totalPriceDisplay.innerText = `Total Price: £${totalPrice.toFixed(2)}`;
  }

  function bookSeats() {
    const selectedSeats = document.querySelectorAll(".seat.selected");

    // Check if seats are selected
    if (selectedSeats.length === 0) {
      alert("Please select at least one seat.");
      return;
    }

    // Get seat IDs and insert into the database
    const seatIds = Array.from(selectedSeats).map(seat => seat.getAttribute("data-seat-id"));

    // Make an AJAX request to insert data into the database
    fetch('bookSeats.php', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ seatIds, screeningId }),
    })
    .then(response => response.json())
    .then(data => {
      console.log('Booking successful:', data);
      // You can update the UI or perform other actions here
    })
    .catch(error => console.error('Error booking seats:', error));

    // Simulate booking with a delay for visual effect
    selectedSeats.forEach(seat => {
      seat.classList.remove("selected");
      seat.classList.add("occupied");
    });

    // Move the updateSelectedSeat function call inside the setTimeout function
    setTimeout(() => {
      updateSelectedSeat();
      alert("Seats booked successfully!");
    }, 500);
  }

  // Attach click event listener to the "Book Selected Seats" button
  const bookSeatsButton = document.getElementById("book-seats-btn");
  if (bookSeatsButton) {
    bookSeatsButton.addEventListener("click", bookSeats);
  }
});






  </script>

<button id="book-seats-btn">Book Selected Seats</button>
 




</body>
</html>

I'm not actually sure what I'm supposed to be looking at in the Network console. Been there many times and it gives me what looks like how many milliseconds the code took to run. But here is a screen shot:

 Thanks

network console.png

11 minutes ago, webdeveloper123 said:

looking at in the Network console

if you open the network tab, first, then trigger the request in question, there will be an entry showing the name of the file that got requested. if you click on the file name, you will get a set of tabs, one of which is the Response.

5 minutes ago, mac_gyver said:

there will be an entry showing the name of the file that got requested

I thought it might be something like that, but underneath the milliseconds part, it says "name", "status", "type" etc but nothing on the file name, just blank. everything blank. 

8 minutes ago, mac_gyver said:

then trigger the request in question

The only thing I can trigger is the book seats function, but even when i do that, nothing comes under : Name, Status etc

just to summarize for anyone reading this. the map2.php code is making ajax fetch requests to get data. the error that is occurring is for a request to - getBookedSeats.php.

It is the getBookedSeats.php code that must only output json encoded data. what is the full code for getBookedSeats.php?

1 hour ago, webdeveloper123 said:
<p class="title"><?= htmlspecialchars($listing['title']) ?></p></br>

is this line in getBookedSeats.php or map2.php? at the point where you posted it, the subject was "things being output by getBookedSeats.php"?

5 hours ago, webdeveloper123 said:

I thought it might be something like that, but underneath the milliseconds part, it says "name", "status", "type" etc but nothing on the file name, just blank. everything blank. 

reload the page after you have opened the network tab.

18 hours ago, mac_gyver said:

what is the full code for getBookedSeats.php?

Is almost identical to what I posted in OP, but left db connect details out. Here it is:
 

<?php
// Replace these values with your actual database connection details
$host = 'xxxxxxx';
$dbname = "xxxxxxx";
$username = "xxxxxx";
$password = "xxxxxxx";

try {
    // Create a PDO connection
    $pdo = new PDO("mysql:host=$host;dbname=$dbname", $username, $password);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    // Assume you have a database connection established

    $screeningId = $_GET['sgid']; // Get screening_id from URL



    // Fetch booked seat IDs
    $query = "SELECT seat_id FROM booking WHERE screening_id = :screeningId";
    $statement = $pdo->prepare($query);
    $statement->bindParam(':screeningId', $screeningId, PDO::PARAM_INT);
    $statement->execute();
    $bookedSeatIds = $statement->fetchAll(PDO::FETCH_COLUMN);


    header('Content-Type: application/json');

    echo json_encode($bookedSeatIds);
} catch (PDOException $e) {
    // Handle database connection errors
    echo json_encode(['error' => 'Database connection error']);
    // Log or display the actual error for debugging
    // echo 'Error: ' . $e->getMessage();
}
?>

 

18 hours ago, mac_gyver said:

is this line in getBookedSeats.php or map2.php?

It is in map2.php. I was debating whether to post it or not, knowing there is virtually 0% chance that it was the problem - but after a week of trying I was ready to try just about anything (plus it did have a "</br>" like the error suggested

 

12 hours ago, mac_gyver said:

reload the page after you have opened the network tab.

tried that as well. Keeping the network tab open, i load the website, go to getBookedSeats.php and load map2.php and trigger the booking - but nothing. Must be a setting somewhere - i'll google around

Ok I got rid of the error.

I finally messed around a bit in network tab and I got the response for getBookedSeats.php. This is it:

<br />
<b>Warning</b>:  Undefined array key "sgid" in <b>/var/www/vhosts/xxx.com/xxxx.xxxx.com/cinemav2/getBookedSeats.php</b> on line <b>23</b><br />
[]

So I used this code:

    if (isset($_GET['sgid'])) { 

    $screeningId = $_GET['sgid']; // Get screening_id from URL

    }

And the error goes away, but The unavailable seats still not showing in red

4 minutes ago, Barand said:

How are you handling the reponse to make them red?

The code is here. I'm not going to sit here and pretend I know what every single line does, but I have a rough idea (I have already double-checked the css)

 fetch('getBookedSeats.php', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ screeningId }),
      })
      .then(response => {
        console.log(response); // Log the entire response
        return response.json();
      })
      .then(bookedSeats => {
        console.log(bookedSeats); // Log the booked seats data
        // Mark booked seats as occupied
        bookedSeats.forEach(bookedSeatId => {
          const bookedSeatElement = document.querySelector(`.seat[data-seat-id="${bookedSeatId}"]`);
          if (bookedSeatElement) {
            bookedSeatElement.classList.add("occupied");
          }
        });
      })
      .catch(error => console.error('Error fetching booked seats:', error));
    })
    .catch(error => console.error('Error fetching price:', error));

There may or may not be JS in different places  - the full code which is in the Original post - that could have an effect on seats turning red

  • Solution

lol.

all the javascript posted for this problem is unnecessary. upon the DOM being loaded/rendered, it's getting data that's known at the time of the request for the map2.php page (the value being sent to getBookedSeats.php is coming from a js variable that's being set to a php value echoed on the page.) this is just a roundabout wall of code and data churn.

here's a list of why this is not working -

1. you are making a POST request to getBookedSeats.php. the value won't be in any $_GET variable and adding an isset() won't make it work. all that did is hide the problem and caused the php code to be skipped over.

2. you are sending JSON encoded data to getBookedSeats.php. you would need to use the following to read and decode the data -

$json = file_get_contents('php://input');
$data = json_decode($json,true);

3. the value will then be in $data['screeningId'], because that's the name of the javascript variable holding the value that you are sending in the ajax fetch request, which is a value that is coming from php in the first place.

 200w.gif.469575c2ada55ccaf0f34596b2aa1c2d.gif

  • Great Answer 1
42 minutes ago, webdeveloper123 said:

should be POST or GET?

Rule of thumb:

  • If all you are doing is GETting data to display then use GET
  • If what you are doing has side-effects, such as logging in or updating a db table, use POST

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.