ag.php
<?php
ignore_user_abort(true);
set_time_limit(0);
header("Cache-Control: no-cache, must-revalidate");
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
$i=0;
while(1){
echo $i;
$i++;
ob_flush();
flush();
if (connection_aborted()){
break;
}
usleep(1000000);
}
ajax:
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
console.log(xhttp.readyState+" "+xhttp.status);
if (xhttp.readyState === 3 && xhttp.status ===200) {
console.log(xhttp.responseText+"\n");
}
};
xhttp.open("GET", "ag.php", true);
xhttp.send();
hi, at above code, i want to make a persistent connection with php and echo data in while block in 1 second interval and data comes browser like this;
0
01
012
0123
...
but i want echo data to browser like;
0
1
2
3
...
but couldn't achive it so i found this [How to clear previously echoed items in PHP
about my question but not exactly what i want i think.
anybody know is there any way to empty/remove previous echoed data? is it possible? help please.
use substr()
var xhttp = new XMLHttpRequest();
var lastResponse = '';
xhttp.onreadystatechange = function() {
//console.log(xhttp.readyState+" "+xhttp.status);
if (xhttp.readyState === 3 && xhttp.status ===200) {
var currentAnswer = xhttp.responseText.substr(lastResponse.length);
lastResponse = xhttp.responseText;
console.log(currentAnswer+"\n");
}
};
xhttp.open("GET", "ag.php", true);
xhttp.send();
Perhaps ob_clean is what you are looking for.
void ob_clean ( void )
This function discards the contents of the output buffer.
This function does not destroy the output buffer like ob_end_clean() does.
The output buffer must be started by ob_start() with PHP_OUTPUT_HANDLER_CLEANABLE flag. Otherwise ob_clean() will not
work.
Related
I'm working on a one-way messaging system using server-sent events. I have a file (server.html) which sends the contents of a textarea to a PHP file (handler.php).
function sendSubtitle(val) {
var xhr = new XMLHttpRequest();
var url = "handler.php";
var postdata = "s=" + val;
xhr.open('POST', url, true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send(postdata);
//alert(val);
}
This works (alert(val) displays the text in the textarea).
My handler.php code looks like this:
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
$stringData = $_POST['s'];
echo "data: Data is {$stringData}\n\n";
flush();
And the relevant part of my SSE receiver file (client.html) is as follows:
if(typeof(EventSource) !== "undefined") {
var source = new EventSource("handler.php");
source.onmessage = function(event) {
var textarea = document.getElementById('subtitles');
textarea.value += event.data + "<br>";
textarea.scrollTop = textarea.scrollHeight;
};
} else {
document.getElementById("subtitles").value = "Server-sent events not supported.";
}
The problem is that client.html only displays "data: Data is", so the text from server.html is getting lost somewhere along the way. I imagine it's the PHP code that's falling over, but I can't work out what's wrong. If anyone can help, I'd appreciate it.
EDIT
I chose to use SSE as opposed to websockets as I only need one-way communication: server.html should push the contents of its textarea to client.html whenever it changes. All the examples of SSE that I've looked at (and I've looked at a lot!) send "automatic" time-based data. I haven't seen any that use real-time user input. So perhaps I should clarify my original question and ask, "How can I use SSE to update a DIV (or whatever) in web page B whenever the user types in a textarea in web page A?"
UPDATE
I've narrowed the issue down to the while loop in the PHP file and have therefore asked a new question: Server-side PHP event page not loading when using while loop
Assuming you want to send a value from server.html and a value at client.html will be automatically updated...
You will need to store the new value somewhere because multiple instances of a script do not share variables just like that. This new value can be stored in a file, database or as a session variable, etc.
Steps:
Send new value to phpScript1 with clientScript1.
Store new value with phpScript1.
Connect clientScript2 to phpScript2.
Send stored value to clientScript2 if it is changed.
Getting the new value 'on the fly' means phpScript2 must loop execution and send a message to clientScript2 whenever the value has been changed by clientScript1.
Of course there are more and different approaches to achieve the same results.
Below there's some code from a scratchpad I've used in previous project.
Most parts come from a class (which is in development) so I had to adopt quite a lot of code. Also I've tried to fit it into your existing code.
Hopefully I didn't introduce any errors.
Do note I did not take any validation of your value into account! Also the code isn't debugged or optimized, so it's not ready for production.
Client side (send new value, e.g. your code):
function sendSubtitle(val) {
var xhr = new XMLHttpRequest();
var url = "handler.php";
var postdata = "s=" + val;
xhr.open('POST', url, true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send(postdata);
//alert(val);
}
Server side (store new value):
<?php
session_start();
$_SESSION['s'] = $_POST['s'];
Client side (get new value):
//Check for SSE support at client side.
if (!!window.EventSource) {
var es = new EventSource("SSE_server.php");
} else {
console.log("SSE is not supported by your client");
//You could fallback on XHR requests.
}
//Define eventhandler for opening connection.
es.addEventListener('open', function(e) {
console.log("Connection opened!");
}, false);
//Define evenhandler for failing SSE request.
es.addEventListener('error', function(event) {
/*
* readyState defines the connection status:
* 0 = CONNECTING: Connecting
* 1 = OPEN: Open
* 2 = CLOSED: Closed
*/
if (es.readyState == EventSource.CLOSED) {
// Connection was closed.
} else {
es.close(); //Close to prevent a reconnection.
console.log("EventSource failed.");
}
});
//Define evenhandler for any response recieved.
es.addEventListener('message', function(event) {
console.log('Response recieved: ' + event.data);
}, false);
// Or define a listener for named event: event1
es.addEventListener('event1', function(event) {
var response = JSON.parse(event.data);
var textarea = document.getElementById("subtitles");
textarea.value += response + "<br>";
textarea.scrollTop = textarea.scrollHeight;
});
Server side (send new value):
<?php
$id = 0;
$event = 'event1';
$oldValue = null;
session_start();
//Validate the clients request headers.
if (headers_sent($file, $line)) {
header("HTTP/1.1 400 Bad Request");
exit('Headers already sent in %s at line %d, cannot send data to client correctly.');
}
if (isset($_SERVER['HTTP_ACCEPT']) && $_SERVER['HTTP_ACCEPT'] != 'text/event-stream') {
header("HTTP/1.1 400 Bad Request");
exit('The client does not accept the correct response format.');
}
//Disable time limit
#set_time_limit(0);
//Initialize the output buffer
if(function_exists('apache_setenv')){
#apache_setenv('no-gzip', 1);
}
#ini_set('zlib.output_compression', 0);
#ini_set('implicit_flush', 1);
while (ob_get_level() != 0) {
ob_end_flush();
}
ob_implicit_flush(1);
ob_start();
//Send the proper headers
header('Content-Type: text/event-stream; charset=UTF-8');
header('Cache-Control: no-cache');
header('X-Accel-Buffering: no'); // Disables FastCGI Buffering on Nginx
//Record start time
$start = time();
//Keep the script running
while(true){
if((time() - $start) % 300 == 0){
//Send a random message every 300ms to keep the connection alive.
echo ': ' . sha1( mt_rand() ) . "\n\n";
}
//If a new value hasn't been sent yet, set it to default.
session_start();
if (!array_key_exists('s', $_SESSION)) {
$_SESSION['s'] = null;
}
//Check if value has been changed.
if ($oldValue !== $_SESSION['s']) {
//Value is changed
$oldValue = $_SESSION['s'];
echo 'id: ' . $id++ . PHP_EOL; //Id of message
echo 'event: ' . $event . PHP_EOL; //Event Name to trigger the client side eventhandler
echo 'retry: 5000' . PHP_EOL; //Define custom reconnection time. (Default to 3000ms when not specified)
echo 'data: ' . json_encode($_SESSION['s']) . PHP_EOL; //Data to send to client side eventhandler
//Note: When sending html, you might need to encode with flags: JSON_HEX_QUOT | JSON_HEX_TAG
echo PHP_EOL;
//Send Data in the output buffer buffer to client.
#ob_flush();
#flush();
}
//Close session to release the lock
session_write_close();
if ( connection_aborted() ) {
//Connection is aborted at client side.
break;
}
if((time() - $start) > 600) {
//break if the time exceeds the limit of 600ms.
//Client will retry to open the connection and start this script again.
//The limit should be larger than the time needed by the script for a single loop.
break;
}
//Sleep for reducing processor load.
usleep(500000);
}
You called handler.php first time in the server.html and again in client.html. Both are different processes. The variable state won't be retained in the web server. You need to store it somewhere if you want that value in another PHP process. May be you can use sessions or database.
While using sessions you can store the values in two files like:
<?php
//server.php
session_start();
$_SESSION['s'] = $_POST['s'];
And in client.php
<?php
//client.php
session_start();
echo "data: Data is ".$_SESSION['s']."\n\n";
Trying to create a small notification system. When user fills out the profile then his verification status is set to 1 in database and then I would like to show a notification once that "hey you are now verified". Been searching a lot on the internet, but nothing has helped me to reach my goal. If the status is 1 in database I get the Event: verification_ok in the test.php but if it is 0 I get Maximum execution time of 120 seconds exceeded. Also I don't see any response in my client side code.
This is the server side code (test.php).
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header("Connection: Keep-alive");
require_once $_SERVER['DOCUMENT_ROOT'].'/PHP/scripts/no_session_redirect.php';
$key = true;
$ver = $user_home->runQuery("SELECT verification_status FROM verification WHERE user_id=:user_id");
$ver->execute(array(":user_id"=>$user_id));
$status = $ver->fetch(PDO::FETCH_ASSOC);
while($key){
if($status["verification_status"] == 1){
pushNotification($status["verification_status"]);
$key = false;
}else{
$status["verification_status"];
sleep(10);
}
}
function pushNotification() {
echo "Event: verification_ok\n";
}
And here is the client side code:
$(document).ready(function() {
if (typeof(EventSource) !== "undefined") {
// Yes! Server-sent events support!
var source = new EventSource("test.php");
source.addEventListener("verification_ok", function(e) {
console.log(e.data);
}, false);
source.addEventListener("open", function(e) {
}, false);
source.addEventListener("error", function(e) {
if (e.readyState == EventSource.CLOSED) {
console.log("Error - connection was lost.");
}
}, false);
} else {
// Sorry! No server-sent events support..
}
});
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>SSE</title>
<script type="text/javascript">
if (!!window.EventSource) {
var source = new EventSource("sse.php");
} else {
alert("Your browser does not support Server-sent events! Please upgrade it!");
}
source.addEventListener("message", function(e) {
console.log(e.data);
if(e.data){
x = document.getElementById("timer");
x.innerHTML=e.data;
console.log(e.data);
}else{
console.log(e.data);
e.close();
}
}, false);
source.addEventListener("open", function(e) {
console.log("Connection was opened.");
}, false);
source.addEventListener("error", function(e) {
console.log("Error - connection was lost."+e);
}, false);
</script>
</head>
<body>
<div id="timer"></div>
</body>
</html>
My Server Side Code
<?php
header("Content-Type: text/event-stream");
header("Cache-Control: no-cache");
header("Connection: keep-alive");
$lastId = 0;
while (true) {
$data =10;
if ($data) {
sendMessage($lastId, $data);
$lastId++;
$data--;
}else{
exit;
}
}
function sendMessage($id, $data) {
//echo "id: $id\n";
echo "$data\n\n";
ob_flush();
flush();
}
?>
What is wrong with my code? Please let me know.
SERVER-SIDE: normally this kind of demo has a sleep between sending each message. What it will do, as it stands, is send 10 packets out in the space of 10ms (or something).
So, the client will get them all at almost the same time, and you will see just the "1" in your timer <div>.
CLIENT-SIDE: It looks okay. It'd be useful to have seen what is being logged to console though. (Probably 10, 10, 9, 9, .., 1, 1, 10, 10, 9, 9, ... repeating forever - see next bit.)
BOTH: I think what will happen when you exit is that the socket will close, the browser will detect that and reconnect. Giving you the same sequence again!
Putting that altogether, change your server-side code main loop to something like:
while (true) {
$data =10;
if ($data) {
sendMessage($lastId, $data);
$lastId++;
$data--;
}else{
sendMessage($lastId, "0");
sleep(1); //Give client time to deal with it.
break;
}
sleep(1); //1 sec between messages
}
I.e. send an explicit "0" to tell the client to disconnect.
Then on the client-side, look out for that explicit close code. (Actually I'd go with "END" or something, as "0" is too easy to evaluated as boolean false!)
source.addEventListener("message", function(e) {
console.log(e.data);
if(e.data==="0")e.close();
else if(e.data){
x = document.getElementById("timer");
x.innerHTML=e.data;
}
//else do nothing
}, false);
I've simplified my code for uploading a file without iFrame or flash engine, and i came up to this ajax function:
<input type="file" name="uploadfile" id="myfile" /><label for="file" id="progress"></label>
<script src="js/jquery-1.7.1.min.js"></script>
<script>
function uploadFile(files) {
var xmlhttp;
if(window.XMLHttpRequest)
xmlhttp = new XMLHttpRequest();
else
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
xmlhttp.upload.onprogress = function(e) {
$("#progress").empty().append(e.loaded + " - " + e.total);
}
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
alert(xmlhttp.responseText + "DONE!");
}
}
xmlhttp.open("post", "post.php", true);
xmlhttp.setRequestHeader("If-Modified-Since", "Mon, 26 Jul 1997 05:00:00 GMT");
xmlhttp.setRequestHeader("Cache-Control", "no-cache");
xmlhttp.setRequestHeader("X-Requested-With", "XMLHttpRequest");
xmlhttp.setRequestHeader("X-File-Name", files[0].fileName);
xmlhttp.setRequestHeader("Content-Type", "multipart/form-data");
xmlhttp.send(files[0]);
}
$(document).ready(function() {
$("#myfile").change(function() {
uploadFile(this.files);
});
});
</script>
This is the php code which reply to the ajax function:
<?php
if(isset(
$_SERVER['CONTENT_TYPE'],
$_SERVER['CONTENT_LENGTH'],
$_SERVER['HTTP_X_FILE_NAME']
) &&
$_SERVER['CONTENT_TYPE'] == 'multipart/form-data'){
$file->name = basename($_SERVER['HTTP_X_FILE_NAME']);
$input = fopen('php://input', 'rb');
$file = fopen('files/'.$file->name, 'wb');
stream_copy_to_stream($input, $file);
fclose($input);
fclose($file);
} else {
echo "Error";
}
?>
The problem is, sometimes it works sometimes it bugs up while trying to upload the same file. I hope there is a solution to fix this issue. The code is simple, when i choose a file with input file type, the uploadFile function executes.
When it bugs out, i can see the file starting to be uploaded but it doesnt have the original size, so somewhere it could bug and stop uploading.
Thank you in advance, Daniel!
I'm not sure it is your problem, but you should anyway make sure your server allows for uploading large enough files and can handle them without timing out.
You can set this in code or php.ini (example in code:)
ini_set('memory_limit', '96M');
ini_set('post_max_size', '64M');
ini_set('upload_max_filesize', '64M');
Then, make sure your server does not time out:
$seconds=120;
set_time_limit ( $seconds );
All this code coes on the top of your PHP file.
I have a simple search form with a search box and a result box.
When I type a search word a request is created like: http://www.site.com/php_handler.php?s=hello
In the php script and a result is given back to the script this way:
<?php return $s; ?>
The problem is that my htmlrequest stops at readyState 3 it doesn't get to 4.
The javascript looks like this:
var xmlhttp = sajax_init_object();
function sajax_init_object() {
var A;
try {
A=new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
A=new ActiveXObject("Microsoft.XMLHTTP");
} catch (oc) {
A=null;
}
}
if(!A && typeof XMLHttpRequest != "undefined")
A = new XMLHttpRequest();
if (!A)
sajax_debug("Could not create connection object.");
return A;
}
function getSearchItem()
{
gs=document.forms.mainform.resultsfield;
var searchword=document.forms.mainform.searchform.value;
if (searchword.length>=3)
{
setWaitCursor();
clearResults();
var uri = "http://site.com/ajax_handler.php?s="+searchword;
console.log(uri);
xmlhttp.open("GET", uri, true);
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4) {
processResults(xmlhttp.responseText);
removeWaitCursor();
}else{
console.log(xmlhttp.readyState);
}
}
xmlhttp.send(null);
}
else
{
alert("please add at least 3 characters .");
}
}
Can someone tell me why it stops at 3?
edit: here is also the php code:
<?php
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
session_start();
//include main file
require_once($_SESSION["FILEROOT"] . "xsite/init.php");
//check if formulier is posted
$zoekterm = C_GPC::getGETVar("s");
$s="";
if ($zoekterm != "") {
$query="SELECT number,name,city,zib,zip_annex FROM articles WHERE version='edit' AND (naam LIKE '%$school%' OR brinnummer='$school') ORDER BY name";
if ($rs=C_DB::fetchRecordSet($query)) {
while ($row=C_DB::fetchRow($rs)) {
if ($row["plaats"]!="") {
$s.=$row["name"].", ".$row["city"]."|".$row["number"]."\n";
} else {
$s.=$row["name"].", ".$row["zip"].$row["zip_annex"]."|".$row["number"]."\n";
}
}
}
}
return $s;
?>
edit:
I missed a semicolon in my php script and now the ready state only gets to 2
edit:
The problem is even different. It gets to 4 but it doesn't show the result text.
1> Don't send Cache-Control: post-check=0, pre-check=0. These don't do what you think they do, and they're entirely unnecessary.
2> Your AJAX results page needs to send a Content-Length or Connection: Close header.
3> Try adding a random to your request URL to ensure you're not looking at a stale cache entry.
ReadyState 3 => Some data has been received
ReadyState 4 => All the data has been received
Maybe the XMLHTTPRequest object is still waiting for some data.
Are you sure your php script ends correctly ?
Is the content-length alright ?
To debug this you have two options, type the URL directly into the browser [since you are using a GET] and see what is happening.
OR
You can use a tool such as Fiddler and see what is exactly happening with the XMLHttpRequest