PHP usleep/sleep inside output buffer - php

I have a PHP application containing these files: landing.php, redirect.php, ajax.php
on a page call to landing.php, I execute a javascript code to capture certain data, and issue an AJAX POST to ajax.php which inserts them into DB. Finally php header() redirects to redirect.php
Currently the above feature is using output buffering, but the header() is executed too soon that the AJAX POST is not finished..ie, no DB query is made.
I tried using sleep() usleep() before header() but they are not working. As I am not very familiar with output buffering, would you please offer a kind hand?
Thank you.
<?php ob_start(); ?>
<scripts type="text/javascript">
var data = 'blah..blah..blah..';
ajaxPost('ajax.php', data);
</scripts>
<?php
sleep(2); // <---- I want the script to sleep here and wait for the AJAX to finish
header('c.php)
ob_end_flush();
?>

If I understood you correctly, you have a fundamental misunderstanding on how web applications work.
Your PHP script can't wait for the AJAX bit to execute, because the whole script is first run on the server, and the output -- part of which the AJAX call is -- is then sent to the browser. You have to rethink the way you're doing this.
For instance, you could have the JavaScript first make the AJAX call, and then redirect the browser.
Edit: OK, now that I've thought about this for a while more, I can see how something like this might work when you're not using output buffering, if the browser executes the script as soon as it sees it (without having the full page loaded). If that is indeed the case, then you're still relying on the browser's timing, the quality of the user's internet connection and so on to keep things in sync. That is decidedly not a good thing.
However, the only way that could work is if the AJAX call got outputted to the browser before your header call -- which is not possible! Headers need to be sent before the content in the HTTP response (which is why you're using output buffering in the first place), so either you won't output the JavaScript or the header call will fail. So I recommend you rethink your approach.

Related

php - Why should I call exit() after calling Location: header?

There are many similar question like php - Should I call exit() after calling Location: header? and do i need to use exit after header("Location: http://localhost/...");? in Stack Over Flow.
They have answers like below.
You definitely should. Otherwise the script execution is not
terminated. Setting another header alone is not enough to redirect.
--
You should call exit() because a header() won't automatically stop the
script from executing - or if it does (I'm honestly not 100% on that),
it definitely doesn't stop the script instantly.
But I can't understand that how someone skip or bypass code like header('Location: http://www.example.com/login.php') ? How someone do it? Because this is a PHP code. This code runs in server. If someone can skip/bypass this code why they can't skip/bypass exit() also?
The header is only a line of data asking the browser to redirect. The rest of the page will still be served by PHP and can be looked at by the client by simply preventing the header command from executing.
If you don't prevent it, PHP will send out the whole body even after a header call. That body is fully available to the recipient.

Delay PHP execution until JavaScript cookie set?

I am trying to delay PHP execution until a cookie is set through JavaScript. The code is below, I trimmed the createCookie JavaScript function for simplicity (I've tested the function itself and it works).
<?php
if(!isset($_COOKIE["test"])) {
?>
<script type="text/javascript">
$(function() {
// createCookie script
createCookie("test", 1, 3600);
});
</script>
<?php
// Reload the page to ensure cookie was set
if(!isset($_COOKIE["test"])) {
header("Location: http://localhost/");
}
}
?>
At first I had no idea why this didn't work, however after using microtime() I figured out that the PHP after the <script> was executing before the jQuery ready function. I reduced my code significantly to show a simple version that is answerable, I am well aware that I am able to use setcookie() in PHP, the requirements for the cookie are client-side.
I understand mixing PHP and JavaScript is incorrect, but any help on how to make this work (is there a PHP delay? - I tried sleep(), didn't work and didn't think it would work, since the scripts would be delayed as well) would be greatly appreciated.
It is not impossible to do what you are trying to do, as other answers have stated, but it is also not trivial and seriously a bad idea for your server to wait per-request for the client to "set a cookie."
But it can be done.
PHP code would write a <script> block for setting the cookie.
PHP code would begin an idle loop, monitoring a session variable. Not a cookie. The cookies for the PHP script executing are already set and are not going to change by JavaScript.
JavaScript block written in #1 would also need to make an AJAX call to the server. The PHP script it calls should set the cookie you care about, but also set the session variable #2 cares about.
The original script, monitoring the session, should wake up and continue as you planned.
While PHP does execute before JavaScript, all browsers incrementally load the HTML/CSS/JavaScript content generated by PHP (or any server-side language). Because of the incremental loading, it is possible for your PHP script to delay for JavaScript to do something (as outlined above) before continuing. But your server is going to have a lot of headache to deal with, such as how long to wait for JavaScript to break the idle loop in #2 if the JavaScript request never comes through, etc.
This is not a normal execution flow for a standard webpage. Unless you really need this, perhaps consider this a proof-of-concept answer.
PHP executes first in its entirety on the server. It then sends the final HTML/Javascript/CSS output to the browser. The browser receives this and executes any Javascript.
It is fundamentally impossible to do what you're trying to do with that code. PHP and Javascript run at completely different times in completely different environments. You need to start another request to the server once Javascript set the cookie to start another PHP script. Redirect using Javascript or look into AJAX.
If you want to execute JavaScript before PHP, you'll have to divide it into two requests. You can load your JavaScript in one request, and execute an Ajax request after your cookie is set. Keep in mind that all server-side code is processed before the client-side code will be executed.
I have to ask though.. why do you want to do it this way? What are you trying to accomplish?
Cookies can be set in PHP with setcookie
setcookie("test",1,time()+3600);
This can't be done within a single request. PHP runs first, then JavaScript. Even incremental loading won't help, because cookies are sent via headers and those have already been sent by the time PHP runs.
However, you can let the JavaScript set the cookie and then reload the page once it's done by using location.reload(). PHP would then only need to print the JavaScript, like so:
<?php
if(!isset($_COOKIE["test"])) {
?>
<script type="text/javascript">
$(function() {
// createCookie script
createCookie("test", 1, 3600);
// reload the page, which would send the cookie at the next request
location.reload();
});
</script>
<?php
// stop execution and wait for JavaScript to call you again.
exit;
}
?>
The PHP executes on the server-side, the JS on the client-side. In a single GET request from the browser, the PHP will always execute before the JS.

How long after sending a header('Location: ...') command will the PHP script process?

I have two PHP scripts which both have an "include_once('authentication.inc');" script near the top. Both scripts reference the same authentication file. That authentication file currently performs a header redirect (like "header('Location: index.php');") if the user is not signed in.
In one file (A.php) the immediate next line of code after the include of the authentication file is:
if(isset($_GET['delete']))
mysql_query("DELETE FROM table WHERE index=".$_GET['delete']);
In the other file (B.php) there are several other includes which occur before the same "delete code" listed above.
So the authenticate.inc file looks like:
if(!valid_credentials($username,$password))
header('Location: index.php');
And file A.php looks like:
include_once('authenticate.inc');
if(isset($_GET['delete']))
mysql_query("DELETE FROM table WHERE index=".$_GET['delete']);
And file B.php looks like:
include_once('authenticate.inc');
include_once('other.php');
include_once('file2.php');
include_once('onemore.php');
if(isset($_GET['delete']))
mysql_query("DELETE FROM table WHERE index=".$_GET['delete']);
Yet when I call A.php?delete=5, that record is deleted from the database while when I call B.php?delete=8 that record is not.
I have checked the 3 intermediary includes and do not see any die() statements, nor any other header redirects.
So while it's clear that A.php is continuing to execute after the header is sent, why isn't B.php doing the same thing? Is the header being sent before the next set of imports?
**
Also: I know to add the die() or exit command after the headers are sent. I'm working on someone else's code and trying to explain behavior, not writing this myself.
**
No way to tell. If the starts are aligned properly, the header coud be sent to the client browser immediately and the bowser will start closing the current connection and request the new URL immediately. This'll cause the current PHP script to start shutting down.
On the other hand, if the caches are slow and the network glitchy, the client browser may not get the redirect header for seconds/minutes/hours, and the script could continue executing indefinitely.
In general you should assume that the moment you've issued a header redirect that the script is basically "walking dead" and should not do any further work.
The sole exception to this rule is that you CAN use ignore_user_abort(TRUE), which tells PHP to NOT shut down when the remote user disconnects. That'd allow you to continue on working even though the browser has shut down the connection and moved on to the new page.
Update your authenticate.inc file to die() after the redirect. This will prevent any other code from executing.
if(!valid_credentials($username,$password)) {
header('Location: index.php');
die();
}
Without it, and depending upon your server configuration, the rest of the PHP code will be executed on the server even after the headers are transmitted back to the client. Until the client closes the connection, the code will run.
Just put an exit() after the header redirect. It will stop all execution after the redirect.
There is probably some output in either of the included files, with echo or other outputting functions. If the browser by then has followed the redirect and aborted the connection, the PHP script will by default exit. You can change this behaviour with ignore_user_abort(true);. You should however use die(); after the Location header. If the query execution is wanted, just put that query before the Location header. Don't forget to use proper escaping for the input, otherwise the script could be a target for a mysql injection attack.
To answer your question, it seems that the browser will wait until your script finished execution and only then will request another location.
Please note that you shouldn't use GET method to delete records.
As for the not deleting id=8 - just debug it. Not a big deal.
A good var_dump() is always better than some vague ideas about headers.

Will all code after redirect header in PHP always get executed?

So I know the general rule of thumb is after doing a header redirect in PHP, you should call exit() to avoid having extra code running, but I want to know if you put code after the redirect header, if it will always run?
I was doing some research on various ways of tracking referrals in Google Analytics and came across this post: Google Analytics Tips & Tricks – Tracking 301 Redirects in Google Analytics
It recommends doing something like this:
<?
Header( “HTTP/1.1 301 Moved Permanently” );
Header( “Location: http://www.new-url.com” );
?>
<script type=”text/javascript”>
var gaJsHost = ((“https:” == document.location.protocol) ? “https://ssl.” : “http://www.”);
document.write(unescape(“%3Cscript src=’” + gaJsHost + “google-analytics.com/ga.js’ type=’text/javascript’%3E%3C/script%3E”));
</script>
<script type=”text/javascript”>
try {
var pageTracker = _gat._getTracker(“UA-YOURPROFILE-ID”);
pageTracker._trackPageview();
} catch(err) {}</script>
From the way I've always understood the header() function, it's up to the browser and it can run the redirect whenever it wants to. So there's no guarantee the JavaScript would actually begin or finish executing prior to the redirect occurring.
PHP's documentation for the header() function indicates the reason for exiting after a redirect is to "make sure that code below does not get executed when we redirect." That doesn't sound like they guarantee all following code will run, just that it could happen.
Regardless, I found a different way to actually manage the tracking, but I wanted to see if I could find out how exactly header() worked in this situation..
Thanks for your help.
Using the header function in PHP only adds to the headers of the response returned by the server. It does not immediately send any data and does not immediately terminate the connection. Any code after the header call will be executed.
In particular, it's a good idea to add a response body even after doing a 301 redirect so that clients that do not support the redirect also get some descriptive response. Infact according to the HTTP 1.1 specification Section 10.3.2 -
Unless the request method was HEAD, the entity of the response SHOULD
contain a short hypertext note with a hyperlink to the new URI(s). If
the 301 status code is received in response to a request other than
GET or HEAD, the user agent MUST NOT automatically redirect the
request unless it can be confirmed by the user, since this might
change the conditions under which the request was issued.
It's a race condition. Once the redirect header is sent to the browser, the browser will close the current connection and open a new one for the redirect URL. Until that original connection is closed and Apache shuts down the script, your code will continue to execute as before.
In theory, if there was a sufficiently fast connection between the client/server, and there was no buffering anywhere in the pipeline, issuing the header would cause the script to be terminated immediately. In reality, it can be anywhere between "now" and "never" for the shutdown to be initiated.
The HTML after your Location line doesn't run inside PHP; it would run in the browser. It's up to the browser whether or not to execute the Javascript that you've included on that page; PHP has nothing to do with it.
To me, the PHP docs imply that any PHP below the header() when you send a redirect will continue to run. But it 'runs' in the PHP interpreter, dumping JS to the browser. There's no relation between what it says in the PHP docs and whether or not the JS gets run by the browser.
EDIT:
Well, as Anupam Jain pointed out, looks like that browsers do not terminate connection without getting the response body and it sounds sensible. So i rethinked my answer
That doesn't sound like they guarantee all following code will run
Exactly More likely it's a warning in case there is some sensible code that shouldn't be executed. A private page contents for example. So, beside sending header you have to also make sure that no sensitive content were sent and exit looks like quite robust solution. So, I'd phrase it as "make sure that sensible code below does not get executed when we redirect."
So there's no guarantee the JavaScript would actually begin or finish executing prior to the redirect occurring.
Exactly It seems it has nothing to do with script execution but rather with browser's will to execute anything after getting 3xx response. I think I'm gonna test it, but you can test it as well too.
I have noticed that the code does still execute and multiple headers based on if statements can cause a "redirect loop error". i made it a habit to now add in die("Redirecting..."); after every header redirect and have not see the problem persist.

Are commands executed after the "header()" function in PHP?

For example, here:
<?php
session_start();
if (!isset($_SESSION['is_logged_in'])) {
header("Location: login.php");
die();
}
?>
<Some HTML content>
Is die() really necessary here ?
Is die() really necessary here ?
It is: Otherwise, the client will still get the HTML code in the response body. The header asks the client to terminate and go to the new page, but it can't force it.
The client can always continue listening to the response, and receive everything output afterwards, which is a fatal security hole e.g. when protecting sensitive data in a login area.
Yes, die() is necessary. A call to header("Location: some-location.php") sends the specified header (a 302 redirect in this case) to the browser; but it DOES NOT terminate the script. It becomes more important if the lines after the redirect statement contains PHP code which may execute unintentionally. So if want to send the redirect header and abort any further processing you must call die, exit, return or any other similar construct.
Note that it is possible to perform further processing after sending the redirect header.
Yes. Simply generating a header, even the Location header, does not terminate the current script. The HTML output will be visible in e.g. a packet sniffer.
I found that: http://www.figured-it-out.com/figured-out.php?sid=181
So according to this it seems that some browsers just stop receiving the html content and redirect directly to the new page where other browsers like IE still wait untill the loading of the page is ready.

Categories