There is a question bothering me, pls help!
I use jquery's ajax to call a php api.
$.ajax({
type:"POST",
dataType:"json",
data:{type:type,fid:fid,model:'star'},
url:'Recommend/Star/mark',
success:function (data) {
//do something
},
...
});
php code in Recommend/Star/mark method:
error_reporting(0);
set_time_limit(0);
ob_implicit_flush(true);
ob_end_clean();
ob_start ();
echo json_encode($boolMark);
ob_flush();
flush();
sleep(3);
$this->afterMark($uid, $fid);
I want php echo result to ajax immediately, but my codes do not work.
How to make php send result to ajax immediately, and continue to execute remaining code?
....
echo json_encode($boolMark . "<br>\n");
// get the size of the output
$size = ob_get_length();
// send headers to tell the browser to close the connection
header("Content-Length: $size");
header('Connection: close');
ob_end_flush();
ob_flush();
flush();
/******** background process starts here ********/
ignore_user_abort(true);
/******** background process ********/
set_time_limit(0); //no time limit
/******** Rest of your code starts here ********/
You also need to call these two functions after flush():
session_write_close();
fastcgi_finish_request();
Related
On a page I have buttons to launch and cancel tasks to be performed in PHP on the server side. While these PHP tasks are running the user cannot navigate away from the page, it just hangs up until the job is done. I'm trying to find what's causing the synchronous behavior.
Jquery:
$(document).ready(function()
{
var id = 0;
$('#tool-execute-btn').click(function()
{
// Pull data from page
var last_response_len = false;
$.ajax(
{
xhrFields:
{
onprogress: function(e)
{
var this_response, response = e.currentTarget.response;
if(last_response_len === false)
{
this_response = response;
last_response_len = response.length;
}
else
{
this_response = response.substring(last_response_len);
last_response_len = response.length;
}
// Get the data from the stream (backend php)
$('#tool-output-area').append(this_response + '<br>');
}
},
method: 'POST',
url: 'run-tool.php', // See block below
data:
{
// Data from page
}
}) // ... Continue
The backend processing PHP page:
/* Setup the page so I can stream the content
* line by line back to the user */
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
/* Set Maximum Execution Time By Plan */
ini_set('max_execution_time', getMaxExeTime());
ini_set('output_buffering', 'off');
ini_set('zlib.output_compression', false);
ini_set('implicit_flush', true);
ob_implicit_flush(true);
while (ob_get_level() > 0)
{
$level = ob_get_level();
ob_end_clean();
if (ob_get_level() == $level) break;
}
if (function_exists('apache_setenv'))
{
apache_setenv('no-gzip', '1');
apache_setenv('dont-vary', '1');
}
/* This section runs a ping and echos out the terminal window */
$descriptorspec =
[
0 => ['pipe', 'r'],
1 => ['pipe', 'w'],
2 => ['pipe', 'w']
];
// Input checking for the post data and interaction with a MySQL database is done here
$tool_command = 'ping 8.8.8.8 -n 10';
$process = proc_open($tool_command, $descriptorspec, $pipes);
stream_set_blocking($pipes[1], false);
stream_set_blocking($pipes[2], false);
$proc_details = proc_get_status($process);
while ($s = fgets($pipes[1]))
{
echo $s;
flush();
sleep(0.3);
}
If at any time during this while loop the user attempts to reload the page, they will just get the tab loading icon. If I attempt to run another PHP script from jQuery, it'll just queue until the while loop is done. What is causing the problem here? PHP, Ajax, the apache server, HTTP requests, something else?
When you use session variables in a script, only one script invocation can access the same session at a time, and PHP blocks any other scripts from the same client.
Use session_write_close() in the script when it's done accessing the session variables, which will allow another script to run. If it needs to access session variables again, it needs to call session_start() again.
This code works well in apache. It pushes a message to the client every second.
But it doesn't work in appweb. Instead, it pushes a message to the client when all message are collected
This is the php code:
<?php
set_time_limit(0);
ob_start();
$i = 1;
while ($i<10) {
echo $i++;
ob_flush();
flush();
sleep(1);
}
?>
I used the default configuration.
PHP how to display a message "newsletter sent, can close page" before sending function is complete?Thank you.
function myfun(){
if(!ob_start("ob_gzhandler"))
ob_start();
$mail_id = $id;
include($_SERVER['DOCUMENT_ROOT']."/newsletter/".$template);// include a newsletter template
$htmltext = ob_get_contents();
ob_end_clean();
ob_end_flush();
ob_flush();
flush();
// close current session
if (session_id())
session_write_close();
sleep(2);
sendmail($htmltext); //sendo more then 2000 whith PHPmailer
}
hey You can simple echo the code of an alert script to display your message. As I am doing below:
echo '<script type="text/javascript">
alert("Your Message");
</script>';
You can even wrap this in a function provide your message as a parameter and call it any where you want to display your message.
I'm new to Server Side Events and started some tests with PHP on the server side and Python on the client side using the sseclient library.
Using a very basic PHP script, based on the w3schools tutorial I can see the data being received in Python:
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
function sendMsg($id, $msg) {
echo "id: $id" . PHP_EOL;
echo "data: $msg" . PHP_EOL;
echo PHP_EOL;
ob_flush();
flush();
}
$time = date('r');
// echo "data: The server time is: {$time}\n\n";
// flush();
sendMsg(time(),"The server time is: {$time}\n\n");
?>
and in Python:
#!/usr/bin/env python
from sseclient import SSEClient
messages = SSEClient('http://pathto/myscript.php')
for msg in messages:
print msg
As a second step I've tried sending data read from an array stored in the $_SESSION variable. This seems to work when I connect to the SSE stream from javascript in the browser, but it doesn't work and I'm not sure why.
Here's my basic PHP script:
<?php
session_start();
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
function sendMsg($id, $msg) {
echo "id: $id" . PHP_EOL;
echo "data: $msg" . PHP_EOL;
echo PHP_EOL;
ob_flush();
flush();
}
// check for session data
if (isset($_SESSION["data"])){
#as long there are elements in the data array, stream one at a time, clearing the array (FIFO)
while(count($_SESSION["data"]) > 0){
$serverTime = time();
$data = array_shift($_SESSION["data"]);
sendMsg($serverTime,$data);
}
}
?>
and the Python script is the same.
Why isn't the sseclient Python script picking up the events from the above PHP script (while a basic JS one does) ?
The PHP session variable is sent as a cookie; if you view your JavaScript version with Firebug (or equivalent) you should see the cookie being sent to the SSE server script.
So you'll need to set up a session for the Python script, and have it send that in a cookie too.
You could confirm this guess by adding some error handling to your PHP script:
...
if (isset($_SESSION["data"])){
//current code here
}else{
sendMsg(time(), "Error: no session");
}
I'm using Laravel and I need to output data as it happens. When I attempt to load the page outside Laravel, it works just fine. If I use this inside Laravel, it doesn't flush, it waits until the end and prints the results.
view.php
<?php
if (ob_get_level() == 0) ob_start();
for ($i = 0; $i <= 10; $i++){
echo "<br> Line to show. $i";
echo str_pad('',4096)."\n";
ob_flush();
flush();
sleep(1);
}
ob_end_flush();
?>
Figured it out, I needed to add ob_flush();
Update, for anyone coming here.
The above solutions didn't work for me. What worked, is adding the
header('X-Accel-Buffering: no');
before any output.
Found it here: https://laracasts.com/discuss/channels/laravel/live-output-in-blade-template-ob-flush
This sequence worked for me.
ob_implicit_flush(true);
echo "Processing ... "; // Or give out JSON output
ob_flush();
sleep(5); //A time-consuming synchronous process (SMTP mail, maybe?)
echo "Done";