<?php
/*********************************************************\
****** bblocked Rewrite 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 Rwrite engine
class Rewrite {
var $_dir;
var $_host;
var $_tags = array("META",
"STYLE",
"SCRIPT",
"FORM"
);
var $_events = array("ONABORT",
"ONBLUR",
"ONCHANGE",
"ONCLICK",
"ONDBLCLICK",
"ONDRAGDROP",
"ONERROR",
"ONFOCUS",
"ONKEYDOWN",
"ONKEYPRESS",
"ONKEYUP",
"ONLOAD",
"ONMOUSEDOWN",
"ONMOUSEOUT",
"ONMOUSEOVER",
"ONMOUSEUP",
"ONMOVE",
"ONRESET",
"ONRESIZE",
"ONSELECT",
"ONSUBMIT",
"ONUNLOAD"
);
function Rewrite($urls, $source, $content_type='text/plain', &$output) {
list($this->_host, $this->_dir) = $urls;
switch(strtolower($content_type)) {
case 'text/css':
$output = $this->css_parse($source); break;
case 'text/javascript':
case 'application/x-javascript':
$output = $this->js_parse($source); break;
case 'text/html':
$output = $this->html_parse($source);
break;
/*
case 'text/xml':
case 'application/xml':
case 'application/xhtml+xml':
return $this->xml_parse(); break;
case 'text/plain':
case 'text/richtext':
case 'text/x-setext':
case 'text/enriched':
case 'text/x-speech':
case 'text/tab-separated-values':
return $source; break;
*/
default:
$output = $source; break;
}
if(strtolower($content_type) === 'text/html') // HTML only
{
if($GLOBALS['_config']['scramble_bad_words'] == 1 && $GLOBALS['_config']['scramble_bad_words'] != 2) {
function sort_strlen($a, $b) {
$a = strlen($a); $b = strlen($b);
return ($a>$b ? 1 : ($a<$b ? -1 : 0));
}
$words = explode(',', $GLOBALS['_config']['bad_words']);
usort($words, "sort_strlen");
foreach($words as $word)
$output = preg_replace("'\b\Q{$word}\E\b'i", '<script>document.write(\'' . implode(preg_split("''", $word, -1, PREG_SPLIT_NO_EMPTY), '\',\'') . '\');</script>', $output);
}
/*elseif($GLOBALS['_config']['scramble_bad_words'] == 2)
{
require($GLOBALS['_config']['rewrite_dir'].'/'.'html_base64.php'); //It already takes care of $output.
}*/
}
}
function redir_url($in, $htmlify = true) {
return "{$GLOBALS['_config']['script_url_full']}?{$GLOBALS['_config']['arg_page']}={$GLOBALS['_config']['request_page']}".(($htmlify) ? '&' : '&')."{$GLOBALS['_config']['arg_url']}=" . encode_url($in);
}
function alter_url($value) {
if(preg_match("'^[\\\/]'", $value{0})) { $value = $this->_host . $value; }
else if(!preg_match("'^[a-z]{3,6}:\/\/[a-z0-9]+'i", $value)) { $value = $this->_dir . preg_replace("'^\.+'", "", $value); }
else if(preg_match("'^[a-z]{3,6}:\/\/[a-z0-9]+'i", $value)) { $value = $value; }
else { $value = $this->_dir . $value; }
return $value;
}
function css_parse($source) {
if($GLOBALS['_config']['rewrite_css'] == false)
return "\n\n// Stylesheets has been disabled.\n\n";
foreach(preg_split("'(\@import\s*(?:\"[^\"]*\"|\'[^\']*\'|[^\s\"\'>]+))'is", $source, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY) as $code) {
if(preg_match("'\@import\s*(\"[^\"]*\"|\'[^\']*\'|[^\s\"\'>]+)'is", $code, $import)) {
$import[1]{0} == '"' ? $delim = '"': $import[1]{0} == "'" ? $delim = '"': $value = $import[1];
!isset($value) ? $value = substr($import[1], 1, -1) : $delim = '';
$source = str_replace($import[1], $delim . $this->redir_url($this->alter_url($value),0) . $delim, $source);
}
}
$split = preg_split("'(url\s?\((?:[^\(\)]+(?:\"[^\"]*\"|\'[^\']*\')?)+\))'i", $source, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
foreach($split as $css) {
if(preg_match("'^url\s?\('i", $css)) {
list($open, $value, $close) = preg_split("'(\(|\))'", $css);
if(preg_match("'^(\"[^\"]*\"|\'[^\']*\')$'", $value)) { $delim = $value{0}; $value = substr($value, 1, -1); }
$out .= "{$open}({$delim}" . $this->redir_url($this->alter_url($value),0) . "{$delim}){$close}";
}
else { $out .= $css; }
}
return $out;
}
function js_parse($source) {
if(preg_match("'^\s*<\!\-\-[.\s]*\-\->\s*$'m", $source))
list($open, $source, $close) = preg_split("'(^\s*<\!\-\-|\-\->\s*$)'is", $source, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
if($GLOBALS['_config']['remove_script'] == true)
return "// Javascript has been disabled.";
if($GLOBALS['_config']['rewrite_script'] == false)
return $open . $source . $close;
if(preg_match("'new\s+SWFobject\s*\((.*?)\)'i", $source, $swf) && !preg_match("'^http\:\/\/(www\.)?youtube\.com'i", $GLOBALS['_config']['request_url'])) {
$url = preg_replace("'^\s*(\'[^\']*\'|\"[^\"]*\"|[^)]*).*'", "\\1", $swf[1]);
$url{0} == '"' ? $delim = '"': $url{0} == "'" ? $delim = '"': $value = $url;
!isset($value) ? $value = substr($url, 1, -1) : $delim = '"';
$source = str_replace($url, $delim . $this->redir_url($this->alter_url($value)) . $delim, $source);
}
//$source = preg_replace("'if\s*\(\s*\w*\.location\s*(\!\=)\s*\w*\.location\s*\)\s*\{?\s*top\.location\s*\=\s*(\w*\.)?location\.href\s*\;?\s*\}?'i", "", $source);
$source = preg_replace("'((?:top\.|window\.|document\.|self\.)?location(?:\.href)?\s*\=)'ie", "'break; // Removed redirection by bblocked'", $source);
preg_match_all("'[\w.-]+\.(?:href|location|action)[\t\s]*\=[\t\s]*(\"[^\"]*\"|\'[^\']*\'|[^\s\"\'\;]*)'i", $source, $action);
foreach($action[1] as $k=>$v) {
$value = $old_funtions[$k] = $v;
if(preg_match("'^(\"[^\"]*\"|\'[^\']*\')$'", $value)) { $delim = $value{0}; $value = substr($value, 1, -1); }
else { $delim = '"'; }
if(preg_match("'\.action[\t\s]*\='", $action[0][$k]))
$new_funtions[$k] = $delim . SCRIPT_URL_FULL . $delim;
else { $new_funtions[$k] = $delim . $this->redir_url($this->alter_url($value)) . $delim; }
}
$source = str_replace($old_funtions, $new_funtions, $source);
$split = preg_split("'(window\.open\s?\((?:(?:(?:\"[^\"]*\"|\'[^\']*\'|[^\(\)]*),?)?)+\))'i", $source, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
foreach($split as $script) {
if(preg_match("'^window\.open\s?\('i", $script)) {
list($open, $atrs, $close) = preg_split("'(\(|\))'", $script);
$atr = explode(",", $atrs);
$value = $atr[0];
if(preg_match("'^(\"[^\"]*\"|\'[^\']*\')$'", $value)) { $delim = $value{0}; $value = substr($value, 1, -1); }
else { $delim = '"'; }
$atr[0] = $delim . $this->redir_url($this->alter_url($value)) . $delim;
$out .= "{$open}(" . implode(",", $atr) . "){$close}";
}
else { $out .= $script; }
}
return $open . $out . $close;
}
function html_parse($source) {
if($GLOBALS['_config']['remove_script'] == true)
$source = preg_replace("'<(\/)?noscript>'i", "<\\1span>", $source);
$html = preg_split("'(<(?![^a-z0-9\/])(?:[^>]+(?:\"[^\"]*\"|\'[^\']*\')?)+>)'i", $source, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
foreach($html as $code) {
if(preg_match("'^<(?![^a-z0-9\/])(?:[^>]+(?:\"[^\"]*\"|\'[^\']*\')?)+>$'i", $code)) {
if($code{1} == "/") { $out .= $code; }
else {
$tag_contents = substr($code, 1, -1);
list($tag_name, $atributes) = preg_split("'\s'", $tag_contents, 2);
if(array_search(strtoupper($tag_name), $this->_tags) === false) {
$parse_tag = preg_split("'([^\s\"\'<>]+(?:\"[^\"]*\"|\'[^\']*\')?)'", $tag_contents, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
$new_tag_contents = array_shift($parse_tag);
foreach($parse_tag as $value) {
if(preg_match("'^\s+$'", $value)) { $new_tag_contents .= $value; }
else { $new_tag_contents .= $this->alter_general($value); }
}
$out .= "<{$new_tag_contents}>";
}
else if(preg_match("'^meta\s+http-equiv\s*=\s*(?:\'|\")?refresh(?:\'|\")?\s+content\s*\=\s*(?:\'|\")?[0-9\s]+;\s*url\s*\=\s*([^\s\"\']*)(?:\'|\")?'i", $tag_contents, $matches))
$out .= '<' . str_replace($matches[1], "{$GLOBALS['_config']['script_url_full']}?{$GLOBALS['_config']['arg_page']}={$GLOBALS['_config']['page_proxy']}&{$GLOBALS['_config']['arg_url']}=" . encode_url($matches[1]), $tag_contents) . '>';
else { $out .= $code; }
}
}
else
$out .= $code;
}
return $this->alter_specific($out);
}
function alter_general($tag_contents) {
if(strpos($tag_contents, "=") !== false) {
list($name, $value) = explode("=", $tag_contents, 2);
if(preg_match("'^(\"[^\"]*\"|\'[^\']*\')$'", $value)) { $delim = $value{0}; $value = substr($value, 1, -1); }
else { $delim = '"'; }
switch(strtoupper($name)) {
case 'ACTION':
case 'BACKGROUND':
case 'HREF':
case 'SRC':
if(!preg_match("'^(?:\#|(?:javascript|mailto)\:)'i", $value))
$tag_contents = "{$name}=" . $delim . $this->redir_url($this->alter_url($value)) . $delim;
break;
case 'STYLE':
$tag_contents = "{$name}=" . $delim . $this->css_parse($value) . $delim;
break;
case 'TARGET':
if($value == ("_top"||"_blank")) { $value = "mainFrame"; }
$tag_contents = "{$name}={$delim}{$value}{$delim}";
break;
default:
break;
}
}
return $tag_contents;
}
function alter_specific($in) {
$html = preg_split("'(<(?:form|style|script)(?:(?:[^>]+(?:\"[^\"]*\"|\'[^\']*\'|[^\s\"\'>]*)?)+)?>|<\/(?:form|style|script)>)'is", $in, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
foreach($html as $k=>$code) {
if(isset($last) && $k<=$last)
continue;
else if(preg_match("'^<form(\s|>)'i", $code)) {
if(preg_match("'<form.*?action\s*\=\s*(\"[^\"]*\"|\'[^\']*\'|[^\s\"\'>]+).*?>'is", $code, $action)) {
$action[1]{0} == '"' ? $delim = '"': $action[1]{0} == "'" ? $delim = '"': $value = $action[1];
!isset($value) ? $value = substr($action[1], 1, -1) : $delim = '"';
$out .= str_replace($action[1], $delim . $GLOBALS['_config']['script_url_full'] . '/' . rawurldecode(encode_url(str_replace('://', '/', $this->alter_url($value)))) . $delim, $code);
}
else {
$out .= preg_replace("'^(<form)'i", '\1 action="' . $GLOBALS['_config']['script_url'] . '/' . rawurldecode(encode_url(str_replace('://', '/', $this->alter_url($value)))) . '"', $code);
}
}
else if(preg_match("'^<style(\s|>)'i", $code)) {
$out .= $code . $this->css_parse($html[$k+1]) . $html[$k+2];
$last = $k+2;
}
else if(preg_match("'^<script(\s|>)'i", $code)) {
$open = $code;
$js = $html[$k+1];
$close = $html[$k+2];
$last = $k+2;
if(stristr($open, 'src')) {
preg_match("'src\s*\=\s*(\"[^\"]*\"|\'[^\']*\'|[^\s\"\'>]+)'i", $open, $src);
$src[1]{0} == '"' ? $delim = '"': $src[1]{0} == "'" ? $delim = '"': $value = $src[1];
!isset($value) ? $value = substr($src[1], 1, -1) : $delim = '"';
$out .= str_replace($src[1], ($GLOBALS['_config']['remove_script'] == true ? '""' : $delim . $this->redir_url($this->alter_url($value)) . $delim), $open) . $js . $close;
}
else
$out .= $open . $this->js_parse($js) . $close;
}
else
$out .= $code;
unset($delim, $value);
}
return $out;
}
}
?>