Prevent local caching of responses in HTTP streaming - php

I am trying to stream data read from a file to chrome client. I am able to stream data successfully but my responses are getting cached and I want to prevent that from happening. This situation is there because my flat file contains data entries which are independent of each other and i want to treat them likewise. For example, my file contains :
{idle_time:94125387364,system_time:98954710321,user_time:3683963615}
{idle_time:94125387789,system_time:98954710456,user_time:3683963845}
{idle_time:94125387876,system_time:98954710678,user_time:3683963986}
so instead of getting
{idle_time:94125387876,system_time:98954710678,user_time:3683963986}
(THIRD ENTRY)
as xmlhttprequest.responsetext, I receive
{idle_time:94125387364,system_time:98954710321,user_time:3683963615} <br/>
{idle_time:94125387789,system_time:98954710456,user_time:3683963845} <br/>
{idle_time:94125387876,system_time:98954710678,user_time:3683963986}
NOTE : I am not worried about breakline tags and blankspace.
My PHP script looks like this,
test.php
<?php
set_time_limit(0);
$filename = 'D:\Smoke_Test\data.txt';
function flush2 (){
echo(str_repeat(' ',256));
// check that buffer is actually set before flushing
if (ob_get_length()){
#ob_flush();
#flush();
#ob_end_flush();
}
#ob_start();
}
$file_last_modified_time = 0;
while(true)
{
$modified_time = filemtime($filename);
$processor_info = "";
if ($file_last_modified_time < $modified_time)
{
header("Expires: Sun, 20 Jan 1985 00:00:00 GMT"); // date in the past
header("Cache-Control: no-cache");
header("Pragma: no-cache");
$file_last_modified_time = $modified_time;
$handle = fopen($filename,"r");
$processor_info = fgets ($handle);
fclose ($handle);
#ob_clean();
echo $processor_info."<br/>";
//flush2();
}
flush2();
sleep(1);
clearstatcache(true, $filename);
}
?>
and my html page looks like this:
Home.htm
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1- transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title></title>
<script type="text/javascript" language = "javascript">
function read_file ()
{
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 || xmlhttp.readyState==3 ) //&& xmlhttp.status==200)
{
handle_data (xmlhttp.responseText);
}
}
xmlhttp.open("POST","test.php",true);
xmlhttp.send();
}
function handle_data (input)
{
document.getElementById("txtResponse").innerHTML=input;
}
</script>
</head>
<body>
<p>
<input type="button" id="dtnSendRequest" value="Send Request" onclick="read_file()"/>
</p>
<p>
response : <span id="txtResponse"></span>
<!-- <input type="text" id="txtResponse" width="500"/> -->
</p>
</body>
</html>

try adding this to the top of your php file
header("Expires: Sun, 20 Jan 1985 00:00:00 GMT"); // date in the past
header("Cache-Control: no-cache");
header("Pragma: no-cache");

Use this to force no-cache:
header("Cache-Control: no-cache, must-revalidate");
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");
Make sure you call this before sending any output.

You cant avoid whats happening with responseText. Its the nature of Http Streaming (not local or any caching) makes that happen. I found a very good article which states my situation as well as the solution.
The article is http://ajaxpatterns.org/archive/HTTP_Streaming.php
Following paragraph contains my situation as well as solution for it.
"The responseText property of XMLHttpRequest always contains the content that's been flushed out of the server, even when the connection's still open. So the browser can run a periodic check, e.g. to see if its length has changed. One problem, though, is that, once flushed, the service can't undo anything its output. For example, the responseText string arising from a timer service might look like this: "12:00:00 12:01:05 12:01:10", whereas it would ideally be just "12:00:00", then just "12:01:05", then just "12:01:10". The solution is to parse the response string and only look at the last value. To be more precise, the last complete value, since it's possible the text ends with a partial result. An example of this technique works in this way. To ease parsing, the service outputs each message delimited by a special token, "#END#" (an XML tag would be an alternative approach). Then, a regular expression can be run to grab the latest message, which must be followed by that token to ensure it's complete"

Related

How to clear previous output and echo in php

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.

PHP generated calendar in Google Calendar - not valid URL

