Extension:SpecialMergeableChanges

From MediaWiki.org
Jump to navigation Jump to search
MediaWiki extensions manual
OOjs UI icon advanced.svg
Mergeable Changes
Release status: beta
Implementation User interface, Special page
Description Show new, updated, or deleted articles and uploads since a given date.
Author(s) Courtney Christensen
Latest version 1.0
MediaWiki 1.11+
License No license specified
Download No link
Translate the SpecialMergeableChanges extension if it is available at translatewiki.net
Check usage and version matrix.

What can this extension do?[edit]

This Special Page shows all changes to the wiki since a given date. The user can also choose to save a zipped bundle of all the new uploads. The user can also get an xml file containing exports of all the new articles since the given date.

Usage[edit]

This is a special page. Go to Special:MergeableChanges, enter a date in the fields, and be amazed as all the changes to your wiki since that date are displayed before your eyes. Changes are nicely categorized as Added, Changed, or Deleted. Those categories are further broken down into Articles vs. Uploads.

This extension uses Special:Export to make an xml file of all new pages so that you can import it into another wiki.

**Note: You can use this extension with older versions of MediaWiki if you replace wfLoadExtensionMessages() with something that will work on your version.

Download instructions[edit]

Copy the files in the #Code section into files and put them into a folder called 'specialMergeableChanges' in your extensions folder.


Installation[edit]

To install this extension, add the following to LocalSettings.php:

#add configuration parameters here
#setup user rights here
require_once("$IP/extensions/specialMergeableChanges/SpecialMergeableChanges.setup.php");

Configuration parameters[edit]

User rights[edit]

Code[edit]

SpecialMergeableChanges.setup.php[edit]

<?php
/**
 * Originally written for the Genealogy Wiki
 * SpecialMergeableChanges
 * Created on May 28, 2008
 * Created by Courtney Christensen
 * Version 0.1
 *
 * This extension should
 * @Requirements:
 * @Expected Input:
 * @Expected Output:
 *
 * Update: Fixed title on the special pages.
 * Update Date: June 17, 2008
 * Mary Beebe
 * Version: 0.2
 *
 * Update: Added list of deleted pages,
 *         Created a new page with the output.
 * Update Date: June 30, 2008
 * Mary Beebe
 * Version: 1.0
 *
 */

# Alert the user that this is not a valid entry point to MediaWiki
if (! defined ( 'MEDIAWIKI' )) {
    echo "To install these extension, put the following line in ";
    echo "extensions/cbrtech/CbrtechIncludes.php:";
    echo " <br />require_once( \"";
    echo "$IP/extensions/cbrtech/recentChanges/SpecialMergeableChanges.setup.php\"";
    echo " );";
    exit ( 1 );
}



$wgExtensionCredits ['specialpage'] [] = array (
        'name' => 'Mergeable Changes',
        'version' => '.1',
        'author' => 'Courtney Christensen',
        'description' => 'The gateway to all that has changed since a given date.',
        'mergablechanges' => 'Mergeable Changes'
);

//Get this from http://www.phpconcept.net, adding this and uncommenting a section in the body file
//give you the option of making a zipped file of all the new uploads
//require_once( 'pclzip.lib.php' );

require_once( 'MergeableChangesDateTime.php' );
require_once( 'ExportToFile.php' );
# Tell MediaWiki to load the extension body.
$wgAutoloadClasses ['MergeableChanges'] = dirname(__FILE__) . '/SpecialMergeableChanges.body.php'; 
$wgExtensionMessagesFiles['MergeableChanges'] = dirname(__FILE__) .'/SpecialMergeableChanges.i18n.php';
# Let MediaWiki know about your new special page.
$wgSpecialPages ['MergeableChanges'] = 'MergeableChanges';

SpecialMergeableChanges.body.php[edit]

<?php

/**
 * Originally written for the project_name Wiki
 * file_name
 * Created on May 28, 2008
 * Created by Courtney Christensen
 * This extension (is for / does ?)
 * @Requirements:
 * @Expected Input:
 * @Expected Output:
 * Version 0.1
 *
 * Update: Fixed title on the special pages.
 * Update Date: June 17, 2008
 * Mary Beebe
 * Version: 0.2
 *
 * Update: Added list of deleted pages,
 *         Created a new page with the output.
 * Update Date: June 30, 2008
 * Mary Beebe
 * Version: 1.0
 *
 * Update: Improve merge query performance.
 * Update Date: July 10, 2008
 * Mary Beebe
 * Version: 1.1
 *
 */

