<?php
/*********************************************************\
****** bblocked Proxy class ******
***** *****
**** Copyleft (C) 2007 bblocked ****
*** ***
** This program is free software; you can redistribute it and/or **
** modify it under the terms of the GNU General Public License **
** as published by the Free Software Foundation; either version 2 **
** of the License, or (at your option) any later version. **
** **
** This program is distributed in the hope that it will be useful, **
** but WITHOUT ANY WARRANTY; without even the implied warranty of **
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the **
** GNU General Public License for more details. **
*** ***
**** ****
**** http://www.bblocked.org/ *****
****** ******
\*********************************************************/
/* Do not remove, prevents direct file access */
if(!defined('BB'))
die();
// Class containing bblocked Proxy engine
class Proxy {
var $_socket;
var $_url;
var $_method;
var $_headers;
var $_page;
var $_content_type;
var $_no_cache;
var $_realm;
var $_cookies = array();
var $_auth = array();
function url_parse($url, &$container) {
$container = array();
$temp = (is_array(@parse_url($url)) ? @parse_url($url) : @parse_url(decode_url($url)));
if(!empty($temp)) {
$temp['port_ext'] = '';
$temp['base'] = $temp['scheme'] . '://' . $temp['host'];
if(isset($temp['port']) && (($temp['scheme'] == 'http' && $temp['port'] != 80) || ($temp['scheme'] == 'ftp' && $temp['port'] != 21)))
$temp['base'] .= $temp['port_ext'] = ':' . $temp['port'];
else
$temp['port'] = $temp['scheme'] === 'https' ? 443 : ($temp['scheme'] === 'ftp' ? 21 : 80);
if($temp['scheme'] == 'https' && (!$GLOBALS['_config']['unsecure_ssl'] && !$_SERVER['HTTPS'])) {
$temp['port_ext'] ? '' : $temp['port'] = 80;
$temp['scheme'] = 'http';
}
$temp['path'] = isset($temp['path']) ? $temp['path'] : '/';
$path = array();
$temp['path'] = explode('/', $temp['path']);
foreach($temp['path'] as $dir) {
if($dir === '..')
array_pop($path);
else if($dir !== '.') {
for ($dir = rawurldecode($dir), $new_dir = '', $i = 0, $count_i = strlen($dir); $i < $count_i; $new_dir .= strspn($dir{$i}, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789$-_.+!*\'(),?:@&;=') ? $dir{$i} : rawurlencode($dir{$i}), ++$i);
$path[] = $new_dir;
}
}
$temp['path'] = str_replace('/%7E', '/~', '/' . ltrim(implode('/', $path), '/'));
$temp['file'] = substr($temp['path'], strrpos($temp['path'], '/')+1);
$temp['dir'] = substr($temp['path'], 0, strrpos($temp['path'], '/'));
$temp['prev_dir'] = substr_count($temp['path'], '/') > 1 ? substr($temp['dir'], 0, strrpos($temp['dir'], '/')+1) : '/';
$temp['full'] = $temp['base'] . $temp['path'] . ($temp['path']{-1} == '/' ? $temp['file'] : '') . ($temp['query'] ? '?' . $temp['query']: '');
$container = $temp;
return true;
}
return false;
}
function write_cache() {
$time = time();
foreach($this->_headers as $k=>$v)
$headers .= "{$k}: {$v}\r\n";
$content = "{$time}\r\n{$headers}\r\n{$this->_page}";
$fp = @fopen($GLOBALS['_config']['cache_dir'] . md5($this->_url['full']) . '.cache', 'w');
@fwrite($fp, $content . "\n\n<!-- servered from cache; cached on " . date("D, d F Y", $time) . ' -->');
@fclose($fp);
}
function read_cache(&$data) {
$cache_file = $GLOBALS['_config']['cache_dir'] . md5($this->_url['full']) . '.cache';
if(file_exists($cache_file)) {
list($date, $data) = explode("\r\n", file_get_contents($cache_file), 2);
if(time() <= $date+$GLOBALS['_config']['cache_time'])
return true;
}
return false;
}
function parse_response($data, $cache=false) {
$headers = array();
list($headers, $this->_page) = preg_split("'(HTTP\/1\.[01] \d{3} [a-zA-Z\x20]+\r\n(?:[a-zA-Z\-]{3,}\s*\:.*?\r\n)+\r\n)'s", $data, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
$headers = explode("\r\n", $headers);
sscanf(array_shift($headers), '%s %s', $http_ver, $response_code);
foreach($headers as $h) {
if($h != '') {
list($k, $v) = explode(':', $h, 2);
if(strtolower(trim($k)) == 'set-cookie')
$header[strtolower(trim($k))][] = trim($v);
else
$header[strtolower(trim($k))] = trim($v);
}
}
if($response_code == 304 && isset($header['last-modifed'])) {
header('HTTP/1.1 304 Not Modified');
header('Date: ' . gmdate("D, d M Y H:i:s", (isset($header['date']) ? intval(@strtotime($header['date'])) : time())));
exit(0);
}
if(isset($header['set-cookie'])) {
if($GLOBALS['_config']['accept_cookies']) {
foreach($header['set-cookie'] as $cookie) {
$name = $value = $expires = $path = $domain = $secure = $expires_time = '';
preg_match("'^\s*([^=;,\s]*)\s*=?\s*([^;]*)'", $cookie, $match) && list(, $name, $value) = $match;
preg_match("';\s*expires\s*=\s*([^;]*)'i", $cookie, $match) && list(, $expires) = $match;
preg_match("';\s*path\s*=\s*([^;,\s]*)'i", $cookie, $match) && list(, $path) = $match;
preg_match("';\s*domain\s*=\s*([^;,\s]*)'i", $cookie, $match) && list(, $domain) = $match;
preg_match("';\s*(secure\b)'i", $cookie, $match) && list(, $secure) = $match;
$expires_time = empty($expires) ? 0 : intval(@strtotime($expires));
$path = empty($path) ? '/' : $path;
if(empty($domain))
$domain = $this->_url['host'];
else {
$domain = '.' . strtolower(str_replace('..', '.', trim($domain, '.')));
if((!preg_match("'\Q" . $domain . "\E$'i", $this->_url['host']) && $domain != '.' . $this->_url['host']) || (substr_count($domain, '.') < 2 && $domain{0} == '.'))
continue;
}
if(count($_COOKIE) >= 15 && time()-$expires_time <= 0)
$this->_cookies[] = add_cookie(current($_COOKIE), '', 1);
if($GLOBALS['_config']['session_cookies'])
$_SESSION['data']['cookies'][serialize("$name;$path;$domain")] = serialize("$value;$secure");
else
$this->_cookies[] = add_cookie("COOKIE;$name;$path;$domain", "$value;$secure", $expires_time);
}
}
unset($header['set-cookie']);
}
if(!empty($this->_cookies))
$header['set-cookie'] = $this->_cookies;
if(isset($header['location'])) {
if(preg_match("'^[\\\/]+'", $header['location']{0}))
$this->HTTP($this->_url['base'] . $header['location']);
else
$this->HTTP($header['location']);
return false;
}
else {
if(isset($header['content-type'])) {
strpos($header['content-type'], ';') !== false ? (list($this->_content_type, $encoding) = explode(';', str_replace(' ', '', $header['content-type']), 2)) : $this->_content_type = $header['content-type'];
if(preg_match("'^(text\/(plain|html))'i", $header['content-type']) && !preg_match("'\.js$'i", $this->_url['full']))
$_SESSION['current_url'] = $this->_url['full'];
}
if(isset($header['content-length'])) {
$content_length = $headers['content-length'];
unset($header['content-length']);
}
if(isset($header['content-disposition']))
$header['content-disposition'] = empty($header['content-disposition']) ? ($header['content-disposition'] == 'application/octet_stream' ? 'attachment' : 'inline') . '; filename="' . $this->_url['file'] . '"' : $header['content-disposition'];
if(isset($header['p3p']) && preg_match("'policyref\s*=\s*[\'\"]?([^\'\"\s]*)[\'\"]?'i", $headers['p3p'][0], $matches))
unset($header['p3p']);
if(isset($header['refresh']) && preg_match("'([0-9]+)\s*;\s*url\=\s*(\S*)'i", $header['refresh'], $matches))
$header['refresh'] = $matches[1] . "; url={$GLOBALS['_config']['script_url_full']}?{$GLOBALS['_config']['arg_page']}=proxy&{$GLOBALS['_config']['arg_url']}=" . encode_url($matches[2]);
if(isset($header['uri']))
unset($header['uri']);
if(isset($header['content-location']))
unset($header['content-location']);
unset($header['connection'], $header['keep-alive']);
if($response_code == 401 && isset($header['www-authenticate']) && preg_match("'basic\s+(?:realm=\"(.*?)\")?'i", $header['www-authenticate'], $matches)) {
unset($header['www-authenticate'], $this->_page);
if(isset($this->_auth[$matches[1]])) {
$this->_realm = $matches[1];
$this->HTTP();
}
else {
$GLOBALS['_config']['realm_name'] = $matches[1];
print_template(TEMPLATE_HTTP_AUTH);
}
}
if($GLOBALS['_config']['request_page'] == 'raw')
$this->_page = $data;
else
$this->_headers = $header;
if($cache == true) {
switch(true) {
case ($response_code != 200):
case (isset($header['set-cookie'])):
case ($this->_no_cache === true):
break;
default:
$this->write_cache();
break;
}
}
return true;
}
}
function output_page() {
global $_config;
if(is_array($this->_headers)) {
foreach($this->_headers as $k=>$v) {
if($k == 'content-type' && preg_match("'^text\/plain(?:\s*\;\s*(.*))?'i", $v, $encoding)) {
header('content-type: text/html'. (isset($encoding[1]) ? "; {$encoding}" : ''));
$this->_page = '<pre>' . htmlentities($this->_page) . '</pre>';
continue;
}
if(is_array($v))
foreach($v as $v2) { header("{$k}: {$v2}"); }
header("{$k}: {$v}");
}
}
$url = $this->_url;
new Rewrite(array($url['base'], $url['base'] . $url['dir'] . '/'), $this->_page, $this->_content_type, $output);
print($output);
preg_match("'<title>(.*)?<\/title>'is", $this->_page, $title);
if($_config['force_title'])
$title = addcslashes(($_config['powered_by'] ? str_replace('{:title:}', ($title[1] ? html_entity_decode(preg_replace("'([\r\n]+\s*)'", " ", $_config['title'])) : $url['full']), $_config['powered_by_text']) : $_config['title']), "'");
else
$title = addcslashes(($_config['powered_by'] ? str_replace('{:title:}', ($title[1] ? html_entity_decode(preg_replace("'([\r\n]+\s*)'", " ", $title[1])) : $url['full']), $_config['powered_by_text']) : $title[1]), "'");
$url = addcslashes($url['full'], "'");
print <<<OUTPUT
<script defer>
<!-- script added by bblocked <http://www.bblocked.org/>
// change title of document
top.document.title='{$title}';
// change URL in bblocked form
top.headerFrame.document.f.{$GLOBALS['_config']['arg_url']}.value='{$url}';
-->
</script>
OUTPUT;
}
}
?>