Location: PHPKode > scripts > NBBS Wizard > nbbs-wizard/wizard.php
<?
/*
NBBS Wizard - Wizard Component & Installation Wizard
Extracted from: The Next BBS - Forums Software
Copyright (C) 2005 Chris F. Ravenscroft

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

Questions? We can be reached at http://forums.sf.net
*/

class Wizard
{
var	$wizard,
	$pages,
	$page,
	$pagename,
	$pageFields,
	$mainPage,
	$cancelCaption,
	$cancelPage,
	$nextCaption,
	$nextPage,
	$prevCaption,
	$prevPage,
	$submitCaption,
	$submitPage,
	$title,
	$width,
	$height,
	$defaults,
	$DB,
	$bProgress,
	$mode,
	$out;

	/**
	 * Constructor.
	 * @param pagename the wizard card's name - null if this is the main wizard card itself and not a subclass
	 */
	function Wizard($pagename=null)
	{
		/** This is the prefix that this class will look for to maintain variables persistency */
		if(!defined('PREFIX'))		define('PREFIX', 'wiz_');
		/** In this mode, the wizard component will be displayed by this class */
		if(!defined('MODE_RENDER'))	define('MODE_RENDER', 0x01);
		/** In this mode, this class will create the wizard component but not display it */
		if(!defined('MODE_BUFFER'))	define('MODE_BUFFER', 0x02);
		/** In this mode, headers and footers will not be displayed */
		if(!defined('MODE_EMBED'))	define('MODE_EMBED',  0x04);

		/** The wizard's pages, AKA 'cards' */
		$this->pages = array();
		$this->pagename = $pagename;
		$this->nextPage =
		$this->prevPage =
		$this->submitPage =
		$this->mainPage =
		$this->wizard =
			null;
		$this->cancelCaption = 'Cancel';
		$this->nextCaption = 'Next';
		$this->prevCaption = 'Prev';
		$this->submitCaption = 'OK';
		$this->cancelPage = true;
		$this->width = 800;
		$this->height = 600;
		$this->title = 'Wizard';
		/** Default form fields values */
		$this->defaults = array();
		/** By default, we are not displaying a progress bar */
		$this->bProgress = false;
		$this->mode = MODE_RENDER;
		/** Output buffer */
		$this->out = '';

		$this->init();
	}

	// ---------------------------------------------------------------------------
	// ---------------------------------------------------------------------------
	// Main wizard class' methods - not for cards
	// ---------------------------------------------------------------------------
	// ---------------------------------------------------------------------------

	/* Display an error message and die
	 * @param e String: an error message
	 * @param g String: where could we go back to?
	 */
	function throwError($e, $g=null)
	{
		?>
		<div align='center'>
		<font color='red'><b>
		<?=$e;?>
		</b></font>
		<?
		if($g!=null)
		{
		?>
			<br /><br />
			<form method='post' action='install.php'>
			<input type='hidden' name='do' value='<?=$g?>'>
			<input type='submit' name='submit' value='Back to <?=$g?>'>
			</form>
			</div>
		<?
		}
		exit;
	}

	/**
	 * Set the wizard mode - method of the main wizard class
	 * @param mode Can be MODE_EMBED (no header/footer), MODE_RENDER (display) or MODE_BUFFER (return buffer)
	 */
	function setMode($mode)
	{
		$this->mode = $mode;
	}

	/**
	 * Set the wizard component's dimensions - method of the main wizard class
	 * @param width component's width, in pixels or %
	 * @param height component's height, in pixels or %
	 */
	function setDimensions($width, $height)
	{
		$this->width = $width;
		$this->height = $height;
	}

	/**
	 * Add a card to the main wizard's cards table
	 * @param key Card name
	 * @param page The card class itself
	 */
	function addPage($key, $page)
	{
		$page->_setWizard(&$this);
		$this->pages[$key] = &$page;
		if($this->mainPage == null)
		{
			$this->setMainPage($key);
		}
	}

	/**
	 * Set a custom main page, rather than the first one
	 * @param key Card name
	 */
	function setMainPage($key)
	{
		$this->mainPage = $key;
	}