class MergeableChanges extends SpecialPage {

    private $mcEndLine="\n";
    private $mcNUM_CELLS_PER_ROW=2;
    private $countPerType=0;
    private $dateTime;
    private $pagesNew=array();
    private $pagesUpdated=array();
    private $addImages=array();
    private $changeImages=array();

    /**
     * Ideally these messages would be added in another file, an i18n file, but
     * our version of MediaWiki does not support this the way it is explained on
     * MediaWiki.org.
     * Adding messages like this, instead of inline, is nice because it is so
     * easy to change the message text and because I don't have to come up with
     * a real message while I am programming.
     *
     * @return MergeableChanges
     */
    function MergeableChanges() {
        $this->dateTime = new MergeableChangesDateTime();
        wfLoadExtensionMessages( 'MergeableChanges' );
        SpecialPage::SpecialPage ( "MergeableChanges" );
        $this->mcEndLine = "\n";
        $this->mcNUM_CELLS_PER_ROW = 2;

    }

    /**
     * The execute function is called by the wiki because this class extends
     * SpecialPage.  This function asks for a date and when it gets a valid date
     * lists all the changes to the wiki since that date
     *
     * @param string $par any parameters to pass in (unused)
     * $par is there for consistency
     */
    function execute($par) {
        global $wgRequest;

        $this->setHeaders ();
        $date = $wgRequest->getVal ( 'date' );
        $time = $wgRequest->getVal ( 'time' );

        if (! isset ( $date ) || ! isset ( $time ) ) {
            $this->dateTime->askForDateTime ( 'mc-blank' );
        } else {
            $this->dateTime->splitDate ( $date,$time );
            if ((! $this->dateTime->isValidDateTime ()) || (! $this->dateTime->mcValidDateTimeFormat)) {
                $this->dateTime->askForDateTime ( 'mc-invalidDate' );
            } else {
                $this->getListOfChanges ();
            }
        }
    }



    /**
     * The getListOfChanges function lays and finds out the changes to the wiki
     * since the chosen date.
     *
     */
    function getListOfChanges() {
        global $wgOut,  $wgScriptPath, $wgSitename;
        // Make the header.
        $msg = array ( );
        $pageName = $this->dateTime->getPageName();
        $msg2 = "\n<br />". wfMsg ( 'cfm-newPageCreated');
        $msg2 .= "<a href='".$wgScriptPath."/index.php?title=$wgSitename:".$pageName."' class='new' title='".$pageName."'>".$pageName."</a>";
        $msg2 .= "\n<hr />";
        $msg [] = "__NOTOC__\n";
        $msg [] = wfMsg ( 'mc-date', "<b>".$this->dateTime->printableDate ()." - ".date('m-d-Y H:i')."</b>" );

        //Get new and updated pages and images.
        $names = $this->newUpdatedSinceDate();

        //Get new images and pages results.
        $output = $this->resultsTable($this->pagesNew);
        //New Images
        $msg[] = "<h2>" . wfMsg ( 'mc-newImages', "<b>".$this->dateTime->printableDate ()."</b>").wfMsg('mc-numberPages').$output['ImageCount'].  "</h2>";
        $msg[] = $output['Image'];

        //New Pages
        $msg [] = "<h2>" . wfMsg ( 'mc-newArticles', "<b>".$this->dateTime->printableDate ()."</b>").wfMsg('mc-numberPages').$output['MainCount'] .  "</h2>";
        $msg[] = $output['Main'];

        //Button only on the output page.
        $msg2 .= $this->export($names);

        //Get updated images and pages results.
        $output = $this->resultsTable($this->pagesUpdated);
        //Updated Images
        $msg [] = "<h2>" . wfMsg ( 'mc-updatedImages', "<b>".$this->dateTime->printableDate ()."</b>") .wfMsg('mc-numberPages').$output['ImageCount'] . "</h2>";
        $msg[] = $output['Image'];

        //Updated Articles

        $msg [] = "<h2>" . wfMsg ( 'mc-updatedArticles', "<b>".$this->dateTime->printableDate ()."</b>").wfMsg('mc-numberPages').$output['MainCount']  . "</h2>";
        $msg[] = $output['Main'];

        //Deleted Images
        $output = $this->deletedSinceDate ( NS_IMAGE );
        $msg [] = "<h2>" . wfMsg ( 'mc-deletedImages', "<b>".$this->dateTime->printableDate ()."</b>").wfMsg('mc-numberPages').$output['ImageCount']   . "</h2>";
        $msg[] = $output['Image'];

        //Deleted Articles
        $output = $this->deletedSinceDate (  NS_MAIN );
        $msg [] = "<h2>" . wfMsg ( 'mc-deletedArticles', "<b>".$this->dateTime->printableDate ()."</b>").wfMsg('mc-numberPages').$output['MainCount']  . "</h2>";
        $msg[] = $output['Main'];

        $msgTxt = implode ( $this->mcEndLine, $msg );

        $summary = wfMsg('cfm-summary');


        $docLinkTitle = Title::newFromText($pageName, NS_PROJECT);
        if ($docLinkTitle) {
            $docLinkArticle = new Article($docLinkTitle);
            $docLinkArticle->doEdit($msgTxt, $summary);
            $msg2 .= "<hr />";
            $wgOut->addHTML ($msg2);
            $wgOut->addWikiText ( $msgTxt );
        }
        else {
            $wgOut->addHTML ("ERROR - Not able to create page.");
        }
    }



