I'm creating a script to validate a form and I was asking myself a question. When I use a header (see example below), do I need to use exit right after? I mean, does using header also means that it is exiting by default therefore I don't need to use the command exit?
// cancel button clicked
if (isset($_POST['cancel'])) {
header("Location: http://localhost/admin/tracks.php");
exit;
}
echo '<p>$name</p>'
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.
For example, try this code:
<?php
header("Location: http://www.google.com");
unlink(__FILE__);
?>
This little script uses header() to redirect you to Google, and then deletes itself. If you run it, you'll notice that after you were redirected, the file was still deleted. This means that the unlink() call was still executed even though the header() call redirected you.
I use exit after the header->location call because I want to be able to rely ABSOLUTELY on the fact that the script won't get past the header->location call.
If there's a bug somewhere and your script starts generating output BEFORE the header->location call, the call will fail, and script execution will continue normally (unless you call exit)
Although the answers above sound great, if you're unsure of your code path, this could lead to unexpected results. For example, if you're using a framework that relies on the fact that code execution will run from beginning to end, you may inadvertently interrupt it.
This might be okay from a user perspective as they will still be redirected and will be none the wiser, but consider the following:
You're using a framework (OS or custom) that is expecting to log redirects, or set additional headers (or any number of other items). By calling exit, you're circumventing that logic and therefore may get unexpected results.
So in short, yes the above methods will work, just a word of caution to know what you're expecting to happen before short circuiting it.
Output is generally not sent (depending on output buffering and so on) if you redirect like that, but as shown by the unlink() example the script does not die with header().
So the exit() or die() calls are necessary if you want to prevent the script from continuing after the redirect.
It does NOT stop your script from running, your script will keep on running and sometimes all a person (could be with bad intentions) needs is your script to reach a certain point where he could do X. Header() will just redirect, exit(); however will stop the script right on the spot (where exit(); is). or as someone else stated under the username:
Cody. A. Ray: Yes, the script continues to process after the call to header('Location: http://google.com') if you don't explicitly terminate it! I just tried this locally. I added test.php to a site in apache with these contents
<?php
header('Location: http://google.com');
error_log("WE MADE IT HERE SOMEHOW");
?>
And checked my /var/log/apache2/error_log for this entry:
[Tue Feb 12 23:39:23 2013] [error] [client 127.0.0.1] WE MADE IT HERE SOMEHOW
so end conclusion: Header doesn't stop the script from running.
does using header also means that it is exiting by default
How so?
What if your header is not Location: one but Content-type: or Cache-control or whatever else?
Related
After calling the redirect function header, should I call exit or not?
<?php // fileA
$urlFailToGoTo = '/formerror.php';
if (sth)
{
header(sprintf("Location: %s", $urlFailToGoTo));
exit(); //should I call exit() here? or return?
}
?>
Thank you
You definitely should. Otherwise the script execution is not terminated. Setting another header alone is not enough to redirect.
You should, just like #rgroli explains. If you do not want to bother with brackets, you can also call header() IN exit():
if(sth) exit(header("Location: http://example.com"));
Location header in HTTP/1.1 always requires absolute path see the note here.
Note: This is not a hack, since the exit code is used only if the parameter is integer, while header() produces void (it exits with code=0, normal exit). Look at it as exit_header() function like it should be after Location header.
It's generally good practice to exit; (note - it's a keyword, so you don't need the ()) after sending a Location: header, since browsers are supposed to redirect to the new page and so further execution of the current script is usually undesired.
If you don't have any code (PHP or HTML) under header, you don't have to.
exit is bad coding.
if you ever develop a big project and want to create PHP Unit Testcases, exit will screw you up.
exit terminates the script and your running test! there is no way to recover the test and tell if it has failed or not ...
organise your code the way, that there is no output and the script ends naturally if you use a redirect ...
After calling the redirect function header, should I call exit or not?
<?php // fileA
$urlFailToGoTo = '/formerror.php';
if (sth)
{
header(sprintf("Location: %s", $urlFailToGoTo));
exit(); //should I call exit() here? or return?
}
?>
Thank you
You definitely should. Otherwise the script execution is not terminated. Setting another header alone is not enough to redirect.
You should, just like #rgroli explains. If you do not want to bother with brackets, you can also call header() IN exit():
if(sth) exit(header("Location: http://example.com"));
Location header in HTTP/1.1 always requires absolute path see the note here.
Note: This is not a hack, since the exit code is used only if the parameter is integer, while header() produces void (it exits with code=0, normal exit). Look at it as exit_header() function like it should be after Location header.
It's generally good practice to exit; (note - it's a keyword, so you don't need the ()) after sending a Location: header, since browsers are supposed to redirect to the new page and so further execution of the current script is usually undesired.
If you don't have any code (PHP or HTML) under header, you don't have to.
exit is bad coding.
if you ever develop a big project and want to create PHP Unit Testcases, exit will screw you up.
exit terminates the script and your running test! there is no way to recover the test and tell if it has failed or not ...
organise your code the way, that there is no output and the script ends naturally if you use a redirect ...
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.
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.
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.