<?php
require_once('mysql.php');
$VERSION = '3.0.2-SS';
## Global variables
$DDIR = WWWROOT . 'topsites/data';
$ADIR = WWWROOT . 'topsites/admin';
$CDIR = WWWROOT . 'topsites/cache';
$TDIR = WWWROOT . 'topsites/templates';
$CRLF = "\r\n";
$LF = "\n";
$DAY = 86400;
$WEEK = 604800;
$MONTH = 2592000;
$FUZZ = 0.0000001;
$PHPSTART = '<?PHP';
$PHPEND = '?'.'>';
$PERMISSIONS_FILE = 0666;
$PERMISSIONS_DIR = 0777;
$NOW = time();
$DB = NULL;
$T = array();
## Setup error reporting
error_reporting(E_ALL & ~E_NOTICE);
set_error_handler('Error');
if(get_magic_quotes_runtime())
{
ini_set('magic_quotes_runtime', 0);
}
register_shutdown_function('DisconnectOnExit');
## Load variables
if( file_exists("{$GLOBALS['DDIR']}/variables") )
{
require_once("{$GLOBALS['DDIR']}/variables");
}
## Adjust for suexec servers
if( $GLOBALS['SUEXEC'] == 1 || (isset($_SERVER['REQUEST_METHOD']) && IsSuexecServer()) )
{
$PERMISSIONS_FILE = 0644;
$PERMISSIONS_DIR = 0755;
}
## Initialize a new database object
$DB = new DB($GLOBALS['HOSTNAME'], $GLOBALS['USERNAME'], $GLOBALS['PASSWORD'], $GLOBALS['DATABASE']);
##############################################################
## Misc Functions ##
##############################################################
function IsSuexecServer()
{
$stat = stat(WWWROOT . 'topsites/tsphp.php');
if($stat['uid'] == posix_getuid())
{
return TRUE;
}
return FALSE;
}
function GetIPFromUrl($url)
{
if( IsEmptyString($url) )
{
return;
}
$pieces = parse_url($url);
return gethostbyname($pieces['host']);
}
function AreArraysIdentical(&$a, &$b)
{
if( count($a) != count($b) )
{
return FALSE;
}
foreach($a as $item)
{
if( !in_array($item, $b) )
{
return FALSE;
}
}
return TRUE;
}
function NumCompare($a, $b)
{
if( $a < $b )
{
return -1;
}
else if( $a > $b )
{
return 1;
}
return 0;
}
function ChangeCase(&$string, $case = NULL)
{
if( $case == NULL )
{
$case = $GLOBALS['TEXT_CASE'];
}
switch($case)
{
case 'AllUpper':
$string = strtoupper($string);
break;
case 'AllLower':
$string = strtolower($string);
break;
case 'FirstUpper':
$string = ucfirst(strtolower($string));
break;
case 'WordsUpper':
$string = ucwords(strtolower($string));
break;
default:
## The default is to do nothing
break;
}
}
function AgeString($time)
{
$days = (int)($time / (60*60*24));
$string = '';
$string .= $days > 0 ? $days . 'd ' : '';
$time -= $days * 60*60*24;
$hours = (int)($time / (60*60));
$string .= $hours > 0 ? sprintf("%02dh ", $hours) : "00h ";
$time -= $hours *60*60;
$minutes = (int)($time / 60);
$string .= $minutes > 0 ? sprintf("%02dm ", $minutes) : "00m ";
$time -= $minutes * 60;
$seconds = sprintf("%02ds", $time);
$string .= $seconds;
return $string;
}
function Mode($mode, $files)
{
if( !is_array($files) )
{
$files = array($files);
}
foreach($files as $file)
{
$stat = stat($file);
if( $stat['uid'] == posix_getuid() )
{
chmod($file, $mode);
}
}
}
function ParseTemplate($template)
{
global $T;
$contents = file_get_contents("{$GLOBALS['TDIR']}/$template");
$contents = preg_replace('/##([^#]+)##/ei', '$T["$1"]', $contents);
eval("?".">" . $contents . "<?php ");
}
function StringParse(&$string, &$template)
{
$string = preg_replace('/##([^#]+)##/ei', '$template["$1"]', $string);
}
function IsEmptyString(&$string)
{
if( preg_match("/^\s*$/s", $string) )
{
return TRUE;
}
return FALSE;
}
function MakeList(&$array)
{
if( !is_array($array) )
{
return "''";
}
else
{
return "'" . join("','", $array) . "'";
}
}
function IniWrite($file, &$hash)
{
foreach($hash as $key => $value)
{
if( !IsEmptyString($value) )
{
$text .= "=>[$key]\n$value\n";
}
}
UnixFormat($text);
FileWrite($file, $text);
}
function &IniParse($string, $isfile = TRUE)
{
$hash = array();
if( $isfile )
{
$string = file_get_contents($string);
}
if( IsEmptyString($string) )
{
return $hash;
}
UnixFormat($string);
preg_match_all("/^(.*\n?)/m", $string, $matches);
foreach($matches[1] as $line)
{
if( preg_match("/^=>\[(.*?)\]\n/", $line, $submatch) )
{
if( isset($key) )
{
$hash[$key] = rtrim($hash[$key]);
}
$key = $submatch[1];
}
else
{
$hash[$key] .= $line;
}
}
if( isset($key) )
{
$hash[$key] = rtrim($hash[$key]);
}
return $hash;
}
function DisconnectOnExit()
{
if( get_class($GLOBALS['DB']) == 'db' )
{
$GLOBALS['DB']->Disconnect();
}
}
function Error($code, $string, $file, $line)
{
$errortype = array (
E_ERROR => 'Error',
E_WARNING => 'Warning',
E_PARSE => 'Parsing Error',
E_NOTICE => 'Notice',
E_CORE_ERROR => 'Core Error',
E_CORE_WARNING => 'Core Warning',
E_COMPILE_ERROR => 'Compile Error',
E_COMPILE_WARNING => 'Compile Warning',
E_USER_ERROR => 'User Error',
E_USER_WARNING => 'User Warning',
E_USER_NOTICE => 'User Notice'
);
if( $code == E_STRICT || $code == E_NOTICE )
{
return;
}
$file = basename($file);
echo <<<HTML
<div>
<h2>$errortype[$code]</h2>
<table>
<tr>
<td>
<b>Error</b><br />
</td>
<td>
<span id="Error">
$string
</span>
<br />
</td>
</tr>
<tr>
<td>
<b>File</b><br />
</td>
<td>
$file<br />
</td>
</tr>
<tr>
<td>
<b>Line</b><br />
</td>
<td>
$line<br />
</td>
</tr>
</table>
</div>
HTML;
exit;
}
## Display the user error page
function UserError($error, $message = NULL)
{
global $T, $showInstantLE, $showTopSearches, $topsearches, $showRecentSearches, $recentsearches, $showRecentDownloads, $recentdownloads, $showSponsoredLinks, $instantLEmaxLinks, $skin, $instantLEsort, $partnerLinksSort;
$lang =& IniParse("{$GLOBALS['DDIR']}/language");
if( isset($lang[$message]) )
{
$T['Error'] = "{$lang[$error]}: {$lang[$message]}";
}
else
{
$T['Error'] = $lang[$error] . ($message != NULL ? ": $message" : '');
}
require("{$GLOBALS['CDIR']}/user_error.tpl");
require(WWWROOT . 'skins/' . $skin . '/footer.php');
exit();
}
function SafeAddSlashes(&$string)
{
$string = preg_replace("/(?<!\\\)'/", "\'", $string);
}
function ArrayAddSlashes(&$array)
{
foreach($array as $key => $value)
{
if( is_array($array[$key]) )
{
ArrayAddSlashes($array[$key]);
}
else
{
$array[$key] = preg_replace("/(?<!\\\)'/", "\'", $value);
}
}
}
function ArrayStripSlashes(&$array)
{
foreach($array as $key => $value)
{
if( is_array($array[$key]) )
{
ArrayStripSlashes($array[$key]);
}
else
{
$array[$key] = stripslashes($value);
}
}
}
function HashToTemplate(&$hash)
{
global $T;
foreach($hash as $key => $value)
{
$T[$key] = $value;
}
}
function UnixFormat(&$string)
{
$string = str_replace(array("\r\n", "\r"), "\n", $string);
}
function PCFormat(&$string)
{
$string = str_replace(array("\r\n", "\r", "\n"), "\r\n", $string);
}
function StripReturns(&$string)
{
$string = str_replace(array("\n", "\r"), '', $string);
}
function StripHTML(&$string)
{
if( is_array($string) )
{
foreach($string as $key => $value)
{
$string[$key] = str_replace(array('&', '<', '>'), array('&', '<', '>'), $value);
}
}
else
{
$string = str_replace(array('&', '<', '>'), array('&', '<', '>'), $string);
}
}
function StripHTMLNoAmp(&$string)
{
if( is_array($string) )
{
foreach($string as $key => $value)
{
$string[$key] = str_replace(array('<', '>'), array('<', '>'), $value);
}
}
else
{
$string = str_replace(array('<', '>'), array('<', '>'), $string);
}
}
function TrimHash(&$hash)
{
foreach($hash as $key => $value)
{
$hash[$key] = trim($value);
}
}
##############################################################
## File Manipulation Functions ##
##############################################################
function IsFile($file)
{
if( !file_exists($file) )
{
return TRUE;
}
else
{
return is_file($file);
}
}
function FileTaint($file)
{
if( !IsFile($file) )
trigger_error("Not A File: $file", E_USER_ERROR);
if( stristr($file, '..') != FALSE )
trigger_error("Security Violation: $file", E_USER_ERROR);
if( stristr($file, '|') != FALSE )
trigger_error("Security Violation: $file", E_USER_ERROR);
if( stristr($file, ';') != FALSE )
trigger_error("Security Violation: $file", E_USER_ERROR);
}
function FileWrite($file, $data, $mode = NULL)
{
FileTaint($file);
$fh = fopen($file, 'w');
flock($fh, LOCK_EX);
fwrite($fh, $data);
flock($fh, LOCK_UN);
fclose($fh);
if( $mode == NULL )
{
$mode = $GLOBALS['PERMISSIONS_FILE'];
}
if( $mode != FALSE )
{
Mode($mode, $file);
}
}
function FileWriteNew($file, $data, $mode = NULL)
{
if( !file_exists($file) )
{
FileWrite($file, $data, $mode);
}
}
function FileAppend($file, $data, $mode = NULL)
{
FileTaint($file);
$fh = fopen($file, 'a');
flock($fh, LOCK_EX);
fwrite($fh, $data);
flock($fh, LOCK_UN);
fclose($fh);
if( $mode == NULL )
{
$mode = $GLOBALS['PERMISSIONS_FILE'];
}
if( $mode != FALSE )
{
Mode($mode, $file);
}
}
function FileRemove($file)
{
FileTaint($file);
unlink($file);
}
function FileCreate($file, $mode = NULL)
{
if( !file_exists($file) )
{
FileWrite($file, '', $mode);
}
}
##############################################################
## Directory Manipulation Functions ##
##############################################################
function IsDirectory($dir)
{
if( !file_exists($dir) )
{
return TRUE;
}
else
{
return is_dir($dir);
}
}
function DirCreate($dir, $mode = NULL)
{
DirTaint($dir);
mkdir($dir, $mode);
if( $mode == NULL )
{
$mode = $GLOBALS['PERMISSIONS_DIR'];
}
if( $mode != FALSE )
{
Mode($mode, $dir);
}
}
function &DirRead($dir, $pattern)
{
$contents = array();
DirTaint($dir);
$dh = opendir($dir);
while( false !== ($file = readdir($dh)) )
{
$contents[] = $file;
}
closedir($dh);
$contents = preg_grep("/" . $pattern . "/i", $contents);
return $contents;
}
function DirTaint($dir)
{
if( !IsDirectory($file) )
trigger_error("Not A Directory: $dir", E_USER_ERROR);
if( stristr($dir, '..') != FALSE )
trigger_error("Security Violation: $dir", E_USER_ERROR);
}
##############################################################
## E-mail Functions ##
##############################################################
## Send an e-mail message
function Email($to, $from, $message, &$template)
{
global $CRLF;
$contents = '';
$boundary = GenerateBoundary();
$is_file = preg_match('/=>\[/', $message) ? False : True;
$email = array();
$email =& IniParse($message, $is_file);
$template['From'] = $from;
StringParse($email['Text'], $template);
StringParse($email['HTML'], $template);
if( !IsEmptyString($email['Text']) && IsEmptyString($email['HTML']) )
{
$headers = "From: $from$CRLF";
$contents = $email['Text'];
}
else if( !IsEmptyString($email['Text']) && !IsEmptyString($email['HTML']) )
{
$headers = "From: $from$CRLF" .
"Mime-Version: 1.0$CRLF" .
"Content-Type: multipart/alternative; boundary=$boundary$CRLF" .
"Content-Transfer-Encoding: 7bit$CRLF";
$contents = "--$boundary$CRLF" .
"Content-Type: text/plain; charset=iso-8859-1$CRLF" .
"Content-Transfer-Encoding: 7bit$CRLF$CRLF" .
"{$email['Text']}$CRLF" .
"--$boundary$CRLF" .
"Content-Type: text/html$CRLF" .
"Content-Transfer-Encoding: 7bit$CRLF$CRLF" .
"{$email['HTML']}$CRLF" .
"--$boundary--";
}
else
{
$headers = "From: $from$CRLF" .
"Mime-Version: 1.0$CRLF" .
"Content-Type: text/html; charset=iso-8859-1$CRLF$CRLF";
$contents = $email['HTML'];
}
UnixFormat($contents);
mail($to, $email['Subject'], $contents, $headers);
}
## Generate a unique value to use as the message boundary
function GenerateBoundary()
{
return "--" . md5(uniqid(rand(), true));
}
##############################################################
## Script Page Template Compiler ##
##############################################################
function CacheTemplate($filename)
{
$file = basename($filename);
$compiled = CompileTemplate($filename);
FileWrite("{$GLOBALS['CDIR']}/$file", $compiled);
}
#REPLACE
function TemplateAdd($key, &$values)
{
global $T;
$T[$key][] = $values;
}
function CompileTemplate($filename)
{
global $PHPSTART, $PHPEND;
$scope = array();
$compiled = '';
$namespace = '$T';
$contents = file_get_contents($filename);
$buffering = FALSE;
$buffer = '';
UnixFormat($contents);
foreach( explode("\n", $contents) as $line )
{
## skip blank lines
if( IsEmptyString($line) )
{
continue;
}
if( preg_match('/<!--\[(.*?)\]-/i', $line, $matches) )
{
$elements = ParseCommand($matches[1]);
switch($elements[0])
{
case 'Define':
if( $elements[1] == 'Start' )
{
$buffering = TRUE;
array_push($scope, 'Define');
}
else if( $elements[1] == 'End' )
{
$compiler = new Compiler();
$options = array();
$compiler->ExtractOptions($buffer, $options);
$compiled .= "$PHPSTART\n";
foreach($options as $name => $value)
{
$compiled .= "\$L_$name = '$value';\n";
}
$compiled .= "$PHPEND\n";
$buffer = '';
$buffering = FALSE;
array_pop($scope);
}
break;
case 'Newsites':
if( $elements[1] == 'Start' )
{
$buffering = TRUE;
array_push($scope, 'Newsites');
}
else
{
ProcessNewsitesDirective($compiled, $buffer);
$buffer = '';
$buffering = FALSE;
array_pop($scope);
}
break;
/*case 'Lookup':
if( $elements[1] == 'Start' )
{
$buffering = TRUE;
array_push($scope, 'Lookup');
}
else
{
ProcessLookupDirective($compiled, $buffer);
$buffer = '';
$buffering = FALSE;
array_pop($scope);
}
break;
case 'Comments':
if( $elements[1] == 'Start' )
{
$buffering = TRUE;
array_push($scope, 'Comments');
}
else
{
ProcessCommentsDirective($compiled, $buffer);
$buffer = '';
$buffering = FALSE;
array_pop($scope);
}
break;*/
case 'Results':
if( $elements[1] == 'Start' )
{
$buffering = TRUE;
array_push($scope, 'Results');
}
else
{
ProcessResultsDirective($compiled, $buffer);
$buffer = '';
$buffering = FALSE;
array_pop($scope);
}
break;
/*case 'Search':
if( $elements[1] == 'Start' )
{
$buffering = TRUE;
array_push($scope, 'Search');
}
else
{
ProcessSearchDirective($compiled, $buffer);
$buffer = '';
$buffering = FALSE;
array_pop($scope);
}
break;*/
case 'Loop':
if( $elements[1] == 'Start' )
{
$namespace = "\$item";
$compiled .= "$PHPSTART\nif( is_array(\$T['$elements[2]']) )\n{\nforeach( \$T['$elements[2]'] as \$item )\n{\n$PHPEND\n";
array_push($scope, 'Loop');
}
else if( $elements[1] == 'End' )
{
$namespace = '$T';
$compiled .= "$PHPSTART\n}\n}\n$PHPEND\n";
array_pop($scope);
}
break;
case 'If':
if( $elements[1] == 'Start' )
{
if( $elements[2] == 'Code' )
{
$compiled .= "$PHPSTART\nif( $elements[3] )\n{\n$PHPEND\n";
}
else
{
$compiled .= "$PHPSTART\nif($namespace"."['$elements[2]'] $elements[3])\n{\n$PHPEND\n";
}
array_push($scope, 'If');
}
else if( $elements[1] == 'Elsif' )
{
if( $elements[2] == 'Code' )
{
$compiled .= "$PHPSTART\n}\nelse if( $elements[3] )\n{\n$PHPEND\n";
}
else
{
$compiled .= "$PHPSTART\n}\nelse if($namespace"."['$elements[2]'] $elements[3])\n{\n$PHPEND\n";
}
}
else if( $elements[1] == 'Else' )
{
$compiled .= "$PHPSTART\n}\nelse\n{\n$PHPEND\n";
}
else if( $elements[1] == 'End' )
{
$compiled .= "$PHPSTART\n}\n$PHPEND\n";
array_pop($scope);
}
break;
case 'Include':
$compiled .= "$PHPSTART readfile('$elements[2]'); $PHPEND\n";
break;
default:
// Do nothing
break;
}
}
## Process non-command lines
else
{
if( $buffering )
{
$buffer .= "$line\n";
}
else
{
$line = preg_replace('/##Global:(.*?)##/', "$PHPSTART echo \$T['$1']; $PHPEND", $line);
$line = preg_replace('/##(.*?)##/', "$PHPSTART echo $namespace"."['$1']; $PHPEND", $line);
$compiled .= "$line\n";
}
}
}
if( count($scope) > 0 )
{
Error('Template control structures are invalid', $filename);
}
return $compiled;
}
function ParseCommand($line)
{
$elements = array();
$stack = array();
$chars = unpack("C*", $line);
$buffer = '';
foreach( $chars as $char )
{
$char = chr($char);
if( count($stack) < 1 && $char == ' ' && !IsEmptyString($buffer) )
{
$elements[] = $buffer;
$buffer = '';
continue;
}
if( $char == '(' )
{
array_push($stack, $char);
if( count($stack) <= 1 )
{
continue;
}
}
else if( $char == ')' )
{
array_pop($stack);
if( count($stack) < 1 && !IsEmptyString($buffer) )
{
$elements[] = $buffer;
$buffer = '';
continue;
}
}
$buffer .= $char;
}
if( !IsEmptyString($buffer) )
{
$elements[] = $buffer;
}
return $elements;
}
function ProcessNewsitesDirective(&$compiled, &$buffer)
{
global $PHPSTART, $PHPEND;
$buffer = preg_replace('/##(.*?)##/', "$PHPSTART echo \$account"."['$1']; $PHPEND", $buffer);
$compiled .= "$PHPSTART\n" .
"\$now = time();\n" .
"\$lang =& IniParse(\"{\$GLOBALS['DDIR']}/language\");\n" .
"\$DB->Connect();\n" .
"\$result = \$DB->Query(\"SELECT * FROM topsites_Snapshot WHERE \$now-Signup <= {\$GLOBALS['NEW_SITE']} ORDER BY Signup DESC LIMIT \$L_AMOUNT\");\n" .
"while(\$account = \$DB->NextRow(\$result))\n" .
"{\n" .
"AccountData(\$account, \$lang);\n" .
"$PHPEND\n" .
$buffer .
"$PHPSTART\n" .
"}\n" .
"\$DB->Free(\$result);\n" .
"$PHPEND\n";
}
function ProcessResultsDirective(&$compiled, &$buffer)
{
global $PHPSTART, $PHPEND;
$buffer = preg_replace('/##(.*?)##/', "$PHPSTART echo \$account"."['$1']; $PHPEND", $buffer);
$compiled .= "$PHPSTART\n" .
"if( \$T['Total'] > 0 )\n" .
"{\n" .
"\$shown = 0;\n" .
"\$DB->Seek(\$result, \$T['Start'] - 1);\n" .
"while(\$account = \$DB->NextRow(\$result) )\n" .
"{\n" .
"AccountData(\$account, \$lang);\n" .
"$PHPEND\n" .
$buffer .
"$PHPSTART\n" .
"\$shown++;\n" .
"if( \$shown >= \$L_PERPAGE )\n" .
"{\n" .
"break;\n" .
"}\n" .
"}\n" .
"}\n" .
"\$DB->Free(\$result);\n" .
"$PHPEND\n";
}
?>