    /**
     * Uses the wiki DB wrapper to request the page info(title, namespace, date)
     * from the database.
     *
     * @param namespace $ns the namespace to look in (Image or Main)
     * @return an associative array of $pages
     */
    function getPageInfoFromDb ( ) {
        $dbr = & wfGetDB ( DB_SLAVE );
        $res = $dbr->select (
            array ('page', 'revision' ), //FROM
            array ('page_title', 'page_namespace', 'rev_timestamp' ), //SELECT
            array (		//WHERE
                    'page_namespace = '.NS_MAIN.' OR '.'page_namespace = '.NS_IMAGE,
                    'page_is_redirect' => '0', //it isn't a redirect
                    'page_id=rev_page'
            ),
            'SELECT',
            array ('ORDER BY' => 'page_title','rev_timestamp' )
        );
        while ( ($s = $dbr->fetchObject ( $res )) ) {
            $title = $s->page_title;
            $time = $s->rev_timestamp;
            //Timestamp is by GMT.  This adjusts to the current timezone.
            $secondsSinceGMT = strtotime($time)+  date('Z');
            $time = date('YmdHis', $secondsSinceGMT);
            $namespace = $s->page_namespace;
            $pages [$time] = array (
                    'page_title' => $title,
                    'page_namespace' => $namespace
            );
        }
        return $pages;
    }

        /**
     * Uses the wiki DB wrapper to request the archive info(title, namespace, date)
     * from the database. (Archive table has deleted pages information).
     *
     * @param namespace $ns the namespace to look in (Image or Main)
     * @return an associative array of $pages
     */
    function getArchiveInfoFromDb ( $ns ) {
        $pages = array();
        $dbr = & wfGetDB ( DB_SLAVE );
        $res = $dbr->select (
            array ('archive', 'logging' ), //FROM
            array ('ar_title', 'ar_namespace', 'ar_timestamp','log_timestamp'), //SELECT
            array (		//WHERE
                    'ar_namespace' => $ns,
                    'log_action' => 'delete', //it is deleted
                    'ar_title=log_title',
                    'ar_title not in (select page_title from page)'
            ),
            'SELECT',
            array ('ORDER BY' => 'ar_title' )
        );

        while ( ($s = $dbr->fetchObject ( $res )) ) {
            $title = $s->ar_title;
            //log_timestamp is the time of delete.
            $time = $s->log_timestamp;
            $namespace = $s->ar_namespace;
            $artime = $s->ar_timestamp;
            $pages [$time] = array (
                'page_title' => $title,
                'page_namespace' => $namespace,
                   'ar_timestamp' => $artime
            );
        }
        return $pages;
    }

