How to continue PHP script after sending HTTP response
In JS:
$(document).ajaxSuccess(function ( event, xhr, settings) {
if(xhr.status === 202) {
//console.log("Your file is in process");
//console.log(xhr.responseJSON);
//Activate interval to check if file is ready
}
});
//Make petition
$.post("petitionsHandler.php", {"texto":"Hello world, greeting from México!"}, function (resp){
//Handle responses
}, "json").fail(function () {
//Handle errors
});
In PHP
<?php
$text = $_POST["text"];
//If you are using sessions don't forget to close the session file
//Or such will be blocked until long script finishes
session_write_close();
header("HTTP/1.1 202 Solicitud recibida"); #This is the code I wanted to send
header("Content-Type: application/json"); #Depends the kind of data you're sending to the client
// Buffer all upcoming output...
ob_start();
// Send your response.
echo '{"success":true, "message":"Your request has been received."}';
// Get the size of the output.
$size = ob_get_length();
// Disable compression (in case content length is compressed).
//header("Content-Encoding: none"); #I didn't need this but check your situation
// Set the content length of the response.
header("Content-Length: {$size}");
// Close the connection.
header("Connection: close");
// Flush all output.
ob_end_flush();
ob_flush();
flush();
//All outputs have now been sent to the client
//You can continue executing your long tasks
include_once('createExcel.php');
createExcel.php
<?php
sleep(10); #You can use to checkthat the code works
//The above code will respond the client immediately and after ten seconds the Excel file will be created
require "PHPSpreadSheet/vendor/autoload.php";
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setCellValue('A1', $text);
$writer = new Xlsx($spreadsheet);
$writer->save('MyFile.xlsx');
Of course you have to make validations, so you don't have lots of running process in background but I hope the general idea has been shown in this example.
This is not exactly the code I use, but this is all it takes to continue executing code after responding the client.
In my own opinion, I thinks this is better than using exec()
or similar functions which invoke the command terminal as that could be a potential vulnerability , so you don't have to change permissions or anything.
Note: If you're using sessions, Please remember to use session_write_close()
because on heavy tasks will block the file until such task is finished.
I hope it helps :)
My answer was based on this blog: https://qastack.mx/programming/15273570/continue-processing-php-after-sending-http-response
Continue PHP execution after sending HTTP response
Have the script that handles the initial request create an entry in a processing queue, and then immediately return. Then, create a separate process (via cron maybe) that regularly runs whatever jobs are pending in the queue.
PHP with AJAX - Continue Processing After Sending Response to the User
It looks like (as @ADyson said in the comment) flushing output doesn't seem work with AJAX. So, the only solution to the problem is to use Cron Job. To do this, I used PHP Cron Scheduler. But crontab can be used directly to add a Cron Job to the list.
I added the post processes to another PHP file with suitable changes so that it can do the same tasks from the script and added the file to the Scheduler.
This solution may seem a real pain, but there is no solution to this problem other than using Cron Job.
Send response and continue executing script - PHP
You can try something like this.
ignore_user_abort(true);
set_time_limit(0);
ob_start();
// do initial processing here
echo $response; // send the response
header('Connection: close');
header('Content-Length: '.ob_get_length());
ob_end_flush();
ob_flush();
flush();
// now the request is sent to the browser, but the script is still running
// so, you can continue...
Compress a manually closed connection AND continue processing
I managed to reduce the code in thanks to a comment by Rush on the ob_get_length documentation page. All three flush commands are required, commenting out any of them results in the page not loading until after sleep(4)
. I tested this to ensure that the connection closed in the browser, was compressed and then switched over to my file manager to see the file created a few seconds later.
<?php
ob_start();
ob_start('ob_gzhandler');
// Send your response.
echo '<style>* {background-color: #000; color: #fff;}</style>';
echo '<p>Testing response: '.time().'.</p>';
// The ob_gzhandler one
ob_end_flush();
header('Content-Length: '.ob_get_length());
// The main one
ob_end_flush();
ob_flush();
flush();
// Close current session (if it exists).
if (session_id()) {session_write_close();}
sleep(4);
file_put_contents('test.txt', 'testing: '.time().'; size: '.$size);
?>
Related Topics
Prevent Direct Access to a PHP Include File
How to Find the Last Day of the Month from Date
How to Validate an Email in PHP
Call to a Member Function Bind_Param() on a Non-Object
How to Send a Firebase Cloud Messaging Notification Without Use the Firebase Console
How to Truncate a String in PHP to the Word Closest to a Certain Number of Characters
How to Read If a Checkbox Is Checked in PHP
Why Can't I Access Datetime-≫Date in PHP'S Datetime Class
Mvc For Advanced PHP Developers
How to Sort Files by Date in PHP
Difference Between Http_Host and Server_Name in PHP
How to Get Id of the Last Updated Row in MySQL
If Block Inside Echo Statement