as a fix to a previous problem of mine, i have thought to run a cURL script using JavaScript to prevent my site waiting for a response of each one.
at the moment I have this script given by a friend and i have noticed something.
Link to JS file
My question is if I were to remove the following lines, would it mean that the page would not wait for a response?
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
setTimeout("location.reload(true)",1500);
}
}
Thanks.
If you remove the lines, it will not go anywhere.
If you want to speed it up, get rid of the setTimeout line, that is not nessecary.
If you were to remove the if statement, and just do the window.locaiton line, it will fire before the request is made since that onreadystatechange fires to tell you when the request is opened, started, transferring, and done.
Ajax 101 Article
Related
I want to know that suppose you did an ajax request to a page that runs PHP code. The page outputs some data (using flush() method or otherwise) but because of a 30second timeout or some other error, the php request ends.
Now when the request ends, I want to find out about it on client side and restart the request.
i.e suppose I have something like this
xmlhttp.onreadystatechange=function(){
if(xmlhttp.readyState==3 && xmlhttp.status==200){
document.getElementById("A").innerHTML=xmlhttp.responseText;
}
else if(xmlhttp.readyState==4 && xmlhttp.status==200){
document.getElementById("A").innerHTML=xmlhttp.responseText;
//plus some additional code to end the process
}
else if(xmlhttp.status== SOMETHING /*WHAT DO I ADD HERE TO KNOW THAT THE SERVER HAS TIMED OUT OR SOMETHING SO I CAN RESTART THE XMLHTTP CYCLE */){
//code to resend xmlhttp request.
}
}
One strategy I used was to set a timer in JS, and then clear it if the call was successful.
var myTimer = setTimeout(stuffToDoOnFailure, 6000); // 6 secs
ajaxCall(function callBack() {
clearTimeout(myTimer);
});
EDIT:
Of course, if the ajax call succeeds after 6 secs, you might end up with both stuffToDoOnFailure and callBack being executed, so you want to handle that case somehow. That depends on your app, though.
I'm sure similar questions have bee answered over and over again. If yes then I googled in the wrong direction and apologize for that.
My problem:
I'm writing a web page with a process running in the background. The process I'm talking about is a R script which runs quite long maybe several days. When the progress is started, its started like that.
exec(sprintf("%s > %s 2>&1 & echo $! >> %s", $cmd, $outputfile, $pidfile));
Id' like to track whether the process is still running. This way, when the user checks he gets either the message that it is finished or not. The tracking starts and stops when the user chooses the input file he uploaded on to the server after for example he logs in again or did something else on the page. I also want it to update the page when the process finishes so the page changes in case he is just looking at it.
I have two possibilities. I can either check it via the process id or whether an output file is generated or not.
I tried
while(is_process_running($ps)){
ob_flush();
flush();
sleep(1);
}
this works kind of, except that all other functionality on the page freezes.
That's my is_process_running($ps) function.
function is_process_running($PID){
exec("ps $PID", $ProcessState);
return(count($ProcessState) >= 2);
}
What I really need is another process running in the background checking whether the first process is still running and if not, refreshes the page when the first process finishes.
How would you do that? Please let me know if you need additional information. All help is much appreciated.
with symcbean's answer I was able to solve it. My javascript code is below maybe its of use to someone who faces the same problem. I'm also open for improvement. I still consider myself a beginner.
function loadXMLDoc(){
var xmlhttp;
if (window.XMLHttpRequest){// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}else{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
return xmlhttp;
}
function start(file,time){
var xmlhttp = loadXMLDoc();
if(lines == 0){
timer = setInterval(function(){sendRequest(xmlhttp,file)},time);
}
}
function sendRequest(xmlhttp,file){
xmlhttp.open("POST",file,true);
xmlhttp.send()
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState==4 && xmlhttp.status==200 && xmlhttp.responseText != ""){
var text = xmlhttp.responseText;
var splitted = text.split("\n");
var length = splitted.length
if(splitted[length-2]=="finished"){
refresh_page();
clearInterval(timer);
lines = 0;
}
}
}
}
The start method is called with file path and the time interval its supposed to check for changes. Note the refresh page method I did not post but that just whatever you want to refresh on your page. The page is refreshed when the last line in the file says finished.
I included the line variable to check whether the process is already started or not. I have not fully tested the code but so far its doing what I want it to do.
First off, there are a number of issues with the way you are starting the process - it really needs to be a in a separate process group from the PHP which launches it.
As to checking its status, again, you don't want PHP stuff hanging around for a long time at the end of an http connection. Also getting the webserver to flush content to the browser on demand AND getting the browser to render it progressively is very difficult - and fragile. Even if you get it working on one browser/webserver combination it's unlikely to work in another.
Use Ajax to poll a simple script which reports back on the process status / progress.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Best way to manage long-running php script?
I have to built a big email list.Everything works perfectly,but when i submit the form page is loading untill every email is send.So i want this email sending script run in background.and notice the user that script is runnign in background.
I cant use Ajax.
i want something like.. proc_open,exec,shell_exec..
You can have cron job which would run php script which will get queue from db and send email
On main script you just need to add emails to queue
I would use ajax only if you need progress bar. With ajax solution you would need to keep window open until it's ended.
You could build an AJAX call that calls the php script. This way, your site will still be operational while the request is fulfilled. And when it's finished, your AJAX will return and you can show a messagebox to the user.
For more information, check at least this and if you understand what AJAX is and what it does, use it with this
Ajax request would be the best choice for this. You can send a request using javascript and even report progress to user (which might require some additional work)
If you find ajax too difficult - run script in an iframe. This is not the most elegant, but the most simple method.
Submit the form with AJAX and update the progress in a Div
For example - write to some place "A"(db or file) current state of your script runtime: "complete"/"incomplete". After start script in background send to your user waiting page which using AJAX handling changes at "A".
This Ajax script will execute a PHP file on the background. It could also send the response to a HTML element if you want.
<script type="text/javascript" language="javascript">
function execute(filename,var1,var2,var3)
{
var xmlhttp;
if(window.XMLHttpRequest)
{
//Code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
}
else if(window.ActiveXObject)
{
//Code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
else
{
alert("Your browser does not support AJAX!");
}
var url = filename+"?";
var params = "var1="+var1+"&var2="+var2+"&var3="+var3;
xmlhttp.open("POST", url, true);
xmlhttp.onreadystatechange=function()
{
if(xmlhttp.readyState==4)
{
//Below line will fill a DIV with ID 'response'
//with the reply from the server. You can use this to troubleshoot
//document.getElementById('response').innerHTML=xmlhttp.responseText;
xmlhttp.close;
}
}
//Send the proper header information along with the request
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xmlhttp.setRequestHeader("Content-length", params.length);
xmlhttp.setRequestHeader("Connection", "close");
xmlhttp.send(params);
}
</script>
You can try to run the script through an ajax function as well if you don't want to set cron script.
PHP has an function that can keep an process running even if the user that requested the page leaves the page : ignore_user_abort if you check the comments there you can see this example :
<?php
ignore_user_abort(1); // run script in background
set_time_limit(0); // run script forever
$interval=60*15; // do every 15 minutes...
do{
// add the script that has to be ran every 15 minutes here
// ...
sleep($interval); // wait 15 minutes
}while(true);
?>
It IS an pure php cron job BUT, the risk with this script is that it continues indefinitely or atleast untill you reset/kill php.
Setting the set_time_limit(0); to set_time_limit(86400); would kill the script after an day.
This should point you in the right direction/.
IMPORTANT
After the problem by the OP, it is advisable to only run this script if you have SSH access to the server so you can KILL/RESTART php apache in case the server keeps hanging.
Also do not run the script on a LIVE server.
I was studying about AJAX and it was about form validation where as soon as the person fills in the username for signing up, it is checked using AJAX while he still can enter all the other fields. so i issued a request and on readystatechange i called a callback function. now i have studied PHP before this, but i never came across returning information from the server. I mean to say that what all goes in my PHP script, and how does i make sure that the request issued is responded as desired. i dont want the exact code, if just bits of it,or the algorithm can be improved,
For example, i know i passed the username along with the url to the php script, and then i checked if it matched any of the existing usernames in my database(MYSQL and queries) , and normally i would just print the form again if there's a match, else i will exit();
but what do i do when i want to respond back to the object request?
It's really quite easy when you get the hang of it. It's even easier if you use jQuery's AJAX, http://api.jquery.com/jQuery.ajax/ - though don't bloat your site with this unless you intend on using loads of javascript (and use google's cdn for it)
In javascript, you make an XHR request either GET or POST to your PHP script. Usually you'll need to create a separate file for the view to any AJAX requests, because AJAX requests shouldn't bring the webpage's template back as well (i.e. if you wanted to return '1', it should only return '1', not <html><body>1</body></html>. ... etc.
Example:
blah.com/index.php needs some AJAX requests.
blah.com has javascript that creates the ajax request by sending a datastring/url (e.g. ajax.php?act=verify_email&email=a#c
blah.com/ajax.php would then have some PHP code that could switch($_GET['act'] or $_POST['act']) with a 'case' statement of 'verify_email'. That code would run some regex or something, and return 1 or 0 to say 1(valid), 0 (invalid). The 'onreadystatechange' holds the status of the request, so I think its usually a function i.e.:
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
}
}
You access the returned '0' or '1' through the xmlhttp.responseText, where xmlhttp is var xmlhttp =new XMLHttpRequest();
Then you just run the request
xmlhttp.open("GET","ajax.php?act=verify_email&email="+document.getElementById('email').value,true);
xmlhttp.send();
Update: In your case with the form, onblur (when they move out of focus of an element), you could run the AJAX request sending the value of the input, and then in the ajax.php script as a GET or POST request, you could run your validation query to check if the user exists already, or if the username isn't valid or whatever. Once the request has completed, it will return the results in the responseText value. Use firebug's console to check the result of an AJAX request if you can, its very useful.
This might not be what you mean but can't you:
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200)
// do something with "xmlhttp.responseText"
var x = xmlhttp.responseText
}
And in the php just:
echo $x;
That works fine for transmitting strings and other info...
I'm writing some PHP that does a fair amount of processing and then generates reports of the results. Previously it would do a periodic flush() but we're moving to Zend Framework and can't do that anymore. Instead, I would like to have some kind of status display that updates while the report is generated. So I made a progress bar that loads in an iframe, added shared memory to the progress bar update action and the report generation action, and caused the output to load via xmlhttprequest. This all works fine. My issue is that the browser wants to do the two requests serially instead of in parallel, so it will request the progress bar and then BLOCK until the progress bar completes BEFORE it requests the actual output. This means that the process will never end since the real work never starts.
I've searched all morning for some way around this and came up empty-handed.
Is there some way to cause two connections, or am I just screwed?
My next action will be to break the processing apart some more and make the status updating action do the actual work, save the result, and then use the other action to dump it. This will be really painful and I'd like to avoid it.
Edit: Here is the javascript, as requested:
function startProgress()
{
var iFrame = document.createElement('iframe');
document.getElementsByTagName('body')[0].appendChild(iFrame);
iFrame.id = 'progressframe';
iFrame.src = '/report/progress';
}
function Zend_ProgressBar_Update(data)
{
document.getElementById('pg-percent').style.width = data.percent + '%';
document.getElementById('pg-text-1').innerHTML = data.text;
document.getElementById('pg-text-2').innerHTML = data.text;
}
function Zend_ProgressBar_Finish()
{
document.getElementById('pg-percent').style.width = '100%';
document.getElementById('pg-text-1').innerHTML = 'Report Completed';
document.getElementById('pg-text-2').innerHTML = 'Report Completed';
document.getElementById('progressbar').style.display = 'none'; // Hide it
}
function ajaxTimeout(){
xmlhttp.abort();
alert('Request timed out');
}
var xmlhttp;
var xmlhttpTimeout;
function loadResults(){
if (window.XMLHttpRequest){
// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}else{
// code for IE6, IE5
xmlhttp=new ActiveXObject(\"Microsoft.XMLHTTP\");
}
xmlhttp.open(\"POST\",\"/report/output\",true);
xmlhttp.onreadystatechange=function(){
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
clearTimeout(xmlhttpTimeout);
document.getElementById('report-output').innerHTML=xmlhttp.responseText;
}
}
var xmlhttpTimeout=setTimeout(ajaxTimeout,600000); // Ten minutes
xmlhttp.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xmlhttp.send('".file_get_contents("php://input")."');
}
This gets called from the following onload script:
onload="startProgress(); setTimeout(loadResults,1000);"
The issue is not in Javascript. If you put an alert() in there, the alert will be triggered at the right time, but the browser is delaying the second http transaction until the first completes.
Thank you everyone for your input.
I didn't come up with a satisfactory answer for this within the timeframe permitted by our development schedule. It appears that every common browser wants to re-use an existing connection to a site when doing multiple transactions with that site. Nothing I could come up with would cause the browser to initiate a parallel connection on demand. Any time there are two requests from the same server the client wants to do them in a serial fashion.
I ended up breaking the processing into parts and moving it into the status bar update action, saving the report output into a temporary file on the server, then causing the status bar finish function to initiate the xmlhttprequest to load the results. The output action simply spits out the contents of the temporary file and then deletes it.
Using two async ajaxes could do the trick. With the first ajax request you should start the process by calling the php-cli to do the actual work deep in the background (so it doesn't expire or cancel) and return the id of the process (task). Now when you have the process id, you can start the periodical ajax to display the process made.
Making a db table containing process_id, state, user would not be a bad thing. In this case even if the user would close the browser while the process is running, the process would continue until done. The user could revisit the page and see the percentage done, because the process running in cli would save the progress into the db table.
Make a system call to the php file and detach it?
ex:
exec('nohup php test.php > test.out 2> test.err < /dev/null &');
echo 'I am totally printing here';
test.php contains a sleep for 2 seconds and prints, but echo returns immediately.
Have it store the results in a file/database/whatever. It will act like a very dirty fork.
You could also do something similar with a CURL call I bet if you have issues executing.
Credit here for the code example from bmellink (mine was way worse than his).
If you are able to load the report in the iFrame, you can kind of reverse your logic (I have done this to track file uploads to PHP).
Load Report in iFrame (can be hidden or whatever you like).
Make ajax call to get progress (step 1 will have to log progress as others have mentioned).
When the progress reports loading complete, you may show the iframe or whatever is needed to complete.
Hope that helps. Just did a whole lot with iFrames, CORS, and Ajax calls to API's.