Source Code Index
<?php
 
/* RECORD.PHP - manipulate 'records' and write/read them to/from database *
 
This module "processes" posts as a step between the display code and the 
database: DISPLAY > RECORD > MYSQL. For example:
 
displayrecord() calls readrecord() which calls dbreadrecord()
 
dbreadrecord() returns a $record and readrecord() validatesand converts the 
record data suitible for displayrecord() to display it via displayhtml()
 
The following functions are defined:
 
	readrecord()			// called by DISPLAY and Admin
	writerecord()			// called by Admin
	createrecord()			// creates a $record with dummy data
	createcomment()			// creates comment $record from POST
 
	stringtorecord()		// converts raw post to $record
					//  dbreadrecord() calls this
	recordtostring()		// converts $record to string
	sortrecords()			// sorts list of record ids
 
	readfilerecord()
 
*/
 
if (!defined('THIS_EOL'))
	define('THIS_EOL',"\n");
 
 
/* readrecord - read an entry (post) by ID and process it into a "record" */
 
// $data is a way for admin to preview (only ADMIN and DISPLAY call this
// function)
 
function readrecord($id, $data = NULL) {
 
	debug("'$id'");
 
	// first, read file into a "record"
 
	if ($data)
		$record = stringtorecord($data);
	else
		$record = dbreadrecord($id);
 
	// $record will be FALSE if record not found - the code actually
	// checks for existence with if (!dblistrecords($id)) so it should
	// never be FALSE
 
	if ($record == FALSE) {
		$record = createrecord("Error #49",htmlgeterror('NOTFOUND'));
		$record['nocomments'] = 1;
	}
 
	$record['id'] = $id;
 
	// create date and time strings if needed; what's weird here is that
	// date is optional (though shouldn't be) and time is created
 
	if (!isset($record['date'])) {
		$record['time'] = time();
		$record['date'] = date(config('datestr'),$record['time']);
	}
 
	if (!isset($record['time']))
		$record['time'] = strtotime($record['date']);
 
	$record['datetime'] = date(DATE_RFC3339,$record['time']);
 
	if (isset($record['from']))
		$record['from'] = convertchars($record['from']);
 
	if (isset($record['title']))
		$record['title'] = convertchars($record['title']);
	else
		$record['title'] = "";          // have to have a title
 
	if (config('headers'))
		_defaultheaders($record);
 
	_recordrefs($record,$record['body']);	// modifies body
 
	if ($record['body'])
		$record['body'] = convert($record['body'],$record);
 
	if (isset($record['more']))
		_morefunc($record);
 
	return $record;
}
 
 
/* readfilerecord - read a file in the format of an internal record */
 
// the pages API is in the PAGES module
 
function readfilerecord($id) {
 
	$record = dbreadpage($id);
	if ($record == FALSE)
		return createrecord("Error #21 ($id)",htmlgeterror('NOTFOUND'));
 
	if (!isset($record['date'])) {
		$record['time'] = time();
		$record['date'] = date(config('datestr'),$record['time']);
	}
 
	if (!isset($record['time']))
		$record['time'] = strtotime($record['date']);
 
	$record['datetime'] = date(DATE_RFC3339,$record['time']);
 
	$record['body'] = convert($record['body'],$record);
 
	return $record;
}
 
 
/* writerecord - write a new record (previously non-existent) */
 
// assumes properly formated data from admin form but it adds the basics 
// if they are missing; if $id assumes already validated that it exists
 
function writerecord($record, $headers = array(), $id = 0) {
 
	debug("");
 
	if (!is_array($record))
		$record = stringtorecord($record);
 
	// do some basic validation
 
	if (!isset($record['title']))
		$record['title'] = 'Title';
 
	if (!isset($record['time']) && !isset($record['date']))
		$record['time'] = time();
 
	if ($headers)
		foreach ($headers as $k => $v) {
			if (is_numeric($k))
				$record[$v] = '';
			else
				$record[$k] = $v;
		}
 
	if ($id)
		return dbputrecord($id,$record);
 
	return dbnewrecord($record);
}
 
 
/* stringtorecord - convert record string to associative array */
 