	/**
	 * Display the wizard: always call last.
	 * @return Buffer's content
	 */
	function display()
	{
		$pName = &$this->pagename;

		// What button was clicked?
		if(isset($_REQUEST['cancel']))
		{
		}
		else if(isset($_REQUEST['prev']) && isset($_REQUEST['onprev']))
		{
			$pName = $_REQUEST['onprev'];
		}
		else if(isset($_REQUEST['next']) && isset($_REQUEST['onnext']))
		{
			$pName = $_REQUEST['onnext'];
		}
		else if (isset($_REQUEST['autosubmit']))
		{
			$pName = $_REQUEST['autosubmit'];
		}
		else if(isset($_REQUEST['oksubmit']))
		{
		}
		// Is there any kind of post-processing we should care about?
		if(isset($_REQUEST['pagename']))
		{
			if(isset($this->pages[$_REQUEST['pagename']]))
			{
				$pcard = $this->pages[$_REQUEST['pagename']];
				if(method_exists($pcard,'action'))
				{
					$pcard->action();
				}
			}
		}
		// Name of the page to display
		if(!isset($this->pages[$pName]))
		{
			// Use default page!
			$pName = &$this->mainPage;
			if(!isset($this->pages[$pName]))
			{
				$this->throwError("Page '".$pName."' does not exist!");
			}
		}
		$card = &$this->pages[$pName];

		$card->displayLayout($this->width, $this->height);
		$card->_displayPage();
		$card->_displayTitle();
		$card->_displayButtons();

		if(MODE_RENDER == ($this->mode & MODE_RENDER))
		{
			$card->_render();
		}

		// Nice when using MODE_BUFFER
		return $this->out;
	}

	/**
	 * Private: Helper, displays progress bar
	 */
	function _displayProgress($message='')
	{
		$this->page = <<<EOB
<script type="text/javascript" language="JavaScript">
aimg=new Image();
aimg.src="progressbar.gif";
</script>
<br /><br /><br /><br />
<table width="100%" border="0"><tr><td align="center">
<div id="progresstext"><b>{$message}</b></div>
<img src="progressbar.gif">
</td></tr></table>
EOB;
	}

	/**
	 * Private: display wizard header
	 * Note: cards can actually override this method if they wish, although this is not my original intent.
	 */
	function _displayHeader()
	{
		if(MODE_EMBED != ($this->mode & MODE_EMBED))
		{
			$this->out .= '<html>
<head>
<style type="text/css">
body {
background-color: #607588;
margin: 0px 0px 0px 0px;padding:0px;
background-repeat: repeat-x;
background-position: 0px 32px;
}
.tableborder {
border:1px solid #B7B7B7;
background-color:#ECECEC;
padding:0;
margin:0
}
.tableborder2 {
border:1px solid #B7B7B7;
background-color:#E9E9E9;
padding:0;
margin:0
}
</style>
</head>
<body>';
		}
	}

	/**
	 * Private: display wizard footer
	 * Note: cards can actually override this method if they wish, although this is not my original intent.
	 */
	function _displayFooter()
	{
		if(MODE_EMBED != ($this->mode & MODE_EMBED))
		{
			$this->out .= '
</body>
</html>';
		}
	}

	/**
	 * Private: display the wizard (for real!)
	 */
	function _render()
	{
		print $this->out;
	}

	// ---------------------------------------------------------------------------
	// ---------------------------------------------------------------------------
	// Wizard card's methods - handle default fields
	// ---------------------------------------------------------------------------
	// ---------------------------------------------------------------------------

	/**
	 * Set default values for given form fields
	 * @param blob An associative array of fields names and values
	 */
	function setDefaults($blob)
	{
		foreach($blob as $key => $value)
		{
			$this->setDefault($key, $value);
		}
	}

	/**
	 * Set a default value for a form field
	 * @param key Field name
	 * @param value Fiel's default value
	 */
	function setDefault($key, $value)
	{
		$this->defaults[$key] = $value;
	}

	/**
	 * Return a field's default value
	 * @param key Field name
	 * @return A default string value, of null if no default value was set
	 */
	function getDefault($key)
	{
		if(isset($this->defaults[$key]))
			return $this->defaults[$key];
		else
			return null;
	}

