-1

I have been trying to export a search result to an Excel file (type .xls), before this, I have been using purely PHP and it works.

However, my client requests to have "live search" effect, so I have to shift to AJAX.

Here is the starting point: User clicks "Export" button, and in the javascript (in the main php file viewdata.php):

    <script src='https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js'></script> 
    ....

    $(document).ready(function () {
        var guid = <?php echo $guid ?>;
        var date = document.getElementById("cbXDate").value;
        var key  = document.getElementById("cbsearch").value;
        console.log("GUID: '" + guid + "', Date: '" + date + "' Key: '" + key + "'");
        $.post("export_contacts.php", 
               { sGuid: guid, sDate: date, sKey: key }, 
               function () { console.log("Complete"); } );
        });

cbXDate is an input field of type date to let user choose a date from whence to export the data, and cbsearch is a text input field to include a search keyword. console commands are added to see where the code execution has went through.

in the export_contact.php:

<?php 
    echo '<script> console.log("Export PHP activated."); </script>';
?>

I removed the PHP MySQL data selection code just to debug the problem (full source code below).

Problem is: export_contacts.php is never called. The "Export PHP activated" message never popped up in the console. The console only displayed the data values and "Completed", i.e. export_contacts.php was never called.

Output:

GUID: '0001', Date: '2021-08-01' Key: 'Jo'
Complete

Out of curiosity, I replaced $.post(...) with $("#export_div").load(...) and the console message showed up:

$(document).ready(function () {
        var guid = <?php echo $guid ?>;
        var date = document.getElementById("cbXDate").value;
        var key  = document.getElementById("cbsearch").value;
        console.log("GUID: '" + guid + "', Date: '" + date + "' Key: '" + key + "'");
        $("#export_div").load("export_contacts.php", 
               { sGuid: guid, sDate: date, sKey: key }, 
               function () { console.log("Complete"); } );
        });

Output:

GUID: '0001', Date: '2021-08-01' Key: 'Jo'
Export PHP activated.
Complete

But this is not what I want, I want to write the output to a file, not display them in a div in the webpage. However, the data shown in the "export_div" div is correct, but the header part is not running, I know the quirkyness in header() calls, but I didn't output anything before the header() calls (unless output from the calling viewdata.php file also count?), here is the full export_contacts.php source code:

<?php
include("./php/auth.php");

$guid = $_POST['sGuid'];
$date = $_POST['sDate'];
$skey = $_POST['sKey'];

$searchKey = $_POST['sKey'];
if($searchKey == "")
{
    $skey = "'%'";
}
else
{    
    $skey = "'%".$searchKey."%'";
}

$sql = "SELECT *, FROM_UNIXTIME(ROUND((date / 1000), 0) + 46800) AS date
FROM contacts 
WHERE owner = '$guid' AND contact <> ''
AND (contact LIKE $skey OR name LIKE $skey) ";
if(!empty($date))
{
    "AND date >= '$date' ";
}
$sql .= "ORDER BY contact;";  

if($result = mysqli_query($link, $sql))
{      
    $columnHeader = '';  
    $columnHeader = "Owner" . "\t" . "Contact" . "\t" . "Name" . "\t" . "SaveDate" . "\t";  
    $setData = '';

    while($rows = mysqli_fetch_assoc($result))
    {        
        $rowData = '';  
        foreach ($rows as $value) 
        {  
            $value = '"' . $value . '"' . "\t";  
            $rowData .= $value;  
        }  
        $setData .= trim($rowData) . "\n";      
    }   
    // in case of .load() used, 
    // code works up until this point
    // code doesn't work since here...
    header("Content-type: application/xls");  
    header("Content-Disposition: attachment; filename=contact_".$guid.".xls");  
    header("Pragma: no-cache");  
    header("Expires: 0");      
    echo ucwords($columnHeader) . "\n" . $setData . "\n";   
    // until here
    // this will show in console in case of .load() used
    echo '<script> console.log("Export PHP activated."); </script>';
    die(); 
}
else
{
    echo "<script>window.alert('ERROR: '".mysqli_error($link).")</script>";
}

include("./php/cleanup.php");

?>

This code is working in the pure PHP version. I don't know why this header() part isn't working in here, could be due to its output got redirected to the div?

To make things clear, my question is: "Why $.post(...) isn't calling the PHP file, while $("#export_div").load(...) did?".

The header() part is just a sub question, and is fine if it's ignored.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Kw Choy
  • 129
  • 1
  • 1
  • 10
  • 1
    `$.post()` simply makes an HTTP request to a given URL. It does not load the contents, which is why you never see "Export PHP activated" in the console. The PHP file is executed on the server, but the output is ignored. You wrote _"I want to write the output to a file, not display them in a div in the webpage"_ but I don't see any code that writes to a file. Instead, it looks like you're outputting an HTML page, complete with HTTP headers. So which is it: display the output in the browser (either in a new tab, the current tab, or a `
    `), or send the output to a file?
    – kmoser Aug 30 '21 at 03:41
  • Thanks for the reply, so, what should I do if I want to call a php file that 1) Query the data, 2) Write the data to a file, 3) Download the file to local PC? My client extremely loathes page loading caused by submitting a form in the php way... The file is written in the header() calls (I don't really know how it worked, I just used whatever I found from a tutorial site, as long as I could get the file downloaded, it's good for me.). Should I be using $.ajax()? – Kw Choy Aug 30 '21 at 03:58
  • You don't need Javascript or AJAX at all, nor do you need to "write the data to a file." Just make the form POST to the URL that sends the headers followed by the contents of the file, which it seems you've already done. The `Content-Disposition: attachment` header will force the browser to save the file, and the original page you were on won't change. Is that what you want? – kmoser Aug 30 '21 at 04:02
  • Ah, now I understand... I was trying to over-engineer my web pages... Silly me. I was confused with $.post() and the METHOD='POST' in the form tag, while ignoring the ACTION='some_php_file' part... Thank you for clearing this up for me, all the tutorial sites, including w3school didn't explain clearly what $.post() is doing, at least not that I could see... – Kw Choy Aug 30 '21 at 04:25
  • **Warning:** You are wide open to [SQL Injections](https://php.net/manual/en/security.database.sql-injection.php) and should use parameterized **prepared statements** instead of manually building your queries. They are provided by [PDO](https://php.net/manual/pdo.prepared-statements.php) or by [MySQLi](https://php.net/manual/mysqli.quickstart.prepared-statements.php). Never trust any kind of input! Even when your queries are executed only by trusted users, [you are still in risk of corrupting your data](http://bobby-tables.com/). [Escaping is not enough!](https://stackoverflow.com/q/5741187) – Dharman Aug 30 '21 at 09:48

1 Answers1

0

As Kmoser pointed out, I was doing things wrong. None of the tutorial sites I visited did mention that $.post() will not return any result at all, while my php code is expecting the return of the search result and write them in a file in the header() calls.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Kw Choy
  • 129
  • 1
  • 1
  • 10