    /**
     * Removes new pages, duplicates, and unchanged pages.
     *
     * @param assoc. array of page info $array
     * @param namespace $ns
     */
    function newUpdatedSinceDate() {
        $pages = array();
        $names = '';
        $pages = $this->getPageInfoFromDb();

        foreach ($pages as $time => $nameNs) {
            $key = $nameNs['page_namespace'].":".$nameNs['page_title'];
            $when[$key][]=$time.":".$nameNs['page_namespace'].":".$nameNs['page_title'];
        }
        $this->pagesUpdated = array();
        $this->pagesNew = array();

        foreach ($when as $link => $page) {
            //if there is only one timestamp the page is new and unchanged
            $date = $this->dateTime->printableDate( 'timestamp' );
            $page[] = $date;
            sort($page);
            $maxDateIndex = (count($page) - 1 );
            $minDateIndex = 0;
            $where = array_search($date, $page);

            if ( (1 < count($page)) &&  ( $where < $maxDateIndex )){
                $ns = $link[0];
                $title = substr($link, 2);


                if ( $page[$minDateIndex] < $page[$where] )  {
                    //Changed but not new.
                    $this->pagesUpdated[$page[$where+1]] = array(
                                    'page_title' => $title,
                                    'page_namespace' => $ns,
                                    'num_revisions'  => ($maxDateIndex-$where),
                    );
                }
                else {
                    //New.
                    $this->pagesNew[$page[$where+1]] = array(
                                    'page_title' => $title,
                                    'page_namespace' => $ns,
                                    'num_revisions'  => ($maxDateIndex-$where),
                    );
                    $parts = split(":", $page[1]);

                    $title = Title::makeTitle(
                        $parts[1],
                        $parts[2]
                    );
                    $names .= $title->getFullText()."\n";
                }
            }
        }

        return $names;
    }

    /**
     * Get the pages that are deleted from the archive table.
     * Removes duplicatates and uses the logging table for the timestamp.
     *
     * @param assoc. array of page info $array
     * @param namespace $ns
     */
    function deletedSinceDate($ns) {
        $pages = array ( );
        $used = array( );
        $old = array( );
        $pages = $this->getArchiveInfoFromDb($ns);

        foreach ($pages as $time => $link) {
            //We need to get rid of duplicates and
            if (in_array($link['page_title'], $used)) {
                $this->deleteArrayElement($time, $pages);
            } else {
                $used[] = $link['page_title'];
            }
            //make sure that only things new since the given date are used.
            $pagesDate = strtotime($time);
            $limitDate = strtotime($this->dateTime->printableDate ( 'timestamp' ));
            if (!in_array($link['page_title'], $old)) {
                if ( $pagesDate < $limitDate ) {
                    $old[] = $link['page_title'];
                    $this->deleteArrayElement($time, $pages);
                }
            } else {
                $this->deleteArrayElement($time, $pages);
            }
        }

        return( $this->resultsTable ( $pages, true ));
    }

