I dont really know how to ask this which is why I am asking it here. So if I was using some code like this:
$.post("/data/something.php", {stuff: 'hi'}, function(data){
$('#box').html(data);
});
Normally if you have php like this you only get 1 result:
<?php echo $_REQUEST['stuff'] ?>
I was wondering if there is any way for the php to send a bit of data, then a little bit more later without it just sending all of it at once like so:
<?php
echo 'Foo';
//Do stuff that takes time
echo 'Bah';
?>
There are 2 ways to accomplish this.
The first uses a standard workflow with the flush command (http://php.net/manual/en/function.flush.php). This means that you can do:
echo "Starting...\n"
flush();
// do long task
echo "Done!\n"
HOWEVER: This often won't work. For example, if your server uses deflate, the Starting likely won't get sent until the request is finished. Many other factors can cause this too (proxies, browser behaviour).
The better option is to use a polling mechanism. Your main script would write its progress to a file (with some session ID related filename), then delete that file when done. You would then add a second script to report the progress in this file (or completion if the file has been deleted) and your JavaScript would send an AJAX request to this checker script (maybe every second or two).
In PHP
<?php
echo 'Foo';
echo '||||';
echo 'Bah';
?>
In Javascript
var responses = data.split('||||');
//you will get
//Foo in responses[0]
//Bar in responses[1]
I expect that php has no problem doing that (as detailed by #Dave). The complicated part, is for javascript to retrieve the first part of the data, before the transmission completes...
I think what you are asking is answered here: Is it possible for an AJAX request to be read before the response is complete?
The way to accomplish this is by listening on the readyState in the the xhr object. When readyState == 3 it means new content has arrived and you can access it. The technique is referred to as Comet.
and...
So finally, yes it is possible, no it is not easy.
Related
I am looking for a way to get an echo (or anything else) between 2 functions, the first being called via Ajax.
Here is what I am doing :
I upload via Ajax a video to the server where it is temporary stored.
then pass the video to a private function that send it to youtube via the API and after, unset the video on the server.
My question : between the 2 functions, is there a way to get from the PHP script something that can be handled by the client to inform him of the progress ?
I tried :
to send JSon
to update a session checked by JS while the Ajax call
flush() and ob_flush()
but always, data is returned at this end of the 2nd function (when I don't need anything anymore), as if, while the call and all that is after, PHP was unable to say something
I 'd like :
function upload()
{
//uploading
if(ok)
{
//echoing something there (the main goal)
goYoutube();
}
}
private function goYoutube() {
//etc...
}
and what I have is :
function upload()
{
//uploading
if(ok)
{
goYoutube();
}
}
private function goYoutube()
{
//etc...
//echoing something there (the bad bad bad useless thing)
}
It is with CodeIgniter and I don't have the hand on the server.
I don't need code, just an idea (which will be greatly appreciated)
Of course, something like "don't lose your time guy, it can't be done" is ok !
Thanks.
PHP is a server side language and I don't think it'll output something until the script finished executing. If I were you I would try to split those functions in two separate AJAX request.
The first request gives the user the answer that everything is ok (or something like "please wait") and the second request makes the call to the YouTube API.
You could do this by establishing a websocket connection and sending events from the server to the client. I usually do this in nodejs using socket.io. I see there is a similar option for PHP: elephant.io
So the order of things would be:
Establish websockets connection with server (before sending video)
In the clientside, listen for the event you will receive and do whatever update there.
Do the video upload.
In the serverside, send a websockets event where you would place you "echo"
Take a look at it, I really think it will do.
I have read many similar questions concerning cancelling a POST request with jQuery, but none seem to be close to mine.
I have your everyday form that has a PHP-page as an action:
<form action="results.php">
<input name="my-input" type="text">
<input type="submit" value="submit">
</form>
Processing results.php on the server-side, based on the post information given in the form, takes a long time (30 seconds or even more and we expect an increase because our search space will increase as well in the coming weeks). We are accessing a Basex server (version 7.9, not upgradable) that contains all the data. A user-generated XPath code is submitted in a form, and the action url then sends the XPath code to the Basex server which returns the results. From a usability perspective, I already show a "loading" screen so users at least know that the results are being generated:
$("form").submit(function() {
$("#overlay").show();
});
<div id="overlay"><p>Results are being generated</p></div>
However, I would also want to give users the option to press a button to cancel the request and cancel the request when a user closes the page. Note that in the former case (on button click) this also means that the user should stay on the same page, can edit their input, and immediately re-submit their request. It is paramount that when they cancel the request, they can also immediately resend it: the server should really abort, and not finish the query before being able to process a new query.
I figured something like this:
$("form").submit(function() {
$("#overlay").show();
});
$("#overlay button").click(abortRequest);
$(window).unload(abortRequest);
function abortRequest() {
// abort correct request
}
<div id="overlay">
<p>Results are being generated</p>
<button>Cancel</button>
</div>
But as you can see, I am not entirely sure how to fill in abortRequest to make sure the post request is aborted, and terminated, so that a new query can be sent. Please fill in the blanks! Or would I need to .preventDefault() the form submission and instead do an ajax() call from jQuery?
As I said I also want to stop the process server-side, and from what I read I need exit() for this. But how can I exit another PHP function? For example, let's say that in results.php I have a processing script and I need to exit that script, would I do something like this?
<?php
if (isset($_POST['my-input'])) {
$input = $_POST['my-input'];
function processData() {
// A lot of processing
}
processData()
}
if (isset($_POST['terminate'])) {
function terminateProcess() {
// exit processData()
}
}
and then do a new ajax request when I need to terminate the process?
$("#overlay button").click(abortRequest);
$(window).unload(abortRequest);
function abortRequest() {
$.ajax({
url: 'results.php',
data: {terminate: true},
type: 'post',
success: function() {alert("terminated");});
});
}
I did some more research and I found this answer. It mentions connection_aborted() and also session_write_close() and I'm not entirely sure which is useful for me. I do use SESSION variables, but I don't need to write away values when the process is cancelled (though I would like to keep the SESSION variables active).
Would this be the way? And if so, how do I make one PHP function terminate the other?
I have also read into Websockets and it seems something that could work, but I don't like the hassle of setting up a Websocket server as this would require me to contact our IT guy who requires extensive testing on new packages. I'd rather keep it to PHP and JS, without third party libraries other than jQuery.
Considering most comments and answers suggest that what I want is not possible, I am also interested to hear alternatives. The first thing that comes to mind is paged Ajax calls (similar to many web pages that serve search results, images, what-have-you in an infinite scroll). A user is served a page with the X first results (e.g. 20), and when they click a button "show next 20 results" those are shown are appended. This process can continue until all results are shown. Because it is useful for users to get all results, I will also provide a "download all results" option. This will then take very long as well, but at least users should be able to go through the first results on the page itself. (The download button should thus not disrupt the Ajax paged loads.) It's just an idea, but I hope it gives some of you some inspiration.
On my understanding the key points are:
You cannot cancel a specific request if a form is submitted. Reasons are on client side you don't have anything so that you can identify the states of a form request (if it is posted, if it is processing, etc.). So only way to cancel it is to reset the $_POST variables and/or refresh the page. So connection will be broken and the previous request will not be completed.
On your alternative solution when you are sending another Ajax call with {terminate: true} the result.php can stop processing with a simple die(). But as it will be an async call -- you cannot map it with the previous form submit. So this will not practically work.
Probable solution: submit the form with Ajax. With jQuery ajax you will have an xhr object which you can abort() upon window unload.
UPDATE (upon the comment):
A synchronous request is when your page will block (all user actions) until the result is ready. Pressing a submit button in the form - do a synchronous call to server by submitting the form - by definition [https://www.w3.org/TR/html-markup/button.submit.html].
Now when user has pressed submit button the connection from browser to server is synchronous - so it will not be hampered until the result is there. So when other calls to server is made - during the submit process is going on - no reference of this operation is available for others - as it is not finished. It is the reason why sending termination call with Ajax will not work.
Thirdly: for your case you can consider the following code example:
HTML:
<form action="results.php">
<input name="my-input" type="text">
<input id="resultMaker" type="button" value="submit">
</form>
<div id="overlay">
<p>Results are being generated</p>
<button>Cancel</button>
</div>
JQUERY:
<script type="text/javascript">
var jqXhr = '';
$('#resultMaker').on('click', function(){
$("#overlay").show();
jqXhr = $.ajax({
url: 'results.php',
data: $('form').serialize(),
type: 'post',
success: function() {
$("#overlay").hide();
});
});
});
var abortRequest = function(){
if (jqXhr != '') {
jqXhr.abort();
}
};
$("#overlay button").on('click', abortRequest);
window.addEventListener('unload', abortRequest);
</script>
This is example code - i just have used your code examples and changed something here and there.
Himel Nag Rana demonstrated how to cancel a pending Ajax request.
Several factors may interfere and delay subsequent requests, as I have discussed earlier in another post.
TL;DR: 1. it is very inconvenient to try to detect the request was cancelled from within the long-running task itself and 2. as a workaround you should close the session (session_write_close()) as early as possible in your long-running task so as to not block subsequent requests.
connection_aborted() cannot be used. This function is supposed to be called periodically during a long task (typically, inside a loop). Unfortunately there is just one single significant, atomic operation in your case: the query to the data back end.
If you applied the procedures advised by Himel Nag Rana and myself, you should now be able to cancel the Ajax request and immediately allow a new requests to proceed. The only concern that remains is that the previous (cancelled) request may keep running in the background for a while (not blocking the user, just wasting resources on the server).
The problem could be rephrased to "how to abort a specific process from the outside".
As Christian Bonato rightfully advised, here is a possible implementation. For the sake of the demonstration I will rely on Symphony's Process component, but you can devise a simpler custom solution if you prefer.
The basic approach is:
Spawn a new process to run the query, save the PID in session. Wait for it to complete, then return the result to the client
If the client aborts, it signals the server to just kill the process.
<?php // query.php
use Symfony\Component\Process\PhpProcess;
session_start();
if(isset($_SESSION['queryPID'])) {
// A query is already running for this session
// As this should never happen, you may want to raise an error instead
// of just silently killing the previous query.
posix_kill($_SESSION['queryPID'], SIGKILL);
unset($_SESSION['queryPID']);
}
$queryString = parseRequest($_POST);
$process = new PhpProcess(sprintf(
'<?php $result = runQuery(%s); echo fetchResult($result);',
$queryString
));
$process->start();
$_SESSION['queryPID'] = $process->getPid();
session_write_close();
$process->wait();
$result = $process->getOutput();
echo formatResponse($result);
?>
<?php // abort.php
session_start();
if(isset($_SESSION['queryPID'])) {
$pid = $_SESSION['queryPID'];
posix_kill($pid, SIGKILL);
unset($pid);
echo "Query $pid has been aborted";
} else {
// there is nothing to abort, send a HTTP error code
header($_SERVER['SERVER_PROTOCOL'] . ' 599 No pending query', true, 599);
}
?>
// javascript
function abortRequest(pendingXHRRequest) {
pendingXHRRequest.abort();
$.ajax({
url: 'abort.php',
success: function() { alert("terminated"); });
});
}
Spawning a process and keeping track of it is genuinely tricky, this is why I advised using existing modules. Integrating just one Symfony component should be relatively easy via Composer: first install Composer, then the Process component (composer require symfony/process).
A manual implementation could look like this (beware, this is untested, incomplete and possibly unstable, but I trust you will get the idea):
<?php // query.php
session_start();
$queryString = parseRequest($_POST); // $queryString should be escaped via escapeshellarg()
$processHandler = popen("/path/to/php-cli/php asyncQuery.php $queryString", 'r');
// fetch the first line of output, PID expected
$pid = fgets($processHandler);
$_SESSION['queryPID'] = $pid;
session_write_close();
// fetch the rest of the output
while($line = fgets($processHandler)) {
echo $line; // or save this line for further processing, e.g. through json_encode()
}
fclose($processHandler);
?>
<?php // asyncQuery.php
// echo the current PID
echo getmypid() . PHP_EOL;
// then execute the query and echo the result
$result = runQuery($argv[1]);
echo fetchResult($result);
?>
With BaseX 8.4, a new RESTXQ annotation %rest:single was introduced, which allows you to cancel a running server-side request: http://docs.basex.org/wiki/RESTXQ#Query_Execution. It should solve at least some of the challenges you described.
The current way to only return chunks of the result is to pass on the index to the first and last result in your result, and to do the filtering in XQuery:
$results[position() = $start to $end]
By returning one more result than requested, the client will know that there will be more results. This may be helpful, because computing the total result size is often much more expensive than returning only the first results.
I hope I understood this correctly.
Instead of letting the browser "natively" submit the FORM, don't: write JS code that does this instead. In other words (I didn't test this; so interpret as pseudo-code):
<form action="results.php" onsubmit="return false;">
<input name="my-input" type="text">
<input type="submit" value="submit">
</form>
So, now, when the that "submit" button is clicked, nothing will happen.
Obviously, you want your form POSTed, so write JS to attach a click handler on that submit button, collect values from all input fields in the form (actually, it is NOT nearly as scary as it sounds; check out the link below), and send it to the server, while saving the reference to the request (check the 2nd link below), so that you can abort it (and maybe signal the server to quit also) when the cancel-button is clicked (alternatively, you can simply abandon it, by not caring about the results).
Submit a form using jQuery
Abort Ajax requests using jQuery
Alternatively, to make that HTML markup "clearer" relative to its functionality, consider not using FORM tag at all: otherwise, what I suggested makes its usage confusing (why it is there if it's not used; know I mean?). But, don't get distracted with this suggestion until you make it work the way you want; it's optional and a topic for another day (it might even relate to your changing architecture of the whole site).
HOWEVER, a thing to think about: what to do if the form-post already reached the server and server already started processing it and some "world" changes have already been made? Maybe your get-results routine doesn't change data, so then that's fine. But, this approach probably cannot be used with change-data POSTs with the expectation that "world" won't change if cancel-button is clicked.
I hope that helps :)
The user doesn't have to experience this synchronously.
Client posts a request
The server receives the client request and assigns an ID to it
The server "kicks off" the search and responds with a zero-data page and search ID
The client receives the "placeholder" page and starts checking if the results are ready based on the ID (with something like polling or websockets)
Once the search has completed, the server responds with the results next time it's polled (or notifies the client directly when using websockets)
This is fine when performance isn't quite the bottleneck and the nature of processing makes longer wait times acceptable. Think flight search aggregators that routinely run for 30-90 seconds, or report generators that have to be scheduled and run for even longer!
You can make the experience less frustrating if you don't block user interactions, keep them updated of search progress and start showing results as they come in if possible.
You must solve this conceptually first before writing any code. Here are some things that come to mind offhand:
What does it mean to free up resources on the server?
What constitutes to a graceful abort that will free up resources?
Is it enough to kill the PHP process waiting for the query result(s)? If so, the route suggested by RandomSeed could be interesting. Just keep in mind that it will only work on a single server. If you have multiple load balanced servers you won't have a way to kill a process on another server (not as easily at least).
Or do you need to cancel the database request from the database itself? In that case the answer suggested by Christian GrĂ¼n is of more interest.
Or is it that there is no graceful shutdown and you have to force everything to die? If so, this seems awfully hacky.
Not all clients are going to explicitly abort
Some clients are going to close the browser, but their last request won't come through; some clients will lose internet connection and leave the service hanging, etc. You are not guaranteed to get an "abort" request when a client disconnects or has gone away.
You have to decide whether to live with potentially unwanted behavior, or implement an additional active state tracking, e.g. client pinging server for keepalive.
Side notes
30 secs or greater query time is potentially long, is there a better tool for the job; so you won't have to solve this with a hack like this?
you are looking for features of a concurrent system, but you're not using a concurrent system; if you want concurrency use a better tool/environment for it, e.g. Erlang.
I know PHP runs first but is there a way to get PHP to wait on an ajax request and then run its script? I have a php script here that I want to run but I NEED a variable from my JS file in order for it to run successfully. So was wondering if it's possible?
What I have is a normal request in my JS:
var myvar = data;
$.get('phpscript.php', {myvar: myvar} );
And in PHP:
$myphp = $_GET['myvar'];
But if i echo $myphp it returns "undefined", if I alert it however It displays the value; which means the php script is running before it even gets the request from ajax. Any way I could make the PHP wait?
Thanks.
Put the PHP that requires a variable in its own script and call it from the ajax call, once the ajax call gets a response update the DOM as needed.
PHP runs on server, then javascript runs on client to make the ajax call, then PHP runs on server returning data, then the javascript gets the data and does something with it.
$.get('phpscript.php', {myvar: myvar}, function(data) {
$('.result').html(data);
});
Inside the php file have something like:
$myphp = $_GET['myvar'];
echo $myphp;
The short answer is, no, you can't make PHP wait. PHP only runs on the server-side, by the time the AJAX request is sent, by definition, the page is already been sent to the client.
You'll probably have to do some refactoring. If the variable absolutely needs to be used for a PHP function, then you may need to move that logic into 'phpscript.php' or (less optimally) you may need to issue another AJAX request when you get the response from the first.
But my guess is that more commonly, you'll probably just have to figure out how to do what you want with javascript. If all you want is something equivalent to a PHP echo, you'll want to use Javascript (or JQuery) DOM manipulation for that.
EDIT: I forgot to mention, the other option is simply to do all the PHP stuff on the server-side before you send the page at all, instead of AJAX you'd want to do something in PHP like including your other php script and calling methods from it. But, everything you do on the server-side, the user is sitting there looking at a blank screen waiting for the page to load. So this isn't an option for anything that's not very quick.
how can i pass a variable from javascript to php using same file
in this example page keeps refreshing and i don't get to see the result
it works only if i separate the scripts... but i need it somehow like on ajax..
<SCRIPT language="JavaScript">
var carname="Volvo";
location.href="http://localhost/put.php?Result=" + carname;
</SCRIPT>
and this is the seccond part of the script ( they are both in same file )
<?php
Id = $_GET[Result];
echo $dbId;
?>
As Brian said you should put it in a conditional statement.. also your PHP is bad. Try the following
<?php if(isset($_GET["Result"])) : ?>
// do work with set variable
<?php $dbID = $_GET["Result"];
echo($dbID); ?>
<?php else : ?>
// "Result" not set
<SCRIPT language="JavaScript">
var carname="Volvo";
location.href="http://localhost/put.php?Result=" + carname;
</SCRIPT>
<? endif; ?>
I think this is a good exercise if you're trying to learn the Ajax method, in the real world I recommend using a framework like jQuery. Of course understanding how this works will help you build better applications in the end.
So you could do something like this in the PHP script:
if (!isset($_GET['Result']))
{
// include the javascript portion with the redirect
}
I'm with the others, though--I'm not seeing the value in a page load followed by an immediate redirect to the same page.
What you are trying to do cannot be done. Your script runs on the client in real time but the php will run on the server during the request. You will need to make an AJAX request.
First you will want to use Firefox with firebug and the web developer toolbar. Firebug gives a great view of ajax traffic and the web developer toolbar helps you see what's going on in the page.
Use jQuery make an ajax request to "send" the value to another php file. Don't be afraid to separate out files, in fact it's encouraged and considered good programming. If you find your sending a lot if information to a php script you will want to use JSON instead of as part of the url.
Man, you should follow a client-server pattern.. So the Client page can use some ajax to make a request to a Server page. This will response to the Client and you can make with the data what you want.
of course it will keep refreshing:)) Because as soon as the browser gets the js code, it will load that page you specify, which will send your browser the same page... you get the idea. It's like writing for(;;){}
Your question is difficult to understand (for me at least.) My guess is that you are wanting to use AJAX to send data to the server and receive a response without leaving the page.
Probably the easiest way to accomplish this is to use a library such as jQuery. (see jQuery.ajax())
PHP only runs on the server and the javascript only runs on the client. By the time your client is running the javascript, no more PHP can be executed on that request.
I understand there is a method send for xmlHttpRequest objects, but I've been working on this site all day and I'm unable to find any halfway decent tutorials on the subject and my brain feels like mush. Ajax is hard.
What I'm trying to do is send data from one Javascript file back to a PHP script on the server, where the data is simply a string and a small number. Is this possible? Why can't I find a good article on the subject?
tl;dr How do I use the send method to pass a string and a number from a javascript file to a php file?
Why don't you user jQuery or similar library?
Sending a variables with jQuery will be simple as that:
$.post("save.php", { name: "John", time: "2pm" } );
In your save.php file you can handle POST variables as you wish:
$name = $_POST["name"];
$time = $_POST["time"];
You can check it out: http://jquery.com/
I think you are wasting your time trying to make self made methods ...
It's definitely possible. This is a really nicely organized tutorial that walks you through the XmlHttpRequest object, how to set it up, and how to consume it on the server.
The server-side code is PHP, and I'm more of a C# guy, and it made total sense to me. (Maybe I should switch to PHP??).
I hope this helps! Good luck.
EDIT: In response to a previous SO question, I put this jsfiddle together to demo how to use XmlHttpRequest. Hope this also helps.
lots of good links here, so I'm not going to add to that. Just as a sidenote, you're dealing with a light case of ajaxness here :) - typically you'd want to send something back from the server that changes the state of the page in response to what was sent from the page in the first place (in fact one might argue why you need ajax in the first place and not simply post, if the page's not supposed to change - but I can see how there might be situations where you'd want ajax anyway). I'm just saying that because you're going to encounter a lot of content about how to deal with the stuff sent back from the server - just making sure you're aware that's not needed for what you're trying to do (I'm always glad when I know what I can leave out in the first pass ;)
step 1:
get jquery. all you have to do is download the latest file and include it on your page.
step 2:
make 2 files:
somepage.html:
<script type='text/javascript' src='jquery.js'></script>
<script type='text/javascript'>
$.get("someScript.php",
// data to send if you want
{
'someVar' : 'someValue'
},
// receive and do something with response
function(response){
alert(response);
} // function (response)
); // .get()
</script>
someScript.php
<?php
echo $_GET['someVar'] . " response!";
?>
step 3:
upload all your files to your server and go to somepage.html
That's all there is to it. Though, you would generally put that code inside some kind of onclick or whatever, depending on what you want to use ajax for. But the comments in there are pretty self explanatory. jquery is used to make the ajax request, with an example of sending data to the server-side script receiving the request (using GET method). You would do whatever in someScript.php but in this example, it simply echoes back the value you sent. Then jquery takes what someScript.php echoes out and just throws it in a popup.
Using jQuery, you can use the post method:
$.post("test.php", { name: "John", number: 2 } );
Behind the scenes, this uses xmlHttpRequest, have a look at the source to see how they do it.