I am a bit new to PHP.
I am trying to filter a ICS file for events containing a certain string. The following script seems to do that job just fine:
<?php
header('Content-type: text/calendar; charset=utf-8');
header('Content-Disposition: attachment; filename=fodda2009.ics');
header("Cache-Control: no-cache, must-revalidate");
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");
function icsFilter($paramUrl,$filterstring) {
$icsFile = file_get_contents($paramUrl);
$icsData = explode("BEGIN:", $icsFile);
foreach($icsData as $value) {
if (strpos($value, "VEVENT") === FALSE) {
echo "BEGIN:";
echo $value;
}
else {
if (strpos($value, $filterstring) !== FALSE) {
echo "BEGIN:";
echo $value;
}
}
}
}
?>
<?php echo icsFilter('http://cal.laget.se/ALMTUNAISHOCKEYSKOLA.ics','dda 2009'); ?>
VEVENT
DESCRIPTION:Dummy info
DTEND;TZID=W. Europe Standard Time:20001010T121500
DTSTAMP:20001005T192952Z
DTSTART;TZID=W. Europe Standard Time:20001010T110000
SUMMARY:Dummy event
UID:200abc01010T110000-8918999#stackoverflow.com
END:VEVENT
END:VCALENDAR
I am hosting the script at http://mydomain.dyndns.com/mycalendar.php. When I enter that URL into Google Calendar (other calendars -> add by URL) I receive a message "[your URL] is not a valid URL".
Is this caused by the script ending in .php?
Do I need to convince my server (Apache) to call the php script at a http://mydomain.dyndns.com/mycalendar.ics URL? How? Is there something else I am doing wrong?
OK, this is a little embarrassing...
The code above works just fine, the source of my error was that I left out the "http://" from the URL. Thus Google Calendar complained that it wasn't a good URL. cough Adding "http://" to my URL worked wonders :)
I'll leave the script here, maybe someone else wants to have a simple PHP script to filter an existing iCal file and serve it to Google Calendar.

HTTP push with multipart/x-mixed-replace php code not working

Have copied some code from the internet to try a HTTP push for images being constantly chnaged by another php code (basically attempting a streaming for images).
but the page does not seem to show any image at all. following is the complete code taken from http://www.howtocreate.co.uk/php/dnld.php?file=6&action=1
function doServerPush($file,$type,$poll) {
if( !file_exists($file) ) {
//on first load, the file must exist, or it ends up sending a broken file
header('Content-type: text/html',true,404);
}
#set_time_limit(0); //PHP must not terminate this script
#ignore_user_abort(false); //do not ignore user aborts (may not be allowed, so status is checked in the loop)
#ini_set( 'zlib.output_compression', 'off' );
$poll *= 1000;
//need a unique boundary
//while it is possible to get a unique boundary for the current image data, it is possible that it will conflict
//with future image data - can't help this, just have to live with it - might as well use a static string
$separator = 'MTWJ_serverpush_boundary_';
for( $i = 0, $randChars = Array('A','B'); $i < 20; $i++ ) {
$separator .= $randChars[rand(0,1)];
}
header('Cache-Control: no-cache');
header('Pragma: no-cache');
//the header that makes server push work
header("Content-Type: multipart/x-mixed-replace;boundary=$separator",true);
$extrabreaks = '';
do {
//send one file starting with a multipart boundary
$filelen = filesize($file);
print "$extrabreaks--$separator\n";
if( !$extrabreaks ) { $extrabreaks = "\n\n"; } //Safari needs exactly one blank line, no extra linebreaks on the first one
print "Content-Type: $type\n";
print "Content-Length: $filelen\n\n";
readfile($file);
//Safari needs 200+ bytes between headers - IE needs 256+ per flush, and this will also take care of that, when IE gets server push
print str_pad('',200-$filelen); //whitespace here is ignored because of content-length
$lastupdsate = filemtime($file);
ob_flush();
flush();
$looptime = time();
do {
clearstatcache(); //need updated file info
usleep($poll);
if( time() - $looptime >= 10 ) {
//every 10 seconds, force it to re-evaluate if the user has disconnected (connection_aborted does not know until this happens)
//most use-cases will not need this protection because they will keep trying to send updates, but it is here just in case
$looptime = time();
print ' '; //whitespace is ignored at this specific point in the stream
ob_flush();
flush();
}
//poll the filesystem until the file changes, then send the update
//the file may not always exist for the instant it is being replaced on the filesystem
//nested loop and filemtime check inspired by http://web.they.org/software/php-push.php
} while( !connection_aborted() && ( !file_exists($file) || ( $lastupdsate == filemtime($file) ) ) );
} while( !connection_aborted() ); //if aborts are ignored, exit anyway to avoid endless threads
}
?>
the php file calling the code is as follows:
require ("serverpush.php");
doServerPush("img.jpg",'image/jpeg',75);
and the html is as follows:
<html>
<head>
<title>Streaming</title>
<style type="text/css" media="screen">
img
{
width: 200px;
height: 200px;
border: 2px solid #ABCDEF;
}
</style>
</head>
<body>
<h1>Image stream test</h1>
<img src="Stream.php" alt="Stream Image" />
</body>
</html>
any assistance will be apprecited. have tried to run the code in Firefox and Chrome

