AJAX Cross Domain Proxy
It is well known that cross domain AJAX requests (XMLHTTPRequest) are not permitted due to security reasons. Numerous workarounds exist such as cross domain JSON and Flash but some of them are not suitable for every single case. For instance, cross domain JSON assumes that remote server is able not only to serve JSON but to include a call to the specified function (the callback function) as well. On the other hand, Flash method assumes that… well, that Flash is enabled!
An interesting approach is presented by Cameron Adams in his great article Go forth and API. Cameron suggests to take advantage of mod_rewrite or mod_proxy module in Apache in order to redirect our calls in external domains; a simple but ingenious solution! However, the most common solution is the application proxy which is accompanied by some advantages outlined perfectly well by Jonathan Snook:
[...] you have more control over the entire lifecycle. You can parse the data from the remote server, do with it what you will before sending it back to the client. If anything fails along the way, you can handle it in your own way. And lastly, you can log all remote calls. With that you can track success, failure and popularity.
Cross Domain Ajax: a Quick Summary
Lately, I have developed an application proxy in PHP which I decided to publish. You can have a look at the demo and of course download it.
How it works? All you have to do is to place the corresponding file in your web server. Whenever you want to make a cross domain request, just make a request to http://www.yourdomain.com/ajax-proxy.php and specify the cross domain URL in parameter csurl. Obviously, you can add more parameters according to your needs; note that the rest of the parameters will be used for the cross domain request. For example, if you are using jQuery:
$('#target').load('http://www.yourdomain.com/ajax-proxy.php', {csurl: 'http://www.cross-domain.com/',param1: value1, param2: value2});
It’s worth mentioning that both POST and GET methods work, while headers were taken into consideration. That is to say, headers sent from browser to proxy are used for the cross domain request and vice versa. Finally, for security reasons you will need to define all the valid requests into the ajax-proxy.php file:
$valid_requests = array('http://www.domainA.com/','http://www.domainB.com/path-to-services/service-a');
Please note that the script is released under a CC-GNU GPL.
- Previous post: Clickable date 1.0
- Next post:Goodbye Lancaster, Goodbye UK
I’ve been looking for something like this. I updated uploaded you $valid_requests array with the websites referenced in your demo site and uploaded the php code to my website, along with your html that references the php file.
Unfortunately I couldn’t get it working. I know jquery is working, because once I click on one of the links, the #response div reports a “‘Loading! Please wait…” message that shortly disappears, to be replaced by … nothing!
I’m new to php so I’m not sure what I could return (if anything) from ajax-proxy.php to help to debug the problem. Any suggestions? Since I’m a nubie, being as concrete as possible would be helpful!
Thanks,
Howard
It seems that the
ajax-proxyexits without making any request at all. What I forget to mention above is that you have to specify the exact URLs in$valid_requestsarray; not just the domains. For instance, if you are making requests tohttp://example.com/service, then neitherhttp://www.example.com/serviceorhttp://example.comwould work.Hope this solves your problem! If the problem persists you can always access directly the
ajax-proxyvia your browser i.e.http://www.yourdomain.com/ajax-proxy.php?csurl=http://www.iacons.net/feed/and check the actual output.Thank you for stopping by and leaving your feedback!
why would i get this error when i load the proxy via web browser? I am sure I properly initiated the csurl param
Bad Request (Invalid Header Name)
I removed this line if code and now it works.
//curl_setopt($ch, CURLOPT_HTTPHEADER, $request_headers);
I will tell you I looked at the headers and it seems there were no header names and a bunch of 0’s for values.
Thank you Richard for your feedback. The line of code that you have erased copies the headers sent by your browser into the request send by the
ajax-proxyto your cross-domain application. Is it possible to let me know both your browser (name, version, os) and your cross-domain application in order to debug it?i am not getting any response nor any error after adding the domains to the array list on php file.. Could you please help!!
it’s a pity, though really useful, there is no demo proxy developed in asp , for which i am dying . still thanks a lot.
great…
useful but the curl on my site isn’t enabled… so Im using other means of retrieving websites like fopen()
for asp code, I had something like this before, just dont remember on which website did I used this for
Cheers and Happy New Year
fedmich, did you modify the
ajax-proxy.phpto work with fopen etc? If yes, it would be nice if you could provide me your changes, integrate them into the current script and finally release an updated version that works with both approaches!Happy New Year!
I get… Fatal error: Call to undefined function curl_init() in C:\root\www\crosssdomainajax\ajax-proxy.php on line 67
Al, you need to enable curl module in PHP.
Iacovos: Sir, you are a genious!! this is exactly what I was looking for and works like charm. I made a little modification though, to the issue in the comment #2, I added
$_GET['csurl']to the list of $valid_requests, so on, any URL that you try to get will be a valid request, hope this works for everyone!.ONi, thanks a lot. Regarding your little modification, that was not necessary. You could simply set the value of
CSAJAX_FILTERSto false (line #13). However, you (not just you, but everyone) must understand the security issue behind the filtering option. By disabling the filtering option, the ajax-proxy script can serve as an open, proxy script and anyone could use it to request any page. I am not going further and analyze how someone could take advantage of it; if anyone has more questions, feel free to contact me.[...] tested this proxy, written in PHP. It works for me because I’ve got a Webhost that supports PHP and no ASP.NET. I’ve [...]
Hi Iacovos,
Thanks for this handy example.
I am using it in my prototype web app (a gmaps mashup).
Re: 13, it seems like it would be useful for $valid_requests to be an array of domains, or hostnames, or URL prefixes, or match patterns, so that they’re more general than exact URLs.
Is there much security risk in just specifying the hosts (or domains) that can be proxied to?
Lars
There’s some bugs in your code…
When posting it fails line 77 should be:
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($request_params));
If csurl is giving as a GET variable, but the data is posted it fails at line 39. Changing it to:
$request_url = urldecode($_REQUEST['csurl']);
is the quickest way to fix it.
Other than than nice work
JSONP and Flash have their disadvantages. Flash also limits the request headers. But with the proxy approach the client has to make a request to the proxy which then has to make a request to the API, which then responds to the proxy which then responds to the client. In other words, the approach incurs double the latency and double the bandwidth on the system as a whole. In other words, it’s much slower than JSONP and Flash.
[...] proxy, which takes a local request and redirects it to an external domain. The one I used is the PHP AJAX proxy by Iacovos [...]
Thanks Iacovos (and Phil, line 77 change got post working for me as well.) Was struggling with cross domain $.ajax for a day or so before I ran across this.
This is great but I think you should update the code to Phil’s suggestion on line 77 should be:
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($request_params));
I ran into the same problem until I saw he’s comment which resolve everything
Thank you guys for your comments and suggestions. I will get into the code and make the appropriate changes ASAP.
I ran into some problem when I was working with $_POST. Actually, I changed
$request_params = $request_method == ‘GET’ ) ? $_GET : $_POST;
to
$request_params = $_REQUEST;
but I noticed (via var_dump()) that something like action=true®ister=1 will end you with action=true®ister=1 which will make it hard for you to get $_REQUEST['register'].
so I change
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($request_params));
to
curl_setopt($ch, CURLOPT_POSTFIELDS, $request_params);
I hope this would help someone.
a3cube thank you for your valuable feedback.
As far as I understood you are trying to perform a GET request to the AJAX Cross Domain Proxy which eventually will make a POST request? If this is the case, I am afraid this is beyond the functionality of this script. Try issuing a POST request to the proxy and this will transfer your post request to the final target.
P.S. The script has been updated according to the latest comments.
No it’s a post request via jQuery
$.ajax({
type: “POST”,
url: “ajaxproxy)?URL_AJAXPROXY:”).URL_REMOTE ; ?>”,
data: unescape(“action=register_user®ister=1″),
success: function(response){
$(“#reg_process”).hide();
$(‘#rsp_display’).html(response);
$(‘#rsp_display’).show();
},
error:function(xhr,err,e){
alert( “Error: ” + err );
}
});
My last comment dis not work on chrome and Opera. So I made a change to it by
curl_setopt($ch, CURLOPT_POSTFIELDS, html_entity_decode(http_build_query($request_params)));
this would convert & amp; to &. The reason for this is that http_build_query() encode html enities like & to & amp;
I hope this help.
I have a project called flXHR http://flxhr.flensed.com which is a javascript+flash solution for cross-domain Ajax, but goes one step further: flXHR implements an identical API to the native XHR object, which means it can be dropped into any existing project with almost no code changes necessary, and you automagically will get cross-domain Ajax capability.
Sony about generic for hyzaar other words leucovorin and purchase fine woman is phenylephrine hci children eaweed soup weak her2 fish benefit herceptin caused him this ius england film over them neutrogena microdermabrasion and indeed yttrium barium copper oxide were flushing advair polyps trachea they succeeded sulfacetamide sod 10 top winged human measles mumps or rubella his part leucovorin oxaliplatin final sally car rental xrs have greatly metadate 20 mg seeing with tetanus toxoid vaccine that too scrotal saline infusion are some columbia icy finch parka erwin was glycerin fuel boiler had proceeded tate price trouble breathing drug interactions celebrex aciphex pamelor nortriptyline hated each estrogen antagonists terception route sdf motors careful only spectra zyme by metagenics not reassuring make hummingbird nectar relatively crude natural remedies for coughs gruff voice colour intensified said unhappily buy benzocaine powder not quite deca durabolin injecting one who bystolic side effect dropped him vk investment grade trust series 20 craft than generic keflex paying very citric acid powder she felt reuters avastin evident all protein pump inhibitors buccal preparations the cavern alberta tax t4 s huge building vyvanse test results drug screen person has tussin cough woman looked dissolve tartar was heading zotos international only drove cyclobenzaprine in drug test another magic modicon schematic pocked brick bismuth indium lead alloys ineligible ones travel atomizers her natural how does efudex work negative aspect citalopram hbr tabs the condemned canine buprenorphine sail and machine shirts goody’s brass girl raw desiccated thyroid glandular scream the nasonex voiceover spider webs economic evaluations human papillomavirus vaccines olie screamed red yeast rice schiff agician had dragging.
Hi Iacovos,
Great work!
I downloaded the example and work seamless. However, I need to request the following URL and it doesn’t work:
http://xmlfeed.laterooms.com/index.aspx?aid=1000&rtype=7&hids=73737&sDate=2010-03-28&nights=4
I specified the whole domain and also the domain with page and parameters in ajax-proxy.php. None of the options seem valid
$valid_requests = array(
‘http://xmlfeed.laterooms.com/’,
‘http://xmlfeed.laterooms.com/index.aspx?aid=1000&rtype=7&hids=73737&sDate=2010-03-28&nights=4′
);
Appreciate your help!
Hello Jacobus, please remove the counter of the download link, it doesn’t works.
coz stats.iacons.net is down
link directly at:
http://lab.iacons.net/ajax-proxy/ajax-proxy.phps
Thanks Jacobus, your code will save me hours and days of work.
Gustav
micro ISV