A malfunctioning or malicious add-on has caused Internet Explorer to close this webpage

This disease suddenly started after I ran an update on my Windows 7 machine, but I’m not really sure if it was an existing addon compatibility issue before I ran the update. Although I am sure that it’s caused partly due to a new security feature in IE 8. (And speaking of diseases, I have the flu ;)

Here’s the real kicker : Microsoft’s recommendation is to turn off a protective feature of the browser itself. IE 8 Now comes with a flag in the advanced security settings…

Enable memory protection to help mitigate on line attacks : Yeah, that's totally not needed. That selection is greyed out anyway, because I didn't select Right Click > Run as Administrator on the IE shortcut.

Once again, encouraging people to turn off protection mechanisms (UAC comes to mind) rather than gracefully handling a misbehaving addon. Nice job, MS!

Obviously, my recommendation is that you leave this setting alone and try turning off some addons insteads. See if you can do without all of them, that isn’t from Microsoft, first and selectively turn them on one by one until you isolate the dud plugin.  I’m fairly sure the new Java VM has something to do with this so I’m trying that first.

Forum core source dump (as of July 31)

I would have finished this a while ago, but I’m in the middle of moving to a new apartment. Until that’s over, I figured I’ll dump what I have so far on the forum.

And I’ve finally settled on a name for this. I shall hereby call this forum script : theForum. Yeah, points for originality there. And of course, this will contain errors, incomplete functions/functionality and other terrible things, so be careful when using any part of this in your own projects. And on top of that the WordPress source code formatting is a bit off making error checking even more vital.

WARNING: This will be a very, very, very long post (7 pages total)!

index.php

/*

	#### theForum : A brand you can trust ####

*/



/******************************************************************************

	Modifying anything below will void the (non-existent) warranty!

*******************************************************************************/

// WARNING: Keep these intact.

// Root location
$rt = dirname(__FILE__) . '/';

// Get the main logic
require_once($rt . 'lib/main.php');

config.php

/******************************************************************************

	Edit your database settings here... (These values go in quotes)

*******************************************************************************/

// Your database server
$presets['db_host'] = 'localhost';

// Database name
$presets['db_name'] = 'wrex';

// Database admin name
$presets['db_user'] = 'wrex_user';

// Database admin password
$presets['db_pass'] = 'password';

// Database type
$presets['db_type'] = 'MySQL';


/******************************************************************************

	Edit your forum settings here... (Some settings require quotes)

*******************************************************************************/


// Forum title (you can include some HTML tags, but they will be stripped for page <title> tags)
$presets['site_title'] = 'the<span>Forum</span>';

// Slogan
$presets['site_slogan'] = 'A brand you can trust';

// Copyright notice
$presets['site_copyright'] = 'Copyright &#169; 2009. All rights reserved.';

// Full site url
$presets['site_url'] = 'http://localhost/';


// Topics per page
$presets['page_topic_limit'] = 15;

// Replies per page
$presets['page_reply_limit'] = 10;


// The relative path to the forums for various paths in themes
$presets['site_path'] = '/';

$presets['site_path_seperator'] = ' &#187; ';

// Present friendly, SEO friendly, URLs by avoiding querystring usage
// (this requires a .htaccess file for Apache or a map/ISAPI filter for IIS)
$presets['site_friendly_urls'] = '1';

// Allow self service creation of accounts. Admins can still create users. (True = 1 / False = 0)
$presets['site_registration'] = '1';

// The default template and styles.
$presets['site_theme'] = 'Section5';

// Closed for maintenance. If set to true, the "Forums closed" message will be displayed
// True = 1 / False = 0
$presets['site_closed'] = '0';

// Forums closed message in HTML format
$presets['site_closed_message'] = '<p>The forums are closed for maintenance. Please check back later.</p>';

// Welcome message (Don't change the "WELCOME" parts). You need to use HTML.
$presets['site_welcome'] =< <<WELCOME



<h2>Welcome
<h3>This is a demonstration template</h3>
<p>Rockwell Accessible is an experimental theme designed to improve web accessibility while maintaining a logical HTML structure. This is one variation of the base theme which is an example of customizability. The idea is to make any changes to the stylesheet while leaving the rest of the HTML intact. It includes provisions for error/notification formatting as well as text and link highlighting.</p>
<p>Read the accompanying <a href="https://eksith.wordpress.com/2009/02/16/rockwell-accessible/">blog post</a>.</p>



