<?php
/************************************************** 
 *                   Proxy w PHP                  * 
 ************************************************** 
 * Wersja: 0.4 Alpha                              * 
 * Autor: Jacek Kowalski (http://jacekk.info)     * 
 *                                                * 
 * Utwór rozprowadzany na licencji                * 
 * http://creativecommons.org/licenses/by-nc/2.5/ * 
 **************************************************/

ini_set('default_charset', '');

function glue_url($parsed) {
	if(!is_array($parsed)) return false;
	$uri = isset($parsed['scheme']) ? $parsed['scheme'].':'.((strtolower($parsed['scheme']) == 'mailto') ? '':'//'): '';
	$uri .= isset($parsed['user']) ? $parsed['user'].($parsed['pass']? ':'.$parsed['pass']:'').'@':'';
	$uri .= isset($parsed['host']) ? $parsed['host'] : '';
	$uri .= isset($parsed['port']) ? ':'.$parsed['port'] : '';
	if(isset($parsed['path'])) {
		$uri .= (substr($parsed['path'],0,1) == '/')?$parsed['path']:'/'.$parsed['path'];
	}
	$uri .= isset($parsed['query']) ? '?'.$parsed['query'] : '';
	$uri .= isset($parsed['fragment']) ? '#'.$parsed['fragment'] : '';
	return $uri;
}

function simple_path_adv($path) {
	$path = explode('/', simple_path($path));
	$new_path = array();
	
	foreach($path as $key => $value) {
		switch($value) {
			case '..':
				array_pop($new_path);
			break;
			case '':
			case '.':
			break;
			default:
				$new_path[] = $value;
			break;
		}
	}
	
	return '/'.implode('/', $new_path);
}

function simple_path($path) {
	$path = trim(str_replace(array('/./', '//', '\\'), '/', $path), '/');
	while(strpos($path, '//')!==FALSE OR strpos($path, '/./')!==FALSE) {
		$path = str_replace(array('/./', '//', '\\'), '/', $path);
	}
	return '/'.$path;
}

function dir_name($path) {
	if(substr($path, -1)!='/') {
		return dirname($path);
	}
	else
	{
		return $path;
	}
}

function base_path($start, $rel) {
	$start = explode('/', simple_path_adv($start));
	$rel = explode('/', $rel);
	
	if($rel[0]=='') {
		$start = array();
	}
	
	foreach($rel as $value) {
		switch($value) {
			case '..':
				array_pop($start);
			break;
			case '':
			case '.':
			break;
			default:
				$start[] = $value;
			break;
		}
	}
	
	return implode('/', $start);
}

function rewrite_html($text) {
	$tags = array(
		'a' => 'href',
		'img' => 'src',
		'link' => 'href',
		'script' => 'src',
		'form' => 'action',
		'embed' => 'src'
	);
	
	foreach($tags as $key => $value) {
		$text = preg_replace_callback("/(<".$key." .*?".$value.".*?=.*?\")(.*?)(\".*?>)/", replacer_html, $text);
	}
	
	return $text;
}

function rewrite_css($text) {
	$tags = array(
		'url(' => ')',
	);
	
	foreach($tags as $key => $value) {
		$text = preg_replace_callback("/(url\()([^\)]*)(\))/", replacer_css, $text);
	}
	
	return $text;
}

function replacer_html($m) {
	global $url;
	$m[2] = trim($m[2], "\r\n\t\0".' "\'');
	
	return $m[1].makelink($m[2], $url).$m[3];
}

function replacer_css($m) {
	global $url;
	$m[2] = trim($m[2], "\r\n\t\0".' "\'');
	
	return 'url(\''.makelink($m[2], $url).'\')';
}

function makelink($to, $link) {
	if(substr($to, 0, 7)!='http://') {
		$link = parse_url($link);
		$link['path'] = ltrim(base_path(dir_name($link['path']), $to), '/');
		$to = glue_url($link);
	}
	
	return './?u='.base64_encode($to);
}

function str_replace_limit($search, $replace, $subject, $limit=-1) {
	if (is_array($search)) {
		foreach ($search as $k=>$v) {
			$search[$k] = '`' . preg_quote($search[$k],'`') . '`';
		}
	}
	else {
		$search = '`' . preg_quote($search,'`') . '`';
	}
	
	return preg_replace($search, $replace, $subject, $limit);
}

function form($address='http://') {
	return '<script type="text/javascript" src="js.js"></script>
<div style="background:#fff; color:#000; border:1px solid black; display:block; position:fixed; bottom:0px;right:0px; left:0px; height:25px;"><form method="get" onsubmit="document.getElementById(\'u\').value=base64_encode(document.getElementById(\'u\').value)">URL: <input type="text" id="u" name="u" value="'.htmlspecialchars($address).'" /> <input type="submit" value="Go" /></form></div>';
}

if(!empty($_GET['u'])) {
	$url = base64_decode($_GET['u']);
}
else
{
	die('No URL!'.form());
}
if(parse_url($url, PHP_URL_SCHEME)!='http') {
	die('Wrong scheme (not http)'.form());
}
if(strtoupper($_SERVER['REQUEST_METHOD'])!='GET' AND strtoupper($_SERVER['REQUEST_METHOD'])!='POST') {
	die('Wrong method (not GET or POST)'.form());
}

$host = parse_url($url, PHP_URL_HOST);

$header .= !empty($_COOKIE[$host]) ? 'Cookie: '.http_build_query($_COOKIE[$host], '', '; ') : '';
$header .= isset($_SERVER['HTTP_ACCEPT']) ? "\r\n".'Accept: '.$_SERVER['HTTP_ACCEPT'] : '';
$header .= isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? "\r\n".'Accept-Language: '.$_SERVER['HTTP_ACCEPT_LANGUAGE'] : '';
$header .= isset($_SERVER['HTTP_ACCEPT_ENCODING']) ? "\r\n".'Accept-Encoding: '.$_SERVER['HTTP_ACCEPT_ENCODING'] : '';
$header .= isset($_SERVER['HTTP_AUTHORIZATION']) ? "\r\n".'Authorization: '.$_SERVER['HTTP_AUTHORIZATION'] : '';
$header .= isset($_SERVER['HTTP_CONTENT_TYPE']) ? "\r\n".'Content-Type: '.$_SERVER['HTTP_CONTENT_TYPE'] : '';
$header .= isset($_SERVER['HTTP_RANGE']) ? "\r\n".'Range: '.$_SERVER['HTTP_RANGE'] : '';
$header .= isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? "\r\n".'If-Modified-Since: '.$_SERVER['HTTP_IF_MODIFIED_SINCE'] : '';
$header = 'User-Agent: PrivProx/1.0'."\r\n".'Connection: close'."\r\n".'X-Forwarded-For: '.$_SERVER['REMOTE_ADDR'];

$context = stream_context_create(
	array(
		'http' => array(
			'method'  => strtoupper($_SERVER['REQUEST_METHOD']),
			'header'  => $header,
			'protocol_version' => '1.0',
			'content' => file_get_contents('php://input'),
		)
	)
);

$fp = fopen($url, 'r', FALSE, $context);

if(!$fp) {
	die('Cannot setup connection');
}

$header = stream_get_meta_data($fp);
$header = $header['wrapper_data'];
foreach($header as $value) {
	$head = explode(':', strtolower(trim($value)), 2);
	$head[0] = trim($head[0]);
	$head[1] = trim($head[1]);
	if($head[0]=='content-type') {
		if(strpos($head[1], ';')!==FALSE) {
			$type = explode(';', $head[1], 2);
			$type = trim($type[0]);
		}
		else
		{
			$type = $head[1];
		}
		if($type=='text/html' OR $type=='application/xhtml+xml') {
			$html = TRUE;
		}
		elseif($type=='text/css') {
			$css = TRUE;
		}
	}
	elseif($head[0]=='set-cookie') {
		$cookie = explode(';', $head[1]);
		$cookie[0] = explode('=', trim($cookie[0]), 2);
		if(strpos($cookie[0][0], '[')!==FALSE) {
			$cookie[0][0] = str_replace_limit('[', '][', $cookie[0][0], 1);
		}
		else
		{
			$cookie[0][0] .= ']';
		}
		$cookie[0][0] = $host.'['.$cookie[0][0];
		$cookie[0] = implode('=', $cookie[0]);
		$cookie = $cookie[0].';'.$cookie[1];
		
		header('Set-Cookie: '.$cookie, FALSE);
		continue;
	}
	elseif($head[0]=='location') {
		header('HTTP/1.1 302 Found');
		header('Location: '.make_link($head[1], $url));
		die();
	}
	header($value);
}

if($html === TRUE) {
	while (!feof($fp)) {
		$tresc .= fread($fp, 8192);
		
		if(strlen($tresc)>102400) {
			$tresc .= '<!-- --> <!-- FILE TOO BIG -->';
		}
	}
	
	echo str_replace_limit('</body>', form($url).'</body>', rewrite_html($tresc), 1);
}
elseif($css === TRUE) {
	while (!feof($fp)) {
		$tresc .= fread($fp, 8192);
		
		if(strlen($tresc)>102400) {
			$tresc .= '/* FILE TOO BIG */';
		}
	}
	
	echo rewrite_css($tresc);
}
else
{
	while (!feof($fp)) {
		echo fread($fp, 8192);
	}
}
?>