// assumes properly formated data; it sort of handles missing headers
 
function stringtorecord($data) {
 
	$data = explode(THIS_EOL,$data);
 
	// PREG_SPLIT__DELIM_CAPTURE is wanted here, but this:
	// $data = preg_split('/(\n)/',$data,-1,PREG_SPLIT_DELIM_CAPTURE);
	// puts the "\n" as a separate array member which is not right
 
	foreach ($data as &$d)
		$d .= THIS_EOL;
	reset($data);
	unset($d);
 
	while (list( ,$_) = each($data)) {
		if ($_ == THIS_EOL) {
			$_ = '';
			break;
		}
 
		$h = explode(':',$_);
		if (count($h) == 1)
			break;
 
		$name = array_shift($h);		//  tag: text
		$name = strtolower($name);		//  tag:
		$value = implode(':',$h);		//  tag: Title:Foobar
		$record[$name] = trim($value);
	}
 
	$record['body'] = $_;
	while (list( ,$_) = each($data))
		$record['body'] .= $_;
 
	return $record;
}
 
 
/* recordtostring - convert record array into a string */
 
function recordtostring($record) {
 
	$data =  '';
	foreach ($record as $key => $value)
		if ($key != 'body')
			$data .= $key.':'.$value.THIS_EOL;
 
	return $data . THIS_EOL . $record['body'];
}
 
 
/* sortentries - sort the entries (natural sort is the default) */
 
function _cmptitle($a, $b) { return strcmp($a['title'],$b['title']); }
function _cmptime($a, $b)  { return strcmp($a['time'],$b['time']);   }
 
function sortrecords(&$ids, $sort = NULL) {
 
	if ($sort === NULL)
		$sort = config('sortfunc');
 
	if ($sort == "date") {
		$i = 0;
		foreach ($ids as $id) {
			$headers[$i] = _getrecordheaders($id);
			$headers[$i]['file'] = $id;
			$i++;
		}
		usort($headers,"_cmptime");
		$i = 0;
		foreach ($headers as $h) {
			$ids[$i] = $h['file'];
			$i++;
		}
	}
	else
	if ($sort == "name") {
		$i = 0;
		foreach ($ids as $id) {
			$headers[$i] = _getrecordheaders($id);
			$headers[$i]['file'] = $id;
			$i++;
		}
		usort($headers,"_cmptitle");
		$i = 0;
		foreach ($headers as $h) {
			$ids[$i] = $h['file'];
			$i++;
		}
	}
 
	if (config('reversesort') || $sort == "rsort")
		$ids = array_reverse($ids);
}
 
/* createrecord - create an empty record */
 
function createrecord($title = NULL, $body = "") {
 
	if ($title == NULL)
		return "date: " . date(config('datestr')) .
			"\ntitle: Title\n\nPlace content here.";
 
	$record['title'] = $title;
	$record['body'] = $body;
	$record['date'] =  date(config('datestr'));
	$record['id'] = 0;
	return $record;
}
 
 
/* createcomment - create a comment from POST data */
 
function createcomment() {
 
	$date = datestrcmt();
	$from = postvar('from');
	$subj = postvar('subj');
	$data = postvar('data');
 
	$record['title'] = $subj;
	$record['from'] = $from;
	$record['date'] = $date;
	$record['body'] = convert_user($data);
 
	recorduserdata($record);                // modifies $record
 
	if ($record['from'] == '') $record['from'] = 'nobody';
	if ($record['title'] == '') $record['title'] = 'nothing';
 
	return $record;
}
 
 
/* recorduserdata - add some server data to a record */
 