WELCOME;

// Footer HTML including copyrights and links etc...
$presets['site_footer'] =< <<FOOTER

	<p>
	<p class="powered">
		<a href="https://eksith.wordpress.com/"><img src="/templates/RockwellGradient/img/ouroboros.png" alt="Design by Eksith" longdesc="https://eksith.wordpress.com/" height="30" width="30" /></a>
	</p>

FOOTER;


/******************************************************************************

	##################### End casual editing #####################
	Edit below (if you know what you're doing) at your own risk!

*******************************************************************************/



// Root location of this file. All file inclusions depend on this.
$presets['site_root'] = dirname(__FILE__) . '/';

// Write enabled directories are required. Please disable execute privileges on these as a security precaution.
$presets['site_upload_directory'] = $presets['site_root'] . 'data/uploads';
$presets['site_cache_directory'] = $presets['site_root'] . 'data/cache';
$presets['site_cache_duration'] = '160';

// The template url is dependent on the SITE_THEME and SITE_TEMPLATE values.

$presets['site_template_directory'] = $presets['site_path'] . 'templates/';
$presets['site_template_url'] = $presets['site_path'] . 'templates/' . $presets['site_theme'] . '/';

// Default language to use in two letter format (preset is English).
$presets['site_lang'] = 'en';


// Security regular expressions
$presets['core_regex_valid_username'] = '/^[\w-_]{4,50}/iu';
$presets['core_regex_valid_displayname'] = '/^[\w\s\.-_]{0,100}/iu';
$presets['core_regex_valid_email'] = '/^[a-zA-Z0-9._-]+@[a-zA-Z0-9-]+\.[a-zA-Z.]{2,5}$/i';
$presets['core_regex_valid_querystring'] = '/^[\d-_a-zA-Z]/i';
$presets['core_regex_valid_htmlparams'] = '/^[\w-_]{4,20}/i';
$presets['core_regex_valid_colors'] = '/^#(([a-fA-F0-9]{3}$)|([a-fA-F0-9]{6}$))/i';
$presets['core_regex_invalid_search'] = '/^[~!\|\'()\[\]\< \>;]/i';

// Formatting allowed HTML tags and allowed corresponding attributes

// Convert deprecated tags.
// Convention: array([old tag], [new tag + formatting], [end tag]);
$presets['ui_format_tags_deprecated'] = array(
	array('b', 'strong', 'strong'),
	array('i', 'em', 'em'),
	array('s', 'span style="text-decoration:strikethrough;"', 'span'),
	array('strike', 'span style="text-decoration:strikethrough;"', 'span'),
	array('center', 'div style="text-align:center"', 'div'),
	array('left', 'div style="text-align:left"', 'div'),
	array('right', 'div style="text-align:right"', 'div'),
	array('u', 'span style="text-decoration:underline;"', 'span')
);

// Allowed HTML tags. All others, except for those found above, will be stripped
// Convention: array([tag name], [allowed attributes]);
$presets['ui_format_tags'] = array(
	array('a', 'style,class,title,href,rel,target'),
	array('abbr', 'style,class,title'),
	array('acronym', 'style,class,title'),
	array('blockquote', 'style,class,title,dir,lang,xml:lang'),
	array('br', 'style,class'),
	array('caption', 'style,class,title'),
	array('cite', 'style,class,title'),
	array('code', 'style,class,title'),
	array('del', 'style,class,title'),
	array('em', 'style,class,title'),
	array('h1', 'style,class,title'),
	array('h2', 'style,class,title'),
	array('h3', 'style,class,title'),
	array('h4', 'style,class,title'),
	array('h5', 'style,class,title'),
	array('h6', 'style,class,title'),
	array('hr', 'style,class'),
	array('img', 'style,class,src,height,width,border,hspace,vspace,alt,longdesc'),
	array('ins', 'style,class,title,cite'),
	array('li', 'style,class,title'),
	array('ol', 'style,class,title'),
	array('p', 'style,class,title,align,dir,lang,xml:lang'),
	array('pre', 'style,class,title,dir,lang,xml:lang'),
	array('strong', 'style,class,title'),
	array('span', 'style,class,title,dir,lang,xml:lang'),
	array('table', 'style,class,title,border\-collapse,bgcolor,background'),
	array('tfoot', 'style,class,title,align'),
	array('thead', 'style,class,title,align'),
	array('tbody', 'style,class,title,align'),
	array('td', 'style,class,title,align,valign'),
	array('th', 'style,class,title,align,valign'),
	array('tr', 'style,class,title,align,valign'),
	array('ul', 'style,class,title')
);

// Prohibited keywords in attribute values (from W3C)
// It is STRONGLY recommended that you not remove any of these 
// as certain browsers may allow their execution in unpredictable ways.
$presets['ui_format_invalid_attributes'] = array(
	'onabort',
	'onactivate',
	'onafterprint',
	'onafterupdate',
	'onbeforeactivate',
	'onbeforecopy',
	'onbeforecut',
	'onbeforedeactivate',
	'onbeforeeditfocus',
	'onbeforepaste',
	'onbeforeprint',
	'onbeforeunload',
	'onbeforeupdate',
	'onblur',
	'onbounce',
	'oncellchange',
	'onchange',
	'onclick',
	'oncontextmenu',
	'oncontrolselect',
	'oncopy',
	'oncut',
	'ondataavaible',
	'ondatasetchanged',
	'ondatasetcomplete',
	'ondblclick',
	'ondeactivate',
	'ondrag',
	'ondragdrop',
	'ondragend',
	'ondragenter',
	'ondragleave',
	'ondragover',
	'ondragstart',
	'ondrop',
	'onerror',
	'onerrorupdate',
	'onfilterupdate',
	'onfinish',
	'onfocus',
	'onfocusin',
	'onfocusout',
	'onhelp',
	'onkeydown',
	'onkeypress',
	'onkeyup',
	'onlayoutcomplete',
	'onload',
	'onlosecapture',
	'onmousedown',
	'onmouseenter',
	'onmouseleave',
	'onmousemove',
	'onmoveout',
	'onmouseover',
	'onmouseup',
	'onmousewheel',
	'onmove',
	'onmoveend',
	'onmovestart',
	'onpaste',
	'onpropertychange',
	'onreadystatechange',
	'onreset',
	'onresize',
	'onresizeend',
	'onresizestart',
	'onrowexit',
	'onrowsdelete',
	'onrowsinserted',
	'onscroll',
	'onselect',
	'onselectionchange',
	'onselectstart',
	'onstart',
	'onstop',
	'onsubmit',
	'onunload'
);




/******************************************************************************

	######################## End editing ########################

*******************************************************************************/

// Class loader (required)
function __autoload($class)
{
	global $presets;
	
	// Try and get a class file
	$cfile = $presets['site_root'] . 'lib/' . $class . '.class.php';
	
	// Or module file
	$mfile = $presets['site_root'] . 'modules/' . strtolower($class) . '/module.php';
	
	if(file_exists($cfile))
		require_once($cfile);
	elseif(file_exists($mfile))
		require_once($mfile);
	else
		exit("Unable to Find $class in the library folder or plugin modules folder");
	
	if(!class_exists($class, false))
		exit("Unable to load $class class");
}

PHP Plugin/Module system

After a lot of head scratching and hair pulling, I finally managed to put together something that works for me. Again, this is highly experimental code so feel free to take it apart for errors before using in your projects.

This will be the default module system for the forum script. As such, a lot of the functionality and render regions will need to be modified to fit your own projects.

Warning:

The WordPress sourcecode formatter introduces some odd artifacts and improper formatting. Please review the code for these mistakes. These artifacts/errors are present even in the “view plain” and “copy to clipboard” options.

Update July 31

I’ve made some modifications to this and most of the other sources.

The Modules class:

/**
* Modules class.
* Extending the base forum functionality through pluggable modules.
*
* @author Jayanath Rodrigo
* @version 0.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
* @access public
*/

final class Modules
{
	static private $instance;		// Singleton instance for this class
	protected $resources = array();		// Loaded modules
	protected $regions = array();		// Output render regions

	/**
	* Modules constructor. Initiates all given modules
	*
	* @param array $props Properties array global
	* @param object $db Database object
	* @param array $modules List of modules to be loaded
	*/
	private function __construct(&amp;$p, &amp;$db, $modules)
	{
		// Start the regions
		$this->initRegions();

		// Load the modules into the $resources array
		foreach($modules as $resource)
			$this->resources[$resource] = new $resource($p, $db);
	}

