Skip to content

Instantly share code, notes, and snippets.

@saltybeagle
Created April 19, 2010 01:02
Show Gist options
  • Save saltybeagle/370653 to your computer and use it in GitHub Desktop.
Save saltybeagle/370653 to your computer and use it in GitHub Desktop.
// XMLHTTP JS class is is developed by Alex Serebryakov (#0.9.1)
// For more information, consult www.ajaxextended.com
// What's new in 0.9.1:
// - fixed the _createQuery function (used to force multipart requests)
// - fixed the getResponseHeader function (incorrect search)
// - fixed the _parseXML function (bug in the ActiveX parsing section)
// - fixed the _destroyScripts function (DOM errors reported)
proxy_xmlhttp = function() {
// The following two options are configurable
// you don't need to change the rest. Plug & play!
var _maximumRequestLength = 1500;
var _apiURL = 'http://www.yourhost.com/xmlhttp.php';
this.status = null;
this.statusText = null;
this.responseText = null;
this.responseXML = null;
this.synchronous = false;
this.readyState = 0;
this.onreadystatechange = function() { };
this.onerror = function() { };
this.onload = function() { };
this.abort = function() {
_stop = true;
_destroyScripts();
};
this.getAllResponseHeaders = function() {
// Returns all response headers as a string
var result = '';
for (var property in _responseHeaders) {
result += property + ': ' + _responseHeaders[property] + '\r\n';
}
return result;
};
this.getResponseHeader = function(name) {
// Returns a response header value
// Note, that the search is case-insensitive
for(var property in _responseHeaders) {
if(property.toLowerCase() == name.toLowerCase()) {
return _responseHeaders[property];
}
}
return null;
};
this.overrideMimeType = function(type) {
_overrideMime = type;
};
this.open = function(method, url, sync, userName, password) {
// Setting the internal values
if (!_checkParameters(method, url)) {
return;
}
_method = (method) ? method : '';
_url = (url) ? url : '';
_userName = (userName) ? userName : '';
_password = (password) ? password : '';
_setReadyState(1);
};
this.openRequest = function(method, url, sync, userName, password) {
// This method is inserted for compatibility purposes only
return this.open(method, url, sync, userName, password);
};
this.send = function(data) {
if (_stop) {
return;
}
var src = _createQuery(data);
_createScript(src);
// _setReadyState(2);
};
this.setRequestHeader = function(name, value) {
// Set the request header. If the defined header
// already exists (search is case-insensitive), rewrite it
if (_stop) {
return;
}
for(var property in _requestHeaders) {
if(property.toLowerCase() == name.toLowerCase()) {
_requestHeaders[property] = value; return;
}
}
_requestHeaders[name] = value;
};
var _method = '';
var _url = '';
var _userName = '';
var _password = '';
var _requestHeaders = {
"HTTP-Referer": escape(document.location),
"Content-Type": "application/x-www-form-urlencoded"
};
var _responseHeaders = { };
var _overrideMime = "";
var self = this;
var _id = '';
var _scripts = [];
var _stop = false;
var _throwError = function(description) {
// Stop script execution and run
// the user-defined error handler
self.onerror(description);
self.abort();
return false;
};
var _createQuery = function(data) {
if(!data) {
data = '';
}
var headers = '';
for (var property in _requestHeaders) {
headers += property + '=' + _requestHeaders[property] + '&';
}
var originalsrc = _method +
'$' + _id +
'$' + _userName +
'$' + _password +
'$' + headers +
'$' + _escape(data) +
'$' + _url;
var src = originalsrc;
var max = _maximumRequestLength, request = [];
var total = Math.floor(src.length / max), current = 0;
while(src.length > 0) {
var query = _apiURL + '?' + 'multipart' + '$' + _id + '$' + current++ + '$' + total + '$' + src.substr(0, max);
request.push(query);
src = src.substr(max);
}
if(request.length == 1) {
src = _apiURL + '?' + originalsrc;
} else {
src = request;
}
return src;
};
var _checkParameters = function(method, url) {
// Check the method value (GET, POST, HEAD)
// and the prefix of the url (http://)
if(!method) {
return _throwError('Please, specify the query method (GET, POST or HEAD)');
}
if(!url) {
return _throwError('Please, specify the URL');
}
if(method.toLowerCase() != 'get' &&
method.toLowerCase() != 'post' &&
method.toLowerCase() != 'head') {
return _throwError('Please, specify either a GET, POST or a HEAD method');
}
if(url.toLowerCase().substr(0,7) != 'http://') {
return _throwError('Only HTTP protocol is supported (http://)');
}
return true;
};
var _createScript = function(src) {
if ('object' == typeof src) {
for(var i = 0; i < src.length; i++) {
_createScript(src[i]);
}
return true;
}
// Create the SCRIPT tag
var script = document.createElement('script');
script.src = src;
script.type = 'text/javascript';
if (navigator.userAgent.indexOf('Safari')){
script.charset = 'utf-8'; // Safari bug
}
script = document.getElementsByTagName('head')[0].appendChild(script);
_scripts.push(script);
return script;
};
var _escape = function(string) {
// Native escape() function doesn't quote the plus sign +
string = escape(string);
string = string.replace('+', '%2B');
return string;
};
var _destroyScripts = function() {
// Removes the SCRIPT nodes used by the class
for(var i = 0; i < _scripts.length; i++) {
if(_scripts[i].parentNode) {
_scripts[i].parentNode.removeChild(_scripts[i]);
}
}
};
var _registerCallback = function() {
// Register a callback variable (in global scope)
// that points to current instance of the class
_id = 'v' + Math.random().toString().substr(2);
window[_id] = self;
};
var _setReadyState = function(number) {
// Set the ready state property of the class
self.readyState = number;
self.onreadystatechange();
if(number == 4) {
self.onload();
}
};
var _parseXML = function() {
var type = self.getResponseHeader('Content-type') + _overrideMime;
if(!(type.indexOf('html') > -1 || type.indexOf('xml') > -1)) {
return;
}
var xml;
if(document.implementation &&
document.implementation.createDocument &&
navigator.userAgent.indexOf('Opera') == -1) {
var parser = new DOMParser();
xml = parser.parseFromString(self.responseText, "text/xml");
self.responseXML = xml;
} else if (window.ActiveXObject) {
xml = new ActiveXObject('MSXML2.DOMDocument.3.0');
if (xml.loadXML(self.responseText)) {
self.responseXML = xml;
}
} else {
xml = document.body.appendChild(document.createElement('div'));
xml.style.display = 'none';
xml.innerHTML = self.responseText;
_cleanWhitespace(xml, true);
self.responseXML = xml.childNodes[0];
document.body.removeChild(xml);
}
};
var _cleanWhitespace = function(element, deep) {
var i = element.childNodes.length;
if(i === 0) {
return;
}
do {
var node = element.childNodes[--i];
if (node.nodeType == 3 && !_cleanEmptySymbols(node.nodeValue)) {
element.removeChild(node);
}
if (node.nodeType == 1 && deep) {
_cleanWhitespace(node, true);
}
} while(i > 0);
};
var _cleanEmptySymbols = function(string) {
string = string.replace('\r', '');
string = string.replace('\n', '');
string = string.replace(' ', '');
return (string.length === 0) ? false : true;
};
this._parse = function(object) {
// Parse the received data and set all
// the appropriate properties of the class
if(_stop) {
return true;
}
if(object.multipart) {
return true;
}
if(!object.success) {
return _throwError(object.description);
}
_responseHeaders = object.responseHeaders;
this.status = object.status;
this.statusText = object.statusText;
this.responseText = object.responseText;
_parseXML();
_destroyScripts();
_setReadyState(4);
return true;
};
_registerCallback();
};
<?php
// XMLHTTP PHP class is developed by Alex Serebryakov (#0.9.1)
// For more information, consult www.ajaxextended.com
// NOTE: THE FILE SHOULD BE SAVED AS UTF-8 WITHOUT BOM
$AJAX = new XMLHTTP();
class XMLHTTP
{
var $env = Array();
var $log = false;
var $abort = false;
function XMLHTTP() {
$query = $_SERVER['QUERY_STRING'];
$query = $this->checkMultipart($query);
$this->getEnvironment($query);
$data = $this->contactServer();
$data = $this->parseData($data);
if($this->log) $this->logRequest('successfull');
$this->respond($data);
}
function checkMultipart($query) {
$q = $this->splitData('$', $query, 5);
if($q[0] != "multipart") return $query;
if(strpos($q[1], ".") > -1) {
$this->logRequest('HACK ATTEMPT ('.$q[1].')');
$this->abort = true; return;
}
$data = $this->getMultipart($q[1]);
$data['max'] = $q[3];
$data[$q[2]] = $q[4];
$alldone = true; $query = "";
for($i = 0; $i <= $q[3]; $i++) {
if(!$data[$i]) { $alldone = false; }
$query .= $data[$i];
}
if($alldone) {
$this->clearMultipart($q[1]);
return $query;
}
$this->saveMultipart($q[1], $data);
$this->env['callback'] = $q[1];
$result = Array("success" => true, "multipart" => true);
$this->respond($result); $this->abort = true;
}
function getMultipart($name) {
if(!file_exists($name)) { return Array(); }
$fp = fopen($name, "r"); $data = "";
while(!feof($fp)) { $data .= fgets($fp); }
fclose($fp); return unserialize($data);
}
function clearMultipart($name) {
if(file_exists($name)) { unlink($name); }
}
function saveMultipart($name, $data) {
$fp = fopen($name, "w");
fwrite($fp, serialize($data)); fclose($fp);
}
function getEnvironment($query) {
if($this->abort) return;
$env = Array();
$query = explode('$', $query);
$env['method'] = strtoupper($query[0]);
$env['url'] = $query[6];
$env['callback'] = $query[1];
$url = $this->splitData('/', substr($env['url'], 7), 2);
$env['page'] = '/'.$url[1];
$env['host'] = explode(':', $url[0]);
$env['port'] = (isset($env['host'][1])) ? $env['host'][1] : 80;
$env['host'] = $env['host'][0];
$env['request'] = $this->decodeQuery($query[5]);
$env['ip'] = $_SERVER['REMOTE_ADDR'];
$env['useragent'] = $_SERVER['HTTP_USER_AGENT'];
$env['headers'] = $query[4];
$env['headers'] = str_replace("=",": ", $env['headers']);
$env['headers'] = str_replace("&","\r\n", $env['headers']);
$env['username'] =$query[2];
$env['password'] = $query[3];
if ($env['method'] != 'GET' && $env['method'] != 'POST' && $env['method'] != 'HEAD')
$this->throwError('Please, specify either a GET, a POST or a HEAD method');
if (substr($env['url'], 0, 7) != 'http://')
$this->throwError('Only HTTP protocol is supported (http://)');
if (strlen($env['callback']) < 2)
$this->throwError('Internal error: callback function undefined');
// Make sure you restrict the host of the request
// Otherwise your server will act like an open proxy
$allowedhosts = array('www.yourhost.com', 'anotherallowedhost.com');
if (!in_array($env['host'], $allowedhosts)) {
$this->throwError('Requested host is not allowed');
}
$this->env = $env;
}
function decodeQuery($query) {
$query = preg_replace('/%(?!5B)(?!5D)([0-9a-f]{2})/si', '%u00\\1', $query);
$query = preg_replace_callback('/%u([0-9A-F]{4})/si', array(&$this, 'decodeChar'), $query);
return $query;
}
function decodeChar($char) {
$charCode = hexdec($char[1]); $result = '';
if (is_callable('iconv')) {
$result = iconv('UCS-2BE', 'UTF-8', pack('n', $charCode));
} else {
// Manual decoding table is still to come. Soon.
if ($charCode < 128) $result = chr($charCode);
}
return $result;
}
function contactServer() {
if($this->abort) return;
$fp = fsockopen($this->env['host'], $this->env['port'], $errno, $errstr, 10);
if(!$fp) $this->throwError('Unable to contact host '.$this->env['host']);
$out = $this->env['method']." ".$this->env['page']." HTTP/1.0\r\n";
$out .= "Host: ".$this->env['host']."\r\n";
$out .= "User-Agent: ".$this->env['useragent']."\r\n";
$out .= "Forwarded: by ".$this->env['host']." for ".$this->env['ip']."\r\n";
$out .= "Accept: text/xml,application/xml,application/xhtml+xml,";
$out .= "text/html;q=0.9,text/plain;q=0.8,q=0.2,text/css\r\n";
$out .= "Accept-Encoding: gzip, deflate, compress;q=0.9\r\n";
$out .= str_replace('HTTP-Referer: http%3A//','Referer: http://',$this->env['headers']);
$out .= 'Authorization: Basic '.base64_encode($this->env['username'].':'.$this->env['password'])."\r\n";
if($this->env['method'] == 'POST')
$out .= 'Content-Length: '.strlen($this->env['request'])."\r\n";
$out .= "Connection: Close\r\n\r\n";
if($this->env['method'] == 'POST')
$out .= $this->env['request']."\r\n";
$data = "";
if ($fp) {
fwrite($fp, $out);
while (!feof($fp)) {
$data .= fgets($fp, 128);
}
fclose($fp);
}
return $data;
}
function parseData($data) {
if($this->abort) return;
$result = Array();
$result['success'] = true;
$result['responseHeaders'] = Array();
$headers = substr($data, 0, strpos($data, "\r\n\r\n"));
$headers = explode("\r\n", $headers);
for ($i = 1; $i < count($headers); $i++) {
$header = $this->splitData(":", $headers[$i], 2);
$result['responseHeaders'][$header[0]] = trim($header[1]);
}
$status = explode(' ', $headers[0]);
$result['status'] = $status[1];
$result['statusText'] = $status[2];
$data = substr($data, strpos($data, "\r\n\r\n") + 4);
if(isset($result['responseHeaders']['Content-Encoding']) && $result['responseHeaders']['Content-Encoding'] == 'gzip') {
$data = substr($data, 10); $data = gzinflate($data);
}
$data = trim($data);
$charset = explode('=', $result['responseHeaders']['Content-Type']);
if (isset($charset[1])) {
$charset = strtolower($charset[1]);
} else {
$charset = '';
}
if($charset == "windows-1251" && is_callable('iconv'))
$data = iconv("windows-1251", "utf-8", $data);
$data = str_replace("\r", '\r', $data);
$data = str_replace("\n", '\n', $data);
$data = str_replace('\'', "\'", $data);
$result["responseText"] = $data;
return $result;
}
function respond($data) {
if($this->abort) return;
$data = $this->parseResponse($data);
echo $this->env['callback']."._parse(".$data.")";
}
function parseResponse($data) {
$output = "";
foreach($data as $key=>$value) {
$v = (is_array($value)) ? $this->parseResponse($value) : "'".$value."'";
$output .= "'$key': $v, ";
}
$output = "{ ".substr($output, 0, -2). " }";
return $output;
}
function splitData($separator, $data, $length) {
if(!$separator) return Array();
if(!$data) return Array();
$data = explode($separator, $data);
if($length) {
while(count($data) > $length) {
$data[count($data)-2] .= $separator.$data[count($data)-1];
array_pop($data);
}
}
return $data;
}
function throwError($description) {
$result = Array("success" => false, "description" => $description);
$this->logRequest('Error: '.$description);
// Since all errors of this script are fatal
// we should terminate it
$this->respond($result); $this->abort = true;
}
function logRequest($extra) {
if($this->abort) return;
if(!$this->log) return;
$fp = fopen("log.txt","a"); if(!$fp) return;
$data = $this->env['ip'].' | '.date("d.m.y H:i:s").' | '.$_SERVER["HTTP_REFERER"]." | ".$this->env['url']." | ".$extra."\r\n";
fwrite($fp, $data); fclose($fp);
}
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment