My JavaScript book is out! Don't miss the opportunity to upgrade your beginner or average dev skills.

Sunday, May 24, 2009

PHP Full Proxy ... A Work In Progress

Something "truly dangerous" to play with: a proxy file able to understand everything via XMLHttpRequest, enabling any sort of cross site requests (no COMET yet, it could arrive soon).
Dunno even why I am posting this "little monster", but I am sure a lot of people would like to have "access to the entire web" simply using Ajax, and nothing else, something like this:

function website_exists(url){
var xhr = new XMLHttpRequest;
xhr.open("HEAD", "proxy.php?url=" + (url), false);
xhr.send(null);
return 199 < xhr.status && xhr.status < 400;
};

if(website_exists("http://gogle.com"))
alert("Of Course, It's Big G!");


WebReflection PHP Proxy



<?php

/** XMLHttpRequest PHP Proxy
* @author Andrea Giammarchi
* @blog http://webreflection.blogspot.com/
* @license Mit Style License
* @requires curl and Apache webserver
* @description basic authentication, GET, POST, HEAD, PUT, DELETE, others requests types.
* Nothing to do on the client side, except put "proxy.php?url=" as request prefix.
* The rest should be like normal in-server interaction
* @note DON'T TRY AT HOME
*/

// if no url has been provided, exit
if(!isset($_GET['url'])){
header('HTTP/1.1 400 Bad Request');
header('X-Proxy-Error: no url');
exit;
}

// work in progress
/* without Apache ... requires alternatives for Authorization and other stuff not in $_SERVER
if(!function_exists('getallheaders')){
function getallheaders(){
$headers= array();
foreach($_SERVER as $key => $value){
if(0 === strpos($key, 'HTTP_'))
$headers[str_replace(' ', '-', ucwords(str_replace('_', ' ', strtolower(substr($key, 5)))))] = $value;
}
return $headers;
}
}
// */

// GET, POST, PUT, HEAD, DELETE, ect ...
$method = $_SERVER['REQUEST_METHOD'];

// curl headers array
$headers= array();
foreach(getallheaders() as $key => $value)
$headers[] = $key.': '.$value;

// curl options
$opts = array(
CURLOPT_HEADER => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_BINARYTRANSFER => true,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => $headers
);

// if request is post ...
if($method === 'POST'){
// populate the array of keys/values to send
$headers = array();
foreach($_POST as $key => $value)
$headers[] = rawurlencode($key).'='.rawurlencode($value);
$opts[CURLOPT_POST] = true;
$opts[CURLOPT_POSTFIELDS] = implode('&', $headers);
}

// if it is a basic authorization request ...
if(isset($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'])){
// create user and pass parameters to send
$opts[CURLOPT_HTTPAUTH] = CURLAUTH_BASIC;
$opts[CURLOPT_PROXYUSERPWD] = '['.
rawurlencode($_SERVER['PHP_AUTH_USER'])
.']:['.
rawurlencode($_SERVER['PHP_AUTH_PW'])
.']'
;
}

// init curl session
$call = $session = curl_init(substr($_SERVER['QUERY_STRING'], 4));

// set all options
curl_setopt_array($call, $opts);

// clear unnecessary variables
unset($opts);
unset($headers);

// retrieve the output
$result = explode(PHP_EOL, curl_exec($call));

// nothing else to do so far (this version is not compatible with COMET)
curl_close($call);

// for each returned information ...
for($i = 0, $length = count($result), $sent = array(); $i < $length; ++$i){
$value = $result[$i];

// if all headers has been sent ...
if($value === '')
// send the output
exit(implode(PHP_EOL, array_splice($result, ++$i)));
else {
// ... or send the header (do not overwrite if already sent)
$tmp = explode(':', $value);
header($value, !isset($sent[strtolower($tmp[0])]));
}
}

?>


Have fun exploring the net ;)

4 comments:

V1 said...

the headers does not always return a empty sting. So if you check $value === '' it could horribly fail. In most cases it returns a new line. So i would suggest;

if($value === '' || $value === "\n" || $value === "\r")

Andrea Giammarchi said...

it's not the header, this is the curl library that separe headers from the rest of the body so at first empty line it means headers have finished. Please try or provide a test case that will fail, thank you.

Anonymous said...

I'm only getting
29 Naahh.. it will not work!

Andrea Giammarchi said...

try with PHP5 and curl extension