	/**
	* Singleton instance.
	*
	* @param array $p The presets in the core passed by reference.
	* @param object $d The database object (MySQL, SQLite et al) passed by reference.
	* @return object Module Singleton instance
	*/
	static function getInstance(&amp;$props, &amp;$db, $modules)
	{
		if(!isset(self::$instance))
			self::$instance = new Modules(&amp;$props, &amp;$db, $modules);

		return self::$instance;
	}

	/**
	* Trigger module events
	* When called within the templates, this function iterates through all loaded modules
	* and calls the appropriate event function.
	*
	* @param string $method Event name ("BeforeHeaderStart", "AfterHeaderEnd" etc...)
	* @param mixed $args This will depend on where the trigger method is called. Generally, will be an array or string.
	*/
	public function __trigger($method, $args)
	{
		// onHeader, onBefore onAfterBody etc... This is the convention used within the module classes.
		$call = "on" . $method;

		// Iterate through each module resource
		foreach($this->resources as $key => $module)
		{
			// If an "on" event function exists for this region...
			if(method_exists($module, $call))
			{
				// Call the function and load the module's output into the region to be injected
				$this->regions[$method] .= call_user_func(array($module, $call), $args);
			}
		}
	}

	/**
	* Gets the module output for a specified region
	*
	* @return string $regions[key] Output HTML from loaded modules
	*/
	public function __render($method)
	{
		return $this->regions[$method];
	}