	// ---------------------------------------------------------------------------
	// ---------------------------------------------------------------------------
	// Wizard card's methods - handle all variables
	// ---------------------------------------------------------------------------
	// ---------------------------------------------------------------------------

	/**
	 * Return a variable's current value
	 * @param varname Variable name
	 * @return Variable's value of null
	 */
	function getVar($varname)
	{
		if(!isset($_REQUEST[$varname]))
			return null;

		return $_REQUEST[$varname];
	}

	/**
	 * Return an associate array of all correctly prefixed variables names and their respective values
	 * @return An associative array
	 */
	function getVars()
	{
		$ret = array();
		foreach($_REQUEST as $varname => $varvalue)
		{
			$p = strpos($varname, PREFIX);
			if($p!==false && $p==0)
			{
				$ret[$varname] = $varvalue;
			}
		}
		return $ret;
	}

	/**
	 * Set a user variable name. These variables are different because they are not set through form submission
	 * @param varname User variable name
	 * @param varvalue Variable's value
	 */
	function setUserVariable($varname, $varvalue)
	{
		$_REQUEST['wiz_uv_'.$varname] = $varvalue;
	}

	/**
	 * Return a user variable name
	 * @param varname User variable name
	 * @return The user variable's value, or null
	 */
	function getUserVariable($varname)
	{
		$actualname = 'wiz_uv_'.$varname;
		if(!isset($_REQUEST[$actualname]))
			return null;

		return $_REQUEST[$actualname];
	}

	/**
	 * Private: tells a card what its main wizard class is
	 */
	function _setWizard($wizard)
	{
		$this->wizard = &$wizard;
	}

	/**
	 * Display progress card
	 */
	function displayProgress()
	{
		$ne = $this->getVar('next');
		if($ne!=null)
		{
			if($this->wizard==null)
				$this->bProgress = true;
			else
				$this->wizard->displayProgress();
		}

	}

	/**
	 * Set the card's title
	 * @param title A title string
	 */
	function setTitle($title)
	{
		$this->title = $title;
	}

	// ---------------------------------------------------------------------------
	// ---------------------------------------------------------------------------
	// Wizard card's methods - override these at will
	// ---------------------------------------------------------------------------
	// ---------------------------------------------------------------------------

	/**
	 * Display the overall wizard + current card layout.
	 * Override this method if you wish to use your own layout
	 * @param width Component width, as set by the wizard
	 * @param height Component height, as set by the wizard
	 */
	function displayLayout($width=800, $height=600)
	{
		$this->_displayHeader();
		$this->out .= '
<table border="0" cellspacing="0" cellpadding="0" align="center" width="100%" height="100%" align="center" valign="center">
<tr><td align="center" valign="center">
<table border="0" cellspacing="0" cellpadding="0" align="center" width='.$width.' height='.$height.'>
<tr bgcolor="#D3D3D6"><td>
<table width="100%" height="100%" border="0" cellspacing="1" cellpadding="1">
<tr><td bgcolor="#F7F7F7" align=right height="1%">
<b><font color="#00A600" style="font-size: 13px;">
[*WIZARDTITLE*]
</font></b>&nbsp;&nbsp;&nbsp;
</td></tr>
<tr><td bgcolor="#FFFFFF" height=100% valign="top">
<table cellspacing="0" cellpadding="2" border="0" align=center width=100% height=100%>
<tr><td colspan = 2>
<table cellspacing="0" cellpadding="6" border="0" align=center width=100% height=100%>
<tr><td>
<table cellspacing="2" cellpadding="2" border="0" width=100% height=100%>
<tr>
<td bgcolor="#F3F3F3" width="100%" height="100%" valign="top">
[*WIZARDBODY*]
</td> </tr> </table>
</td> </tr> </table>
</td> </tr> </table>
</td> </tr> </table>
</td><tr><tr><td bgcolor="#F7F7F7" align=middle height="1%">
[*WIZARDBUTTONS*]
</td> </tr> </table>
</td> </tr> </table>';
		$this->_displayFooter();
	}

