getUsers(); $output = ''; if ($json === false) { foreach ($users as $name) { $output .= '
:: '; $output .= ''; $output .= ($action && !$system) ? ''.$name.' ' : ''; $output .= $fields[3] . '
' . "\n"; } return $output; } /** * getName() * * Attempt to find a user's name in the $_POST * and $_COOKIE variables */ function getName() { // Look for the name in $_POST then in // $_COOKIE, or give a new generic name if (array_key_exists('name', $_POST) && mb_strlen(trim($_POST['name'])) > 0) { $name = urldecode($_POST['name']); setcookie(LACE_NAME_COOKIE, $name, time()+3600*24*30, LACE_URL_REL); } else $name = cookieVar(LACE_NAME_COOKIE, 'Guest ' . mb_substr(rand(0,9999), 0, 4)); return $name; } /** * extractMessageArray() * * Convert a record from the data file * into a usable array of data */ function extractMessageArray($line) { $linearray = explode('||', $line); // Snag the unix timestamp and perform some date calculations $datetime = array_shift($linearray); // Time elapsed (e.g. 1.5 hours, 4 days, etc.) $age = duration_str(time() - $datetime, false, 2); // Long format date $date_full = date("l, d F Y", $datetime); // Short format date $date = date('m/d/Y', $datetime); // Time of day $time = date('H:i', $datetime); // Day of week $day = date('l', $datetime); // Hour $hour = date('H', $datetime); // Next snag the name $name = array_shift($linearray); // Check for action or system notice $action = ($name{0} == '*') ? true : false; $notice = ($name{0} == '!') ? true : false; if ($action || $notice) $name = mb_substr($name, 1); // Now put the post back together $words = trim(implode(' ', $linearray)); // return this mess of info return array ( 'timestamp' => $datetime, 'date_full' => $date_full, 'date' => $date, 'time' => $time, 'day' => $day, 'hour' => $hour, 'age' => $age, 'action' => $action, 'notice' => $notice, 'name' => $name, 'text' => $words ); } /** * preFilterName() * * Perform custom filtering on names * that lib_filter doesn't cover */ function preFilterName($name) { $name = trim($name); // Prevent long names from disrupting mesage flow. $name = mb_substr($name, 0, 12); // System messages are from the user Lace. No one // can use the name Lace. if ($name == 'Lace') $name = 'Not Lace'; //$name = htmlentities($name); // Lace uses an asterisk prefix in the name to denote actions, // so users can't have one in that position. if ($name{0} == '*') $name = mb_substr($name, 1); // Lace uses a bang prefix in the name to denote system notices, // so users can't have one in that position if ($name{0} == '!') $name = mb_substr($name, 1); // Replace all < and > characters with entities // And, sorry, Lace uses pipes as delimiters... no soup for you! $search = array('<', '>', '|'); $replace = array('<', '>', ''); $name = str_replace($search, $replace, $name); return $name; } /** * preFilterLink() * * Filter Link text by separating the URL from the link text * and filtering the link text as normal. * * If the URL somehow contains malicious characters, they should * be filtered out by htmlentities() when the URL is output as * a link, but this might break the link. */ function preFilterLink($text) { $array = explode(' ', $text); $url = array_shift($array); $text = implode(' ', $array); $text = preFilterText($text); return $url . ' ' . $text; } /** * codeTagFilter() * * Replace the contents of tags with HTML Entities so
* that lib_filter will leave it alone.
*
* Note:
* If the closing tag is missing, this step is skipped and
* when lib_filter kicks in, malicious code will be stripped
* and the closing tag added, which means the contents of any code
* tags will likely be missing or mangled.
*/
function codeTagFilter($text)
{
$pattern = '%()(.*?)()%se';
$replace = "'\\1'.htmlentities(codeTagFilter('\\2')).'\\3'";
return stripslashes(preg_replace($pattern, $replace, $text));
}
/**
* preFilterText()
*
* Perform custom filtering that lib_filter normally misses.
*/
function preFilterText($text)
{
// Make sure the submitted text isn't too long
// This shouldn't affect valid URLs as AutoLinks
if (mb_strlen($text) > LACE_MAX_TEXT_LENGTH)
$text = mb_substr($text, 0, LACE_MAX_TEXT_LENGTH);
// Wrap long lines if there are more than 35 characters
// and less than three spaces.
if (mb_strlen($text) > 35 && mb_substr_count($text, ' ') < 3)
$text = real_wordwrap($text, 35, ' ');
// Filter the contents of tags so that lib_filter
// doesn't interfere with them.
$text = codeTagFilter($text);
// Add rel attribute to links
if (mb_strpos($text, ' 200 400 > 200
// 100 <>500 100 <> 500
// etc...
$pattern = '%(\d)\s*([<>=]{1,2})\s*(\d)%se';
$replace = "'\\1'.htmlentities(' \\2 ').'\\3'";
$text = preg_replace($pattern, $replace, $text);
// Replace all orphaned < and > characters with entities to keep
// lib_filter from hosing them...
// And, sorry, Lace uses pipes as delimiters - broken vertical bar for you!
$search = array(' < ', ' > ', '|');
$replace = array(' < ', ' > ', '¦');
$text = str_replace($search, $replace, $text);
// Replace all mid-message newlines with
tags
// Currently, this break large blocks of code within
// tags...
$text = str_replace("\n", '
', $text);
// Replace all
tags with
tags
$text = str_replace('
', '
', $text);
// Reduce groups of 3
tags to just 2
while(mb_strpos($text, '
') !== false)
{
$text = str_replace('
', '
', $text);
}
return $text;
}
/**
* getCommand()
* Parse incoming message text for a command
*
* Commands must be within the first 4 characters
* of the message
*
* The two supported commands are actions
* (designated by '/me ' or '\me '), and links
* (designated by 'http' or 'www.')
*/
function getCommand($text)
{
$cmd = strtolower(mb_substr($text, 0, 4));
switch ($cmd)
{
case '/me ':
case '\me ':
$command = 'action';
break;
case 'http':
case 'www.':
$command = 'link';
break;
default:
$command = false;
break;
}
return $command;
}
/**
* prepareMessage()
*
* Prepare incoming message data for storage
*/
function prepareMessage(&$name, $text)
{
$message = array();
// Parse text for commands and format accordingly
$cmd = getCommand($text);
// Perform some custom prefiltering
$name = prefilterName($name);
$text = ($cmd == 'link') ? preFilterLink($text) : preFilterText($text);
// HTML filter
$filter = new lib_filter();
$action = false;
switch ($cmd)
{
case 'action':
// Action
$action = true;
$text = $filter->go(mb_substr($text, 3));
break;
case 'link':
// AutoLink
// Grab the URL from the message
$input = explode(' ', trim($text));
$url = array_shift($input);
if (mb_substr($url, 0, 4) == 'www.')
$url = 'http://'.$url;
$urlparts = @parse_url($url);
if (array_key_exists('host', $urlparts))
{
// Url is most likely valid (parse_url() is
// not the best way to check this)
if (count($input) > 0)
// There is link text
$urltext = implode(' ', $input);
else
// the url becomes the link text, and is shotened if necessary
$urltext = (mb_strlen($url) > 40) ? str_shorten($url, 25) : $url;
$text = '';
$text.= htmlentities($urltext).'';
}
else
// Url is most likely invalid
return false;
break;
default:
// No command
$text = $filter->go($text);
break;
}
if (mb_strlen(trim($text)) == 0)
// Message text is invalid
return false;
$message['action'] = $action;
$message['time'] = time();
$message['name'] = $name;
$message['text'] = $text;
return $message;
}
/**
* newLog()
*
* Create a new archive log file and delete ones past their prime
*/
function newLog($log, $date)
{
// Find the age threshold for deleting old logs
$minage = time() - LACE_ARCHIVE_DAYS * 86400;
// Delete logs that are too old
$handle = opendir(LACE_LOGDIR);
while ($file = readdir($handle))
{
if($file == '.' || $file == '..')
continue;
if (getDateFromFileName($file) < $minage)
unlink(LACE_LOGDIR.$file);
}
closedir($handle);
// Write the new log file
$filename = date('mdY', $date).'.dat';
$log = implode("\n", array_map('trim',$log))."\n";
$handle = fopen(LACE_LOGDIR.$filename, 'a');
fwrite($handle, $log);
fclose($handle);
// return an empty array, signifying
// that the main logfile is empty
return array();
}
/**
* logMessage()
*
* Add message to the logfile
*/
function logMessage($line) {
// Pull the current log contents
$log = file(LACE_LOGFILE);
// Grab the date of the
// most recent post in the log
$date = (count($log) > 0)
? array_shift($temp = explode('||', $log[0]))
: false;
// Write yesterday to file if necessary
if($date !== false && date('d', $date) != date('d'))
$log = newLog($log, $date);
// Write the new message
$logfile = fopen(LACE_LOGFILE, 'w');
fwrite($logfile, $line."\n");
// Write any other remaining messages
if (count($log) > 0)
fwrite($logfile, implode("\n", array_map('trim',$log))."\n");
fclose($logfile);
}
/**
* addNameChange()
*
* Add message to the main data file
*/
function addNameChange($from, $to)
{
global $A; // Activity object
$A->changeName($from, $to);
if (LACE_SHOW_NAME_CHANGE)
{
$message = array
(
'action' => true,
'time' => time(),
'name' => 'Lace',
'text' => ''.$from.' is now '.$to.'',
);
addMessage($message);
}
}
/**
* addMessage()
*
* Add message to the main data file
*/
function addMessage($message)
{
$name = ($message['action']) ? '*'.$message['name'] : $message['name'];
$text = $message['text'];
$time = $message['time'];
if(mb_strlen($name) == 0)
return;
$line = $time.'||'.$name.'||'.$text;
// Pull the current file contents
$fileContents = file(LACE_FILE);
$size = count($fileContents);
if ($size >= LACE_FILE_MAX_SIZE)
{
// Push the oldest entries out
// and put the new one in
for ($i = 0; $i <= $size - LACE_FILE_MAX_SIZE; $i++)
array_shift($fileContents);
$fileContents[] = $line;
$fileContents = implode("\n", array_map('trim', $fileContents))."\n";
// Write it to file
file_put_contents(LACE_FILE, trim($fileContents));
}
else
{
// No need to push anything off the stack,
// just write to file
$file = fopen(LACE_FILE, 'a');
fwrite($file, $line."\n");
fclose($file);
}
// Add to the log
logMessage($line);
}
/**
* printLogList()
*
* Display the log history navigation
*/
function printLogList($currentFile)
{
// Grab the filenames from the
// log directory
$recentLogs = array();
$handle = opendir(LACE_LOGDIR);
while ($file = readdir($handle))
{
if($file == '.' || $file == '..' || $file == 'index.php')
continue;
$recentLogs[] = $file;
}
closedir($handle);
// Date preparations
$today = date('d');
$filemtime = filemtime(LACE_LOGFILE);
$filedate = date('d', $filemtime);
if ($today == $filedate)
$day = 'Today';
else if (date('d', time()-3600*24) == $filedate)
$day = 'Yesterday';
else
$day = date('d F', $filemtime);
// Print the list
$output = "View Logs
\n";
$output .= ''."\n";
if (count($recentLogs) > 0)
{
$class = ($currentFile == LACE_LOGFILE) ? ' class="this"' : '';
$output .= '- '.$day.'
'."\n";
// We just want the 'date' part of the filenames
// so we can parse it, and also use it to
// make pretty URLs
$currentFile = str_replace('.dat', '', basename($currentFile));
// Sort logs most recent first
sort($recentLogs);
$recentLogs = array_reverse($recentLogs);
foreach($recentLogs as $log)
{
$log = str_replace('.dat', '', $log);
$date = getDateFromFileName($log);
$title = (date('j') - 1 == (int)$d) ? 'Yesterday' : $date;
$class = ($log == $currentFile) ?' class="this"' : '';
$output .= '- '.$title.'
'."\n";
}
}
else
$output .= '- No logs.
';
$output .= "
\n";
echo $output;
}
function getDateFromFileName($filename, $dateFormat = 'd F')
{
$m = mb_substr($filename, 0, 2);
$d = mb_substr($filename, 2, 2);
$y = mb_substr($filename, 4, 4);
return date($dateFormat, strtotime("$m/$d/$y"));
}