strange problem, i'm opening a connection with fsockopen() to a page,
that page has a header(location:xx) to the same page (i'm just refreshing the script), but it'seems that the redirect isn't working...
obviously everything is working if i'm replicating it with a browser...
some code:
CONNECTION PAGE:
$socketcon = fsockopen($_SERVER['HTTP_HOST'],80,$errorno,$errorstr,10);
if($socketcon) {
$socketdata = "GET http://www.example.com/test2.php HTTP/1.0\r\nHost: ".$_SERVER['HTTP_HOST']."\r\nConnection: Close\r\n\r\n";
fwrite($socketcon,$socketdata);
fclose($socketcon);
}
CONNECTED PAGE (test2.php):
<?
//other code (working fine)
if($_GET["AAA"]){
//REDIRECT WORKED !
} else {
header("location:test2.php?AAA=1"); //same page but with a get param
}
?>
the REDIRECT WORKED part never get executed...
any suggestions ?
EDIT: the connection MUST be asynchronous
any suggestions ?
Yes, stop using a socket to do what cURL can do better ;) A header('Location: X') will actually send you a 301/303 HTTP response, which you (or the browser) should handle by making a new request. However, you don't seem to handle redirects. cURL, on the other hand, mimics browser-like functionality and it can follow redirects by using curl_setopt( $curlResource, CURLOPT_FOLLOWLOCATION, true );
Consider Is making asynchronous HTTP requests possible with PHP? which is a similar question.
Using exec()-family functions might be a good bet if you don't need return values; you can just call curl appended by & and it'll run in the background.
If you really, truly want to do this in PHP, you can either: spawn a new process (using pcntl_fork()) or handle redirects yourself.
To handle redirects you'll need to:
Determine what your response code is by looking at the first three characters read from the stream. A 200 means sucess, anything in the 300s means partial success.
Once you've found a 302 (or 307) in the first three characters, search for a location header. This will match the regex /\s*location:\s*(.+)$/m, I believe.
Validate that the URL you have from the location field matches your expectations and is trustworthy. It should be an absolute URL, but you'll need to check it for a safe server, safe port, safe URL and safe parameters. parse_url() may come in handy, but does not check for potential security issues.
Open a new connection to the new URL matched above (or, if it's the same host and you're using HTTP 1.1 with Keep-Alive, reuse your connection) to send the appropriate data.
Deal with any results/clean-up as required.
You can see this is very complex. This will also be recursive. What you're really talking about doing is writing a rudimentary HTTP parser in PHP. This is not a good idea - use cURL and find some other way to make it asynchronous.
Your connect function does not handle redirects.
If you want to support it you have to write the code yourself, or use a library like curl to make the connection.
Related
I created a PHP page that is allowed only for one person, That's OK but when the non allowed user write in address bar view-source:tstwebsite.com/test/page.php it shows the user the source of the page can I block the source code from the user? this is my code that allow this page only for one user.
$aiwab = mysql_query("SELECT * FROM `table`");
while($aiwa = mysql_fetch_array($aiwab)){
$alo = $aiwa['allowed'];
if ($alo == 2 ){
}else{
echo "<script>javascript:history.go(-1)</script>";
}
}
So how Can I block the user from viewing the source code?
Using javascript to "block" a user is, frankly, stupid. javascript can be disabled/ignored/bypassed, exactly as you've seen with your view-source "hack". "Security" can never be established if you're relying on the CLIENT to cooperate.
Use proper server-side authentication, e.g. even HTTP basic authentication, to protect the script.
If you just want to quickly change this from client-side authentication to server-side, then you could make the following change:
if ($alo == 2) {
}
else {
// Redirect them by sending a HTTP Location header
header("Location: www.yourdomain.com/path/to/another/page");
}
Note that the above solution will only work if header() is called before any output is sent to the browser (HTTP headers have to be sent before the body of the message begins).
This functions very similarly to your current solution, with the difference that the redirect is caused by code on the server rather than in the browser. view-source lets someone get around your authentication as it allows them to load the page in their browser, without running the client side code.
This is just a quick fix that should help illustrate the difference between client side and server side authentication. If this is for anything beyond just messing about and learning a little code, then you should really be learning more about security. Also note that the mysql functions you're using are currently deprecated and you should instead be using mysqli, or pdo
You will also want to read up on the uses of client-side versus server-side code, just to get a grasp of what to use for what tasks and why.
I'm trying to do a header redirect in PHP doing something like:
header("Location: http://www.domain.com/some/url");
exit;
This works fine when making a GET and POST request however it doesn't seem to work with PUT and DELETE requests.
I've tried doing:
header("Location: DELETE/PUT http://www.domain.com/some/url");
exit;
But that doesn't seem to work, also calling the url directly works fine. I can echo some text before and after the header call, so everything is working, seems to just ignore PUT and DELETE requests?
Similar question, possible same answer applies to you
The header function is used to send HTTP response headers back to the
user (i.e. you cannot use it to create request headers.
May I ask why are you doing this? Why simulate a POST request when you
can just right there and then act on the data someway? I'm assuming of
course script.php resides on your server.
To create a POST request, open a up a TCP connection to the host using
fsockopen(), then use fwrite() on the handler returned from
fsockopen() with the same values you used in the header functions in
the OP. Alternatively, you can use cURL.
PS: I see that it is also displayed under Linked tab :)
Using Location is not the proper way to set the HTTP Method header.
Try the following:
header("Request-Type: DELETE");
header("Location: http://www.domain.com/some/url");
exit;
However, I am not sure you can set request types with header() alone. I know you can with cURL.
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.
All over the Internet, included even here at Stack Overflow, people state that a good way to check if a request is AJAX or not is to do the following:
if (strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest' ) {...}
However, I don't see $_SERVER['HTTP_X_REQUESTED_WITH'] in the official PHP documentation
And when I try to do the following:
echo $_SERVER['HTTP_X_REQUESTED_WITH'];
Nothing is outputted.
Am I doing something wrong? Because I'd really like to be able to use $_SERVER['HTTP_X_REQUESTED_WITH'] if it's available.
The variables in $_SERVER are not really part of PHP, which is why you won't find them in the PHP documentation. They are prepared by the Web server which passes them on to the scripting language.
As far as I know, the X-Requested-With is sent by the Ajax functions of most major Frameworks but not all (Dojo, for example, added it only two years ago: #5801). As such, and taking into considerations #bobince' comments, it's safe to say it's not generally a 100% reliable method to determine whether a request is an AJAX request or not.
The only 100% secure way is to send a pre-defined flag (e.g. a GET variable) along with the request and for the receiving page to check for the presence of that flag.
don't forget that you can easily spoof any header with cURL like so
curl_setopt($ch,CURLOPT_HTTPHEADER,array("X-Requested-With : XMLHttpRequest"));
$_SERVER keys that start with HTTP_ are generated from HTTP request headers. In this case, the X-Requested-With header.
This header is a standardization-in-progress from all of the AJAX libraries out there.
It won't be documented in the php documentation per-se, but rather in the different AJAX libraries that set this header. Common libraries do sent this header: jQuery, Mojo, Prototype, ...
Usually these library will set the header using
xhrobj.setRequestHeader("X-Requested-With", "XMLHttpRequest");
Here's a quick function with example usage:
function isXmlHttpRequest()
{
$header = isset($_SERVER['HTTP_X_REQUESTED_WITH']) ? $_SERVER['HTTP_X_REQUESTED_WITH'] : null;
return ($header === 'XMLHttpRequest');
}
// example - checking our active call
if(!isXmlHttpRequest())
{
echo 'Not an ajax request';
}
else
{
echo 'is an ajax request';
}
echo $_SERVER['HTTP_X_REQUESTED_WITH'];
What'd you expect from such a code? Assume you're running it directly from the browser, not using AJAX request. So, how come this header could be set?
Well the Answer to the Ultimate Question of Life, the Universe, and Everything - an HTTP sniffer! Get yourself one and forget of printing $_SERVER variable.
Firebug has one, or you may want to use Fiddler HTTP proxy or LiveHTTPHeaders Mozilla plugin. I'm bored to make links but it easily googled.
So, with HTTP sniffer you can be sure of any HTTP header ever.
Note that you can't prevent any "direct access" by using XHR, as every HTTP request to your server is already "direct".
You have to set it specifically in your ajax request object (that is if you are not using a framework like jQuery), but core Javascript; like so:
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
Where xhr is your request object.
Then, PHP will now receive and set it in the global variable $_SERVER like so:
$_SERVER['HTTP_X_REQUESTED_WITH']
Otherwise $_SERVER['HTTP_X_REQUESTED_WITH'] will always be null.
Note: In your javascript, Please make sure you set headers after the request is open. I mean after xhr.open() method.
You can also blame some browser bugs - see this question and its solution for Firefox
Firefox does not preserve custom headers during Ajax request redirect: an ASP.NET MVC solution
IE also having caching issue which is more serious then detection of request method.
You anyway needs to add cache busters to avoid caching, so why not use another flag to specify the ajax call - or more better you can use different URL like http://ajax.mysite.com/endpoint/sevice?params
I agree Pekka. There is no reliable native method between front side and back side that can auto-detect if a client is really calling an endpoint using AJAX.
For my own use, I have few main ways to check if a client is requesting one of my endpoint:
I can use HTTP_X_REQUESTED_WITH when I'm not in cross domain context.
instead of checking "X-requested-with", I'm checking $_SERVER['HTTP_ORIGIN'] (that is sent from AJAX request) intending to handle cross domain permissions. Most of time, the main reason why I'm checking if a request is an AJAX request, is especially because of cross domain permissions, using this PHP code: header('Access-Control-Allow-Origin: '.$_SERVER['HTTP_ORIGIN']); // If this "HTTP_ORIGIN" is in my white list
my APIs expect from the client to explicit, in few cases, the datatype (JSON, HTML etc.) into a GET or a POST var. For example, I check if $_REQUEST['ajax'] is not empty or equal to an expected value.
The best solution to make sure if an HTTP request is truly sent via AJAX is using SESSION checking , you send session_id in a get parameter and you check this session if it's allowed or not !
$headers = apache_request_headers();
$is_ajax = (isset($headers['X-Requested-With']) && $headers['X-Requested-With'] == 'XMLHttpRequest');
My web hosting provider does not permit to use curl FOLLOWLOCATION option so I'm trying to
do it manually by using the header function.
My problem is that I need to keep my PHP script running and to be able to get the redirected URL data for parsing.
How do I do that?
Technically the PHP script continues running after the header () function is called. How you get URL data is another question. Can you not use get_file_contents () or readfile () on the URL?
You read the RAW data the request returns, you check for the redirect header(s), fetch the related URL(s) and do a new get with that URL (dry, rinse, repeat). As simple as that...
Alternatively you could stop being so lazy, check the curl_setopt documentation in the PHP reference manual and find solutions - by reading the comments at the bottom of the page - on how to solve this problem of course.