I've got a web page that allows to start a certain process and then redirects to another page that displays log file of that process. Since execution takes up to 10 minutes, I want log page to autoupdate itself or load data from the file periodically.
Right now I added
<meta http-equiv="refresh" content="5;url=log.php#bottom" />
to html/head but wondering if there may be a better solution. Can someone give any advice on aproaching this problem?
I do it this way:
var current_length = 0;
function update() {
setTimeout(update, 3000);
$.post("/update_url", { 'current_length': current_length }, function(data) {
if (data.current_length != current_length) return; //it's too old answer
$("#log").html($("#log").html() + data.text);
current_length += data.text.length;
}, "json");
}
update();
The server must skip several bytes at beginning and send json with current_length and the rest of file.
I prefer using memcached to store process output.
You could:
Periodically poll the server to see if there are more messages, basically you would call a PHP script with javascript and would pass the length of the log file in the last poll and then insert into the document the new data. The server would return all the data after that offset and also the new length.
(simpler) Make a long lived PHP script that keeps reading the file and echo and flush it as soon as there's new data. See PHP: How to read a file live that is constantly being written to.
Use AJAX to do this. Easy in jQuery:
<script type="text/javascript">
$(function(){
window.setInterval('updateLog()', 5000);
});
function updateLog() {
$.get('log.php');
}
</script>
Why not use javascript?
Use setInterval and run an AJAX call to log.php periodically.
You could also use an iframe, but the AJAX perdiodical call is a better way of doing it in my opinion.
Related
I'd like to set a cookie in PHP for my website visitors after they have been on my site for at least 2 minutes.
I guess the sleep() function could do just that, but I read that it might delay loading of the entire page.
Is there any other way to this?
You can create an ajax request from the JavaScript which will load a PHP file after 2 minutes.
In JS:
<script>
setTimeout(function() {
// create the AJAX request to set_the_cookie.php
}, 120000);
</script>
Information about AJAX requests.
In PHP (set_the_cookie.php):
<?php
$value = 'yours_value';
setcookie('cookie_name', $value);
?>
I have php script which can take quite a lot of time (up to 3-5 minutes), so I would like to notify user how is it going.
I read this question and decided to use session for keeping information about work progress.
So, I have the following instructions in php:
public function longScript()
{
$generatingProgressSession = new Zend_Session_Namespace('generating_progress');
$generatingProgressSession->unsetAll();
....
$generatingProgressSession->total = $productsNumber;
...
$processedProducts = 0;
foreach($models as $model){
//Do some processing
$processedProducts++;
$generatingProgressSession->processed = $processedProducts;
}
}
And I have simple script for taking data from session (number of total and processed items) which return them in json format.
So, here is js code for calling long script:
$.ajax({
url: 'pathToLongScript',
data: {fileId: fileId, format: 'json'},
dataType: 'json',
success: function(data){
if(data.success){
if(typeof successCallback == "function")
successCallback(data);
}
}
});
//Start checking progress functionality
var checkingGenerationProgress = setInterval(function(){
$.ajax({
url: 'pathToCheckingStatusFunction',
data: {format: 'json'},
success: function(data){
console.log("Processed "+data.processed+" items of "+data.total);
if(data.processed == data.total){
clearInterval(checkingGenerationProgress);
}
}
});
}, 10000)
So, long scripted is called via ajax. Then after 10 seconds checking script is called one time, after 20 second - second time etc.
The problem is that none of requests to checking script is completed until main long script is complete. So, what does it mean? That long script consumes too many resources and server can not process any other request? Or I have some wrong ajax parameters?
See image:
-----------UPD
Here is a php function for checking status:
public function checkGenerationProgressAction()
{
$generatingProgressSession = new Zend_Session_Namespace('generating_progress');
$this->view->total = $generatingProgressSession->total;
$this->view->processed = $generatingProgressSession->processed;
}
I'm using ZF1 ActionContext helper here, so result of this function is json object {'total':'somevalue','processed':'another value'}
I'd
exec ('nohup php ...');
the file and send it to background. You can set points the long running script is inserting a single value in DB to show it's progress. Now you can go and check every ten or whatever seconds if a new value has been added and inform the user. Even might be possible to inform the user when he is on another page within your project, depending on your environment.
Yes, it's possible that the long scripts hogs the entire server and any other requests made in that time are waiting to get their turn. Also i would recommend you to not run the check script every 10 seconds no matter if the previous check has finished or not but instead let the check script trigger itself after it has been completed.
Taking for example your image with the requests pending, instead of having 3 checking request running at the same time you can chain them so that at any one time only one checking request is run.
You can do this by replacing your setInterval() function with a setTimeout() function and re-initialize the setTimeout() after the AJAX check request is completed
Most likely, the following calls are not completing due to session locking. When one thread has a session file open, no other PHP threads can open that same file, as it is read/write locked until the previous thread lets go of it.
Either that, or your Server OR Browser is limiting concurrent requests, and therefore waiting for this one to complete.
My solution would be to either fork or break the long-running script off somehow. Perhaps a call to exec to another script with the requisite parameters, or any way you think would work. Break the long-running script into a separate thread and return from the current one, notifying the user that the execution has begun.
The second part would be to log the progress of the script somewhere. A database, Memcache, or a file would work. Simply set a value in a pre-determined location that the follow-up calls can check on.
Not that "pre-determined" should not be the same for everyone. It should be a location that only the user's session and the worker know.
Can you paste the PHP of "pathToCheckingStatusFunction" here?
Also, I notice that the "pathToCheckingStatusFunction" ajax function doesn't have a dataType: "json". This could be causing a problem. Are you using the $_POST['format'] anywhere?
I also recommend chaining the checks into after the first check has completed. If you need help with that, I can post a solution.
Edit, add possible solution:
I'm not sure that using Zend_namespace is the right approach. I would recommend using session_start() and session_name(). Call the variables out of $_SESSION.
Example File 1:
session_name('test');
session_start();
$_SESSION['percent'] = 0;
...stuff...
$_SESSION['percent'] = 90;
Example File 2(get percent):
session_name('test');
session_start();
echo $_SESSION['percent'];
i need a a script that will refresh the functions:
$ping, $ms
every 30 seconds, with a timer shown,
i basicly got this script:
window.onload=function(){
var timer = {
interval: null,
seconds: 30,
start: function () {
var self = this,
el = document.getElementById('time-to-update');
el.innerText = this.seconds;
this.interval = setInterval(function () {
self.seconds--;
if (self.seconds == 0)
window.location.reload();
el.innerText = self.seconds;
}, 1000);
},
stop: function () {
window.clearInterval(this.interval)
}
}
timer.start();
}
but it refreshes the whole page, not the functions i want it to refresh, so, any help will be appriciated, thanks!
EDIT:
I forgot to mention that the script has to loop infinatly
This here reloads the whole page:
window.location.reload();
Now what you seem to want to do is reload portions of the page, those portions having been generated by php functions. Unfortunately php is server side so that means you cant get the client browser to run php. Your server runs the php to generate stuff that browsers can understand. In a web browser open a page you made using php and choose to view source and you'll see what I mean.
Here's what you'll need to do:
Make your two functions ping and ms accessable via ajax
Instead of window.location.reload() do a call to jQuery.ajax. on success write to your page
Here's what I think would be the ideal way of dealing with this... I haven't seen the php side of your problem but anyway:
make a file called ping.php and put all your ping function code in there. ditto for ms
in your original php file that called those functions, make a div at each point where you wanted a function call. Give them appropriate ids. Eg: "ping_contents" and "ms_contents"
You can populate these with some initial data if you want.
In your js put in something like this:
jQuery.ajax(
{
url : url_of_ping_function,
data : {anything you need},
type : 'POST', //or 'GET'
dataType: 'html',
success : function(data)
{
document.getElementById("ping_contents").innerHTML = data;
}
});
do another one for the other function
What you want is AJAX, Asynchronous JavaScript and XML
You can use jQuery for that.
I can put an example here, but there is a lot of information to be found on the internet. In the past I wrote my own AJAX code, but since I started using jQuery, it's all a lot easier. Look at the jQuery link I provided. There is some usefull information. This example code might be the easiest to explain.
$.ajax({
url: "test.php"
}).done(function() {
alert("done");
});
A some moment, for example on a click on a button, the file test.php is executed. When it's done, a alert box with the text "done" is shown. That's the basic.
I'm having some trouble getting some php code working in my app.
The setup is rather easy: 1 button, 1 function and 1 php file.
script.js
$(document).ready(function ()
{
$("#btnTestConnectie").click(testConnectie);
});
function testConnectie()
{
$.get("script/SQL/testConnection.php");
}
testConnection.php
<?php
echo "It works!";
php?>
According to this post, it should work (How do I run PHP code when a user clicks on a link?)
Some sources claim that it is impossible to execute php via javascript, so I don't know what to believe.
If I'm wrong, can somebody point me to a method that does work (to connect from a javascript/jQuery script to a mySQL database)?
Thanks!
$.get('script/SQL/testConnection.php', function(data) {
alert(data)
});
You need to process Ajax result
You need to do something with the response that your php script is echoing out.
$.get("script/SQL/testConnection.php", function(data){
alert(data);
});
If you are using chrome of firefox you can bring up the console, enable xhr request logging and view the raw headers and responses.
Javascript is run by the browser (client) and php is run on the remote server so you cannot just run php code from js. However, you can call server to run it for you and give the result back without reloading of the page. Such approach is called AJAX - read about it for a while.
I see you are using jQuery - it has pretty nice API for such calls. It is documented: here
In your case the js should be rather like:
$(document).ready(function ()
{
$("#btnTestConnectie").click($.ajax({
url: '/testConnection.php',
success: function(data) {
//do something
}
}));
});
[EDIT]
Let's say you have simple script on the server that serves data from database based on id given in GET (like www.example.com/userInfo.php?id=1). In the easiest approach server will run userInfo.php script and pass superglobal array $_GET with key id ($_GET['id']=1 to be exact). In a normal call you would prepare some query, render some html and echo it so that the browser could display a new page.
In AJAX call it's pretty much the same: server gets some call, runs a script and return it's result. All the difference is that the browser does not reload page but pass this response to the javascript function and let you do whatever you want with it. Usually you'll probably send only a data encoded (I prefer JSON) and render some proper html on the client side.
You may have a look on the load() of jQuery http://api.jquery.com/load/
You should place all of your functions in the document ready handler:
$(document).ready(function(){
function testConnectie() {
$.get("script/SQL/testConnection.php");
}
$("#btnTestConnectie").click(function(e) {
e.preventDefault();
testConnectie();
});
});
You will have to have your browser's console open to see the result as a response from the server. Please make sure that you change the closing PHP bracket to ?> in testConnection.php.
One other note, if you're testing AJAX functions you must test them on a webserver. Otherwise you may not get any result or the results may not be what you expect.
<?
if($_POST['begin'])
{
while(1)
{
echo "1";
sleep(2);
}
die();
}
?>
<span class="answer"></span>
<script type="text/javascript">
$(document).ready(function() {
$.ajax({
type: "POST",
url: "exp.php",
data: "begin=1",
success: function(msg){
$(".answer").html(msg);
}
})
})
</script>
It, of course, doesn't work. What should I change to make it work? Can I avoid using setInterval, setTimeout or other functions in javascript?
By the way, what I am trying to do here is to write number 1 every two seconds.
I've never tried it, but the XMLHttpRequest interface supposedly supports streamed requests. In particular there is the .readyState==3 which denotes partial results (See spec http://www.w3.org/TR/XMLHttpRequest/#event-handler-attributes).
When you don't want to set an interval handler, then you will have to override the actual XHR callback, because the jQuery success: will really only fire on completion.
xmlHttp = $.ajax({ ... });
xmlHttp.onreadystatechange = function () {
if (xmlHttp.readyState >= 3) {
alert(xmlHttp.responseText);
}
};
Note that the responseText will always contain the accumulated data. So you have to split it up on \n or something, if you want to read the latest 1.
Ok, I think I know what you want. It's weird .. but fine.
<script type="text/javascript">
$(document).ready(function() {
function fetch_a_one() {
$.ajax({
type: "POST",
url: "exp.php",
data: "begin=1",
success: function(msg){
$(".answer").html(msg);
fetch_a_one();
}
})
}
fetch_a_one();
})
</script>
<div class="answer"></div>
PHP script:
<?php
sleep(2); // way two seconds
exit(1); // print 1
?>
Minus some delay from starting the Ajax request and lag from the server, this should print '1' every 2 seconds .. no idea why you want this.
This is the wrong approach, because your success function isn't going to run until it receives a response from the server which isn't going to happen as it's in an endless loop.
You will need to handle the timings in JavaScript with, as you say, setInterval. Of course if all you're trying to do is simply print the number 1 every five seconds you don't need to make any calls to the server-side (although I presume there's something more you're trying to achieve eventually - you might want to expand on that a little).
You could look into opening a WebSocket back to the server do handle this kind of ongoing communication. Look into something like PusherApp - http://pusher.com/
You're probably going to have to use JavaScript for this. You can continually poll the server resource to get information from it, but the actual looping and delaying will need to be in JavaScript.
The reason for this is because the PHP script needs to finish processing at some point. It's not streaming output to the client, it's building output to send to the client. In the code you provide, it's forever building the output and never sending it.
You can try to flush your buffer from the PHP script to send some output to the client while still building more output, but take a look at the caveats in that link. It's not really a clean way to accomplish this and will probably cause more problems than it solves in this case. At some point the server resource needs to stop processing and commit to a response. Trying to short-circuit that basic concept of HTTP will likely be a bit of a hack.
I think the problem is, that you're writing endless PHP loop.
jQuery when starting ajax request, will be waiting for script to finish his job. However the script would never ends - so the browser will never get the full answer.
You need to use setTimeout, there is no other way - at least no other easy and safe way.