=====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 .= '
'.FORM_LEGEND.''."\n"; $form1 .= '
'."\n"; // ranged drop-down $pages_opts = optionRanges($page_limits,$numpages,DEFAULT_MIN_RECORDS_DISPLAY); $form1 .= ' '."\n"; $form1 .= '
'."\n"; // build pager links if ($s > 0) { $prev = ''.($s-$l+1).'-'.$s.' | '."\n"; } if ($numpages > ($s + $l)) { $next = ' | '.($s+$l+1).'-'.($s+2*$l).''."\n"; } $form1 .= FORM_RESULT_INFO.' ('.$numpages.'): '.$prev.($s+1).'-'.($s+$l).$next.'
'."\n"; $form1 .= '('.FORM_RESULT_SORTED_BY.''.$sort.', '.$d.')'."\n"; $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 = ''.TABLE_HEADING_REVISIONS_ALT.''; $htmlout = "\n". "\n\n". " \n". " \n". " \n". " \n". " \n". " \n". " \n". " \n". " \n". " \n". " \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"; #enable alternate row color } else { $htmlout .= "\n"; #disable alternate row color } $htmlout .=" \n". # modified JW 2005-07-19 " \n". " \n". " \n". " \n". " \n". " \n". " \n". " \n". " \n". /*>>>*/ " \n". " \n\n"; //increase row counter ----- alternate row colors if ($r_color == 1) $r++; } $htmlout .= '
 ".$tagheader."".$ownerheader."".$userheader."".$lasteditheader."\"".TABLE_HEADING_HITS_ALT."\"/".$revisionsheader."\"".TABLE_HEADING_COMMENTS_ALT."\"/\"".TABLE_HEADING_BACKLINKS_ALT."\"/\"".TABLE_HEADING_REFERRERS_ALT."\"/".TABLE_HEADING_ACTIONS."
".$showpage."".$owner."".$user."0)? 'title="['.$page['note'].']"' : 'title="'.NO_EDIT_NOTE.'"').">".$lastedit."".$hitspage."".$revpage."".$commentspage."".$backlinkpage."".$refpage."".$editpage." :: ".$deletepage." :: ".$clonepage." :: "./*$renamepage*." :: ".*/$aclpage." :: ".$infopage." :: ".$prunepage."
'."\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 '
'.FORM_MASSACTION_LEGEND.''; echo '['.CHECK_ALL.' | '.UNCHECK_ALL.']
'; echo ' '; 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