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:
- 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 - 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
Why Does PHP Not Complain When I Treat a Null Value as an Array Like This
What Is a Good Method to Sanitize the Whole $_Post Array in PHP
Single Session Login in Laravel
PHP Soap Client That Understands Multi-Part Messages
Creating an Image Without Storing It as a Local File
How to Call a Python Script from PHP
Chart.Js - Getting Data from Database Using MySQL and PHP
What Is the Postman-Token Header Attribute in Generated Code from Postman
What Does the Dot-Slash Do to PHP Include Calls
Check If String Contains Word in Array
Codeigniter: 404 Page Not Found on Live Server
Make a Https Request Through PHP and Get Response
Apple Sign in "Invalid_Client", Signing Jwt for Authentication Using PHP and Openssl