    /**
     * resultsTable takes an array of page info
     * [timestamp] =>  page_title
     *			   =>  page_namespace
     * and returns a well formatted html table listing and linking to those pages
     *
     * @param assoc. array of page info $pages
     * @return string $out (an html table of the results)
     */
    function resultsTable($pages,$isDelete=false) {
        $lineMain = 0;
        $lineImage = 0;
        $outMain = "<table border=\"0\" cellspacing=\"0\" width=\"100%\">\n";
        $outImage = "<table border=\"0\" cellspacing=\"0\" width=\"100%\">\n";
        $countMain = 0;
        $countImage = 0;
        ksort($pages);

        foreach ( $pages as $time => $pageTitleParts ) {
            $title = Title::makeTitle(
                $pageTitleParts['page_namespace'],
                $pageTitleParts['page_title']
            );
            if ($isDelete) {
                $link=$pageTitleParts['page_title'];
            }
            else {
                $link='[[:'.htmlspecialchars($title->getPrefixedURL()).']]';
            }
            $time=split(":",$time);

            $date = date ( 'm-d-o H:i', strtotime ( $time[0] ) );
            if ($pageTitleParts['page_namespace'] == NS_IMAGE) {
                if ($lineImage % $this->mcNUM_CELLS_PER_ROW == 0) {
                    $outImage .= "\t<tr>\n";
                }
                $outImage .= "\t\t<td width=\"33%\"><ul><li>$link ~";
                if (isset($pageTitleParts['num_revisions'])) {
                    $outImage .= " (". $pageTitleParts['num_revisions'].") ~";
                }
                $outImage .=  $date. "</li></ul></td>\n";
                $lineImage ++;
                if ($lineImage % $this->mcNUM_CELLS_PER_ROW == 0) {
                    $outImage .= "\t</tr>\n";
                }
                $countImage ++;
            }
            elseif ($pageTitleParts['page_namespace'] == NS_MAIN) {
                if ($lineMain % $this->mcNUM_CELLS_PER_ROW == 0) {
                    $outMain .= "\t<tr>\n";
                }
                $outMain .= "\t\t<td width=\"33%\"><ul><li>$link ~";
                if (isset($pageTitleParts['num_revisions'])) {
                    $outMain .= " (". $pageTitleParts['num_revisions'].") ~";
                }
                $outMain .=  $date. "</li></ul></td>\n";
                $lineMain ++;
                if ($lineMain % $this->mcNUM_CELLS_PER_ROW == 0) {
                    $outMain .= "\t</tr>\n";
                }
                $countMain ++;
            }


        }

        while ($lineImage % $this->mcNUM_CELLS_PER_ROW != 0) {
            $outImage .= "<td width=\"33%\">&nbsp;</td>";
            $lineImage++;
        }
        $outImage .= "</table>\n";
        while ($lineMain % $this->mcNUM_CELLS_PER_ROW != 0) {
            $outMain .= "<td width=\"33%\">&nbsp;</td>";
            $lineMain++;
        }
        $outMain .= "</table>\n";
        $out = array('Main'=>$outMain,'MainCount'=>$countMain,'Image'=>$outImage,'ImageCount'=>$countImage);
        return $out;
    }


    /**
     * deletes the specified element from the array
     *
     * @param string $index
     * @param array &$array
     */
    function deleteArrayElement ( $index, &$array ) {
        unset($array[$index]);
    }


    /**
     * This mimics the wiki export form, asking for an xml file of all newly
     * added pages so they can be imported into the recipient wiki.
     * @TODO: if you got the pclzip library uncomment the two lines below to use the upload zipping functionality
     *
     * @param string $pages list of pages to export
     * @return string (an html form requesting export of pages)
     */
    function export($pages) {
        //$this->makeImageBundle($pages);
        $this->xmlStream( $pages );
        //$button  = wfMsg('mc-imageFile')."<br />";
        $button .= wfMsg('mc-buttonInstruct', $this->dateTime->printableDate());
        return $button;
    }


    /**
     * This takes the list of pages to export and zips up all the uploads in
     * their wiki file structure.  Uses pclzip.lib.php
     *
     * @param string $titlesText list of pages
     */
    function makeImageBundle( $titlesText ) {
        global $wgTmpDirectory, $IP, $wgScriptPath;
        if (!file_exists($wgTmpDirectory)) {
            mkdir($wgTmpDirectory, 0777);
        }
        $ziplist = array();
        $fileList = "The following files should be included in this zip:\n";
        $titles = explode("\n",$titlesText);
        foreach ($titles as $title) {
            if ( stripos($title, /*I*/"mage") ) { //There is nothing to export if it isn't an image(upload)
                $image = str_replace("Image:", "", $title);
                $image = str_replace(" ", "_", $image);
                $imagePath = urldecode(Image::imageUrl($image));
                $imagePath = $IP.str_replace($wgScriptPath, "", $imagePath);
                $fileList .= $imagePath . "\n";
                $ziplist[] = $imagePath;
            }
        }

        file_put_contents($wgTmpDirectory."/fileList.txt", $fileList);
        $ziplist[] = $wgTmpDirectory."/fileList.txt";

        $locale = $wgTmpDirectory."/";
        if ( file_exists($locale.'images.zip') ) {
            unlink($locale.'images.zip'); //delete the previous zip file
        }
        $bundle = new PclZip($locale.'images.zip'); //make a handle for the new zip file
        $bundle->create( $ziplist );
    }


