Cross Domain AJAX Using A Proxy

The web is full of people stating that you cannot make an XMLHttpRequest (or the Microsoft equivalent) for another domain. However, this is only a half truth, because you can with a proxy server. JavaScript strictly prohibits making an XMLHttpRequest directly to another domain, but you can always forward a remote request through a proxy service running on your own domain. Here is the script that I use:

Example 1: PHP Proxy Script

<?php
// add domains here to prevent proxy chaining by nefarious people; default allows all domains
$domainWhitelist = array("core.localhost", "localhost", "mattsnider.com");
$isDomainValid = true;
if (sizeof($domainWhitelist)) {
	$domain = preg_replace("/^www\./", "", $_SERVER["HTTP_HOST"]);
	// this attempts to prevent proxy chaining
	$isXMLHttpRequest = array_key_exists("HTTP_X_REQUESTED_WITH", $_SERVER) && "XMLHttpRequest" === $_SERVER["HTTP_X_REQUESTED_WITH"];
	$isDomainValid = $isXMLHttpRequest && in_array($domain, $domainWhitelist);
}

if ($isDomainValid) {
// Get the url of to be proxied
// Is it a POST or a GET?
$isPost = array_key_exists("url", $_POST);
$url = ($isPost) ? $_POST["url"] : $_GET["url"];
$headers = "";
$mimeType = "";

if ($isPost) {
	if (array_key_exists("headers", $_POST)) {$headers = $_POST["headers"];}
	if (array_key_exists("mimeType", $_POST)) {$mimeType = $_POST["mimeType"];}
}
else {
	if (array_key_exists("headers", $_GET)) {$headers = $_GET["headers"];}
	if (array_key_exists("mimeType", $_GET)) {$mimeType = $_GET["mimeType"];}
}

//Start the Curl session
$session = curl_init($url);

// If it’s a POST, put the POST data in the body
if ($isPost) {
	$postvars = "";
	while ($element = current($_POST)) {
		$postvars .= key($_POST)."=".$element."&";
		next($_POST);
	}
	curl_setopt ($session, CURLOPT_POST, true);
	curl_setopt ($session, CURLOPT_POSTFIELDS, $postvars);
}

// Don’t return HTTP headers. Do return the contents of the call
curl_setopt($session, CURLOPT_HEADER, ($headers == "true") ? true : false);

curl_setopt($session, CURLOPT_FOLLOWLOCATION, true);
// prevents an accidental or intentional DoS attack
curl_setopt($session, CURLOPT_MAXREDIRS, 2);
//curl_setopt($ch, CURLOPT_TIMEOUT, 4);
curl_setopt($session, CURLOPT_RETURNTRANSFER, true);

// Make the call
$response = curl_exe\c($session); // remove the "\" between the "exe" and "c", this was causing issues with wordpress

if ($mimeType != "") {
	// The web service returns XML. Set the Content-Type appropriately
	header("Content-Type: ".$mimeType);
}

echo $response;
curl_close($session);

} ?>

This is a modified version of PHP Proxy Script for Cross Domain Requests by Abdul Qabiz. It is very simple to use, just pass the request that you would have sent to the remote URL to this script instead, storing the remote URL in the url parameter. If it is a post request, then this script forwards the post parameters as well. If the remote URL response provides a mimeType then this script will return the same mimeType as the proxied response.

The script has improved handling of POST and GET detection, as I believe older versions of PHP (when Abdul’s script was originally written) handled missing associated array keys without throwing an error. As per some good advice by Steve Webster, I have added support for a whitelist of domains that can use the proxy. If you do not use the whitelist, then nefarious developers can hijack your proxy to mask malicious activity, making it seem like their malicious attacks comes from your servers. Example 1 shows that I have whitelisted two of my local servers and "mattsnider.com". Lastly, when using CURLOPT_FOLLOWLOCATION one should also set CURLOPT_MAXREDIRS, so that you cannot accidentally setup an infinite loop by redirecting to your own proxy.

Below is an example URL that you could use to get the IP address of a visitor to your site:

Example 2: A Test Url

// cross-domain url = http://jsonip.appspot.com/?callback=getip
// "proxy.php?url=" + encodeURIComponent("http://jsonip.appspot.com/?callback=getip")
var AjaxUrl = "proxy.php?url=http%3A%2F%2Fjsonip.appspot.com%2F%3Fcallback%3Dgetip";

This script uses the curl library, which is not usually defaulted on in PHP. To turn it on, simply uncomment the "extension=php_curl.dll" line in your "php.ini" file and restart your server.