	/**
	 * This definitely is _the_ method you want to override. You card's content goes here.
	 */
	function setPage()
	{
		$this->page ='* Do not forget to override setPage() *';
	}

	/**
	 * You _must_ override this method. This is where you are preparing various components.
	 * Note that the default implementation is meant to be invoked by the main wizard class ONLY.
	 */
	function init()
	{
		$splash = new Splash('splash');
		$this->addPage('splash', &$splash);
	}

	/** This method is called after clicking a navigation button
	 * ONLY create it if you need some post-processing to happen
	function action()
	{
	}
	*/

	// ---------------------------------------------------------------------------
	// ---------------------------------------------------------------------------
	// Wizard card's methods - buttons panel management
	// ---------------------------------------------------------------------------
	// ---------------------------------------------------------------------------

	/**
	 * Set caption of 'Cancel' button
	 * @param caption Button caption
	 */
	function setCancelCaption($caption)
	{
		$this->cancelCaption = $caption;
	}

	/**
	 * Set page to go to when the 'Cancel' button is clicked
	 * @param page Card's name
	 */
	function setCancel($page)
	{
		$this->cancelPage = $page;
	}

	/**
	 * Set caption of 'Next' button
	 * @param caption Button caption
	 */
	function setNextCaption($caption)
	{
		$this->nextCaption = $caption;
	}

	/**
	 * Set page to go to when the 'Next' button is clicked
	 * @param page Card's name
	 */
	function setNext($page)
	{
		$this->nextPage = $page;
	}

	/**
	 * Set caption of 'Prev' button
	 * @param caption Button caption
	 */
	function setPrevCaption($caption)
	{
		$this->prevCaption = $caption;
	}

	/**
	 * Set page to go to when the 'Prev' button is clicked
	 * @param page Card's name
	 */
	function setPrev($page)
	{
		$this->prevPage = $page;
	}

	/**
	 * Set caption of 'Submit' button
	 * @param caption Button caption
	 */
	function setSubmitCaption($caption)
	{
		$this->submitCaption = $caption;
	}

	/**
	 * Set page to go to when the 'Submit' button is clicked
	 * @param page Card's name
	 */
	function setSubmit($page)
	{
		$this->submitPage = $page;
	}

	// ---------------------------------------------------------------------------
	// ---------------------------------------------------------------------------
	// Wizard card's methods - card designer helper class
	// ---------------------------------------------------------------------------
	// ---------------------------------------------------------------------------

	/**
	 * Return a paragraph framed in a block
	 * @param blockBody Paragraph to frame
	 * @return Framed paragraph
	 */
	function getBlockCode($blockBody)
	{
		return <<<EOB
<div align="center">
<table border="0" cellpadding="8" cellspacing="0" width="95%" class="tableborder">
<tr><td>
{$blockBody}
</td></tr></table>
<br />
</div>

EOB;
	}

	// ---------------------------------------------------------------------------
	// ---------------------------------------------------------------------------
	// Wizard card's methods - internal helper classes
	// ---------------------------------------------------------------------------
	// ---------------------------------------------------------------------------

