I was wondering if it was possible to send HTTP response immediately and continue the script.
Background: Among all the petition I make to the server there’s one that creates an Excel file (using PHPSpreadSheet), since creating this files can take a little longer I was thinking of responding a HTTP 202 status code to the Client, something like:
header("HTTP/1.1 202 Excel file in process");
and program in JavaScript a listener on the main js file for every time that status code arrives to activate an interval (setInterval()
) and ask every certain amount of seconds whether the Excel file is ready or not
$(document).ajaxSuccess(function ( event, xhr, settings) { if(xhr.status === 202) { //Activate the setInterval function to ask the server every 10 seconds whether the file is ready or not } });
(I know I have to be activating/deactivating the interval)
So whenever I receive a petition on my createExcel.php file I would like to respond the user immediately that the petition has being received and start the making of such Excel file(s)
Something like:
<?php //Tell user that the petition has being received header("HTTP/1.1 202 Excel file in process"); //Kill this process or close this connection but continue executing //Call createExcel.php
the createExcel.php file would update some table in the database the confirm the file has been created, same table that the interval petition will be consulting every 10 seconds
That’s what I’m attempting to do, I would just like you guys to tell me how to call another another file without waiting for such called file to finish to respond the user.
I was thinking of using exec()
but I have never used it (I’m testing it right after I post this), and most importantly any experience or tips would be greatly appreciated (like optimization tips and the like)
I saw this question here on Stack Overflow, but the answer suggests to create a cron service which is not a solution for me.
Thank you!
Edit—
Hey in case someone sees this I found two solutions to my question: The first one I tried but gave a lot of trouble with permissions is this: https://code-boxx.com/php-background-process/
But this one would work beautifully if you run it from cmd, but when you run it thought the browser, Apache forbids you from using executing commands; so exec()
, popen()
, and similar commandss won’t work unless you change your permissions in your folders, which I consider a security issue, so I found out this very beautiful function fastcgi_finish_request()
Edit 2 – solution https://qastack.mx/programming/15273570/continue-processing-php-after-sending-http-response this works we flush all content in buffer and close the connection and then we just continue the execution of the script.
Advertisement
Answer
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 PhpOfficePhpSpreadsheetSpreadsheet; use PhpOfficePhpSpreadsheetWriterXlsx; $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