	/**
	* Template render injection regions.
	* Initiates $regions array into accessible empty keys. Note: Template designers MUST use these keys!
	*/
	private function initRegions()
	{

		/**
		* Generic regions
		*/
		$this->regions["Head"] = '';						// On head tag

		$this->regions["BeforeBody"] = '';					// After body tag
		$this->regions["Body"] = '';						// On body
		$this->regions["AfterBody"] = '';					// Before body end tag

		$this->regions["BeforeHeaderStart"] = '';			// Before header start
		$this->regions["BeforeHeader"] = '';				// After header start
		$this->regions["Header"] = '';						// On header
		$this->regions["AfterHeader"] = '';				// Before header end
		$this->regions["AfterHeaderEnd"] = '';				// After header end

		$this->regions["BeforeContentStart"] = '';			// Before content start
		$this->regions["BeforeContent"] = '';				// After content start
		$this->regions["Content"] = '';					// On content
		$this->regions["AfterContent"] = '';				// Before content end
		$this->regions["AfterContentEnd"] = '';			// After content end

		/**
		* List regions
		*/
		$this->regions["BeforeForumsStart"] = '';			// Before forums list start
		$this->regions["BeforeForums"] = '';				// Before first list item start
		$this->regions["Forums"] = '';						// On forum list as item
		$this->regions["AfterForums"] = '';				// After last forum list item end
		$this->regions["AfterForumsEnd"] = '';				// After forums list end

		$this->regions["BeforeTopicsStart"] = '';			// Before topics list start
		$this->regions["BeforeTopics"] = '';				// Before first topics list item start
		$this->regions["Topics"] = '';						// On topics list as item
		$this->regions["AfterTopics"] = '';				// After last topic list item end
		$this->regions["AfterTopicsEnd"] = '';				// After topics list end

		$this->regions["BeforeRecentStart"] = '';			// Before recent topics list start
		$this->regions["BeforeRecent"] = '';				// Before first topic list item start
		$this->regions["Recent"] = '';						// On topics list as item
		$this->regions["AfterRecent"] = '';				// Before recent topics list end
		$this->regions["AfterRecentEnd"] = '';				// After recent topics list end

		$this->regions["BeforeRepliesStart"] = '';			// Before replies start
		$this->regions["BeforeReplies"] = '';				// After replies start
		$this->regions["Replies"] = '';					// On replies
		$this->regions["AfterReplies"] = '';				// Before replies end
		$this->regions["AfterRepliesEnd"] = '';			// After replies end 

		$this->regions["BeforePagerStart"] = '';			// Before pager start
		$this->regions["BeforePager"] = '';				// After pager start
		$this->regions["Pager"] = '';						// On pager
		$this->regions["AfterPager"] = '';					// Before pager end
		$this->regions["AfterPagerEnd"] = '';				// After pager end 

		/**
		* Individual item regions
		* NOTE: Singular! (no 's' at the end)
		* Content for these regions will be refreshed with each iteration within a loop
		*/
		$this->regions["BeforeForumStart"] = '';			// Before forum item start
		$this->regions["BeforeForum"] = '';				// After forum item start
		$this->regions["Forum"] = '';						// On forum list as item
		$this->regions["AfterForum"] = '';					// Before forum end item
		$this->regions["AfterForumEnd"] = '';				// After forum end item

		$this->regions["BeforeTopicStart"] = '';			// Before topic item start
		$this->regions["BeforeTopic"] = '';				// After topic item start
		$this->regions["Topic"] = '';						// On topics list as item
		$this->regions["AfterTopic"] = '';					// Before topic end item
		$this->regions["AfterTopicEnd"] = '';				// After topic end item

		$this->regions["BeforeLockedTopicStart"] = '';		// Before locked topic item start
		$this->regions["BeforeLockedTopic"] = '';			// After locked topic item start
		$this->regions["LockedTopic"] = '';				// On locked topics list as item
		$this->regions["AfterLockedTopic"] = '';			// Before locked topic item end
		$this->regions["AfterLockedTopicEnd"] = '';		// After locked topic item end

		$this->regions["BeforeStickyTopicStart"] = '';		// Before sticky topic start item
		$this->regions["BeforeStickyTopic"] = '';			// After sticky topic start item
		$this->regions["StickyTopic"] = '';				// On sticky topics list as item
		$this->regions["AfterStickyTopic"] = '';			// Before sticky topic item end
		$this->regions["AfterStickyTopicEnd"] = '';		// After sticky topic item end

		$this->regions["BeforeGlobalTopicStart"] = '';		// Before global sticky topic item start
		$this->regions["BeforeGlobalTopic"] = '';			// After sticky topic item start
		$this->regions["GlobalTopic"] = '';				// On global sticky topic item
		$this->regions["AfterGlobalTopic"] = '';			// Before global sticky topic item end
		$this->regions["AfterGlobalTopicEnd"] = '';		// After global sticky topic item end

		$this->regions["BeforeReplyStart"] = '';			// Before reply item start
		$this->regions["BeforeReply"] = '';				// After reply item start
		$this->regions["Reply"] = '';						// On reply item
		$this->regions["AfterReply"] = '';					// Before reply item end
		$this->regions["AfterReplyEnd"] = '';				// After reply item end

		/**
		* Form data
		*/
		$this->regions["BeforeTopicFormStart"] = '';		// Before new topic form start
		$this->regions["BeforeTopicForm"] = '';			// After new topic form start
		$this->regions["TopicForm"] = '';					// On new topic form
		$this->regions["AfterTopicForm"] = '';				// Before new topic form end
		$this->regions["AfterTopicFormEnd"] = '';			// After new topic form end

		$this->regions["BeforeReplyFormStart"] = '';		// Before new reply form start
		$this->regions["BeforeReplyForm"] = '';			// After new reply form start
		$this->regions["ReplyForm"] = '';					// On new reply form
		$this->regions["AfterReplyForm"] = '';				// Before new reply form end
		$this->regions["AfterReplyFormEnd"] = '';			// After new reply form end

		$this->regions["BeforeLoginFormStart"] = '';		// Before login form start
		$this->regions["BeforeLoginForm"] = '';			// After login form start
		$this->regions["LoginForm"] = '';					// On login form
		$this->regions["AfterLoginForm"] = '';				// Before login form end
		$this->regions["AfterLoginFormEnd"] = '';			// After login form end

		$this->regions["BeforeReigsterFormStart"] = '';	// Before register form start
		$this->regions["BeforeReigsterForm"] = '';			// After register form start
		$this->regions["RegisterForm"] = '';				// On register form
		$this->regions["AfterRegisterForm"] = '';			// Before register form end
		$this->regions["AfterRegisterFormEnd"] = '';		// After register form end

		$this->regions["BeforeSearchStart"] = '';			// Before search form start
		$this->regions["BeforeSearch"] = '';				// After search form start
		$this->regions["Search"] = '';						// On search form
		$this->regions["AfterSearch"] = '';				// Before search form end
		$this->regions["AfterSearchEnd"] = '';				// After search form end

		/**
		* Individual form fields
		*/
		$this->regions["SearchFieldStart"] = '';			// Before search input field start
		$this->regions["SearchFieldEnd"] = '';				// After search input field end

		$this->regions["UsernameFieldStart"] = '';			// Before login username input field start
		$this->regions["UsernameFieldEnd"] = '';			// After login username input field end

		$this->regions["PasswordFieldStart"] = '';			// Before login password input field start
		$this->regions["PasswordFieldEnd"] = '';			// After login password input field end

		$this->regions["TopicTitleFieldStart"] = '';		// Before topic title input field start
		$this->regions["TopicTitleFieldEnd"] = '';			// After topic title input field end

		$this->regions["TopicContentFieldStart"] = '';		// Before topic content textarea field start
		$this->regions["TopicContentFieldEnd"] = '';		// After topic content textarea field end

		$this->regions["TopicForumFieldStart"] = '';		// Before topic forum select field start
		$this->regions["TopicForumFieldEnd"] = '';			// After topic forum select field end

		$this->regions["ReplyContentFieldStart"] = '';		// Before reply content textarea start
		$this->regions["ReplyContentFieldEnd"] = '';		// After reply content textarea end

		/**
		* These fields will only be present if the user is anonymous.
		* Registered users will have the username called from their login information.
		*/
		$this->regions["TopicNameFieldStart"] = '';		// Before topic author name input field start
		$this->regions["TopicNameFieldEnd"] = '';			// After topic author name input field end

		$this->regions["TopicEmailFieldStart"] = '';		// Before topic author email input field start
		$this->regions["TopicEmailFieldEnd"] = '';			// After topic author email input field end

		$this->regions["ReplyNameFieldStart"] = '';		// Before reply author name input field start
		$this->regions["ReplyNameFieldEnd"] = '';			// After reply author name input field end

		$this->regions["ReplyNameFieldStart"] = '';		// Before reply author email input field start
		$this->regions["ReplyNameFieldEnd"] = '';			// After reply author email input field end

		/**
		* Navigation regions and items
		*/
		$this->regions["BeforeBreadcrumbStart"] = '';		// Before breadcrumb links start
		$this->regions["BeforeBreadcrumb"] = '';			// After breadcrumb links start
		$this->regions["Breadcrumb"] = '';					// On breadcrumb
		$this->regions["AfterBreadcrumb"] = '';			// Before breadcrumb end
		$this->regions["AfterBreadcrumbEnd"] = '';			// After breadcrumb end

		$this->regions["BeforeCrumbItemStart"] = '';		// Before breadcrumb link item start
		$this->regions["BeforeCrumbItem"] = '';			// After breadcrumb link item start
		$this->regions["CrumbItem"] = '';					// On breadcrumb item
		$this->regions["AfterCrumbItem"] = '';				// Before breadcrumb item end
		$this->regions["AfterCrumbItemEnd"] = '';			// After breadcrumb item end

		$this->regions["BeforeNavigationStart"] = '';		// Before navigation list start
		$this->regions["BeforeNavigation"] = '';			// After navigation list start
		$this->regions["Navigation"] = '';					// On navigation list as list item
		$this->regions["AfterNavigation"] = '';			// After last navigation list item
		$this->regions["AfterNavigationEnd"] = '';			// After navigation list end

		$this->regions["BeforeNavItemStart"] = '';			// Before navigation item start
		$this->regions["BeforeNavItem"] = '';				// After navigation item start
		$this->regions["NavItem"] = '';					// On navigation list item
		$this->regions["AfterNavItem"] = '';				// Before navigation list item end
		$this->regions["AfterNavItemEnd"] = '';			// After navigation list item end

		/**
		* Ancillary regions
		* Sidebar, footer etc...
		*/
		$this->regions["BeforeSidebarStart"] = '';			// Before sidebar start
		$this->regions["BeforeSidebar"] = '';				// After sidebar start
		$this->regions["Sidebar"] = '';					// On sidebar
		$this->regions["AfterSidebar"] = '';				// Before sidebar end
		$this->regions["AfterSidebarEnd"] = '';			// After sidebar end

		$this->regions["BeforeSideWidgetStart"] = '';		// Before sidebar widget item start
		$this->regions["BeforeSideWidget"] = '';			// After sidebar widget item start
		$this->regions["SideWidget"] = '';					// On sidebar widget
		$this->regions["AfterSideWidget"] = '';			// Before sidebar widget end
		$this->regions["AfterSideWidgetEnd"] = '';			// After sidebar widget end

		$this->regions["BeforeSideItemStart"] = '';		// Before sidebar widget item start (module specific)
		$this->regions["BeforeSideItem"] = '';				// After sidebar widget item start
		$this->regions["SideItem"] = '';					// On sidebar widget item
		$this->regions["AfterSideItem"] = '';				// Before sidebar widget item end
		$this->regions["AfterSideItemEnd"] = '';			// After sidebar widget item end

		$this->regions["BeforeFooterStart"] = '';			// Before footer start
		$this->regions["BeforeFooter"] = '';				// After footer start
		$this->regions["Footer"] = '';						// On footer
		$this->regions["AfterFooter"] = '';				// Before footer end
		$this->regions["AfterFooterEnd"] = '';				// After footer end
	}
}

