PHP - Flushing While Loop Data with Ajax

PHP - Flushing While Loop Data with Ajax

Using:

  • jQuery kill ajax request
  • ignore_user_abort()
  • ob_flush()

should do all you need in one php thread

EDIT

Take a look at nickb's answer, if you're looking for a way how to do this simply it would be following algorithm:

  1. javascript opens process.php via ajax (which will do all the work AND print status reports), you have to look up whether jQuery ajax supports continuous loading
  2. if user decides to stop refreshes you'll kill loading as show in provided link

In process.php:

ignore_user_abort(); // Script will finish in background
while(...){
echo "Page: $i\n";
ob_flush();
}

EDIT 2 requested example (bit of different and ugly, but simple). test_process.php:

// This script will write numbers from 1 to 100 into file (whatever happens)
// And sends continuously info to user
$fp = fopen( '/tmp/output.txt', 'w') or die('Failed to open');
set_time_limit( 120);
ignore_user_abort(true);

for( $i = 0; $i < 100; $i++){
echo "<script type=\"text/javascript\">parent.document.getElementById( 'foo').innerHTML += 'Line $i<br />';</script>";
echo str_repeat( ' ', 2048);
flush();
ob_flush();
sleep(1);
fwrite( $fp, "$i\n");
}

fclose( $fp);

And main html page:

<iframe id="loadarea"></iframe><br />
<script>
function helper() {
document.getElementById('loadarea').src = 'test_process.php';
}
function kill() {
document.getElementById('loadarea').src = '';
}
</script>

<input type="button" onclick="helper()" value="Start">
<input type="button" onclick="kill()" value="Stop">
<div id="foo"></div>

After hitting start lines as:

Line 1
Line 2

Appeared in the div #foo. When I hit Stop, they stopped appearing but script finished in background and written all 100 numbers into file.

If you hit Start again script starts to execute from the begging (rewrite file) so would parallel request do.

For more info on http streaming see this link

Flush data in php complex loop

I'd try adding ob_flush() in there.

Edit: in your first code , just put ob_flush() after your first flush()
and see how that works.

http://php.net/manual/en/function.flush.php

flush() may not be able to override the buffering scheme of your web
server and it has no effect on any client-side buffering in the
browser. It also doesn't affect PHP's userspace output buffering
mechanism. This means you will have to call both ob_flush() and
flush() to flush the ob output buffers if you are using those.

While Loop update first Row data only when use with AJAX PHP

This is the general idea. I don't know if I caught all the problems.

What if instead of:

if ($already_like == 1) { ?>

<button class="unlikebtn" name="unlike" id="unlike_btn">
<span class="like_toggle">
<svg aria-label="Unlike" class="like_ico" fill="#ed4956" height="24" viewBox="0 0 48 48" width="24">
<path clip-rule="evenodd" d="M35.3 35.6c-9.2 8.2-9.8 8.9-11.3 8.9s-2.1-.7-11.3-8.9C6.5 30.1.5 25.6.5 17.8.5 9.9 6.4 3.5 13.7 3.5 20.8 3.5 24 8.8 24 8.8s3.2-5.3 10.3-5.3c7.3 0 13.2 6.4 13.2 14.3 0 7.8-6.1 12.3-12.2 17.8z" fill-rule="evenodd">
</path>
</svg>
</span>
</button>
<input type="text" name="post_id" id="post_u_id" hidden="true" value="<?php echo $post_id ?>">
<a href="post.php?id=<?php echo $post_id?>">
<svg aria-label="Comment" class="comment_ico " fill="#262626" height="24" viewBox="0 0 48 48" width="24">
<path clip-rule="evenodd" d="M47.5 46.1l-2.8-11c1.8-3.3 2.8-7.1 2.8-11.1C47.5 11 37 .5 24 .5S.5 11 .5 24 11 47.5 24 47.5c4 0 7.8-1 11.1-2.8l11 2.8c.8.2 1.6-.6 1.4-1.4zm-3-22.1c0 4-1 7-2.6 10-.2.4-.3.9-.2 1.4l2.1 8.4-8.3-2.1c-.5-.1-1-.1-1.4.2-1.8 1-5.2 2.6-10 2.6-11.4 0-20.6-9.2-20.6-20.5S12.7 3.5 24 3.5 44.5 12.7 44.5 24z" fill-rule="evenodd">
</path>
</svg>
</a>

<?php } elseif($already_like == 0){ ?>

<button name="like" class="likebtn" id="like_btn" data-itemID="<?php echo $post_id?>">
<span class="like_toggle">
<svg aria-label="Like" class="like_ico" fill="#262626" height="24" viewBox="0 0 48 48" width="24">
<path clip-rule="evenodd" d="M34.3 3.5C27.2 3.5 24 8.8 24 8.8s-3.2-5.3-10.3-5.3C6.4 3.5.5 9.9.5 17.8s6.1 12.4 12.2 17.8c9.2 8.2 9.8 8.9 11.3 8.9s2.1-.7 11.3-8.9c6.2-5.5 12.2-10 12.2-17.8 0-7.9-5.9-14.3-13.2-14.3zm-1 29.8c-5.4 4.8-8.3 7.5-9.3 8.1-1-.7-4.6-3.9-9.3-8.1-5.5-4.9-11.2-9-11.2-15.6 0-6.2 4.6-11.3 10.2-11.3 4.1 0 6.3 2 7.9 4.2 3.6 5.1 1.2 5.1 4.8 0 1.6-2.2 3.8-4.2 7.9-4.2 5.6 0 10.2 5.1 10.2 11.3 0 6.7-5.7 10.8-11.2 15.6z" fill-rule="evenodd">
</path>
</svg>
</span>
</button>
<a href="post.php?id=<?php echo $post_id?>">
<svg aria-label="Comment" class="comment_ico " fill="#262626" height="24" viewBox="0 0 48 48" width="24">
<path clip-rule="evenodd" d="M47.5 46.1l-2.8-11c1.8-3.3 2.8-7.1 2.8-11.1C47.5 11 37 .5 24 .5S.5 11 .5 24 11 47.5 24 47.5c4 0 7.8-1 11.1-2.8l11 2.8c.8.2 1.6-.6 1.4-1.4zm-3-22.1c0 4-1 7-2.6 10-.2.4-.3.9-.2 1.4l2.1 8.4-8.3-2.1c-.5-.1-1-.1-1.4.2-1.8 1-5.2 2.6-10 2.6-11.4 0-20.6-9.2-20.6-20.5S12.7 3.5 24 3.5 44.5 12.7 44.5 24z" fill-rule="evenodd">
</path>
</svg>
</a>
<?php } ?>

and

<div class="add_a_comment">

<div class="add_comment_section">
<span class="hor-line">
</span>
<div>
<textarea contenteditable aria-label="Add a comment…" placeholder="Add a comment…" class="addcomment_ta" autocomplete="off" autocorrect="off" id="comment_content" name="comment_content" id="editable_comment">
</textarea>
</div>
<div class="post_btn">
<button id="btn_comment" >POST
</button>
</div>
</div>
<input type="text" name="post_id" id="post_id" hidden="true" value="<?php echo $row['post_id'] ?>">

</div>

We get rid of the hidden input tag that holds the $post_id and instead use that as the id for the button:

if ($already_like == 1) { ?>

<button class="unlikebtn" name="unlike" id="<?php echo $post_id ?>">
<span class="like_toggle">
<svg aria-label="Unlike" class="like_ico" fill="#ed4956" height="24" viewBox="0 0 48 48" width="24">
<path clip-rule="evenodd" d="M35.3 35.6c-9.2 8.2-9.8 8.9-11.3 8.9s-2.1-.7-11.3-8.9C6.5 30.1.5 25.6.5 17.8.5 9.9 6.4 3.5 13.7 3.5 20.8 3.5 24 8.8 24 8.8s3.2-5.3 10.3-5.3c7.3 0 13.2 6.4 13.2 14.3 0 7.8-6.1 12.3-12.2 17.8z" fill-rule="evenodd">
</path>
</svg>
</span>
</button>
?>">
<a href="post.php?id=<?php echo $post_id?>">
<svg aria-label="Comment" class="comment_ico " fill="#262626" height="24" viewBox="0 0 48 48" width="24">
<path clip-rule="evenodd" d="M47.5 46.1l-2.8-11c1.8-3.3 2.8-7.1 2.8-11.1C47.5 11 37 .5 24 .5S.5 11 .5 24 11 47.5 24 47.5c4 0 7.8-1 11.1-2.8l11 2.8c.8.2 1.6-.6 1.4-1.4zm-3-22.1c0 4-1 7-2.6 10-.2.4-.3.9-.2 1.4l2.1 8.4-8.3-2.1c-.5-.1-1-.1-1.4.2-1.8 1-5.2 2.6-10 2.6-11.4 0-20.6-9.2-20.6-20.5S12.7 3.5 24 3.5 44.5 12.7 44.5 24z" fill-rule="evenodd">
</path>
</svg>
</a>

<?php } elseif($already_like == 0){ ?>

<button name="like" class="likebtn" id="<?php echo $post_id?>">
<span class="like_toggle">
<svg aria-label="Like" class="like_ico" fill="#262626" height="24" viewBox="0 0 48 48" width="24">
<path clip-rule="evenodd" d="M34.3 3.5C27.2 3.5 24 8.8 24 8.8s-3.2-5.3-10.3-5.3C6.4 3.5.5 9.9.5 17.8s6.1 12.4 12.2 17.8c9.2 8.2 9.8 8.9 11.3 8.9s2.1-.7 11.3-8.9c6.2-5.5 12.2-10 12.2-17.8 0-7.9-5.9-14.3-13.2-14.3zm-1 29.8c-5.4 4.8-8.3 7.5-9.3 8.1-1-.7-4.6-3.9-9.3-8.1-5.5-4.9-11.2-9-11.2-15.6 0-6.2 4.6-11.3 10.2-11.3 4.1 0 6.3 2 7.9 4.2 3.6 5.1 1.2 5.1 4.8 0 1.6-2.2 3.8-4.2 7.9-4.2 5.6 0 10.2 5.1 10.2 11.3 0 6.7-5.7 10.8-11.2 15.6z" fill-rule="evenodd">
</path>
</svg>
</span>
</button>
<a href="post.php?id=<?php echo $post_id?>">
<svg aria-label="Comment" class="comment_ico " fill="#262626" height="24" viewBox="0 0 48 48" width="24">
<path clip-rule="evenodd" d="M47.5 46.1l-2.8-11c1.8-3.3 2.8-7.1 2.8-11.1C47.5 11 37 .5 24 .5S.5 11 .5 24 11 47.5 24 47.5c4 0 7.8-1 11.1-2.8l11 2.8c.8.2 1.6-.6 1.4-1.4zm-3-22.1c0 4-1 7-2.6 10-.2.4-.3.9-.2 1.4l2.1 8.4-8.3-2.1c-.5-.1-1-.1-1.4.2-1.8 1-5.2 2.6-10 2.6-11.4 0-20.6-9.2-20.6-20.5S12.7 3.5 24 3.5 44.5 12.7 44.5 24z" fill-rule="evenodd">
</path>
</svg>
</a>
<?php } ?>

and we create a form with a name for adding a comment so that we can get the value of the post id using document.add_comment.post_id.value:

<div class="add_a_comment">
<div class="add_comment_section">
<span class="hor-line">
</span>
<div>
<form name="add_comment">
<textarea contenteditable aria-label="Add a comment…" placeholder="Add a comment…" class="addcomment_ta" autocomplete="off" autocorrect="off" id="comment_content" name="comment_content" id="editable_comment">
</textarea>
<div class="post_btn">
<id="btn_comment">POST</button>
</div>
<input type="text" name="post_id" hidden="true" value="<?php echo $row['post_id'] ?>">
</div>
</div>
</div>

Then the JavaScript becomes:

$(document).ready(function(){
$("#btn_comment").click(function(){
$.post("inc/add_comment.php" ,
{
comment_content: $("#comment_content").val(),
post_id: document.add_comment.post_id.value
},
function(data){
alert("data");
})

});
});
$(document).ready(function() {
$(".likebtn").click(function() {
let post_u_id = $(this).attr('id');
$.post("inc/like.php",
{
post_u_id: post_u_id
},
function(data){
})
});
});
$(document).ready(function() {
$(".unlikebtn").click(function() {
let post_u_id = $(this).attr('id');
$.post("inc/unlike.php",
{
post_id: post_u_id
},
function(data){
})
});
});

Suggestion

You are currently using AJAX to delete, update and add comments. But you are neglecting to update the presentation (the DOM) on return from a successful AJAX call. For example, on a successful delete of a comment you should be removing the comment from the DOM. If a comment is "unliked", it should now be shown as an unliked comment. Since you are not doing any of this, it would be better not to be using AJAX at all and to just instead create forms like the following:

You should reorganizing your HTML so that you create forms for each comment. An example:

<form action="inc/unlike.php" method="post">
<input type="hidden" name="post_id" value="<?php echo $post_id ?>">
<button type="submit">
<span class="like_toggle">
<svg aria-label="Unlike" class="like_ico" fill="#ed4956" height="24" viewBox="0 0 48 48" width="24">
<path clip-rule="evenodd" d="M35.3 35.6c-9.2 8.2-9.8 8.9-11.3 8.9s-2.1-.7-11.3-8.9C6.5 30.1.5 25.6.5 17.8.5 9.9 6.4 3.5 13.7 3.5 20.8 3.5 24 8.8 24 8.8s3.2-5.3 10.3-5.3c7.3 0 13.2 6.4 13.2 14.3 0 7.8-6.1 12.3-12.2 17.8z" fill-rule="evenodd">
</path>
</svg>
</span>
</button>
</form>

Your unlike.php script would then complete by redirecting back to index.php to recreate an updated presentation.

PHP flush loop with Ajax

https://www.php.net/manual/en/function.ob-implicit-flush.php

implicit-flush will help you.

And, you modify 'xmlhttp.readyState==4' to 'xmlhttp.readyState==3'

PHP while loop, update information to page using ajax

Having posted a comment saying "You can't do it in a single instance of PHP" I will now go ahead and prove myself wrong.

It is possible to do this using a sort of server push setup. Consider the following code:

<?php

// Do all your preliminary stuff here

?>
<html>
<head>
<title>Server push demo</title>
<script type="text/javascript">
function updateTries(tries) {
document.getElementById('num_tries').innerHTML = tries;
}
function pushEvent(str) {
var event = document.createElement('div');
event.innerHTML = str;
document.getElementById('stream_container').appendChild(event);
}
</script>
</head>
<body>
<div>
Number of tries:
<span id="num_tries"></span>
</div>
<div id="stream_container"></div>
<?php

// Push all output so far to the client
flush();

// Start status check loop
CheckStatus($tries, $device, $deviceip, $deviceport, $devicemac1, $devicemac2, $maxtries, $broadcast, $udport, $timeout);

function CheckStatus($tries, $device, $deviceip, $deviceport, $devicemac1, $devicemac2, $maxtries, $broadcast, $udport, $timeout){

while ($tries < $maxtries) {

echo "<script type='text/javascript'>updateTries($tries);</script>";
flush();

if (portcheck($deviceip, $deviceport) != 0){

echo "<script type='text/javascript'>pushEvent('Could NOT open connection to $device at $deviceip on port $deviceport');</script>";
flush();

} else {

echo "<script type='text/javascript'>pushEvent('TESTED OKAY! $device');</script>";
flush();
return TRUE;

}

$tries++;

}

echo "<script type='text/javascript'>pushEvent('MAX TRIES REACHED... COULD NOT CONNECT!');</script>";
flush();
return FALSE;

}

?>
</body></html>

However, I still maintain it is better to abstract the loop to the client side and use AJAX to poll the server, which performs one check at a time.

Flush problem with ajax

HTTP-Streaming can not be done simply using $.get

insert <script> tags as following: http://ajaxpatterns.org/archive/HTTP_Streaming.php.

 <?
while (true) {
?>
<script type="text/javascript">
$('news').innerHTML = '<?= getLatestNews() ?>';
</script>
<?
flush(); // Ensure the Javascript tag is written out immediately
sleep(10);
}
?>

HTTP-streaming is a very complicated hack. You should consider using long-polling instead which works in every browser. It seems there are some solutions (slide 54)

Simple long-polling example topic:

How do I implement basic "Long Polling"?

This video shows how to do long-polling: http://www.screenr.com/SNH

P.S: this will kill your(bad performance) server for sure. You should have a look at http://pusherapp.com which is free for small sites.

echo/print issue in php while loop

Nice that everyone explained why.

This is because by default PHP will process everything before it 'flushed' anything out to the browser. By just printing each line, it's storing that information in the buffer which will all be printed simultaneously once PHP is finished executing.

If you want PHP to flush that content to the browser immediately after the line, you need to call flush() after each one, then it will output the text one line at a time after each one is called.

AJAX live feed from PHP

Sorry but to you can do this you need create this logic on the front-end with javascript/jQuery and use only back-end(php) to get the feeds.

setInterval(function(){
//jQuery code..
$.ajax({
url: 'url_to_get_feeds',
data: {}, //if need put some param on request
success: function(callback){
//logic to put call content to html
//callback recive all content gerenated on the page 'url_to_get_feeds'
$('body').append(callback)
}
})
});


Related Topics



Leave a reply



Submit