inc/record.php -
index
<?php
// RECORD.PHP - manipulate 'records' and write/read them to/from database
//
// This code was written in like 1982 but will only occasionally get tweaked.
//
// The following functions are defined:
//
// readrecord()
// readfilerecord()
// writerecord()
// createrecord()
// arraytorecord()
// recordtostring()
// sortrecords()
// recorduserdata()
/* readrecord - read an entry (post) and process it into a "record" */
// Fields are verified, adjusted, translated, etc. This function is for
// reading before displaying. $data is a way for admin to preview.
function readrecord($id, $data = NULL) {
debug("'$id'");
// first, read file into a "record"
if ($data)
$record = arraytorecord($data);
else
$record = dbreadrecord($id);
// $record will be FALSE if record not found - an alternative is to
// check for existence with if (!dblistrecords($id)) ... which is
// what we now do (only ADMIN and DISPLAY call this function)
if ($record == FALSE) {
$record = createrecord("Error #49",htmlgeterror('NOTFOUND'));
$record['nocomments'] = 1;
}
$record['id'] = $id;
// look at all these things here - this is a perfect example of code that
// should be "data code" so that all of these defaults and things are
// set/determined by an external, editible data file so we do not have to
// keep updating this code to support new features! and in providing for that
// each installation -- and theme -- can do their own thing! and *THAT* is the
// meaning of "customizable"
// if date string use it else use time string
if (!isset($record['date']) && isset($record['time']))
$record['date'] = date(config('datestr'),$record['time']);
if (!isset($record['time']) && isset($record['date']))
$record['time'] = strtotime($record['date']);
if (!isset($record['time']))
$record['time'] = time();
if (!isset($record['date']))
$record['date'] = date(config('datestr'),$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 (!isset($record['linktitle']))
$record['linktitle'] = $record['title'];
_recordrefs($record,$record['body']); // modifies body
// NOTE this is where usercode skips the convert code; we are thinking about
// changing this
if ($record['body'] != "" && !isset($record['usercode']))
$record['body'] = convert($record['body']);
if (isset($record['more']))
_morefunc($record);
return $record;
}
/* readfilerecord - read a file in the format of an internal record */
function readfilerecord($id) {
// $record will be FALSE if page not found - an alternative is to
// check for existence with if (!dblistpages($id)) ... which is
// what we now do (only ADMIN and DISPLAY call this function)
// although the function name to read a page begins with 'db' that is a
// misnomer as the page is actually a file - but we like the consistency!
// (the page API is INC/PAGES.PHP)
$record = dbreadpage($id);
if ($record == FALSE)
return createrecord("Error #21 ($id)",htmlgeterror('NOTFOUND'));
$record['body'] = convert($record['body']);
return $record;
}
/* writerecord - write a new record (previously non-existent) */
function writerecord($record, $logdata = true) {
debug("");
if (!is_array($record))
$record = arraytorecord($record);
if (!isset($record['time']) && !isset($record['date']))
$record['time'] = time();
if (config('loguserdata') && $logdata)
recorduserdata($record); // modifies $record
return dbnewrecord($record);
}
/* arraytorecord - convert record string/array to associative array */
function arraytorecord(/*mixed*/ $data) {
if (!is_array($data))
$data = explode(THIS_EOL,$data);
// PREG_SPLIT__DELIM_CAPTURE is wanted here... we put the LFs back
// we think this (or something like it) is more logical (slower)
// function nl(&$a) { $a = $a.THIS_EOL; }
// array_walk($data,'nl');
// as this modifies itself inside the loop which is odd (faster)
foreach ($data as $a => $b)
$data[$a] = $b.THIS_EOL;
// but they both need this!
reset($data);
while (list( ,$_) = each($data)) {
if ($_ == THIS_EOL) break;
$h = explode(':',$_);
$name = array_shift($h);
$name = strtolower($name);
$value = implode(':',$h);
$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);
}
/* _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;
}
/* 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;
}
/* 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'];
}
/* _recordrefs - replace record vars (marked by "[]") in a string */
// This substitutes a [words] 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!".
// this is currently a "used here only function" but it spcifically lacks
// a leading underscore...
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 */
/* _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;
$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) {
// this would be nice:
//$count = array_search('moremark',$data);
// but we need a substring search, i.e. array_strstr()...
for ($i = 0, $n = count($data); $i < $n; $i++)
if (strstr($data[$i],config('moremark')))
break;
$count = $i+1; // NOTE note next line; this fixes a really bad bug
// if the moremark immediately follows a <?php
// block in a post body
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
}
?>