0

I have a bare bones AJAX script that calls a PHP page to retrieve data from the database. The database call is definitely working. I am getting the below error in the console which seems to indicate that the php script is returning the entire html of the page rather than just the json object post recordset retrieval, but I am not sure. Please see below for error, ajax code and php code.

Error: SyntaxError: Unexpected token '<', ..."<table sty"... is not valid JSON at parse () at jquery.min.js:2:77349 at l (jquery.min.js:2:77466) at XMLHttpRequest. (jquery.min.js:2:80265)

Ajax Script From Client/UI Page: Change to the cboYear html select fires the database call.

<script>

        //This method is the event that is triggered once the document is loaded.  That way 
        //no code is executed in a partial load state.
        $(document).ready(function(){

            $("#cboYear").change(function(){

                var iYear = $('#cboYear').val();

                //If a year is selected call the php page to retrieve the db values while passing in the selected year for the where clause
                //of the SQL statement
                if (iYear != "") {
                    
                    $.ajax({
                        url: <?php echo( chr(39) . $_SESSION['Web_Application_Root_Directory'] . 'db_includes/get_DR_Design.php' . chr(39) )?>,    
                        type: 'post',    
                        dataType: 'json',
                        data: {YearID: iYear},
                        
                        success: function (response) {
                            console.log('success start');
                            console.log(response);
                            console.log('success end');
                            //parse json
                            response = JSON.parse(response);
                            console.log(response);
                        },
                        error: function(xhr, status, error) {
                            console.error('Error:', error);
                            console.error('Status:', status);
                            console.error('Response:', xhr.responseText);
                        }
                    });

                }

                
            });

        });

   </script>

PHP Page Which Opens Up Recordset from DB and Returns JSON

<?php 

    require_once $_SERVER['DOCUMENT_ROOT'] . '/DR/lib_includes/config.php';
   
    
    $iYearID= $_POST['YearID'];

    $sSQL = "SELECT * FROM tb_Design WHERE Year_ID = " . $iYearID;
    $DRDesignArray = [];

    $oDB = new cDatabase();
    $oRst = $oDB->mOpenRecordset($sSQL);

    // Fetch data and convert to JSON

    while ($row = odbc_fetch_array($oRst)) {
        $DRDesignArray[] = $row; // Add each row to the array
    }

    // Convert the array to JSON
    $jsonData = json_encode($DRDesignArray);

    // Output the JSON
    mLogString($jsonData);
    echo($jsonData);