	/**
	 * Private: Prepare component code.
	 */
	function _displayPage()
	{
		$p = $this->wizard==null ? $this->bProgress : $this->wizard->bProgress;
		if(!$p)
		{
			$this->setPage();
		}
		else
		{
			$this->setNext($this->wizard->pagename);
			$this->_displayProgress("Click on [Next] to proceed");
		}

		$this->out = str_replace('[*WIZARDBODY*]',
			"<form method=\"post\" action=\"{$_SERVER['PHP_SELF']}\" name=\"WIZARDFORM\">[*HF*]" .
			$this->page,
			$this->out);
		// Various input fields...
		// 1-current page name
		$hf = '<input type="hidden" name="pagename" value="'.$this->pagename.'">';
		// Get POST vars
		$vars = &$this->getVars();
		preg_match_all('[\*(wiz_.+?)\*]', $this->out, $usedstruct);
		$used = &$usedstruct[1];
		// 2-check for all variables
		// Look for composed variables
		$repfrom = array();
		$repto = array();
		$displayed = array();
		foreach($used as $tupple)
		{
			$u = explode('.', $tupple);
			// Do we know this variable?
			if(isset($vars[$u[0]]))
			{
				if(count($u)<2)
				{
					$repfrom[] = '[*'.$tupple.'*]';
					$repto[] = $vars[$u[0]];
				}
				else
				{
					$repfrom[] = '[*'.$tupple.'*]';
					if($tupple == $u[0].'.'.$vars[$u[0]])
					{
						$repto[] = 'checked selected';
					}
					else
					{
						$repto[] = '';
					}
				}
				$displayed[$u[0]] = true;
			}
			else
			{
				if(count($u)<2)
				{
					$repfrom[] = '[*'.$tupple.'*]';
					$def = &$this->getDefault($tupple);
					$repto[] = $def==null?'':$def;
				}
				else
				{
				}
			}
		}
		$this->out = str_replace($repfrom, $repto, $this->out);
		// 3-store various variables
		foreach($vars as $key => $value)
		{
			if(isset($displayed[$key]))
				continue;
			// Not displayed yet...just hide it
			$hf .= '<input type="hidden" name="'.$key.'" value="'.$value.'">';
		}
		// Done
		$this->out = str_replace('[*HF*]', $hf, $this->out);
	}

	/**
	 * Private: 'display' card title
	 */
	function _displayTitle()
	{
		$this->out = str_replace('[*WIZARDTITLE*]', $this->title, $this->out);
	}

	/**
	 * Private: 'display' buttons panel
	 */
	function _displayButtons()
	{
		$b_out = '
<script type="text/javascript" language="JavaScript">
document.onkeypress = enterHandler;
function enterHandler(ev)
{
	if(!ev)
		ev = window.event;
	k = ev.keyCode;
	if (k==13)
	{
		if(!document.WIZARDFORM.next.disabled)
			document.WIZARDFORM.next.click();
		else if(!document.WIZARDFORM.prev.disabled)
			document.WIZARDFORM.prev.click();
	}
} 
</script>
<table border="0" cellpadding="0" cellspacing="0"><tr>';

		$sAdd = $this->cancelPage==null ? ' disabled' : '';
		$b_out .= '<td><input type="submit" name="cancel" tabindex="2" value="'.$this->cancelCaption.'"'.$sAdd.'>&nbsp;</td>';

		$sAdd = $this->prevPage==null ? ' disabled' : '';
		$b_out .= '<td><input type="hidden" name="onprev" value="'.$this->prevPage.'"><input type="submit" name="prev" tabindex="1" value="'.$this->prevCaption.'"'.$sAdd.'>&nbsp;</td>';

		$sAdd = $this->nextPage==null ? ' disabled' : '';
		$b_out .= '<td><input type="hidden" name="onnext" tabindex="0" value="'.$this->nextPage.'"><input type="submit" name="next" value="'.$this->nextCaption.'"'.$sAdd.'>&nbsp;</td>';
		if($this->wizard->bProgress)
		{
			$b_out .= '<input type="hidden" name="autosubmit" value="'.$this->wizard->pagename.'">';
		}

		$b_out .= '</form><td>';

		if($this->submitPage==null)
		{
			$b_out .= '<input type="submit" name="oksubmit" tabindex="3" value="'.$this->submitCaption.'" disabled>';
		}
		else
		{
			$b_out .= <<<EOB
<form method="post" action="{$this->submitPage}" name="EXITFORM">
<input type="submit" name="oksubmit" value="{$this->submitCaption}">
</form>
EOB;
		}

		$b_out .= '</td></tr></table>';

		if($this->wizard->bProgress)
		{
			$b_out .= <<<EOB

<script type="text/javascript" language="JavaScript">
document.WIZARDFORM.next.disabled=true;
document.getElementById("progresstext").innerHTML="<b>Please Wait</b>";
setTimeout("document.WIZARDFORM.submit()", 1000);
</script>

EOB;
		}

		$this->out = str_replace('[*WIZARDBUTTONS*]', $b_out, $this->out);
	}

