=====PageAdminPrune Action=====
This is the development page for the PageAdminPrune action.
>>==See also:==
Documentation: PageAdminPruneActionInfo.>>
This action allows you (the owner of a page or the sysadmin) to choose to keep a number of a page's revisions or page revisions from a certain date onwards.
I have tested this with Firefox 1.5, PHP 5.1, IIS6 and Wikka 1.1.6
**PLEASE USE CAREFULLY!**
**I believe I have guarded against SQL injection attacks, however I'd appreciate any comments on the security of this action!**
It consists of
- pageadmin.php: Modified so it contains hooks to the new action
- Date.class.php: Class that contains date functions.
- Prune.php: Contains the actual code for pruning. This class currently only manages page revisions. A variation of this could also do page comment pruning.
Save this in actions\pageadmin.php
**Please note that I did not write this class. Credit goes to DarTar.** (See PageAdminAction)
I merely added hooks for the Prune aspect.
I have marked the lines I changed with /* > > > */ (with no spaces between the >)
%%(php)
= $max)
{
// add $max to the list; then break out of the loop
$opts[] = $max;
break;
}
// when $limit is reached, it becomes the new start and increment for the next 'range'
$inc = $limit;
}
return $opts;
}
// restrict access to admins
if ($this->IsAdmin($this->GetUser())) {
// -------------------------------------
// set default values as constants
define('DEFAULT_RECORDS_LIMIT', '20'); # number of records per page
define('DEFAULT_MIN_RECORDS_DISPLAY', '5'); # min number of records
define('DEFAULT_RECORDS_RANGE',serialize(array('10','50','100','500','1000'))); #range array for records pager
define('DEFAULT_SORT_FIELD', 'time'); # sort field
define('DEFAULT_SORT_ORDER', 'desc'); # sort order, ascendant or descendant
define('DEFAULT_START', '0'); # start record
define('DEFAULT_SEARCH', ''); # keyword to restrict page search
define('DEFAULT_TAG_LENGTH', '12'); # max. length of displayed pagename
define('DEFAULT_URL_LENGTH', '15'); # max. length of displayed user host
define('DEFAULT_TERMINATOR', '…'); # standard symbol replacing truncated text (ellipsis) JW 2005-07-19
define('ALTERNATE_ROW_COLOR', '1'); # switch alternate row color
define('STAT_COLUMN_COLOR', '1'); # switch color for statistics columns
// -------------------------------------
// User-interface: icons
define('HITS_ICON', 'images/icons/16x16/stock_about.png');
define('REVISIONS_ICON', 'images/icons/16x16/stock_book_open.png');
define('COMMENTS_ICON', 'images/icons/16x16/stock_help-agent.png');
define('BACKLINKS_ICON', 'images/icons/16x16/stock_link.png');
define('REFERRERS_ICON', 'images/icons/16x16/stock_internet.png');
// -------------------------------------
// User-interface: strings
define('PAGE_TITLE','Page Administration');
define('FORM_LEGEND','Filter view:');
define('FORM_SEARCH_STRING_LABEL','Search page:');
define('FORM_SEARCH_STRING_TITLE','Enter a search string');
define('FORM_SEARCH_SUBMIT','Submit');
define('FORM_PAGER_LABEL_BEFORE','Show');
define('FORM_PAGER_TITLE','Select records-per-page limit');
define('FORM_PAGER_LABEL_AFTER','records per page');
define('FORM_PAGER_SUBMIT','Apply');
define('FORM_PAGER_LINK','Show records from %d to %d');
define('FORM_RESULT_INFO','Records');
define('FORM_RESULT_SORTED_BY','Sorted by:');
define('TABLE_HEADING_PAGENAME','Page Name');
define('TABLE_HEADING_PAGENAME_TITLE','Sort by page name');
define('TABLE_HEADING_OWNER','Owner');
define('TABLE_HEADING_OWNER_TITLE','Sort by page owner');
define('TABLE_HEADING_LASTAUTHOR','Last Author');
define('TABLE_HEADING_LASTAUTHOR_TITLE','Sort by last author');
define('TABLE_HEADING_LASTEDIT','Last Edit');
define('TABLE_HEADING_LASTEDIT_TITLE','Sort by edit time');
define('TABLE_SUMMARY','List of pages on this server');
define('TABLE_HEADING_HITS_TITLE','Hits');
define('TABLE_HEADING_REVISIONS_TITLE','Sort by number of revisions (DEBUG ONLY)');
define('TABLE_HEADING_COMMENTS_TITLE','Comments');
define('TABLE_HEADING_BACKLINKS_TITLE','Backlinks');
define('TABLE_HEADING_REFERRERS_TITLE','Referrers');
define('TABLE_HEADING_HITS_ALT','Hits');
define('TABLE_HEADING_REVISIONS_ALT','Revisions');
define('TABLE_HEADING_COMMENTS_ALT','Comments');
define('TABLE_HEADING_BACKLINKS_ALT','Backlinks');
define('TABLE_HEADING_REFERRERS_ALT','Referrers');
define('TABLE_HEADING_ACTIONS','Actions');
define('ACTION_EDIT_LINK_TITLE','Edit %s');
define('ACTION_DELETE_LINK_TITLE','Delete %s');
define('ACTION_CLONE_LINK_TITLE','Clone %s');
define('ACTION_RENAME_LINK_TITLE','Rename %s (DISABLED)');
define('ACTION_ACL_LINK_TITLE','Change Access Control List for %s');
define('ACTION_INFO_LINK_TITLE','Display information and statistics for %s');
/*>>>*/ define('ACTION_PRUNE_LINK_TITLE','Display misc options for %s');
define('ACTION_EDIT_LINK','edit');
define('ACTION_DELETE_LINK','delete');
define('ACTION_CLONE_LINK','clone');
define('ACTION_RENAME_LINK','rename');
define('ACTION_ACL_LINK','acl');
define('ACTION_INFO_LINK','info');
/*>>>*/ define('ACTION_PRUNE_LINK','prune');
define('TAKE_OWNERSHIP_LINK','Take ownership of');
define('NO_OWNER','(Nobody)');
define('TABLE_CELL_HITS_TITLE','Hits for %s (%d)');
define('TABLE_CELL_REVISIONS_TITLE','Display revisions for %s (%d)');
define('TABLE_CELL_COMMENTS_TITLE','Display comments for %s (%d)');
define('TABLE_CELL_BACKLINKS_TITLE','Display pages linking to %s (%d)');
define('TABLE_CELL_REFERRERS_TITLE','Display external sites linking to %s (%d)');
define('SELECT_RECORD_TITLE','Select %s');
define('NO_EDIT_NOTE','[No edit note]');
define('CHECK_ALL_TITLE','Check all records');
define('CHECK_ALL','Check all');
define('UNCHECK_ALL_TITLE','Uncheck all records');
define('UNCHECK_ALL','Uncheck all');
define('FORM_MASSACTION_LEGEND','Mass-action');
define('FORM_MASSACTION_LABEL','With selected');
define('FORM_MASSACTION_SELECT_TITLE','Choose action to apply to selected records (DISABLED)');
define('FORM_MASSACTION_OPT_DELETE','Delete all');
define('FORM_MASSACTION_OPT_CLONE','Clone all');
define('FORM_MASSACTION_OPT_RENAME','Rename all');
define('FORM_MASSACTION_OPT_ACL','Change Access Control List');
define('FORM_MASSACTION_SUBMIT','Submit');
define('ERROR_NO_MATCHES','Sorry, there are no pages matching "%s"');
// -------------------------------------
// Initialize variables
$r = 1; #initialize row counter
$r_color = ALTERNATE_ROW_COLOR; #get alternate row color option
$c_color = STAT_COLUMN_COLOR; #get column color option
// record dropdown
$page_limits = unserialize(DEFAULT_RECORDS_RANGE);
// pager
$prev = '';
$next = '';
//override defaults with action parameters
if (is_array($vars))
{
foreach ($vars as $param => $value)
{
switch ($param)
{
case 'colcolor':
$c_color = (preg_match('/[01]/',$value))? $value : STAT_COLUMN_COLOR;
break;
case 'rowcolor':
$r_color = (preg_match('/[01]/',$value))? $value : ALTERNATE_ROW_COLOR;
break;
}
}
}
//perform mass-operations if required (forthcoming)
if (isset($_GET['action']))
{
if ($_GET['action'] == 'massdelete')
{
echo $this->Action('massdelete');
}
elseif ($_GET['action'] == 'massrename')
{
echo $this->Action('massrename');
}
elseif ($_GET['action'] == 'massacls')
{
echo $this->Action('massacls');
}
}
else
{
// process URL variables
# JW 2005-07-19 some modifications to avoid notices but these are still not actually secure
// number of records per page
if (isset($_POST['l']))
{
$l = $_POST['l'];
}
elseif (isset($_GET['l']))
{
$l = $_GET['l'];
}
else
{
$l = DEFAULT_RECORDS_LIMIT;
}
// sort field
$sort = (isset($_GET['sort'])) ? $_GET['sort'] : DEFAULT_SORT_FIELD;
// sort order
$d = (isset($_GET['d'])) ? $_GET['d'] : DEFAULT_SORT_ORDER;
// start record
$s = (isset($_GET['s'])) ? $_GET['s'] : DEFAULT_START;
// search string
if (isset($_POST['q']))
{
$q = $_POST['q'];
}
elseif (isset($_GET['q']))
{
$q = $_GET['q'];
}
else
{
$q = DEFAULT_SEARCH;
}
// select all added JW 2005-07-19
$checked = '';
if (isset($_GET['selectall']))
{
$checked = (1 == $_GET['selectall']) ? ' checked="checked"' : '';
}
// restrict MySQL query by search string modified JW 2005-07-19
$where = ('' == $q) ? "`latest` = 'Y'" : "`tag` LIKE '%".$q."%' AND `latest` = 'Y'";
// get total number of pages
$numpages = $this->getCount('pages',$where);
// print page header
echo $this->Format('==== '.PAGE_TITLE.' ==== --- ');
// build pager form
$form1 = $this->FormOpen('','','post','page_admin_panel');
$form1 .= '
'.$this->FormClose()."\n";
// print form
echo $form1;
// sort by counted values
switch($sort)
{
case 'edits': #alpha --- 'latest' needs to be disabled
//sample query:
//SELECT *, COUNT(*) as edits FROM `wikka1160_pages` GROUP BY tag ORDER BY edits DESC
$count = ', COUNT(*) as edits';
$group = 'GROUP BY tag';
$where = '1';
//$where = ('' == $q) ? "1" : "`tag` LIKE '%".$q."%'";
$table = 'pages';
break;
case 'comments': #to implement
/*
// SELECT wikka1160_pages.tag, COUNT( * ) AS comments FROM wikka1160_pages, wikka1160_comments WHERE wikka1160_pages.tag = wikka1160_comments.page_tag GROUP BY wikka1160_pages.tag ORDER BY comments DESC
$count = ', COUNT(*) as edits';
$group = 'GROUP BY tag';
$where = '1';
*/
break;
default:
$table = 'pages';
}
// get page list
$pagedata = $this->LoadAll("SELECT *".$count." FROM ".$this->config["table_prefix"].$table." WHERE ".
$where." ".$group." ORDER BY ".$sort." ".$d." LIMIT ".$s.", ".$l);
if ($pagedata)
{
// build table headers
$tagheader = ''.TABLE_HEADING_PAGENAME.'';
$ownerheader = ''.TABLE_HEADING_OWNER.'';
$userheader = ''.TABLE_HEADING_LASTAUTHOR.'';
$lasteditheader = ''.TABLE_HEADING_LASTEDIT.'';
$revisionsheader = '';
$htmlout = "
\n".
"\n
\n".
"
\n".
"
".$tagheader."
\n".
"
".$ownerheader."
\n".
"
".$userheader."
\n".
"
".$lasteditheader."
\n".
"
\n".
"
".$revisionsheader."
\n".
"
\n".
"
\n".
"
\n".
"
".TABLE_HEADING_ACTIONS."
\n".
"
\n\n";
// feed table with data
foreach($pagedata as $page)
{
// truncate long page names
$pagename = (strlen($page['tag']) > DEFAULT_TAG_LENGTH) ? substr($page['tag'], 0, DEFAULT_TAG_LENGTH).DEFAULT_TERMINATOR : $page['tag'];
// build handler links
$lastedit = $page['time'];
if ($pagename != $page['tag'])
{
$showpage = ''.$pagename.'';
}
else
{
$showpage = ''.$pagename.'';
}
$editpage = ''.ACTION_EDIT_LINK.'';
$deletepage = ''.ACTION_DELETE_LINK.'';
$clonepage = ''.ACTION_CLONE_LINK.'';
// renaming disabled
$renamepage = ''.ACTION_RENAME_LINK.'';
$aclpage = ''.ACTION_ACL_LINK.'';
$infopage = ''.ACTION_INFO_LINK.'';
/*>>>*/ $prunepage = ''.ACTION_PRUNE_LINK.'';
// get page owner
if ($page['owner'])
{
// is the owner a registered user?
if ($this->LoadUser($page['owner']))
{
// does user's homepage exist?
if ($this->ExistsPage($page['owner']))
{
$owner = $this->Link($page['owner']);
}
else
{
$owner = $page['owner'];
}
}
else
{
$owner = $page['owner'];
}
}
else
{
// page has empty owner field: print claim link
$owner = $this->Link($page['tag'], 'claim','(Nobody)','','',TAKE_OWNERSHIP_LINK.' '.$page['tag']);
}
// get last author
if ($page['user'])
{
// is the author a registered user?
if ($this->LoadUser($page['user']))
{
// does user's homepage exist?
if ($this->ExistsPage($page['user']))
{
$user = $this->Link($page['user']);
}
else
{
$user = $page['user'];
}
}
else
{
// truncate long host names
$user = (strlen($page['user']) > DEFAULT_URL_LENGTH) ? substr($page['user'], 0, DEFAULT_URL_LENGTH).DEFAULT_TERMINATOR : $page['user'];
# added JW 2005-07-19
if ($user != $page['user'])
{
$user = ''.$user.'';
}
}
}
else
{
// page has empty user field
$user = NO_OWNER;
}
// get counts - JW 2005-07-19
$whereTag = "`tag` = '".$page['tag']."'";
$wherePageTag = "`page_tag` = '".$page['tag']."'";
$whereToTag = "`to_tag` = '".$page['tag']."'";
$hn = 0;
$rv = $this->getCount('pages',$whereTag);
$cn = $this->getCount('comments',$wherePageTag);
$bn = $this->getCount('links',$whereToTag);
$rn = $this->getCount('referrers',$wherePageTag);
// get page hits (forthcoming)
$hitspage = ($hn > 0) ? ''.$hn.'' : '0';
// get page revisions and create revision link if needed
$revpage = ($rv > 0) ? ''.$rv.'' : '0';
// get page comments and create comments link if needed
$commentspage = ($cn > 0) ? ''.$cn.'' : '0';
// get page backlinks and create backlinks link
$backlinkpage = ($bn > 0) ? ''.$bn.'' : '0';
// get page referrers and create referrer link
$refpage = ($rn > 0) ? ''.$rn.'' : '0';
// build table body
$htmlout .= "\n";
if ($r_color == 1)
{
$htmlout .= "
'."\n";
// print the table
echo $this->FormOpen('','','get');
echo $htmlout;
// multiple-page operations (forthcoming) JW 2005-07-19 accesskey removed (causes more problems than it solves)
echo '';
echo $this->FormClose();
}
else
{
// no records matching the search string: print error message
echo '
'.sprintf(ERROR_NO_MATCHES, $q).'
';
}
}
}
else
{
// current user is not admin: show plain page index
echo $this->Action('pageindex');
}
?>
%%
Save this as handlers\page\prune.php
%%(php)
LoadSingle() obviously didn't work but neither did LoadSingle(). I know I am missing something :-)
- I am unable to return to the calling page via Redirect. I did have it working but I don't understand what made it break. It now goes to
the page that is being worked on instead. I was forced to specify 'PageAdmin' as the page to return to, which I am not happy with :-(
*/
define('PAGE_TITLE','Prune actions on %s');
define('TABLENAME', $this->config['table_prefix']."pages");
if (!($this->UserIsOwner() || $this->IsAdmin()))
{
$this->redirect($this->Href(), "Only the owner of this page can make these changes.");
}
else
{
// If we are in phase 1, show initial form
if (! $_POST)
{
echo $this->FormOpen("prune");
echo $this->Format('=== '.sprintf(PAGE_TITLE,'[['.$this->tag.']]').' ===----');
?>
tag\""; ?> >
No. of revisions to keep for this page
Or
Delete revisions prior to date (inclusive)
FormClose();
}
// ---------------------------------------------------------------------------------------
// Phase 2: show what we are about to do and ask for ok to do so.
elseif ($_POST['Phase2'])
{
echo $this->FormOpen("prune");
$pageRevisions2Keep = trim($_POST["NumOfRevs2Keep"]);
$purgeRevisionsBeforeDate = trim($_POST["PurgeRevisionsBeforeDate"]);
// Dummy DO loop that simply allows multiple exits to a single point.
$ok = false;
do
{
// If both date and # of revs have been specified, use the date in preference of # of revs
// Has a date been specified?
if ($purgeRevisionsBeforeDate)
{
$dateError = "";
// Check data, record errors in $dateError and return db-friendly formatted date
$purgeRevisionsBeforeDate = IsValidDate($purgeRevisionsBeforeDate, $dateError);
if ($dateError != "")
{
echo " ".$dateError;
break;
}
echo " Keeping page revisions from ".$purgeRevisionsBeforeDate." onwards";
$ok = true;
break;
}
// User specified (only!) # of revs to keep. Validate number, find what date that number corresponds to
// in the PAGES table and act as if he specified a date rather than # of revs.
if ($pageRevisions2Keep)
{
if (! is_numeric($pageRevisions2Keep))
{
echo "This is not a valid number (".$pageRevisions2Keep.")";
break;
}
if ($pageRevisions2Keep < 1)
{
echo "Hmmm. You want me to keep less than 1 revisions, eh? I refuse!";
break;
}
echo " Keeping only the ".$pageRevisions2Keep." most recent revisions";
$tag = $_POST["tag"];
$tag = addslashes($tag);
$sql = "SELECT time FROM ".TABLENAME." WHERE tag='".$tag."' ORDER BY time DESC LIMIT ".$pageRevisions2Keep.",1";
if (! $tablepgname = $this->LoadSingle($sql))
{
echo " There are less page revisions than what you specified. I've got nothing to do.";
break;
}
// Pickup the timestamp of the record corresponding to the # of revisions we requested.
// ie, if we speficied 2, we need to look at the timestamp of the 3rd record and delete
// from there on backwords in time (including that record)
$purgeRevisionsBeforeDate = $tablepgname['time'];
$purgeRevisionsBeforeDate = addslashes($purgeRevisionsBeforeDate);
echo " Deleting revisions dated ".$purgeRevisionsBeforeDate." and older";
$ok = true;
break;
}
echo "That's funny, that is! Am I meant to guess your intentions then? Please provide some input!";
break;
} while (false);
// this is the exit point for the above DO loop. When we get here, $ok will be true or false
// and it will be used below to enable/disable to GoAhead button.
?>
>
>
>
>
FormClose();
}
elseif ($_POST['Phase3'])
// ---------------------------------------------------------------------------------------
// Phase 3? User has pressed the GoAhead button
{
echo $this->FormOpen("prune");
do
{
if (! $tag = $_POST["tag"])
{
echo "Tag variable was not set!???";
break;
}
$tag = addslashes($tag);
if (! $purgeRevisionsBeforeDate = $_POST["purgeRevisionsBeforeDate"])
{
$dateError = "";
$purgeRevisionsBeforeDate = IsValidDate($purgeRevisionsBeforeDate, $dateError);
if ($dateError != "")
{
echo $dateError;
break;
}
}
echo $sql = "DELETE from ".TABLENAME." WHERE tag = '".$tag."' AND time <= '".$purgeRevisionsBeforeDate."'";
$this->Query($sql);
$msg = "Deleted revisions dated ".$purgeRevisionsBeforeDate." and older";
} while (false);
echo $this->FormClose();
// redirect back to page
//************************************************************************************
//************************************************************************************
//************************************************************************************
//************************************************************************************
$this->redirect($this->config['base_url'].'PageAdmin', $msg);
//************************************************************************************
//************************************************************************************
//************************************************************************************
//************************************************************************************
}
elseif ($_POST["Cancel"])
// ---------------------------------------------------------------------------------------
// Phase 3? User chickened out
{
//************************************************************************************
//************************************************************************************
//************************************************************************************
//************************************************************************************
// Is there a better way to go back to the page that called me (actually, 2 pages back!)
$this->redirect($this->config['base_url'].'PageAdmin');
//************************************************************************************
//************************************************************************************
//************************************************************************************
//************************************************************************************
}
}
function IsValidDate($theDate, &$err)
{
// Do date validation
$dateobj = new DateClass;
// Validate date and convert to database-friendly format
if (! $internaldate = $dateobj->getInternalDate($theDate))
{
$err = $dateobj->errors." (".$theDate.")";
$result = null;
}
else
{
$result = $dateobj->getExternalDate($internaldate);
}
return $result;
}
?>
%%
Save this in date.class.php (same dir as wikka.php)
**Please note that I did not write this class. Credit goes to A J Marston**
%%(php)
// Distributed under the GNU General Public Licence
//*****************************************************************************
class DateClass
{
// member variables
var $monthalpha; // array of 3-character month names
var $internaldate; // date as held in the database (yyyymmdd)
var $externaldate; // date as shown to the user (dd Mmm yyyy)
var $errors; // error messages
// ****************************************************************************
// class constructor
// ****************************************************************************
function DateClass ()
{
$this->monthalpha = array(1=>'Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
} // DateClass
// ****************************************************************************
// accessor functions
// ****************************************************************************
function getInternalDate ($input)
// convert date from external format (as input by user)
// to internal format (as used in the database)
{
// look for d(d)?m(m)?y(yyy) format
$pattern = '(^[0-9]{1,2})' // 1 or 2 digits
.'([^0-9a-zA-Z])' // not alpha or numeric
.'([0-9]{1,2})' // 1 or 2 digits
.'([^0-9a-zA-Z])' // not alpha or numeric
.'([0-9]{1,4}$)'; // 1 to 4 digits
if (ereg($pattern, $input, $regs)) {
$result = $this->verifyDate($regs[1],$regs[3],$regs[5]);
return $result;
} // if
// look for d(d)?MMM?y(yyy) format
$pattern = '(^[0-9]{1,2})' // 1 or 2 digits
.'([^0-9a-zA-Z])' // not alpha or numeric
.'([a-zA-Z]{1,})' // 1 or more alpha
.'([^0-9a-zA-Z])' // not alpha or numeric
.'([0-9]{1,4}$)'; // 1 to 4 digits
if (ereg($pattern, $input, $regs)) {
$result = $this->verifyDate($regs[1],$regs[3],$regs[5]);
return $result;
} // if
// look for d(d)MMMy(yyy) format
$pattern = '(^[0-9]{1,2})' // 1 or 2 digits
.'([a-zA-Z]{1,})' // 1 or more alpha
.'([0-9]{1,4}$)'; // 1 to 4 digits
if (ereg($pattern, $input, $regs)) {
$result = $this->verifyDate($regs[1],$regs[2],$regs[3]);
return $result;
} // if
// look for MMM?d(d)?y(yyy) format
$pattern = '(^[a-zA-Z]{1,})' // 1 or more alpha
.'([^0-9a-zA-Z])' // not alpha or numeric
.'([0-9]{1,2})' // 1 or 2 digits
.'([^0-9a-zA-Z])' // not alpha or numeric
.'([0-9]{1,4}$)'; // 1 to 4 digits
if (ereg($pattern, $input, $regs)) {
$result = $this->verifyDate($regs[3],$regs[1],$regs[5]);
return $result;
} // if
// look for MMMddyyyy format
$pattern = '(^[a-zA-Z]{1,})' // 1 or more alpha
.'([0-9]{2})' // 2 digits
.'([0-9]{4}$)'; // 4 digits
if (ereg($pattern, $input, $regs)) {
$result = $this->verifyDate($regs[2],$regs[1],$regs[3]);
return $result;
} // if
// look for yyyy?m(m)?d(d) format
$pattern = '(^[0-9]{4})' // 4 digits
.'([^0-9a-zA-Z])' // not alpha or numeric
.'([0-9]{1,2})' // 1 or 2 digits
.'([^0-9a-zA-Z])' // not alpha or numeric
.'([0-9]{1,2}$)'; // 1 to 2 digits
if (ereg($pattern, $input, $regs)) {
$result = $this->verifyDate($regs[5],$regs[3],$regs[1]);
return $result;
} // if
// look for ddmmyyyy format
$pattern = '(^[0-9]{2})' // 2 digits
.'([0-9]{2})' // 2 digits
.'([0-9]{4}$)'; // 4 digits
if (ereg($pattern, $input, $regs)) {
$result = $this->verifyDate($regs[1],$regs[2],$regs[3]);
return $result;
} // if
// look for yyyy?MMM?d(d) format
$pattern = '(^[0-9]{4})' // 4 digits
.'([^0-9a-zA-Z])' // not alpha or numeric
.'([a-zA-Z]{1,})' // 1 or more alpha
.'([^0-9a-zA-Z])' // not alpha or numeric
.'([0-9]{1,2}$)'; // 1 to 2 digits
if (ereg($pattern, $input, $regs)) {
$result = $this->verifyDate($regs[5],$regs[3],$regs[1]);
return $result;
} // if
$this->errors = 'This is not a valid date';
return FALSE;
} // getInternalDate
// ****************************************************************************
function getInternalTime ($input)
// convert time from external format (as input by user)
// to internal format (as used in the database)
{
// look for HH?MM?SS format
$pattern = '(^[0-9]{2})' // 2 digits
.'([^0-9a-zA-Z])' // not alpha or numeric
.'([0-9]{2})' // 2 digits
.'([^0-9a-zA-Z])' // not alpha or numeric
.'([0-9]{2}$)'; // 2 digits
if (ereg($pattern, $input, $regs)) {
$result = $this->verifyTime($regs[1],$regs[3],$regs[5]);
return $result;
} // if
// look for HHMMSS format
$pattern = '(^[0-9]{2})' // 2 digits
.'([0-9]{2})' // 2 digits
.'([0-9]{2}$)'; // 2 digits
if (ereg($pattern, $input, $regs)) {
$result = $this->verifyTime($regs[1],$regs[2],$regs[3]);
return $result;
} // if
$this->errors = 'This is not a valid time';
return FALSE;
} // getInternalTime
// ****************************************************************************
function verifyDate($day, $month, $year)
{
// convert alpha month to digits
if (eregi('([a-z]{3})', $month)) {
$month = ucfirst(strtolower($month));
if (!$month = array_search($month, $this->monthalpha)) {
$this->errors = 'Month name is invalid';
return FALSE;
} // if
} // if
// ensure that year has 4 digits
if (strlen($year) == 1) {
$year = '200' .$year;
} // if
if (strlen($year) == 2) {
$year = '20' .$year;
} // if
if (strlen($year) == 3) {
$year = '2' .$year;
} // if
if (!checkdate($month, $day, $year)) {
$this->errors = 'This is not a valid date';
return FALSE;
} else {
if (strlen($day) < 2) {
$day = '0' .$day; // add leading zero
} // if
if (strlen($month) < 2) {
$month = '0' .$month; // add leading zero
} // if
$this->internaldate = $year .'-' .$month .'-' .$day;
return $this->internaldate;
} // if
return;
} // verifyDate
// ****************************************************************************
function verifyTime($hours, $minutes, $seconds)
{
if ($hours > 24) {
$this->errors = 'Invalid HOURS';
return FALSE;
} // if
if ($minutes > 59) {
$this->errors = 'Invalid MINUTES';
return FALSE;
} // if
if ($minutes > 59) {
$this->errors = 'Invalid MINUTES';
return FALSE;
} // if
return "$hours:$minutes:$seconds";
} // verifyTime
// ****************************************************************************
function getExternalDate ($input)
// convert date from internal format (as used in the database)
// to external format (as shown to the user))
{
// input may be 'yyyy-mm-dd' or 'yyyymmdd', so
// check the length and process accordingly
if (strlen($input) == 8) {
// test for 'yyyymmdd'
$pattern = '(^[0-9]{4})' // 4 digits (yyyy)
.'([0-9]{2})' // 2 digits (mm)
.'([0-9]{2}$)'; // 2 digits (dd)
if (ereg($pattern, $input, $regs)) {
if (!checkdate($regs[2], $regs[3], $regs[1])) {
$this->errors = 'This is not a valid date';
return FALSE;
} else {
$monthnum = (int)$regs[2];
$this->externaldate = "$regs[3] " .$this->monthalpha[$monthnum] ." $regs[1]";
return $this->externaldate;
} // if
} // if
$this->errors = "Invalid date format: expected 'yyyymmdd'";
return FALSE;
} // if
if (strlen($input) == 10) {
// test for 'yyyy-mm-dd'
$pattern = '(^[0-9]{4})' // 4 digits (yyyy)
.'([^0-9])' // not a digit
.'([0-9]{2})' // 2 digits (mm)
.'([^0-9])' // not a digit
.'([0-9]{2}$)'; // 2 digits (dd)
if (ereg($pattern, $input, $regs)) {
if (!checkdate($regs[3], $regs[5], $regs[1])) {
$this->errors = 'This is not a valid date';
return FALSE;
} else {
$monthnum = (int)$regs[3];
$this->externaldate = "$regs[5] " .$this->monthalpha[$monthnum] ." $regs[1]";
return $this->externaldate;
} // if
} // if
$this->errors = "Invalid date format: expected 'dd-mm-yyyy'";
return FALSE;
} // if
$this->errors = 'This is not a valid date';
return $input;
} // getExternalDate
// ****************************************************************************
function addDays ($internaldate, $days)
// add a number of days (may be negative) to $internaldate (YYYY-MM-DD)
// and return the result in the same format
{
// ensure date is in internal format
$internaldate = $this->getInternalDate($internaldate);
// convert to the number of days since basedate (4714 BC)
$julian = GregoriantoJD(substr($internaldate,5,2)
,substr($internaldate,8,2)
,substr($internaldate,0,4));
$days = (int)$days;
$julian = $julian + $days;
// convert from Julian to Gregorian (format m/d/y)
$gregorian = JDtoGregorian($julian);
// split date into its component parts
list ($month, $day, $year) = split ('[/]', $gregorian);
// convert back into standard format
$result = $this->getInternaldate("$day/$month/$year");
return $result;
} // addDays
// ****************************************************************************
function getErrors ()
{
return $this->errors;
} // getErrMsg
// ****************************************************************************
} // end DateClass
// ****************************************************************************
?>
%%
~Add prune link to footer:
Open templates/footer.php
find the following:
%%(php)
echo $this->HasAccess('write') ? 'Edit ::'."\n" : '';
%%
add after:
%%(php)
echo $this->HasAccess('write') ? 'Prune ::'."\n" : '';
%%
Addition by [[http://grez868.info/sniper/wiki/HomePage | GrahamKelly]]
====Categories====
CategoryUserContributions