?>
8
  • Well, what do you get when you call the .php manually (typing the AJAX-called URL in your browser's URL bar, hardcoding YearID in your PHP to test) or simply looking at your browser's network inspector to get the full contents? I suspect you're either receiving a good big error message from your PHP, formatted as HTML; or the URL isn't this of your JSON-generating endpoint, rather an index.php or such that calls your "PHP page", but only after having included another PHP responsible of the HTML layout of your site. Commented Jul 4 at 16:54
  • Also there is ZERO need for jQuery here. fetch and some template literals would take this into the 2020s Commented Jul 4 at 17:14
  • @GuillaumeOutters The php page works perfectly. The one error is the one shown. Commented Jul 4 at 17:37
  • @mplungjan what is the advantage of jquery vs fetch? Not familiar with template literals, can you expand on that? I have seen fetch examples. Commented Jul 4 at 17:39
  • 1
    @GuillaumeOutters Thanks for your response. Your confirmation that the html was being returned to the ajax call as json helped me to find the problem. There was an include page in the "PHP Page Which Opens Up the Recordset Returns JSON" which had the header html banner. So I needed to change the include pages. I also found that I was double processing the json response, once in PHP using json_encode and once in ajax using JSON.parse, so I had to fix that. Still learning the developer tools in the browser but I am getting a little better with them. Will look at all recs. Commented Jul 4 at 19:10

3 Answers 3

1

Your SQL is

$sSQL = "SELECT * FROM tb_Design WHERE Year_ID = " . $iYearID;

(ensuring that $iYearID is integer would prevent SQL injection which you currently allow and which is extremely unsecure, I strongly advise you to look into parameterized queries)

This is a table about tbDesign and you load all fields where the year id matches the parameter. You are converting it into JSON via

$jsonData = json_encode($DRDesignArray);

so it is reasonable to think that it should work, but you may end up having an error on server-side (check the server logs for that) or you are reaching out to the wrong page, or parsing the response failed for some reason. In the browser's Dev Tools you have a Network tab where you can study the response. You can copy it into your favorite editor and see the full error, search for the error message and stack trace inside. You will thusly identify what the error is and at what line it occurred.

Sign up to request clarification or add additional context in comments.

Comments

1

Possible PHP issues - like outputting content before the JSON

<?php
// Start output buffering to prevent accidental output
ob_start();

require_once $_SERVER['DOCUMENT_ROOT'] . '/DR/lib_includes/config.php';

$iYearID = $_POST['YearID']; // mybe sanitize?

$sSQL = "SELECT * FROM tb_Design WHERE Year_ID = " . $iYearID;
$DRDesignArray = [];

$oDB = new cDatabase();
$oRst = $oDB->mOpenRecordset($sSQL);

if ($oRst) {
  while ($row = odbc_fetch_array($oRst)) {
    $DRDesignArray[] = $row;
  }
} else {
  // DB query failed or no results
  header('Content-Type: application/json', true, 500);
  echo json_encode(['error' => 'Database query issue.']);
  exit;
}

$jsonData = json_encode($DRDesignArray);

if (json_last_error() !== JSON_ERROR_NONE) {
    // JSON encoding failed
    header('Content-Type: application/json', true, 500);
    echo json_encode(['error' => 'JSON encoding failed.']);
    exit;
}

// Clear buffer before output
ob_clean();

// Set JSON header and output data
header('Content-Type: application/json');
echo $jsonData; // here we have the only valid output

// No closing ?> tag is often best practice for pure PHP files

@mplungjan what is the advantage of jquery vs fetch? Not familiar with template literals, can you expand on that? I have seen fetch examples.

Well the biggest advantage is not loading an unnecessary library

window.addEventListener('load', () => { // when the elements are available
  const cboYear = document.getElementById('cboYear');
  const designResultsContainer = document.getElementById('designResults'); // or whatever you have called it

  cboYear.addEventListener('change', () => {
    const iYear = cboYear.value;

    // Clear previous results in case we get an error in the fetch
    designResultsContainer.innerHTML = '';

    if (iYear !== "") {
      fetch(`<?php echo($_SESSION['Web_Application_Root_Directory'] . 'db_includes/get_DR_Design.php'); ?>`, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({
            YearID: iYear
          })
        })
        .then(response => {
          if (!response.ok) { // some error
            // Attempt to read the error message from the server if available
            return response.json().then(err => {
              throw new Error(`HTTP error! Status: ${response.status} - ${err.error || response.statusText}`);
            }).catch(() => {
              // If response.json() fails (e.g., non-JSON error from server), fall back
              throw new Error(`HTTP error! Status: ${response.status} - ${response.statusText}`);
            });
          }
          return response.json(); // Parse the JSON response - which is now available as "data" in the next .then
        })
        .then(data => { // this is an object now
          // console.log('Success:', data); // Log the parsed data

          if (data.length === 0) {
            designResultsContainer.innerHTML = '<p>No designs found for this year.</p>';
            return;
          }

          // Use map() and template literals (`) to transform each design object into an HTML string 
          // Then use join('') to concatenate all the HTML strings into one big string
          const designHtml = data.map(design => `   
            <div class="design-item" style="border: 1px solid #ccc; margin-bottom: 10px; padding: 10px;">
              <h3>${design.DesignName || 'N/A'}</h3>
              <p><strong>ID:</strong> ${design.ID || 'N/A'}</p>
              <p><strong>Year:</strong> ${design.Year_ID || 'N/A'}</p>
              <p><strong>Description:</strong> ${design.Description || 'No description provided.'}</p>
            </div>`).join('');
          // Insert the generated HTML into the container
          designResultsContainer.innerHTML = designHtml;
        })
        .catch(error => {
          console.error('Error fetching designs:', error);
          designResultsContainer.innerHTML = `<p style="color: red;">Failed to load designs: ${error.message || 'Unknown error'}</p>`;
        });
    }
  });
});

Comments

0

(retro-answering from the comments)

The error message Unexpected token '<', ..."<table sty"... is not valid JSON gives us a hint at what is passed to response = JSON.parse(response);:
there's a bit of HTML that could be the start of <table style="…"><tr><td>…</td>….

But having a longer extract of this HTML could help us understand what's in there.

So first we have to get the full HTML body, or at least a longer start:

  • either by looking in the web browser's network tab, that, if open before running the AJAX call, will save the entire payload
  • or by including a JS alert(response); just before the JSON.parse(response); that crashes
  • or by calling by hand the URL called by the AJAX (pasting the URL into the address bar of the browser) but this will require changing _POST into _GET for the duration of the test, to be able to pass YearID in the URL instead of by POST

Then we probably have a better idea of what outputs this HTML, instead of the expected JSON:

  • either it's one of your pages:
    <table style="…"><tr><td>Here is the generic header for my site</td>… (possibly ending with the expected JSON data),
    then it may be sign that your PHP includes another PHP, responsible of the HTML layout of your site, before running the json_encode()
  • or the page looks like the one of the framework or PHP:
    <table style="…"><tr><td>Framework speaking: an uncaught exception was thrown on yourscript.php at line 123: illegal this and that</td>…
  • or the URL has been mistyped and it's the webserver replying:
    <table style="…"><tr><td>Error 404: you are now allowed to access yourscriptwithatypo.php</td>…

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.