The Module base class (all modules must inherit this) :

/**
* Module class.
* Sets the default module functionality. All modules must inherit this class to be usable.
*
* @author Jayanath Rodrigo
* @version 0.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
* @access public
*/

class Module
{
	protected $props;			// Stored properties passed by main class
	protected $database;		// Database object

	/**
	* Module constructor. Sets the database and presets.
	*
	* @param array $p Properties passed by Modules class (which in turn gets it from global configurations)
	* @param object $db Database object
	*/
	protected function __construct(&amp;$p, &amp;$db)
	{
		$this->props = $p;
		$this->database = $db;
	}

	/**
	* Set properties
	*
	* @param string $name Property name to modify
	* @param mixed $value New property value
	*/
	protected function __set($name, $value)
	{
		// No "isset" check as new values may be shared between modules.
		$this->props[$name] = $value;
	}

	/**
	* Get properties
	*
	* @param string $name Property name to get
	* @return mixed $props[$name] Property value, if it exists.
	*/
	protected function __get($name)
	{
		if(isset($this->props[$name]))
			return $this->props[$name];

		return null;
	}

	/**
	* Helper function to check if a property value exists.
	*
	* @param string $name Property name to check
	* @return bool true If the property exists or returns false.
	*/
	protected function __isset($name)
	{
		return isset($this->props[$name]);
	}