	// ---------------------------------------------------------------------------
	// ---------------------------------------------------------------------------
	// Installation Wizard - coder helper methods - use 'em!
	// ---------------------------------------------------------------------------
	// ---------------------------------------------------------------------------

	/**
	 * Return a password
	 * @return a password, 6 characters.
	 */
	function getNewPassword()
	{
		return substr(md5(time()),0,6);
	}

	/**
	 * Low level: open database and return a handle
	 * @param dblayer Abstraction layer: ado or pear
	 * @param dbengine MySQL or other...
	 * @param dbhost DB Server hostname
	 * @param dbname Database name
	 * @param dbuser Database user name
	 * @param dbpassword Database user password
	 * @return Database handler
	 */
	function opendb($dblayer, $dbengine, $dbhost, $dbname, $dbuser, $dbpassword)
	{
		require "dbdriver.php";
		$this->DB = factoryGetDriver($dblayer);
		$this->DB->report_next_error();
		return $this->DB->connect($dbengine, $dbhost, $dbname, $dbuser, $dbpassword);
	}

	/**
	 * Low level: perform a database query
	 * @param qry Query text
	 * @return A resultset
	 */
	function dbquery($qry)
	{
		$this->DB->report_next_error();
		$res = $this->DB->query($qry);
		return $res;
	}

	/**
	 * Low level: close database connections
	 */
	function dbcleanup()
	{
		$this->DB->cleanup();
	}

	/**
	 * High level: check a database user's privileges
	 * @param dblayer Abstraction layer: ado or pear
	 * @param dbengine MySQL or other...
	 * @param dbhost DB Server hostname
	 * @param dbname Database name
	 * @param dbuser Database user name
	 * @param dbpassword Database user password
	 * @return An associative array of privileges=>booleans
	 */
	function checkdb($dblayer, $dbengine, $dbhost, $dbname, $dbuser, $dbpassword)
	{
		$diags = array(
			'Connect' => false,
			'Create' => false,
			'Insert' => false,
			'Update' => false,
			'Select' => false,
			'Delete' => false,
			'Drop' => false);

		if(null==$this->opendb($dblayer, $dbengine, $dbhost, $dbname, $dbuser, $dbpassword))
		{
			return $diags;
		}
		$diags['Connect'] = true;
		$qry = "CREATE TABLE nwiztestdropme(afield integer(10))";
		if(null==$this->dbquery($qry))
		{
			return $diags;
		}
		$diags['Create'] = true;
		$qry = "INSERT INTO nwiztestdropme(afield) VALUES('1')";
		if(null==$this->dbquery($qry))
		{
			return $diags;
		}
		$diags['Insert'] = true;
		$qry = "UPDATE nwiztestdropme SET afield='2'";
		if(null==$this->dbquery($qry))
		{
			return $diags;
		}
		$diags['Update'] = true;
		$qry = "SELECT * FROM nwiztestdropme";
		if(null==$this->dbquery($qry))
		{
			return $diags;
		}
		$diags['Select'] = true;
		$qry = "DELETE FROM nwiztestdropme";
		if(null==$this->dbquery($qry))
		{
			return $diags;
		}
		$diags['Delete'] = true;
		$qry = "DROP TABLE nwiztestdropme";
		if(null==$this->dbquery($qry))
		{
			return $diags;
		}
		$diags['Drop'] = true;
		return $diags;
	}

