7

I have two files, domain.com/test2.php:

<div id="testDiv"></div>

<script src="http://domain.com/packages/jquery.js"></script>
<script>$("#testDiv").load("http://domain.com/test3.php", {var1:1, var2:2});</script>

and domain.com/test3.php:

<b>var1: <?php echo $var1; ?> , var2: <?php echo $var2; ?></b>

In this case domain.com/test2.php outputs var1: 1 , var2: 2 as one would expect, but let's now say I want to make a test2.php in a subdomain. To stop problems with cross-domain scripting, I would add this extra line to the start of sub.domain.com/test2.php:

<script>document.domain = "domain.com";</script>

This extra line stops the cross-domain error from showing up, but now the file no longer outputs var1: 1 , var2: 2. Why is this and how can I fix this?

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
Edward Stumperd
  • 137
  • 1
  • 7

1 Answers1

12

The document.domain mechanism is intended for allowing client-side communication between frames, rather than client-to-server communication. If you have one frame containing a page from example.com and another frame containing a page from foo.example.com then the two cannot access each other's DOM unless the latter sets document.domain to example.com as you showed in your example.

The modern preferred mechanism for cross-domain AJAX requests is Cross-Origin Resource Sharing, or "CORS". This mechanism involves having the target resource return a special HTTP response header that indicates that cross-domain requests are allowed. In your scenario you'd make your test3.php return the following HTTP response header:

Access-Control-Allow-Origin: sub.domain.com

In PHP you'd do this as follows:

header("Access-Control-Allow-Origin: sub.domain.com");

You can also set this header value to just * in order to allow cross-domain requests from any origin, but be aware that this will allow requests from sites you don't control.

Requests from client-side JavaScript libraries often also include the additional header X-Requested-With that is not in the standard set allowed by CORS, so it may be necessary to explicitly allow this header via an additional response header:

Access-Control-Allow-Headers: X-Requested-With

CORS is only supported in modern browsers. For older browsers the common convention is to use JSON-P, which is a trick exploiting the fact that a page on one server is able to load and execute a script file from another server. This technique requires that the target resource be a valid JavaScript program that calls a function in the page, so it's not as elegant and seamless as CORS but it should work in any browser that supports JavaScript.

Martin Atkins
  • 62,420
  • 8
  • 120
  • 138
  • Yeah. And setting the to * means any domain can load data from it. –  Mar 28 '13 at 18:28
  • Oh yes... I added this to my answer. Thanks. – Martin Atkins Mar 28 '13 at 18:45
  • When I try this I get a 500 Internal Server Error: `Internal Server Error The server encountered an internal error or misconfiguration and was unable to complete your request. Additionally, a 404 Not Found error was encountered while trying to use an ErrorDocument to handle the request.` – Edward Stumperd Mar 28 '13 at 18:48
  • Is there anything useful in your server's error log that might help explain what happened? – Martin Atkins Mar 28 '13 at 18:50
  • @MartinAtkins The following showed up in the apachelogs: malformed header from script. Bad header=Access-Control-Allow-Origin: test2.php – Edward Stumperd Mar 28 '13 at 19:33
  • Edward, that looks like a separate PHP-specific problem that isn't directly related to CORS, and I'm not a PHP expert; it might be most productive to start a new question about setting the CORS header from PHP, which will allow you to include a more complete code snippet and would then hopefully attract PHP experts to answer your question (whereas this question attracts those knowledgeable about JavaScript and CORS). However, I will note that the value of this header needs to be the *domain* the request will come from, not the *filename*. – Martin Atkins Mar 28 '13 at 19:43
  • Well, do I necessarily have to set the header in php? Because -if I'm understanding you correctly- I could also use the command `Access-Control-Allow-Origin: sub.domain.com`. If I'm understanding that correctly, then where would I put this? – Edward Stumperd Mar 28 '13 at 19:57
  • Perhaps I got the PHP example wrong; you could try instead `header("Access-Control-Allow-Origin: sub.domain.com")` ... let me know if that works better and I'll update my answer. – Martin Atkins Mar 28 '13 at 20:18
  • I checked the PHP manual and confirmed that I got the `header` call wrong; I just updated my answer to the correct form. Sorry about that. – Martin Atkins Mar 28 '13 at 20:19
  • Np. The Internal Server Error is gone now, but I'm sorry to say it's still not working. The network log still shows the request-status as cancelled. – Edward Stumperd Mar 28 '13 at 20:36
  • Well the next thing I would check is to see if anything is showing up in the error console and to see if the Network tab in the developer tools shows the `Access-Control-Allow-Origin` header; an important pitfall with PHP is that a call to `header` must be made *before* any response content appears, otherwise the header won't be added. I still think asking a separate question about sending the CORS headers from PHP is a good strategy at this point, and then both questions together should get you up and running. – Martin Atkins Mar 28 '13 at 21:55
  • @Edward Stumperd Which browser are you using? Maybe one not supporting CORS? See the list at http://en.wikipedia.org/wiki/Cross-origin_resource_sharing#Browser_support – FrankPl Mar 28 '13 at 22:45
  • @FrankPl Both chrome and firefox don't respond. @MartinAtkins My original question includes "and how can I fix this" which isn't yet fulfilled since your answer is yet to work. I placed `` on line 1 of test3.php and I'm getting no errors regarding the header in the errorlog so that can't be the problem, right? – Edward Stumperd Mar 29 '13 at 09:26
  • Well if you think that this is best addressed as a continuation of your original question then please at least edit the question to include your updated code and re-tag it to include `php`. (I personally interpreted your question as being about why `document.domain` doesn't work for AJAX; I know the answer to that, but I don't know PHP.) – Martin Atkins Mar 29 '13 at 14:55
  • @EdwardStumperd, This may be silly to think about, but make sure that your parent domain is indeed "domain.com", and sub-domain is "sub". Sometimes example includes conventions, not real names. – Tengiz Mar 29 '13 at 15:05
  • Martin, that's probably a fair point. Still, I would be very happy with someone telling me why the possible solution you gave me doesn't work. @Tengiz Yes, I made sure of that. – Edward Stumperd Mar 30 '13 at 13:00