    function xmlStream( $page ) {
        if( $page != '' ) {
            $pages = explode( "\n", $page );

            $db =& wfGetDB( DB_SLAVE );
            //TRUE - Means only the most current pages.
            $exporter = new WikiExporterToFile( $db, TRUE, 'import' );
            $exporter->list_authors = FALSE ;
            $exporter->openStream();

            foreach( $pages as $page ) {
                $exporter->pageByName( $page );
            }

            $exporter->closeStream();
            return;
        }
    }

}

SpecialMergeableChanges.i18n.php[edit]

<?php
/**
 * Originally written for the Genealogy Wiki
 * Internationalized Language file for
 * Created on May 28, 2008
 * Created by Courtney Christensen
 * Version 0.1
 *
 * This extension (is for / does ?)
 * @Requirements:
 * @Expected Input:
 * @Expected Output:
 * 
 * Update: Made the messages work.  Transferred messages from body to here.
 * Update Date: June 30, 2008
 * Mary Beebe
 * Version: 1.0
 *
 * Update: Improve merge query performance.
 * Added some new messages.
 * Update Date: July 10, 2008
 * Mary Beebe
 * Version: 1.1
 */

global $wgMessageCache;
$messages = array();

$messages['en'] = array(
        'cfm-summary' => 'Automatically created(edited): Mergeable Changes list of files',
        'cfm-prePageName' => 'M_Changes',
        'cfm-newPageCreated' => 'New Page Created: ',
        'mergeablechanges'=> 'Mergeable Changes' ,
        'mc-date'=> 'Date and Time from which to check for new, changed, or deleted data: $1' ,
        'mc-dateFormat'=> 'Date format: MM-DD-YYYY  Time format: HH:MM (military time - 13:00 is 1:00 PM).' ,
        'mc-blank'=> '' ,
        'mc-invalidDate'=> 'This is an invalid date or time - ' ,
        'mc-newImages'=> 'Uploaded Files Added Since $1' ,
        'mc-newArticles'=> 'Articles Added Since $1' ,
        'mc-updatedImages'=> 'Uploaded Files Changed Since $1' ,
        'mc-updatedArticles'=> 'Articles Changed Since $1' ,
        'mc-deletedImages'=> 'Uploaded Files Deleted Since $1' ,
        'mc-deletedArticles'=> 'Articles Deleted Since $1' ,
        'mc-exportArticles'=> 'Export New Uploads and Articles' ,
        'mc-timeLabel' => 'Time (EST):',
        'mc-imageFile' => 'The file <a href="images/tmp/images.zip">images.zip</a>, which contains the new uploads, has been created in the images/tmp folder.',
        'mc-buttonInstruct'=> 'Right click this link and save as to a local file location you will remember: <a href="images/tmp/import.xml">Import.xml</a>'  ,
        'mc-numberPages'=> '  Total:'
);


ExportToFile.php[edit]

<?php
/**
 * This class extends the core wiki classes in Export.php
 */
/**
 *
 * @package MediaWiki
 * @subpackage SpecialPage
 */

require_once( $IP . '/includes/Export.php' );

class WikiExporterToFile extends WikiExporter  {
    function WikiExporterToFile( &$db, $history = WikiExporter::CURRENT,
        $fileName = 'filename',
        $buffer = WikiExporter::BUFFER, $text = WikiExporter::TEXT
    ) {
        $this->db =& $db;
        $this->history = $history;
        $this->buffer  = $buffer;
        $this->writer  = new XmlDumpWriter();
        $this->sink    = new DumpOutputToFile($fileName);
        $this->text    = $text;
    }


}


/**
 * Base class for output stream; prints to stdout or buffer or whereever.
 */
class DumpOutputToFile extends DumpOutput {
    private $fileResource;

    function DumpOutputToFile($fileName) {
        global $wgTmpDirectory;
        if (!file_exists($wgTmpDirectory)) {
            mkdir($wgTmpDirectory, 0777);
        }
        $this->fileResource = fopen($wgTmpDirectory."/$fileName.xml", "w+");
    }

    function writeCloseStream( $string ) {
        $this->write( $string );
        fclose($this->fileResource);
    }


    /**
     * Writes to file
     */
    function write( $string ) {
        fwrite($this->fileResource, $string);
    }
}


MergeableChangesDateTime.php[edit]