IE not populating select through ajax request

Hi I have two dropdowns and I am populating second one on the basis of first one. My first select is
<select name="projects" id="projects" onchange="populate_users(this.value);">
<option value='1'>ABC</option>
<option value='2'>DEF</option>
</select>
And I populate second select box on the basis of first one which is
<select name="users" id="users">
</select>
Here is my populate_users method
function populate_users(project_id)
{
var url='<?php echo($this->url(array(),'admin/clientproject1'));?>';
url2=url+'project_id='+project_id;
//alert(url2);
jQuery('#users').html('<div style="position:absolute;">'+jQuery('#users').html());
//ajax call
jQuery.ajax({url:url2,success:function(data){jQuery('#users').html(data);}});
}
And on admin/clientproject1 I simply query to table and start a loop to draw options like this
$rd=$db->fetchAll($q);
for($i = 0; $i < count($rd); $i++)
{
?>
<option value="<?php echo($rd[$i]->id);?>">
<?php echo($rd[$i]->username);?></option>
<?php
}
?>
$rd is having values. The second select is populated and all values are showing in
Firefox but in IE it is just showing blank dropdown and not showing any error.
You should return a json string of values and create the option elements in javascript. Then inject those option elements into your select. A bit more coding, but it's better.
Whenever I see the words AJAX, IE, and not populating, I think of the IE cache and how it doesn't play nice with AJAX. Since the issue is browser based, I don't see how it can be a problem with your actual php and the formatting appears to be correct, maybe try setting some headers in the php page that is querying the db.
header("Expires: Sun, 19 Nov 1978 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");
My solution is create the 'option adding' in server and javascript 'eval' in client the passing Ajax result:
Server Sample PHP code Populate Select :
leetablaIE.php :
$DBName=$_GET["db"];
$tabla=$_GET["tabla"];
$Query=$_GET["query"];
$id=$_GET["id"];
$User="???????";
$Host="????????";
$Password="????????";
$Link=mysql_connect( $Host, $User, $Password);
if (!$Link) {
die('Could not connect: ' . mysql_error());
}
mysql_select_db($DBName, $Link) or die('Could not select database.');
$Result=mysql_db_query ($DBName , $Query , $Link);
echo 'var obj_option;';
echo "obj_option = document.createElement('option');" ;
echo "obj_option.setAttribute('value', '');";
echo "obj_text = document.createTextNode('".utf8_encode('Select Value')."');" ;
echo "obj_option.appendChild(obj_text);";
echo "document.getElementById('$id')".".appendChild(obj_option);"; //myselect
while($Row = mysql_fetch_array($Result)) {
$valor=utf8_encode($Row[0]);
$texto=utf8_encode($Row[1]);
echo "obj_option = document.createElement('option');" ;
echo "obj_option.setAttribute('value', '".$valor."');";
echo "obj_text = document.createTextNode(\"".$texto."\");" ;
echo "obj_option.appendChild(obj_text);";
echo "document.getElementById('$id')".".appendChild(obj_option);"; //myselect
}
mysql_free_result($Result);
in Javascript Client :
function leetabla(db,tabla,query,id,bro){
// bro = passing browser ex: MSIE
// id = passing id select to populate in example myselect
// db = database
// tabla = table (mysql id this case)
// query = query you need to populate ('select ....')
////////////////////////////////////////////////////
if (window.XMLHttpRequest)
{
xmlhttp=new XMLHttpRequest();
}
else
{
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
if(bro!='MSIE'){
document.getElementById(id).innerHTML="";
document.getElementById(id).innerHTML=xmlhttp.responseText;
}
else
{
//alert(xmlhttp.responseText);
eval(xmlhttp.responseText);
}
}
}
if(bro!='MSIE'){
//alert(query);
//normal populate code not in this code 'leetabla.php'
xmlhttp.open("GET","leetabla.php? db="+db+"&tabla="+tabla+"&query="+query+"&id="+id,true);
}
else
{
//alert(query);
// call to php script to IE case leetablaIE.php (upper sample)
xmlhttp.open("GET","leetablaIE.php? db="+db+"&tabla="+tabla+"&query="+query+"&id="+id,true);
}
xmlhttp.send();
}

xmlhttprequest onlys gets to status 3

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

Categories