	/**
	* Helper function to delete a property value.
	*
	* @param string $name Property value to delete.
	*/
	protected function __unset($name)
	{
		if(isset($this->props[$name]))
			unset($this->props[$name]);
	}

	/**
	* Helper function to include custom JavaScript or CSS files.
	*
	* @param string $file Path to include (depends on preset globals passed to modules)
	* @param string $type File type. "js" For JavaScript or "css" for stylesheets.
	* @return string $path Formated <script> or <link> tags for JS or CSS extras.
	*/
	protected function libInject($file, $type)
	{
		$path = '';
		switch(strtolower($type))
		{
			case "js":
				$path = '<script type="text/javascript" src="'. $file .'"></script>';
				break;
			case "css":
				$path = '<link rel="stylesheet" href="'. $file .'" />';
				break;
		}

		return $path;
	}
}

An example module. In this case a WYSIWYG control based on Paul James’ simple but elegant script.

Note: The modules are placed within the /modules folder of your root directory. In my case, the root path is a preset global. You should use your own system for this.

/**
* WYSIWYG (What You See Is What You Get) editor plugin.
* Uses JavaScript by Paul James (licensed under BSD). Inherits "Module".
*
* @author Jayanath Rodrigo.
* @version 0.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
* @link http://www.peej.co.uk/sandbox/wysiwyg/ Paul James
* @access public
*/

final class Wysiwyg extends Module
{
	/**
	* Module constructor. Sets the database and presets.
	* This particular example doesn't use the database object.
	*
	* @param array $p Properties passed by Modules class (which in turn gets it from global configurations)
	* @param object $db Database object
	*/
	public function __construct(&amp;$p, &amp;$db)
	{
		parent::__construct($p, $db);
	}