<?php
/**
 * Originally written for the project_name Wiki
 * MergeableChangesDateTime
 * Created on July 11, 2008
 * Created by Mary Beebe
 * This extension manages date and time functions for SpecialMergeableChanges
 * @Requirements:
 * @Expected Input:
 * @Expected Output:
 * Version 0.1
 *
 */

class MergeableChangesDateTime {	

    public   $mcValidDateTimeFormat;
    private  $mcMonth;
    private  $mcDay;
    private  $mcYear;
    private  $mcHour;
    private  $mcMinute;

    /**
     * prints a form asking for the date.
     *
     * @param message key (string) $warning which message to print if bad date
     */
    public function askForDateTime($warning) {
        global $wgTitle, $wgOut;
        $warn = '';
        $action = $wgTitle->escapeLocalUrl ();
        if ('mc-blank' != $warning) {
            $warn .= "<span style=\"color:red;\">";
            $warn .= wfMsg ( $warning );
            $warn .= "<b>" . $this->printableDate () . "</b>";
            $warn .= "</span>\n";
        }
        $form = $warn;
        $form .= "<form action=\"$action\" method=\"post\">\n\r";
        $form .= "\t <label for=\"date\">";
        $form .= wfMsg ( 'mc-date' , wfMsg ( 'mc-dateFormat' ) ) . "</label>";
        $form .= "<p class=\"lastup\"><input type=\"text\" ";
        $form .= "class=\"format-m-d-y divider-dash\" ";
        $form .= "id=\"date\" name=\"date\" maxlength=\"10\" value=\"\" />";
        $form .= "&nbsp;&nbsp;&nbsp;<label for=\"time\">".wfMsg ( 'mc-timeLabel' ). "</label><input type=\"text\" ";
        $form .= "id=\"time\" name=\"time\" maxlength=\"6\" value=\"\" /></p>";
        $form .= "<input type=\"submit\" value=\"Submit\" />\r\n";
        $form .= "</form>";
        $wgOut->addHTML ( $form );
    }


    /**
     * a check to see whether the date is a real month, day, year and time.
     * @return boolean
     */
    public function isValidDateTime() {
        if ($this->mcHour <= "24" && $this->mcHour >= "00"
            && $this->mcMin <= "59" && $this->mcMin >= "00") {
            return checkdate ( $this->mcMonth, $this->mcDay, $this->mcYear );

        }
        else {
            return false;
        }
    }

    /**
     * Since a date is entered as a single string of the form MM-DD-YYYY
     * and three variables are easier to work with, this function breaks it
     * down and stores it in private variables.
     *
     * @param string $date
     */
    public function splitDate($date,$time) {
        $dateParts = array ( );
        $datePattern = '/(\d\d)-(\d\d)-(\d\d\d\d)/';
        $timeParts = array ( );
        $timePattern = '/(\d\d):(\d\d)/';

        $this->mcValidDateTimeFormat = preg_match($datePattern, $date, $dateParts);
        $this->mcMonth = $dateParts [1];
        $this->mcDay = $dateParts [2];
        $this->mcYear = $dateParts [3];

        if ($this->mcValidDateTimeFormat) {
            //If no time is entered then start at 00:00.
            if ($time ) {
                $this->mcValidDateTimeFormat = preg_match($timePattern, $time, $timeParts);
                $this->mcHour = $timeParts [1];
                $this->mcMin = $timeParts [2];
            }
            else {
                $this->mcHour = "00";
                $this->mcMin = "00";
            }
        }
    }
    /**
     * This returns the pagename.
     *
     * @param
     * @return pagename.
     */
    public function getPageName() {
        $FirstPart  = wfMsg('cfm-prePageName');
        $PageName = $FirstPart."_".$this->printableDate()."_".date('m-d-Y H:i');
        return $PageName;
    }

    /**
     * This returns the date in the format you specify ('' or 'timestamp')
     *
     * @param date format (''|'timestamp') $format
     * @return date string
     */
    public function printableDate($format = null) {
        if ('timestamp' == $format) {
            return $this->mcYear . $this->mcMonth . $this->mcDay . $this->mcHour. $this->mcMin. '00';
        }
        return $this->mcMonth."-".$this->mcDay."-".$this->mcYear."  ".$this->mcHour.":".$this->mcMin;
    }
}


See also[edit]