	/**
	 * High level: Import an SQL file
	 * @param dblayer Abstraction layer: ado or pear
	 * @param dbengine MySQL or other...
	 * @param dbhost DB Server hostname
	 * @param dbname Database name
	 * @param dbuser Database user name
	 * @param dbpassword Database user password
	 * @param filename Name of the file to import
	 * @param oldprefix Tables prefix to be replaced in the import file
	 * @param dbprefix Prefix to replace the old prefix with
	 * @param substitutions An associative array of values to dynamically replace while importing the file
	 * @return String: 'OK' upon success, another string otherwise.
	 */
	function importdb($dblayer, $dbengine, $dbhost, $dbname, $dbuser, $dbpassword, $filename, $oldprefix, $dbprefix, $substitutions)
	{
		if(null==$this->opendb($dblayer, $dbengine, $dbhost, $dbname, $dbuser, $dbpassword))
		{
			return "Sorry, unable to open database";
		}
		$fromvals = $tovals = array();
		foreach($substitutions as $fromval => $toval)
		{
			$fromvals[] = $fromval;
			$tovals[] = $toval;
		}
		$queries = array();
		$f=fopen($filename, "r");
		$qry = '';
		while (!feof($f))
		{
			$sql = fgets($f, 65535);
			$l = strlen($sql);
			while(ord($sql[$l-1])<32 && $l>1)
				$l--;
			$sql = substr($sql, 0, $l);
			if(strlen($sql)<2 || $sql[0]=='-')
				continue;
			$qry .= $sql;
			if($sql[$l-1]==';')
			{
				$qry = str_replace($oldprefix, $dbprefix, $qry);
				$qry = str_replace($fromvals, $tovals, $qry);
				$queries[] = $qry;
				$qry = '';
			}
		}
		fclose($f);
		for($i=0;$i<count($queries);$i++)
		{
			if(null == $this->dbquery($queries[$i]))
			{
				return "Sorry, unable to run query:<br />".$queries[$i];
			}
		}

		return 'OK';
	}

	/**
	 * Create a directory. Will recursively create all directories required.
	 * @param dirname Directory full path
	 * @return false upon failure; true otherwise.
	 */
	function mkdir($dirname)
	{
		if(@is_dir($dirname) || @empty($dirname))
		{
			return true;
		}

		$subdirname = substr($dirname, 0, strrpos($dirname, DIRECTORY_SEPARATOR));
		if($this->mkdir($subdirname))
		{
			if(!@file_exists($dirname))
			{
				return @mkdir($dirname);
			}
		}
	}

	/**
	 * Remove a directory.
	 * @param dirname Directory full path
	 * @return false upon failure; true otherwise.
	 */
	function rmdir($dirname)
	{
		return @rmdir($dirname);
	}

	/**
	 * Change a file's access mode
	 * @param filename File name
	 * @return false upon failure; true otherwise.
	 */
	function chmod($filename, $mode)
	{
		return @chmod($filename, $mode);
	}

	/**
	 * Suck in the content of a file
	 * @param file String: name of the file to read
	 * @return String the file content, or false.
	 */
	function readFile($filename)
	{
		$f = @fopen($filename, "r");
		if(!$f)
		{
			return false;
		}
		$contents = fread($f, filesize($filename));
		fclose($f);
		return $contents;
	}

	/**
	 * Write a file to disk
	 * @param filename String: name of the file to write
	 * @param contents String: the new file contents
	 * @return false upon failure; true otherwise.
	 */
	function writeFile($filename, $contents)
	{
		$f = @fopen($filename, "w");
		if(!$f)
		{
			return false;
		}
		if(!fwrite($f, $contents))
		{
			fclose($f);
			return false;
		}
		fclose($f);
		return true;
	}

	/**
	 * Delete a file
	 * @param filename String: name of the file to delete
	 * @return false upon failure; true otherwise.
	 */
	function deletefile($filename)
	{
		return @unlink($filename);
	}
}

/**
 * Default wizard main page - splash screen, credits.
 */
class Splash extends Wizard 
{
        function init() 
        {       
                $this->setNext('selector'); // Self by default: will be changed dynamically down the road...
                $this->setTitle('NBBS Wizard v1.0');
        }

	/**
	 * Of course, you can change this method's content; however if would be greatly appreciated if you left
	 * some sort of notice, crediting the author.
	 */
        function setPage()
	{
		$this->page = <<<EOB
<div align="right" style="font-size: 9pt;">The <a href="http://bb.militate.com">NBBS</a> Install Wizard - &copy; Chris F Ravenscroft 2005<br />
	<div style="font-size: 7pt; font-style: italic;">please do not remove this notice</div>
</div>
<div align="center">
<br />
<br />
<br />
<br />
<br />
<br />
<img src="nextbbs.jpg">;
</div>
EOB;
	}
}
?>
Return current item: NBBS Wizard