I am running a shell script in the background and redirecting the output to a log file in php. I want to display the contents from the log file on the page. I am able to do that using the code below.
<?php
$logfile = "hello";
?>
function displayOutput()
{
var html = <?php
echo filesize($logfile)
? json_encode(file_get_contents($logfile))
: '"Log file is getting generated"';
?>;
document.form.text1.value = html;
}
However, the log file keeps updating till the script completes executing. How can i reload the updated contents from the file on the same page?
The technique that I developed + discuss here may be useful:
https://web.archive.org/web/20150206001444/http://commavee.com/2007/04/13/ajax-logfile-tailer-viewer/
It's been around for a while + works well.
You need to set an interval timer to call your function every n seconds. Have a look at this answer to help you out - how to schedule ajax calls every N seconds?.
setInterval(displayOutput, (10 * 1000));
// reload log contents every 10 seconds
Maybe what you want basic XMLHttpRequest usage.
I am not really php guy, neiter javascript guru, just trying to give you an idea
function refreshText()
{
if (window.XMLHttpRequest)
{
xhttp = new XMLHttpRequest();
}
else // for IE 5/6, just in case
{
xhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xhttp.open("GET","/page.php?action=download_log_file", false);
xhttp.send();
document.form.text1.value = xhttp.responseXML;
}
setInterval(refreshText, (10 * 1000)); // refresh text1.value every 10 seconds
same thing using jQuery
setInterval(function {
$.get('/page.php?action=download_log_file', function(data) {
$('#text1').val(data);
});
}, (10 * 1000));
The handler script at the server just prints file data, see
http://www.w3schools.com/xml/xml_server.asp for example
I've implemented "COMET-like" functionality recently to do just this. The way it works is to have an AJAX poll with a long timeout:
var lines = 0
function getLog(file, lines) {
$.ajax({
type: 'POST',
url: 'http://thissite.com/getLogFile.php?File=' + file + '&Lines=' + lines,
dataType: 'json',
timeout: 400000,
error:
function() {
return false;
},
success:
function(data) {
if (data.Error) {
alert(data.Message)
} else {
if (data.Lines > lines) {
// do something with data.LogLines, e.g. add to a textarea
}
getLogFile(file, data.Lines)
}
}
})
}
The back end script then simply loops like this:
Count the number of lines in the log file
If it's the same as lines, sleep (say for a second), then go back to 1
If the number of lines is greater, return the new lines, and the new line count, and exit
After some number of iterations (I use 100), exit and return the existing line count
The data structure returned by the back end script is JSON:
{
Error: // 0 or 1,
Lines: // Number of lines
Text: // New lines from log file
}
This works just like 'tail -f' in UNIX, but in a browser!
Related
So I have been working on this for hours now, I have read a bunch of StackOverflow posts and I am still having no luck.
I have a page that has 2 sections to it, depending on the int in the database will depend on which section is being displayed at which time.
My goal is to have the page look to see if the database status has changed from the current one and if it has then refresh the page, if not then do nothing but re-run every 10 seconds.
I run PHP at the top of my page that gets the int from the database
$online_status = Online_status::find_by_id(1);
I then use HTML to load the status into something that jquery can access
<input type="hidden" id="statusID" value="<?php echo $online_status->status; ?>">
<span id="result"></span>
So at the bottom of my page, I added some jquery and ajax
$(document).ready(function(){
$(function liveCheck(){
var search = $('#statusID').val();
$.ajax({
url:'check_live.php',
data:{search:search},
type:'POST',
success:function(data){
if(!data.error){
$newResult = $('#result').html(data);
window.setInterval(function(){
liveCheck();
}, 10000);
}
}
});
});
liveCheck();
});
this then goes to another PHP page that runs the following code
if(isset($_POST['search'])){
$current_status = $_POST['search'];
$online_status = Online_status::find_by_id(1);
if($current_status != $online_status->status){
echo "<script>location.reload();</script>";
}else{
}
}
the jquery then loads into the HTML section with the id of "result" as shown earlier. I know this is a very bad way to do this, and as a result, it will work at the beginning but the longer you leave it on the page the slower the page gets, till it just freezes.
If anyone is able to point me towards a proper method I would be very grateful.
Thank you!!
js:
(function(){
function liveCheck(){
var search = $('#statusID').val();
$.ajax({
url:'check_live.php',
data:{search:search},
type:'POST',
success:function(data){
if(data.trim() == ''){
location.reload();
}else{
$('#result').html(data);
window.setTimeout(function(){
liveCheck();
}, 10000);
}
}
});
}
$(function(){
liveCheck();
});
})(jQuery)
php:
<?php
if(isset($_POST['search'])){
$current_status = $_POST['search'];
$online_status = Online_status::find_by_id(1);
if($current_status != $online_status->status){
$data = '';
}else{
$data = 'some html';
}
echo $data;
}
Your page is slowing down because you are creating a new interval every time you call the liveCheck function. Over time, you have many intervals running and sending requests to your PHP file concurrently. You can verify this behavior by opening the developer console in your browser and monitoring the Network tab.
What you should do instead is set the interval once, and perform the $.ajax call inside that interval. Additionally, it's good practice to not send a new request if a current request is pending, by implementing a boolean state variable that is true while an request is pending and false when that request completes.
It looks like the intended behavior of your function is to just reload the page when the $online_status->status changes, is that correct? If so, change your PHP to just echo true or 1 (anything really) and rewrite your JS as:
function liveCheck() {
if (liveCheckPending == true)
return;
liveCheckPending = true;
var search = $('#statusID').val();
$.ajax({
url:'check_live.php',
data:{search:search},
type:'POST'
}).done(function(data){
if (!data.error)
location.reload();
}).always(function(data){
liveCheckPending = false;
});
}
var liveCheckPending = false;
setInterval(liveCheck, 10000);
I have a .txt file on my server. I need a script to read it in an infinite loop, at every 500ms. Basically, that variable should be updated every 500ms and displayed on a .php page.
Any suggestions?
here is the code for reading the text file;
readTextFile("file:///C:/your/path/to/file.txt");
function readTextFile(file)
{
var rawFile = new XMLHttpRequest();
rawFile.open("GET", file, false);
rawFile.onreadystatechange = function ()
{
if(rawFile.readyState === 4)
{
if(rawFile.status === 200 || rawFile.status == 0)
{
var allText = rawFile.responseText;
alert(allText);
}
}
}
rawFile.send(null);
}
I use setTimeout because request maybe waits a long time.If you want no waiting use setInterval instead of setTimeout but give heed to ram usage.
var currentText=null;
var getText=function(){
$.ajax({
url: "http://www.sample-videos.com/text/Sample-text-file-10kb.txt",
success: function (r) { currentText=r;alert(currentText);setTimeout(getText,500); },
error: function () { alert('it doesnt work') }
});}
setTimeout(getText,500)
I'm using jQuery + PHP on my website and I want to do something like this:
To simplify things I've got a page with 2 buttons () and according to which I click I want to start a script in background (php script) so I do a simple thing with jquery:
$("#button1").click(function(){
$.post("script.php", {val:"but1"}, function(result){
alert(result); // I want something with the result
});
});
$("#button2").click(function(){
$.post("script.php", {val:"but2"}, function(result){
alert(result);
});
});
and in the script.php I've got a simple if statement deciding what I should do.
In the php script I'm downloading a file and I want to create a progress bar of the file download. The php script would return me values (echo percentage; flush();) in some time interval.
And here comes the problem - when I echo those percentage values and flush it refreshes it "just in php" but the jquery waits until the script is finished anyway. Is there a way to get those values as they appear (after flush) or is there a completely other approach to this? I can't think of anything else right now, maybe I shouldn't be using jquery at all.
Thanks for the help.
You can store the progress in a text file or DB while running the script and then have another file get the result via AJAX calls.
JS/HTML
<script>
$(function() {
var id;
var timeoutLength = 1000;
$("#button1").click(function() {
$("#result").html("");
// Create unique identifier
id = (new Date().getTime()) + "-" + Math.floor(Math.random()*100);
$.get("script.php", {id: id}, function(result){
$("#result").html(result);
});
setTimeout(checkProgress, timeoutLength);
});
function checkProgress() {
$.get("script.php", {progress: true, id: id}, function(data) {
prog = parseInt(data);
// Display progress bar
if(prog < 100) {
$("#progress").css({ display: 'block', width: prog });
$("#progress").html(prog + "%");
setTimeout(checkProgress, timeoutLength);
} else {
$("#progress").css('display', 'none');
}
});
}
})
</script>
<button id="button1">Click</button>
<div id="progress" style="background: green"></div>
<div id="result"></div>
script.php
<?php
function getProgress($file) {
return (file_exists($file)) ? file_get_contents($file) : 0;
}
function setProgress($file, $progress) {
file_put_contents($file, $progress);
}
// Remove invalid characters
$id = str_replace('/[^a-zA-Z0-9\-_]/', '', $_GET['id']);
$file = "progress-" . $id . ".txt";
if(isset($_GET['progress'])) {
echo getProgress($file);
} else {
// Do something and update progress
for($i = 10; $i <= 100; $i += 10) {
// Do something
setProgress($file, $i);
sleep(1);
}
unlink($file);
echo "Result: " . rand(1, 100);
}
Edit:
Added support for multiple requests and simple progress bar.
i believe that what all you need is the pecl uploadprogress package
it is not very easy to install and its not sure it works, i have find hard to make it work under certain server configurations, but i think its a good shot
EDIT: sorry i didnt see you mention download so have a look here
Below script will work for the progress-bar.
But, what I would do is, trigger an AJAX call to start the download and trigger another AJAX call to start receiving the input (using How to show file download progress in PHP Shell Scripting?).
PHP:
<?php
echo "wget '$feedURL'\n";
$execute = "wget -O ".$filePath." '$feedURL'\n";
$systemOutput = shell_exec($execute);
$systemOutput = str_replace( "\n", "\n\t", $systemOutput);
echo "\t$systemOutput\n";
?>
GetProgress:
function getProgress(){
GDownloadUrl("getprogress.php?progress_key=<?php echo($unique_id)?>",
function(percent, responseCode) {
document.getElementById("progressinner").style.width = percent+"%";
if (percent < 100){
setTimeout("getProgress()", 100);
}
});
}
Here is nice implementation with the help PHP's APC to get a nice progress-bar during UPLOAD of a file - http://www.haughin.com/2007/10/23/php-upload-progress-with-php-52-apc/
Alternative solution:
You can store the progress of downloading file into $_SESSION array inside PHP.
Besides that, you can write a dedicated PHP to only retrieve this percentage from session. This PHP will be called from your client's AJAX. This way the proccess won't take so much resources from server to calculate or to echo the download's percentage.
Try to avoid I/O from files if you are going to handle high rates of reading/writing onto them. Session variables are less expensive to achieve this functionality.
Provided that your PHP has some way to know the progress percentage, you should do multiple requests for progress updates:
function receiveProgress(data) {
// update progres indicator here
if (parseFloat(data) < 100) {
setTimeout(checkProgress, 100);
} else {
pressedButton = '';
}
}
function checkProgress() {
$.post("script.php", {val:pressedButton}, receiveProgress);
}
var pressedButton = '';
$("#button1").click(function(){
pressedButton = 'but1';
checkProgress();
});
This will ask server for progress updates every 100ms
I've my site pages structure as
1) index.php which calls addline.php using ajax and the html returned is appended to the index.php
2) the addline.php calls another page more.php using ajax which again appends the returned html to it
3) Again more.php calls another file update.php and in the update.php, I've my following js codes
var number = parseInt("<?php echo $delFlag; ?>");
if ( number == 1) {
// Calling updateLine() function after 5 mins
timer = setTimeout("updateLine()",1000*5*60);
}
function updateLine() {
var flagId = <?php echo $flagId; ?>;
var dataPass = 'flagId=' + flagId;
$.ajax({
type: "POST",
url: "proc/updateLine.php",
data: dataPass,
cache: false,
success: function(){
// Show error if error is there
}
});
}
All the time, my location is still index.php.
The javascript function works properly if I do not reload the page. If I reload the page, it doesn't work. I want the setTimeOut() call to be active in the background even after the reload takes place. It should trigger the function call after 5 mins.
How do I achieve it??
Reloading a page resets the Javascript state and there is no direct way to keep things running in the background.
If the requirement is to continue the timeout counter automatically after the page reload, then the counter state has to be persisted somehow.
It means that every timeout start has to be accounted for. One option would be to do it with PHP and load and unload events, along the lines of:
// timeout.php -- persists and returns the last timeout start by session
<?php
session_start();
$key = 'lastTimeoutStart';
if (isset($_GET[$key]))
$_SESSION[$key] = $_GET[$key];
else if (isset($_SESSION[$key]))
echo $_SESSION[$key];
?>
Plus the Javascript part that handles persisting and loading:
var lastTimeoutStart = 0;
if ( number == 1) {
// Calling updateLine() function after 5 mins
lastTimeoutStart = new Date().getTime();
timer = setTimeout("updateLine()",1000*5*60);
}
//
// Other code
//
$(document).load(function () {
$.get('timeout.php', function (data, textStatus, jqXHR) {
var persistedStart = data.lastTimeoutStart;
var tempTimeout = persistedStart + 1000*5*60 - new Date().getTime();
if (tempTimeout > 0) {
clearTimeout(timer);
timer = setTimeout("updateLine()", tempTimeout);
}
});
});
$(document).unload(function () {
var data = {"lastTimeoutStart": lastTimeoutStart};
$.get('timeout.php', data, function (data, textStatus, jqXHR) {});
});
There may be bugs in the above code but hopefully you get the idea.
I'm new to AJAX, and trying to use it to speed up the display of results for a PHP full-text file search. I have about 1700 files to search, so instead of waiting for the server to process everything I want to send just the first 100 to the script and display the results, then the next 100 etc., so users get instant gratification.
To do this, I call a function callftsearch with the names of all the files in a string and some other information needed for the PHP function on the other side to run the search. callftsearch creates arrays of each 100 files, joins them in strings and sends that to ftsearch.php through the javascript function ftsearch. The PHP runs the search and formats the results for display, and sends the HTML string with the table back. addresults() just appends that table onto an existing div on the page.
Here's the javascript:
function GetXmlHttpObject()
{
var xmlHttp=null;
try { xmlHttp=new XMLHttpRequest(); }
catch (e) { try { xmlHttp=new ActiveXObject('Msxml2.XMLHTTP'); }
catch (e) { xmlHttp=new ActiveXObject('Microsoft.XMLHTTP'); } }
return xmlHttp;
}
function callftsearch(allfiles, count, phpfilenames, keywordscore, keywordsboolean, ascii) {
var split_files = allfiles.split("|");
var current_files = new Array();
var i;
for (i = 1; i<=count; i++) {
file = split_files.shift();
current_files.push(file);
if (i%100 == 0 || i == count) {
file_batch = current_files.join('|');
ftsearch(file_batch, phpfilenames, keywordscore, keywordsboolean, ascii);
current_files.length = 0;
}
}
}
function ftsearch(file_batch, phpfilenames, keywordscore, keywordsboolean, ascii)
{
xmlHttp=GetXmlHttpObject();
if (xmlHttp==null) { return; }
// If our 'socket' has changed, send the response to addresults()
xmlHttp.onreadystatechange=addresults;
xmlHttp.open('POST','ftsearch.php', true);
var content_type = 'application/x-www-form-urlencoded';
xmlHttp.setRequestHeader('Content-Type', content_type);
xmlHttp.send('f='+file_batch+'&pfn='+phpfilenames+'&kw='+keywordscore+'&kwb='+keywordsboolean+'&a='+ascii);
}
function addresults()
{
var displayarray = new Array();
if (xmlHttp.readyState==4)
{
var ftsearchresults = xmlHttp.responseText;
$('#result_tables').append(ftsearchresults);
}
}
The problem: the page displays the exact same table repeatedly, with only the first few results. When I add alert(file_batch) to callftsearch it shows that it's sending the correct packets of files in succession. But when I alert(ftsearchresults) in addresults() it shows that it's receiving the same string over and over. I even added a timestamp at one point and it was the same for all of the printed tables.
Why would this happen?
A few things here.
First: it looks like you are already using jQuery since you have the line,
$('#result_tables')
If thsts the case, then why not use jQuerys built in ajax functionality? You could just do something like this,
$.ajax({
type: "POST",
url: "ftsearch.php",
data: 'f='+file_batch+'&pfn='+phpfilenames+'&kw='+keywordscore+'&kwb='+keywordsboolean+'&a='+ascii,
success: function(response){
$('#result_tables').append(response);
}
});
Second: If the output continues to be the same first few items each time, have you tried outputting the information that the ajax page is receiving? If it is receiving the correct information, then that meens there is something wrong with your PHP logic, which you do not have posted.