function recorduserdata(&$record) {
 
	if (isset($_SERVER['REMOTE_ADDR']))
		$record['REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'];
	if (isset($_SERVER['HTTP_USER_AGENT']))
		$record['HTTP_USER_AGENT'] = $_SERVER['HTTP_USER_AGENT'];
	if (isset($_SERVER['HTTP_REFERER']))
		$record['HTTP_REFERER'] = $_SERVER['HTTP_REFERER'];
}
 
 
/* _internal functions */
 
 
/* _getrecordheaders - read a record header into an associative array */
 
function _getrecordheaders($id) {
 
	debug("'$id'");
 
	// no error checking as we have a valid ID at this point
 
	$record = dbreadrecord($id);
	unset($record['body']);
 
	$record['id'] = $id;
 
	// if no date create it (convert time from number to people string)
 
	if (!isset($record['date']))
		$record['date'] = date(config('datestr'),$record['time']);
 
	return $record;
}
 
 
/* _defaultheaders - check for and/or create additional headers */
 
function _defaultheaders(&$record) {
 
	$headers = config('headers');
	if (!is_array($headers))
		return;
 
	foreach ($headers as $key => $val)
		if (!isset($record[$key]))
			$record[$key] = $val;
}
 
 
/* _recordrefs - replace record vars (marked by "[]") in a string */
 
// This substitutes a [word] in body with a record header value, ie.
// with a record header of "title: Foobar", the string "Hey there, [title]!"
// would result in "Hey there, Foobar!".
 
function _recordrefs($record,&$body) {
 
	$re = '/\[([a-zA-Z]+)\]/';
	if (preg_match_all($re,$body,$res))
		foreach ($res[0] as $k => $v) {
			$h = $res[1][$k];
			if (isset($record[$h]))
				$body = str_replace($v,$record[$h],$body);
		}
}
 
 
/* "more" functions */
 
// these functions try to locate the "more" string in a post and truncate
// the post at that point - they are not too clear and not too efficient...
 
/* _morefunc - process "more" function */
 
function _morefunc(&$record) {
 
	$bodydata = explode(THIS_EOL,$record['body']);
 
	if (($t = $record['more']))
		if (!is_numeric($t) || ($t < 0 || $t >= count($bodydata)))
			$t = 0;	// force _morecheck()
 
	$c = ($t) ? $t : _morecheck($bodydata);
 
	if ($c) {
		$bodydata = _moretruncate($bodydata,$c);
		$record['more'] = implode(THIS_EOL,$bodydata);
	}
}
 
 
/* _morecheck - return index to "more" marker (or Nth blank line) */
 
function _morecheck($data) {
 
// many settings do not have defaults, but if this one not set there are
// way too many errors... we actually do not like wasting the code's time
// with such defaults (and too many comments! - but we put this one here in
// hope that people are actually reading this code)
 
	$moremark = ($t = config('moremark')) ? $t : '<!--more-->';
 
	// this would be nice:
	//$count = array_search('moremark',$data);
	// but we need a substring search, i.e. array_strstr()...
 
// a side effect of the conversion code (CONVERT.PHP) leaves the more mark
// within '<p></p>' but that is okay as this is a strstr(); the translate.ini
// file now skips that so we should rewrite this...
 
	for ($count = 0, $n = count($data); $count < $n; $count++)
		if (strstr($data[$count],$moremark))
			break;
 
	if ($count == $n)			// hit end
		return $count;
 
	if (!$count) {
		$p = ($p = config('morepara')) ? $p : 6;
		$para = 0;
 
		while (list( ,$_) = each($data)) {
			if ($para++ == $p)
				break;
			$count++;
		}
	}
 
	return $count;
}
 
 
/* _moretruncate - truncate body array at more marker index */
 
function _moretruncate($data, $count) {
 
	return array_slice($data,0,$count);
// the arbitrariness of the slice can possibly result in the removal of a
// needed closing tag so the <!--more--> marker must not be placed before
// an ending tag
}
 
?>
 
THIS source compiler