	/**
	* Set properties
	*
	* @param string $name Property name to modify
	* @param mixed $value New property value
	*/
	public function __set($name, $value)
	{
		if(isset($name) &amp;&amp; isset($value))
			parent::__set($name, $value);
	}

	/**
	* Get properties
	*
	* @param string $name Property name to get
	* @return mixed $props[$name] Property value, if it exists.
	*/
	public function __get($name)
	{
		return parent::__get($name);
	}

	/**
	* Helper function to check if a property value exists.
	*
	* @param string $name Property name to check
	* @return bool true If the property exists or returns false.
	*/
	public function __isset($name)
	{
		return parent::__isset($name);
	}

	/**
	* Helper function to delete a property value.
	*
	* @param string $name Property value to delete.
	*/
	public function __unset($name)
	{
		parent::__unset($name);
	}

	/**
	* onHead event (see Modules class for a complete list of events).
	* Injects the css class and JavaScrpt file for WYSIWYG
	*
	* @param mixed $args This depends on where the event is called.
	* @return string $html Rendered output to be placed within regions.
	*/
	public function onHead(&amp;$args)
	{
		// Load CSS
		$html = parent::libInject($this->props["site_path"] . "modules/wysiwyg/wysiwyg.css", "css") . "\n";

		// Load JavaScript
		$html .=  "\n". parent::libInject($this->props["site_path"] . "modules/wysiwyg/wysiwyg.js", "js") . "\n";
		return $html;
	}
}

This is an example of how to use this script. I initiated the modules (Note, only the Wysiwyg module is being loaded in this example) :

$modules = Modules::getInstance($presets, $database, array("Wysiwyg"));

And use this helper function to both trigger an event within the modules and get it’s rendered output

function triggerRender($method)
{
	global $modules;
	$modules->__trigger($method, array($forums_list, $topics_list, $replies_list));
	return $modules->__render($method);
}

In my forum script, I placed regular code files within a /lib folder. But I placed all modules within their own folders inside a /modules folder.

I.E. The WYSIWYG would be installed as follows :

/modules/wysiwyg

All modules must contain a “module.php” file which is the primary class file for that module.

To load everything during runtime, I used the autoload functionality. Note: All directory names and module file names are lowercase. Only the class names (in the /lib folder) uses mixed case.

function __autoload($class)
{
	global $presets;

	// Try and get a class file
	$cfile = $presets['site_root'] . 'lib/' . $class . '.class.php';

	// Or module file
	$mfile = $presets['site_root'] . 'modules/' . strtolower($class) . '/module.php';

	if(file_exists($cfile))
		require_once($cfile);
	elseif(file_exists($mfile))
		require_once($mfile);
	else
		exit("Unable to Find $class in the library folder or plugin modules folder");

	if(!class_exists($class, false))
		exit("Unable to load $class class");
}

All modules are called within the templates. A specific region, E.G. “Head” should trigger the “onHead” method within all modules which have this event.

This is an example of a template file (very similar to what I’ve written for the forum templates) :

// Begin the HTML header
// Note: $tpl is the output variable to store all the HTML. I figured this would be easier to manage.
$tpl =< <<HTML_HEADER
<?xml version="1.0" encoding="UTF-8" ?>
< !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title>{$presets['site_title']}</title>
	<link rel="stylesheet" href="{$presets['site_template_url']}style.css" />
	<link rel="stylesheet" href="{$presets['site_template_url']}colors.css" />
HTML_HEADER; // End first part of the header

// Trigger and get the output for the "Head" region from the modules
$tpl .= triggerRender("Head");

// Finish off the header
$tpl .=< <<HTML_HEADER
</head>
<body dir="ltr">
HTML_HEADER;

Update

In retrospect, the above example of a template is really ugly.

The following is a far more elegant method of calling functions within heredocs…

// Create function method for rending regions
$render = create_function('$region', 'return triggerRender($region);');

// Begin template header
$tpl =< <<HTML_HEADER
<?xml version="1.0" encoding="UTF-8" ?>
< !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title>{$presets['site_title']}</title>
	<link rel="stylesheet" href="{$presets['site_template_url']}style.css" />
	<link rel="stylesheet" href="{$presets['site_template_url']}colors.css" />
	{$render("Head")}
</head>
<body dir="ltr">
	{$render("BeforeBody")}