After the hoster upgraded from PHP 4.x to PHP 5.4.1 a friend of mine has a huge problem accessing $_SESSION variables when doing it via XMLHttpRequest (he uses jQuery for that).
I hope the following snippets of his code are illustrating his problem:
index.php
<?PHP
session_start ();
$_SESSION['chatfenster'] = array();
$_SESSION['user'] = 1;
?>
<!-- HTML Markup -->
<script type="text/javascript" src="../scripts/jquery/js/jquery-1.8.2.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
setInterval(function() {
$.post("http://www.his-domain.at/ticker_tracker.php", function( feedback ) { alert(feedback); } )
},
10000);
});
ticker_tracker.php:
<?PHP
session_start();
var_dump($_SESSION);
?>
When he browses to index.php and afterwards manually to ticker_tracker.php, the $_SESSION variables are var_dumped correctly, but if the php file is called via $.post(), the $_SESSION variables are all empty, thus alerting just "array{}".
Hosters support says everything is fine and they didn't change any settings at all, but I noticed that Chrome blocks the XMLHttpRequest due to cross domain requests, giving the error message (also only appearing after upgrade to PHP 5.4.1):
XMLHttpRequest cannot load. No 'Access-Control-Allow-Origin' header is present.
Adding Access-Control-Allow-Origin headers on the very top of every php solves this error, but the main problem (empty $_SESSION variables) still remains.
Any advice is appreciated. Thanks in advance!
If you get the access-control-allow-origin error (that can be solved as you said by adding a header), then you are doing a cross-domain request. That's why you have different session contents: they are different sessions!
This can be from one machine (domain) to the other (www.one.com to www.two.com), this could be from one subdomain to the other (www.one.com vs one.com) or this could be a different service (e.g. http vs https, and these might be served by a different machine or process).
All these things have one thing in common: you have a request that seems to go to a different place (hence the allow origin). And a different place has different sessions, as they are not shared.
Check why you have the access control thingy going on: the request isn't going to the same place. So 'fixing' it with headers is just a fix for the origin: remove that 'fix', and make the request not needing it. then you're back at the same server/process/whatever, and will have the same session.
Related
I am calling a php file using $.post. From the server I am returning json response. When I open the server url directly in browser it returns successfully. But from js it is not working.
The link I am calling is this(http://54.249.240.120/qcorner/login).
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
</head>
<body>
<input type="button" id="testID">
<script type="text/javascript">
$(document).ready(function() {
$("#testID").click(function() {
$.post('http://54.249.240.120/qcorner/login',function(result){
alert(result);
});
});
});
</script>
</body>
</html>
I also tried in Firefox. In that I get 200 OK, but no response.
Why this is happening
The problem is that it is a cross domain request the error being returned can be viewed by turning on the javascript console:
XMLHttpRequest cannot load http://54.249.240.120/qcorner/login. Origin null is not allowed by Access-Control-Allow-Origin.
You will need to make sure that the Access-Control-Allow-Origin headers are set to allow this to happen or Chrome will cancel the request.
I suspect you're running into a Cross-origin resource sharing problem. I'm guessing you're not accessing this page from http://54.249.240.120/, given that Chrome is showing it explicitly in the network tab (usually it doesn't do that if it's the same domain).
Long story short, you can't post via Javascript to another domain name. If you're accessing this at www.example.com, the browser won't recognize the IP address as the same domain name (even if the domain name resolves there). Easiest way, if you're in control of the whole situation, is just put that login code on the same domain as the code you're testing. In a local environment you can do this with your [hosts file, something like 54.249.240.120 www.example.com to redirect example.com (replace with your own domain that you are accessing the test page from) to the IP address. This won't work for the public internet, however.
If you must POST to another domain via javascript, you'll need to look into implementing the CORS standard. Here's an article I found explaining how to implement it in PHP.
An HTML 200 OK is not the same as a valid response. It means the server got your request, but it doesn't mean that your PHP file actually returned usable data. It could be returning an empty response altogether. It's time to debug the PHP file. I'd suggest logging to a file temporarily or use FirePHP. If error display is disable (as it should be on a production server), this can happen if your script is failing before any output is generated.
What exactly is happening with the request? You can't make an ajax request cross-domain with what you have listed in the question.
However, you're sending an empty POST request to the URL, and when I replicate an empty post request, it responds with an HTTP 206 error, which is what you need to sort out.
curl -X POST http://54.249.240.120/qcorner/login
{"head":{"status":206,"message":"Only 0 fields received, required 2"},"body":""}
I had the same issue as you and what I did is very simple.
In you PHP file receiving the ajax request, just add this line before sending the response :
<?php
header("Access-Control-Allow-Origin: *");
... // your code here
?>
i've got a slight problem with JS enabled detection.
not too big, because i know i'm on the right track.
but here's my deal:
when i try to set a cookie in JS (jQuery) using this code
$(window).load(function(){
$.cookies.set('c_jsEnabled', 'true');
});
or just in plain JS using this code
function setCookie()
{
document.cookie='c_jsEnabled=true';
}
<body onload="setCookie();">
and then try to detect it in PHP using this code
if($_COOKIE['c_jsEnabled'] == 'true')
{
if(file_exists('./main.php'))
{
require_once ('./main.php');
}
echo getIndex();
}
else
{
if(file_exists('./noJS.php'))
{
require_once ('./noJS.php');
}
echo getIndex();
}
setcookie('c_jsEnabled', '');
it takes 2 page refreshes to actually get the right value into PHP.
my guess is that this bascially means that the PHP script is executed before the JS function is fired.
could this be because all codes shown above are in the same script (index.php)?
This is kind of a problem for me, because i want to prevent people from using my website when they have JS disabled.
is there a way to set the cookie before php tries to get the cookie variable?
PHP is always "fired" before JavaScript because PHP is processed on the server and then sends out the HTML and JavaScript for the browser to process and render. You can never expect JavaScript to execute before PHP for this reason.
In your case, use JavaScript to set the cookie and then do a redirect to refresh the page so PHP can get the cookie value and act accordingly.
You should be setting the cookie directly from the PHP file. That way, you know that it exists, and more importantly, you have control of the cookie. You can set it from the client, but that will always execute after the HTML has been sent to the browser, so the PHP file won't get it until the next request.
PHP only sends the cookie header when content is sent to the browser. Javascript then executes after that, so you would need a second load of the page to detect the cookie.
This can trigger infinite redirection loops (especially if the user has cookies disabled), so be careful.
To disable the site to users without Javascript, consider the following.
<div id="noscript" style="width:100%; height:100%; z-index:999; position:absoloute; top:0px; left:0px; background-color:#CC9900; display:block">
Please Enable Javascript!</div>
<script type="text/javascript">
document.getElementById('noscript').style.display = 'none';
</script>
I find the <noscript> tag is unreliable (there was a bug in iOS causing it to only show when there was Javascript, if I remember correctly).
A second option:
You can have the PHP check for a cookie. If it isn't set, have it redirect (header("Location: aaa.html");) to a page with the Javascript to set the cookie and redirect back. (Alternatively, have the PHP output Javascript to set the cookie reload the page.) You then only have to worry about users who "spoof" the cookie, although you will also lock out users who have cookies disabled.
Nope - PHP will always be called before client-side JavaScript, so with this method you'll always have to refresh the page at least once. You're better to develop your site so that non-JS users have a worse-but-still-acceptable experience, or at worst use the <noscript> HTML tag to serve alternative content to those users.
You can't get a cookie in PHP that's being set by JavaScript before the page renders/executes.
You could set the cookie using PHP, however. That will ensure it's set and available regardless of JavaScript or multiple page refreshes.
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.
I have a situation like this.
<php>
<redirect the page >
<exit>
<javascript>
<redirect the page again>
I want to have javascript that basicall disables the PHP redirect. So if Javascript is enabled on the browser, the javascript redirect will work, if it disable, the PHP redirect will work. Should I just enclose the PHP code in span and make it invisible? Any ideas?
Addition ok this is not a simple redirect. the form authentication is rather odd. Register.php -> register_submit.php -> Was there an error -> yes go back to register.php (everything is javascript at this point). What I have added is PHP authentication as well so if I see javascript is not enabled, I take the user to register.php *after it does the regular checking of fields *.
PHP is a server-side technology. By the time Javascript even sees what's happened, it's too late.
Short answer, JS can't intercept/block PHP (as long as PHP is being called first).
Order of events:
Client requests page
PHP executes and generates output of page
Browser receives output
Browser begins parsing what was sent by what PHP already spit out.
Remove your PHP redirection and add this in your <head>:
<noscript>
<meta http-equiv="refresh" content="0; http://www.example.com/1" />
</noscript>
<script>
window.location = 'http://www.example.com/2';
</script>
This will redirect to http://www.example.com/1 when javascript is disabled, and to http://www.example.com/2 when it's enabled.
PHP code is executed on the server-side, while JS is client-side. So with that structure the PHP will kick in before the JS is executed. If you want JS to control PHP you need to make use of AJAX to control it.
Also enclosing PHP code in a "span" won't have any effect.
Javascript and PHP do not directly interact (exceptions apply, don't worry about them now :D). The best way to implement this type of interaction between these two disparate languages is to use the query string or cookies.
I think there may be some confusion here about when and how PHP is executed as opposed to when and how javascript is executed. Think of PHP as the factory - the goods are physically produced there. Think of your server as the loading dock, the internet as the shipping company. Your browser is the store, HTML is the shelves; Javascript is the window decorations on the store that sells the merchandise. The window decorations have no affect on the production, the factory can make some window decorations, but it doesn't use them, it just ships them right along with the merchandise for the store to use. PHP is the factory, javascript is the decoration. There are some problems with taking this analogy too literally, but there it is in a nutshell.
You can make the PHP redirect conditional on the presence or absence of a specific query string variable:
<?php
// redirect if $_GET['no_redirect'] is NOT set. Reverse the true/false to invert this rule
$do_redirect = (isset($_GET['no_redirect']) === false ? true : false);
// perform the redirect, if required
if ($do_redirect === false)
header('Location:http://mydomain.com');
?>
Javascript:
window.location = 'http://mydomain.com/?no_redirect=1';
EDIT If you're trying to detect if javascript is enabled, then the best way is for javascript to set a cookie if it is enabled. PHP can then check for this cookie, and if it isn't found then you'll know that javascript didn't get a chance to set it, so it must be disabled (or the user edited their cookies).
Take a look at some code snippets for dealing with cookies in javascript, and check out the documentation for dealing with cookies in PHP.
Using JSONP on a site say xyz.com, I am calling a site abc.com/test.php. However, everytime I call this site, I get a new session id in IE6 and IE7. In other browsers it remains constant.
The code of test.php is something like:
<?php
session_start();
echo session_id();
?>
However, after I visit http://abc.com/test.php in another window, and then refresh my page at xyz.com with JSONP code, it shows a constant ID. I have no clue why. Any suggestions?
This happens only in IE6 and IE7. Rest all work as expected. Somehow IE6 and IE7 dont seam to retain the session id (i.e. cookie name) until I actually visit the site in another window.
Based on some info on PHP.net, will adding this header work?
<?php header('P3P: CP="CAO PSA OUR"'); ?>
Quote:
"workaround when using session variables in a .php file referred by a frame (.html, or
other file type) at a different server than the one serving the .php:
Under these conditions IE6 or later silently refuses the session cookie that is
attempted to create (either implicitly or explicitly by invoquing session_start()).
As a consequence, your session variable will return an empty value.
According to MS kb, the workaround is to add a header that says your remote .php page
will not abuse from the fact that permission has been granted.
Place this header on the .php file that will create/update the session variables you want:"
If this doesn't solve it, it might be something to do with the HTTReferer as IE doesn't send it on requests that initiate from JavaScript (e.g. doing this in IE will fail to send the HTTR Referer document.location.href = 'http://example.com/';