Propset eol-style to CRLF

simplified paragraph tag cleanup regex
diff --git a/system/libraries/Email.php b/system/libraries/Email.php
index ac96882..e414d84 100644
--- a/system/libraries/Email.php
+++ b/system/libraries/Email.php
@@ -1,1955 +1,1955 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
-/**
- * CodeIgniter
- *
- * An open source application development framework for PHP 4.3.2 or newer
- *
- * @package		CodeIgniter
- * @author		ExpressionEngine Dev Team
- * @copyright	Copyright (c) 2008, EllisLab, Inc.
- * @license		http://codeigniter.com/user_guide/license.html
- * @link		http://codeigniter.com
- * @since		Version 1.0
- * @filesource
- */
-
-// ------------------------------------------------------------------------
-
-/**
- * CodeIgniter Email Class
- *
- * Permits email to be sent using Mail, Sendmail, or SMTP.
- *
- * @package		CodeIgniter
- * @subpackage	Libraries
- * @category	Libraries
- * @author		ExpressionEngine Dev Team
- * @link		http://codeigniter.com/user_guide/libraries/email.html
- */
-class CI_Email {
-
-	var	$useragent		= "CodeIgniter";
-	var	$mailpath		= "/usr/sbin/sendmail";	// Sendmail path
-	var	$protocol		= "mail";	// mail/sendmail/smtp
-	var	$smtp_host		= "";		// SMTP Server.  Example: mail.earthlink.net
-	var	$smtp_user		= "";		// SMTP Username
-	var	$smtp_pass		= "";		// SMTP Password
-	var	$smtp_port		= "25";		// SMTP Port
-	var	$smtp_timeout	= 5;		// SMTP Timeout in seconds
-	var	$wordwrap		= TRUE;		// TRUE/FALSE  Turns word-wrap on/off
-	var	$wrapchars		= "76";		// Number of characters to wrap at.
-	var	$mailtype		= "text";	// text/html  Defines email formatting
-	var	$charset		= "utf-8";	// Default char set: iso-8859-1 or us-ascii
-	var	$multipart		= "mixed";	// "mixed" (in the body) or "related" (separate)
-	var $alt_message	= '';		// Alternative message for HTML emails
-	var	$validate		= FALSE;	// TRUE/FALSE.  Enables email validation
-	var	$priority		= "3";		// Default priority (1 - 5)
-	var	$newline		= "\n";		// Default newline. "\r\n" or "\n" (Use "\r\n" to comply with RFC 822)
-	var $crlf			= "\n";		// The RFC 2045 compliant CRLF for quoted-printable is "\r\n".  Apparently some servers,
-									// even on the receiving end think they need to muck with CRLFs, so using "\n", while
-									// distasteful, is the only thing that seems to work for all environments.
-	var $send_multipart	= TRUE;		// TRUE/FALSE - Yahoo does not like multipart alternative, so this is an override.  Set to FALSE for Yahoo.
-	var	$bcc_batch_mode	= FALSE;	// TRUE/FALSE  Turns on/off Bcc batch feature
-	var	$bcc_batch_size	= 200;		// If bcc_batch_mode = TRUE, sets max number of Bccs in each batch
-	var $_safe_mode		= FALSE;
-	var	$_subject		= "";
-	var	$_body			= "";
-	var	$_finalbody		= "";
-	var	$_alt_boundary	= "";
-	var	$_atc_boundary	= "";
-	var	$_header_str	= "";
-	var	$_smtp_connect	= "";
-	var	$_encoding		= "8bit";
-	var $_IP			= FALSE;
-	var	$_smtp_auth		= FALSE;
-	var $_replyto_flag	= FALSE;
-	var	$_debug_msg		= array();
-	var	$_recipients	= array();
-	var	$_cc_array		= array();
-	var	$_bcc_array		= array();
-	var	$_headers		= array();
-	var	$_attach_name	= array();
-	var	$_attach_type	= array();
-	var	$_attach_disp	= array();
-	var	$_protocols		= array('mail', 'sendmail', 'smtp');
-	var	$_base_charsets	= array('us-ascii', 'iso-2022-');	// 7-bit charsets (excluding language suffix)
-	var	$_bit_depths	= array('7bit', '8bit');
-	var	$_priorities	= array('1 (Highest)', '2 (High)', '3 (Normal)', '4 (Low)', '5 (Lowest)');
-
-
-	/**
-	 * Constructor - Sets Email Preferences
-	 *
-	 * The constructor can be passed an array of config values
-	 */
-	function CI_Email($config = array())
-	{
-		if (count($config) > 0)
-		{
-			$this->initialize($config);
-		}
-		else
-		{
-			$this->_smtp_auth = ($this->smtp_user == '' AND $this->smtp_pass == '') ? FALSE : TRUE;
-			$this->_safe_mode = ((boolean)@ini_get("safe_mode") === FALSE) ? FALSE : TRUE;
-		}
-
-		log_message('debug', "Email Class Initialized");
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Initialize preferences
-	 *
-	 * @access	public
-	 * @param	array
-	 * @return	void
-	 */
-	function initialize($config = array())
-	{
-		$this->clear();
-		foreach ($config as $key => $val)
-		{
-			if (isset($this->$key))
-			{
-				$method = 'set_'.$key;
-
-				if (method_exists($this, $method))
-				{
-					$this->$method($val);
-				}
-				else
-				{
-					$this->$key = $val;
-				}
-			}
-		}
-
-		$this->_smtp_auth = ($this->smtp_user == '' AND $this->smtp_pass == '') ? FALSE : TRUE;
-		$this->_safe_mode = ((boolean)@ini_get("safe_mode") === FALSE) ? FALSE : TRUE;
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Initialize the Email Data
-	 *
-	 * @access	public
-	 * @return	void
-	 */
-	function clear($clear_attachments = FALSE)
-	{
-		$this->_subject		= "";
-		$this->_body		= "";
-		$this->_finalbody	= "";
-		$this->_header_str	= "";
-		$this->_replyto_flag = FALSE;
-		$this->_recipients	= array();
-		$this->_headers		= array();
-		$this->_debug_msg	= array();
-
-		$this->_set_header('User-Agent', $this->useragent);
-		$this->_set_header('Date', $this->_set_date());
-
-		if ($clear_attachments !== FALSE)
-		{
-			$this->_attach_name = array();
-			$this->_attach_type = array();
-			$this->_attach_disp = array();
-		}
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Set FROM
-	 *
-	 * @access	public
-	 * @param	string
-	 * @param	string
-	 * @return	void
-	 */
-	function from($from, $name = '')
-	{
-		if (preg_match( '/\<(.*)\>/', $from, $match))
-		{
-			$from = $match['1'];
-		}
-
-		if ($this->validate)
-		{
-			$this->validate_email($this->_str_to_array($from));
-		}
-
-		if ($name != '' && strncmp($name, '"', 1) != 0)
-		{
-			$name = '"'.$name.'"';
-		}
-
-		$this->_set_header('From', $name.' <'.$from.'>');
-		$this->_set_header('Return-Path', '<'.$from.'>');
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Set Reply-to
-	 *
-	 * @access	public
-	 * @param	string
-	 * @param	string
-	 * @return	void
-	 */
-	function reply_to($replyto, $name = '')
-	{
-		if (preg_match( '/\<(.*)\>/', $replyto, $match))
-		{
-			$replyto = $match['1'];
-		}
-
-		if ($this->validate)
-		{
-			$this->validate_email($this->_str_to_array($replyto));
-		}
-
-		if ($name == '')
-		{
-			$name = $replyto;
-		}
-
-		if (strncmp($name, '"', 1) != 0)
-		{
-			$name = '"'.$name.'"';
-		}
-
-		$this->_set_header('Reply-To', $name.' <'.$replyto.'>');
-		$this->_replyto_flag = TRUE;
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Set Recipients
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	void
-	 */
-	function to($to)
-	{
-		$to = $this->_str_to_array($to);
-		$to = $this->clean_email($to);
-
-		if ($this->validate)
-		{
-			$this->validate_email($to);
-		}
-
-		if ($this->_get_protocol() != 'mail')
-		{
-			$this->_set_header('To', implode(", ", $to));
-		}
-
-		switch ($this->_get_protocol())
-		{
-			case 'smtp'		: $this->_recipients = $to;
-			break;
-			case 'sendmail'	: $this->_recipients = implode(", ", $to);
-			break;
-			case 'mail'		: $this->_recipients = implode(", ", $to);
-			break;
-		}
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Set CC
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	void
-	 */
-	function cc($cc)
-	{
-		$cc = $this->_str_to_array($cc);
-		$cc = $this->clean_email($cc);
-
-		if ($this->validate)
-		{
-			$this->validate_email($cc);
-		}
-
-		$this->_set_header('Cc', implode(", ", $cc));
-
-		if ($this->_get_protocol() == "smtp")
-		{
-			$this->_cc_array = $cc;
-		}
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Set BCC
-	 *
-	 * @access	public
-	 * @param	string
-	 * @param	string
-	 * @return	void
-	 */
-	function bcc($bcc, $limit = '')
-	{
-		if ($limit != '' && is_numeric($limit))
-		{
-			$this->bcc_batch_mode = TRUE;
-			$this->bcc_batch_size = $limit;
-		}
-
-		$bcc = $this->_str_to_array($bcc);
-		$bcc = $this->clean_email($bcc);
-
-		if ($this->validate)
-		{
-			$this->validate_email($bcc);
-		}
-
-		if (($this->_get_protocol() == "smtp") OR ($this->bcc_batch_mode && count($bcc) > $this->bcc_batch_size))
-		{
-			$this->_bcc_array = $bcc;
-		}
-		else
-		{
-			$this->_set_header('Bcc', implode(", ", $bcc));
-		}
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Set Email Subject
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	void
-	 */
-	function subject($subject)
-	{
-		if (strpos($subject, "\r") !== FALSE OR strpos($subject, "\n") !== FALSE)
-		{
-			$subject = str_replace(array("\r\n", "\r", "\n"), '', $subject);
-		}
-
-		if (strpos($subject, "\t"))
-		{
-			$subject = str_replace("\t", ' ', $subject);
-		}
-
-		$this->_set_header('Subject', trim($subject));
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Set Body
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	void
-	 */
-	function message($body)
-	{
-		$this->_body = stripslashes(rtrim(str_replace("\r", "", $body)));
-	}
- 
-	// --------------------------------------------------------------------
-
-	/**
-	 * Assign file attachments
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	void
-	 */
-	function attach($filename, $disposition = 'attachment')
-	{
-		$this->_attach_name[] = $filename;
-		$this->_attach_type[] = $this->_mime_types(next(explode('.', basename($filename))));
-		$this->_attach_disp[] = $disposition; // Can also be 'inline'  Not sure if it matters
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Add a Header Item
-	 *
-	 * @access	private
-	 * @param	string
-	 * @param	string
-	 * @return	void
-	 */
-	function _set_header($header, $value)
-	{
-		$this->_headers[$header] = $value;
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Convert a String to an Array
-	 *
-	 * @access	private
-	 * @param	string
-	 * @return	array
-	 */
-	function _str_to_array($email)
-	{
-		if ( ! is_array($email))
-		{
-			if (strpos($email, ',') !== FALSE)
-			{
-				$email = preg_split('/[\s,]/', $email, -1, PREG_SPLIT_NO_EMPTY);
-			}
-			else
-			{
-				$email = trim($email);
-				settype($email, "array");
-			}
-		}
-		return $email;
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Set Multipart Value
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	void
-	 */
-	function set_alt_message($str = '')
-	{
-		$this->alt_message = ($str == '') ? '' : $str;
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Set Mailtype
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	void
-	 */
-	function set_mailtype($type = 'text')
-	{
-		$this->mailtype = ($type == 'html') ? 'html' : 'text';
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Set Wordwrap
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	void
-	 */
-	function set_wordwrap($wordwrap = TRUE)
-	{
-		$this->wordwrap = ($wordwrap === FALSE) ? FALSE : TRUE;
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Set Protocol
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	void
-	 */
-	function set_protocol($protocol = 'mail')
-	{
-		$this->protocol = ( ! in_array($protocol, $this->_protocols, TRUE)) ? 'mail' : strtolower($protocol);
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Set Priority
-	 *
-	 * @access	public
-	 * @param	integer
-	 * @return	void
-	 */
-	function set_priority($n = 3)
-	{
-		if ( ! is_numeric($n))
-		{
-			$this->priority = 3;
-			return;
-		}
-
-		if ($n < 1 OR $n > 5)
-		{
-			$this->priority = 3;
-			return;
-		}
-
-		$this->priority = $n;
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Set Newline Character
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	void
-	 */
-	function set_newline($newline = "\n")
-	{
-		if ($newline != "\n" AND $newline != "\r\n" AND $newline != "\r")
-		{
-			$this->newline	= "\n";
-			return;
-		}
-
-		$this->newline	= $newline;
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Set CRLF
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	void
-	 */
-	function set_crlf($crlf = "\n")
-	{
-		if ($crlf != "\n" AND $crlf != "\r\n" AND $crlf != "\r")
-		{
-			$this->crlf	= "\n";
-			return;
-		}
-
-		$this->crlf	= $crlf;
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Set Message Boundary
-	 *
-	 * @access	private
-	 * @return	void
-	 */
-	function _set_boundaries()
-	{
-		$this->_alt_boundary = "B_ALT_".uniqid(''); // multipart/alternative
-		$this->_atc_boundary = "B_ATC_".uniqid(''); // attachment boundary
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Get the Message ID
-	 *
-	 * @access	private
-	 * @return	string
-	 */
-	function _get_message_id()
-	{
-		$from = $this->_headers['Return-Path'];
-		$from = str_replace(">", "", $from);
-		$from = str_replace("<", "", $from);
-
-		return  "<".uniqid('').strstr($from, '@').">";
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Get Mail Protocol
-	 *
-	 * @access	private
-	 * @param	bool
-	 * @return	string
-	 */
-	function _get_protocol($return = TRUE)
-	{
-		$this->protocol = strtolower($this->protocol);
-		$this->protocol = ( ! in_array($this->protocol, $this->_protocols, TRUE)) ? 'mail' : $this->protocol;
-
-		if ($return == TRUE)
-		{
-			return $this->protocol;
-		}
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Get Mail Encoding
-	 *
-	 * @access	private
-	 * @param	bool
-	 * @return	string
-	 */
-	function _get_encoding($return = TRUE)
-	{
-		$this->_encoding = ( ! in_array($this->_encoding, $this->_bit_depths)) ? '8bit' : $this->_encoding;
-
-		foreach ($this->_base_charsets as $charset)
-		{
-			if (strncmp($charset, $this->charset, strlen($charset)) == 0)
-			{
-				$this->_encoding = '7bit';
-			}
-		}
-
-		if ($return == TRUE)
-		{
-			return $this->_encoding;
-		}
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Get content type (text/html/attachment)
-	 *
-	 * @access	private
-	 * @return	string
-	 */
-	function _get_content_type()
-	{
-		if	($this->mailtype == 'html' &&  count($this->_attach_name) == 0)
-		{
-			return 'html';
-		}
-		elseif	($this->mailtype == 'html' &&  count($this->_attach_name)  > 0)
-		{
-			return 'html-attach';
-		}
-		elseif	($this->mailtype == 'text' &&  count($this->_attach_name)  > 0)
-		{
-			return 'plain-attach';
-		}
-		else
-		{
-			return 'plain';
-		}
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Set RFC 822 Date
-	 *
-	 * @access	private
-	 * @return	string
-	 */
-	function _set_date()
-	{
-		$timezone = date("Z");
-		$operator = (strncmp($timezone, '-', 1) == 0) ? '-' : '+';
-		$timezone = abs($timezone);
-		$timezone = floor($timezone/3600) * 100 + ($timezone % 3600 ) / 60;
-
-		return sprintf("%s %s%04d", date("D, j M Y H:i:s"), $operator, $timezone);
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Mime message
-	 *
-	 * @access	private
-	 * @return	string
-	 */
-	function _get_mime_message()
-	{
-		return "This is a multi-part message in MIME format.".$this->newline."Your email application may not support this format.";
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Validate Email Address
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	bool
-	 */
-	function validate_email($email)
-	{
-		if ( ! is_array($email))
-		{
-			$this->_set_error_message('email_must_be_array');
-			return FALSE;
-		}
-
-		foreach ($email as $val)
-		{
-			if ( ! $this->valid_email($val))
-			{
-				$this->_set_error_message('email_invalid_address', $val);
-				return FALSE;
-			}
-		}
-
-		return TRUE;
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Email Validation
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	bool
-	 */
-	function valid_email($address)
-	{
-		return ( ! preg_match("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix", $address)) ? FALSE : TRUE;
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Clean Extended Email Address: Joe Smith <joe@smith.com>
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	string
-	 */
-	function clean_email($email)
-	{
-		if ( ! is_array($email))
-		{
-			if (preg_match('/\<(.*)\>/', $email, $match))
-			{
-		   		return $match['1'];
-			}
-		   	else
-			{
-		   		return $email;
-			}
-		}
-
-		$clean_email = array();
-
-		foreach ($email as $addy)
-		{
-			if (preg_match( '/\<(.*)\>/', $addy, $match))
-			{
-		   		$clean_email[] = $match['1'];
-			}
-		   	else
-			{
-		   		$clean_email[] = $addy;
-			}
-		}
-
-		return $clean_email;
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Build alternative plain text message
-	 *
-	 * This function provides the raw message for use
-	 * in plain-text headers of HTML-formatted emails.
-	 * If the user hasn't specified his own alternative message
-	 * it creates one by stripping the HTML
-	 *
-	 * @access	private
-	 * @return	string
-	 */
-	function _get_alt_message()
-	{
-		if ($this->alt_message != "")
-		{
-			return $this->word_wrap($this->alt_message, '76');
-		}
-
-		if (preg_match('/\<body.*?\>(.*)\<\/body\>/si', $this->_body, $match))
-		{
-			$body = $match['1'];
-		}
-		else
-		{
-			$body = $this->_body;
-		}
-
-		$body = trim(strip_tags($body));
-		$body = preg_replace( '#<!--(.*)--\>#', "", $body);
-		$body = str_replace("\t", "", $body);
-
-		for ($i = 20; $i >= 3; $i--)
-		{
-			$n = "";
-
-			for ($x = 1; $x <= $i; $x ++)
-			{
-				 $n .= "\n";
-			}
-
-			$body = str_replace($n, "\n\n", $body);
-		}
-
-		return $this->word_wrap($body, '76');
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Word Wrap
-	 *
-	 * @access	public
-	 * @param	string
-	 * @param	integer
-	 * @return	string
-	 */
-	function word_wrap($str, $charlim = '')
-	{
-		// Se the character limit
-		if ($charlim == '')
-		{
-			$charlim = ($this->wrapchars == "") ? "76" : $this->wrapchars;
-		}
-
-		// Reduce multiple spaces
-		$str = preg_replace("| +|", " ", $str);
-
-		// Standardize newlines
-		if (strpos($str, "\r") !== FALSE)
-		{
-			$str = str_replace(array("\r\n", "\r"), "\n", $str);
-		}
-
-		// If the current word is surrounded by {unwrap} tags we'll
-		// strip the entire chunk and replace it with a marker.
-		$unwrap = array();
-		if (preg_match_all("|(\{unwrap\}.+?\{/unwrap\})|s", $str, $matches))
-		{
-			for ($i = 0; $i < count($matches['0']); $i++)
-			{
-				$unwrap[] = $matches['1'][$i];
-				$str = str_replace($matches['1'][$i], "{{unwrapped".$i."}}", $str);
-			}
-		}
-
-		// Use PHP's native function to do the initial wordwrap.
-		// We set the cut flag to FALSE so that any individual words that are
-		// too long get left alone.  In the next step we'll deal with them.
-		$str = wordwrap($str, $charlim, "\n", FALSE);
-
-		// Split the string into individual lines of text and cycle through them
-		$output = "";
-		foreach (explode("\n", $str) as $line)
-		{
-			// Is the line within the allowed character count?
-			// If so we'll join it to the output and continue
-			if (strlen($line) <= $charlim)
-			{
-				$output .= $line.$this->newline;
-				continue;
-			}
-
-			$temp = '';
-			while((strlen($line)) > $charlim)
-			{
-				// If the over-length word is a URL we won't wrap it
-				if (preg_match("!\[url.+\]|://|wwww.!", $line))
-				{
-					break;
-				}
-
-				// Trim the word down
-				$temp .= substr($line, 0, $charlim-1);
-				$line = substr($line, $charlim-1);
-			}
-
-			// If $temp contains data it means we had to split up an over-length
-			// word into smaller chunks so we'll add it back to our current line
-			if ($temp != '')
-			{
-				$output .= $temp.$this->newline.$line;
-			}
-			else
-			{
-				$output .= $line;
-			}
-
-			$output .= $this->newline;
-		}
-
-		// Put our markers back
-		if (count($unwrap) > 0)
-		{
-			foreach ($unwrap as $key => $val)
-			{
-				$output = str_replace("{{unwrapped".$key."}}", $val, $output);
-			}
-		}
-
-		return $output;
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Build final headers
-	 *
-	 * @access	private
-	 * @param	string
-	 * @return	string
-	 */
-	function _build_headers()
-	{
-		$this->_set_header('X-Sender', $this->clean_email($this->_headers['From']));
-		$this->_set_header('X-Mailer', $this->useragent);
-		$this->_set_header('X-Priority', $this->_priorities[$this->priority - 1]);
-		$this->_set_header('Message-ID', $this->_get_message_id());
-		$this->_set_header('Mime-Version', '1.0');
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Write Headers as a string
-	 *
-	 * @access	private
-	 * @return	void
-	 */
-	function _write_headers()
-	{
-		if ($this->protocol == 'mail')
-		{
-			$this->_subject = $this->_headers['Subject'];
-			unset($this->_headers['Subject']);
-		}
-
-		reset($this->_headers);
-		$this->_header_str = "";
-
-		foreach($this->_headers as $key => $val)
-		{
-			$val = trim($val);
-
-			if ($val != "")
-			{
-				$this->_header_str .= $key.": ".$val.$this->newline;
-			}
-		}
-
-		if ($this->_get_protocol() == 'mail')
-		{
-			$this->_header_str = substr($this->_header_str, 0, -1);
-		}
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Build Final Body and attachments
-	 *
-	 * @access	private
-	 * @return	void
-	 */
-	function _build_message()
-	{
-		if ($this->wordwrap === TRUE  AND  $this->mailtype != 'html')
-		{
-			$this->_body = $this->word_wrap($this->_body);
-		}
-
-		$this->_set_boundaries();
-		$this->_write_headers();
-
-		$hdr = ($this->_get_protocol() == 'mail') ? $this->newline : '';
-
-		switch ($this->_get_content_type())
-		{
-			case 'plain' :
-
-				$hdr .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline;
-				$hdr .= "Content-Transfer-Encoding: " . $this->_get_encoding();
-
-				if ($this->_get_protocol() == 'mail')
-				{
-					$this->_header_str .= $hdr;
-					$this->_finalbody = $this->_body;
-
-					return;
-				}
-
-				$hdr .= $this->newline . $this->newline . $this->_body;
-
-				$this->_finalbody = $hdr;
-				return;
-
-			break;
-			case 'html' :
-
-				if ($this->send_multipart === FALSE)
-				{
-					$hdr .= "Content-Type: text/html; charset=" . $this->charset . $this->newline;
-					$hdr .= "Content-Transfer-Encoding: quoted-printable";
-				}
-				else
-				{
-					$hdr .= "Content-Type: multipart/alternative; boundary=\"" . $this->_alt_boundary . "\"" . $this->newline;
-					$hdr .= $this->_get_mime_message() . $this->newline . $this->newline;
-					$hdr .= "--" . $this->_alt_boundary . $this->newline;
-
-					$hdr .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline;
-					$hdr .= "Content-Transfer-Encoding: " . $this->_get_encoding() . $this->newline . $this->newline;
-					$hdr .= $this->_get_alt_message() . $this->newline . $this->newline . "--" . $this->_alt_boundary . $this->newline;
-
-					$hdr .= "Content-Type: text/html; charset=" . $this->charset . $this->newline;
-					$hdr .= "Content-Transfer-Encoding: quoted-printable";
-				}
-
-				$this->_body = $this->_prep_quoted_printable($this->_body);
-
-				if ($this->_get_protocol() == 'mail')
-				{
-					$this->_header_str .= $hdr;
-					$this->_finalbody = $this->_body . $this->newline . $this->newline;
-
-					if ($this->send_multipart !== FALSE)
-					{
-						$this->_finalbody .= "--" . $this->_alt_boundary . "--";
-					}
-
-					return;
-				}
-
-				$hdr .= $this->newline . $this->newline;
-				$hdr .= $this->_body . $this->newline . $this->newline;
-
-				if ($this->send_multipart !== FALSE)
-				{
-					$hdr .= "--" . $this->_alt_boundary . "--";
-				}
-
-				$this->_finalbody = $hdr;
-				return;
-
-			break;
-			case 'plain-attach' :
-
-				$hdr .= "Content-Type: multipart/".$this->multipart."; boundary=\"" . $this->_atc_boundary."\"" . $this->newline;
-				$hdr .= $this->_get_mime_message() . $this->newline . $this->newline;
-				$hdr .= "--" . $this->_atc_boundary . $this->newline;
-
-				$hdr .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline;
-				$hdr .= "Content-Transfer-Encoding: " . $this->_get_encoding();
-
-				if ($this->_get_protocol() == 'mail')
-				{
-					$this->_header_str .= $hdr;
-
-					$body  = $this->_body . $this->newline . $this->newline;
-				}
-
-				$hdr .= $this->newline . $this->newline;
-				$hdr .= $this->_body . $this->newline . $this->newline;
-
-			break;
-			case 'html-attach' :
-
-				$hdr .= "Content-Type: multipart/".$this->multipart."; boundary=\"" . $this->_atc_boundary."\"" . $this->newline;
-				$hdr .= $this->_get_mime_message() . $this->newline . $this->newline;
-				$hdr .= "--" . $this->_atc_boundary . $this->newline;
-
-				$hdr .= "Content-Type: multipart/alternative; boundary=\"" . $this->_alt_boundary . "\"" . $this->newline .$this->newline;
-				$hdr .= "--" . $this->_alt_boundary . $this->newline;
-
-				$hdr .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline;
-				$hdr .= "Content-Transfer-Encoding: " . $this->_get_encoding() . $this->newline . $this->newline;
-				$hdr .= $this->_get_alt_message() . $this->newline . $this->newline . "--" . $this->_alt_boundary . $this->newline;
-
-				$hdr .= "Content-Type: text/html; charset=" . $this->charset . $this->newline;
-				$hdr .= "Content-Transfer-Encoding: quoted-printable";
-
-				$this->_body = $this->_prep_quoted_printable($this->_body);
-
-				if ($this->_get_protocol() == 'mail')
-				{
-					$this->_header_str .= $hdr;
-
-					$body  = $this->_body . $this->newline . $this->newline;
-					$body .= "--" . $this->_alt_boundary . "--" . $this->newline . $this->newline;
-				}
-
-				$hdr .= $this->newline . $this->newline;
-				$hdr .= $this->_body . $this->newline . $this->newline;
-				$hdr .= "--" . $this->_alt_boundary . "--" . $this->newline . $this->newline;
-
-			break;
-		}
-
-		$attachment = array();
-
-		$z = 0;
-
-		for ($i=0; $i < count($this->_attach_name); $i++)
-		{
-			$filename = $this->_attach_name[$i];
-			$basename = basename($filename);
-			$ctype = $this->_attach_type[$i];
-
-			if ( ! file_exists($filename))
-			{
-				$this->_set_error_message('email_attachment_missing', $filename);
-				return FALSE;
-			}
-
-			$h  = "--".$this->_atc_boundary.$this->newline;
-			$h .= "Content-type: ".$ctype."; ";
-			$h .= "name=\"".$basename."\"".$this->newline;
-			$h .= "Content-Disposition: ".$this->_attach_disp[$i].";".$this->newline;
-			$h .= "Content-Transfer-Encoding: base64".$this->newline;
-
-			$attachment[$z++] = $h;
-			$file = filesize($filename) +1;
-
-			if ( ! $fp = fopen($filename, FOPEN_READ))
-			{
-				$this->_set_error_message('email_attachment_unreadable', $filename);
-				return FALSE;
-			}
-
-			$attachment[$z++] = chunk_split(base64_encode(fread($fp, $file)));
-			fclose($fp);
-		}
-
-		if ($this->_get_protocol() == 'mail')
-		{
-			$this->_finalbody = $body . implode($this->newline, $attachment).$this->newline."--".$this->_atc_boundary."--";
-
-			return;
-		}
-
-		$this->_finalbody = $hdr.implode($this->newline, $attachment).$this->newline."--".$this->_atc_boundary."--";
-
-		return;
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Prep Quoted Printable
-	 *
-	 * Prepares string for Quoted-Printable Content-Transfer-Encoding
-	 * Refer to RFC 2045 http://www.ietf.org/rfc/rfc2045.txt
-	 *
-	 * @access	private
-	 * @param	string
-	 * @param	integer
-	 * @return	string
-	 */
-	function _prep_quoted_printable($str, $charlim = '')
-	{
-		// Set the character limit
-		// Don't allow over 76, as that will make servers and MUAs barf
-		// all over quoted-printable data
-		if ($charlim == '' OR $charlim > '76')
-		{
-			$charlim = '76';
-		}
-
-		// Reduce multiple spaces
-		$str = preg_replace("| +|", " ", $str);
-
-		// kill nulls
-		$str = preg_replace('/\x00+/', '', $str);
-
-		// Standardize newlines
-		if (strpos($str, "\r") !== FALSE)
-		{
-			$str = str_replace(array("\r\n", "\r"), "\n", $str);
-		}
-
-		// We are intentionally wrapping so mail servers will encode characters
-		// properly and MUAs will behave, so {unwrap} must go!
-		$str = str_replace(array('{unwrap}', '{/unwrap}'), '', $str);
-
-		// Break into an array of lines
-		$lines = explode("\n", $str);
-
-		$escape = '=';
-		$output = '';
-
-		foreach ($lines as $line)
-		{
-			$length = strlen($line);
-			$temp = '';
-
-			// Loop through each character in the line to add soft-wrap
-			// characters at the end of a line " =\r\n" and add the newly
-			// processed line(s) to the output (see comment on $crlf class property)
-			for ($i = 0; $i < $length; $i++)
-			{
-				// Grab the next character
-				$char = substr($line, $i, 1);
-				$ascii = ord($char);
-
-				// Convert spaces and tabs but only if it's the end of the line
-				if ($i == ($length - 1))
-				{
-					$char = ($ascii == '32' OR $ascii == '9') ? $escape.sprintf('%02s', dechex($ascii)) : $char;
-				}
-
-				// encode = signs
-				if ($ascii == '61')
-				{
-					$char = $escape.strtoupper(sprintf('%02s', dechex($ascii)));  // =3D
-				}
-
-				// If we're at the character limit, add the line to the output,
-				// reset our temp variable, and keep on chuggin'
-				if ((strlen($temp) + strlen($char)) >= $charlim)
-				{
-					$output .= $temp.$escape.$this->crlf;
-					$temp = '';
-				}
-
-				// Add the character to our temporary line
-				$temp .= $char;
-			}
-
-			// Add our completed line to the output
-			$output .= $temp.$this->crlf;
-		}
-
-		// get rid of extra CRLF tacked onto the end
-		$output = substr($output, 0, strlen($this->crlf) * -1);
-
-		return $output;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Send Email
-	 *
-	 * @access	public
-	 * @return	bool
-	 */
-	function send()
-	{
-		if ($this->_replyto_flag == FALSE)
-		{
-			$this->reply_to($this->_headers['From']);
-		}
-
-		if (( ! isset($this->_recipients) AND ! isset($this->_headers['To']))  AND
-			( ! isset($this->_bcc_array) AND ! isset($this->_headers['Bcc'])) AND
-			( ! isset($this->_headers['Cc'])))
-		{
-			$this->_set_error_message('email_no_recipients');
-			return FALSE;
-		}
-
-		$this->_build_headers();
-
-		if ($this->bcc_batch_mode  AND  count($this->_bcc_array) > 0)
-		{
-			if (count($this->_bcc_array) > $this->bcc_batch_size)
-				return $this->batch_bcc_send();
-		}
-
-		$this->_build_message();
-
-		if ( ! $this->_spool_email())
-		{
-			return FALSE;
-		}
-		else
-		{
-			return TRUE;
-		}
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Batch Bcc Send.  Sends groups of BCCs in batches
-	 *
-	 * @access	public
-	 * @return	bool
-	 */
-	function batch_bcc_send()
-	{
-		$float = $this->bcc_batch_size -1;
-
-		$set = "";
-
-		$chunk = array();
-
-		for ($i = 0; $i < count($this->_bcc_array); $i++)
-		{
-			if (isset($this->_bcc_array[$i]))
-			{
-				$set .= ", ".$this->_bcc_array[$i];
-			}
-
-			if ($i == $float)
-			{
-				$chunk[] = substr($set, 1);
-				$float = $float + $this->bcc_batch_size;
-				$set = "";
-			}
-
-			if ($i == count($this->_bcc_array)-1)
-			{
-				$chunk[] = substr($set, 1);
-			}
-		}
-
-		for ($i = 0; $i < count($chunk); $i++)
-		{
-			unset($this->_headers['Bcc']);
-			unset($bcc);
-
-			$bcc = $this->_str_to_array($chunk[$i]);
-			$bcc = $this->clean_email($bcc);
-
-			if ($this->protocol != 'smtp')
-			{
-				$this->_set_header('Bcc', implode(", ", $bcc));
-			}
-			else
-			{
-				$this->_bcc_array = $bcc;
-			}
-
-			$this->_build_message();
-			$this->_spool_email();
-		}
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Unwrap special elements
-	 *
-	 * @access	private
-	 * @return	void
-	 */
-	function _unwrap_specials()
-	{
-		$this->_finalbody = preg_replace_callback("/\{unwrap\}(.*?)\{\/unwrap\}/si", array($this, '_remove_nl_callback'), $this->_finalbody);
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Strip line-breaks via callback
-	 *
-	 * @access	private
-	 * @return	string
-	 */
-	function _remove_nl_callback($matches)
-	{
-		if (strpos($matches[1], "\r") !== FALSE OR strpos($matches[1], "\n") !== FALSE)
-		{
-			$matches[1] = str_replace(array("\r\n", "\r", "\n"), '', $matches[1]);
-		}
-
-		return $matches[1];
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Spool mail to the mail server
-	 *
-	 * @access	private
-	 * @return	bool
-	 */
-	function _spool_email()
-	{
-		$this->_unwrap_specials();
-
-		switch ($this->_get_protocol())
-		{
-			case 'mail'	:
-
-					if ( ! $this->_send_with_mail())
-					{
-						$this->_set_error_message('email_send_failure_phpmail');
-						return FALSE;
-					}
-			break;
-			case 'sendmail'	:
-
-					if ( ! $this->_send_with_sendmail())
-					{
-						$this->_set_error_message('email_send_failure_sendmail');
-						return FALSE;
-					}
-			break;
-			case 'smtp'	:
-
-					if ( ! $this->_send_with_smtp())
-					{
-						$this->_set_error_message('email_send_failure_smtp');
-						return FALSE;
-					}
-			break;
-
-		}
-
-		$this->_set_error_message('email_sent', $this->_get_protocol());
-		return TRUE;
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Send using mail()
-	 *
-	 * @access	private
-	 * @return	bool
-	 */
-	function _send_with_mail()
-	{
-		if ($this->_safe_mode == TRUE)
-		{
-			if ( ! mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str))
-			{
-				return FALSE;
-			}
-			else
-			{
-				return TRUE;
-			}
-		}
-		else
-		{
-			// most documentation of sendmail using the "-f" flag lacks a space after it, however
-			// we've encountered servers that seem to require it to be in place.
-			if ( ! mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str, "-f ".$this->clean_email($this->_headers['From'])))
-			{
-				return FALSE;
-			}
-			else
-			{
-				return TRUE;
-			}
-		}
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Send using Sendmail
-	 *
-	 * @access	private
-	 * @return	bool
-	 */
-	function _send_with_sendmail()
-	{
-		$fp = @popen($this->mailpath . " -oi -f ".$this->clean_email($this->_headers['From'])." -t", 'w');
-
-		if ( ! is_resource($fp))
-		{
-			$this->_set_error_message('email_no_socket');
-			return FALSE;
-		}
-
-		fputs($fp, $this->_header_str);
-		fputs($fp, $this->_finalbody);
-		pclose($fp) >> 8 & 0xFF;
-
-		return TRUE;
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Send using SMTP
-	 *
-	 * @access	private
-	 * @return	bool
-	 */
-	function _send_with_smtp()
-	{
-		if ($this->smtp_host == '')
-		{
-			$this->_set_error_message('email_no_hostname');
-			return FALSE;
-		}
-
-		$this->_smtp_connect();
-		$this->_smtp_authenticate();
-
-		$this->_send_command('from', $this->clean_email($this->_headers['From']));
-
-		foreach($this->_recipients as $val)
-		{
-			$this->_send_command('to', $val);
-		}
-
-		if (count($this->_cc_array) > 0)
-		{
-			foreach($this->_cc_array as $val)
-			{
-				if ($val != "")
-				{
-					$this->_send_command('to', $val);
-				}
-			}
-		}
-
-		if (count($this->_bcc_array) > 0)
-		{
-			foreach($this->_bcc_array as $val)
-			{
-				if ($val != "")
-				{
-					$this->_send_command('to', $val);
-				}
-			}
-		}
-
-		$this->_send_command('data');
-
-		// perform dot transformation on any lines that begin with a dot
-		$this->_send_data($this->_header_str . preg_replace('/^\./m', '..$1', $this->_finalbody));
-
-		$this->_send_data('.');
-
-		$reply = $this->_get_smtp_data();
-
-		$this->_set_error_message($reply);
-
-		if (strncmp($reply, '250', 3) != 0)
-		{
-			$this->_set_error_message('email_smtp_error', $reply);
-			return FALSE;
-		}
-
-		$this->_send_command('quit');
-		return TRUE;
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * SMTP Connect
-	 *
-	 * @access	private
-	 * @param	string
-	 * @return	string
-	 */
-	function _smtp_connect()
-	{
-		$this->_smtp_connect = fsockopen($this->smtp_host,
-										$this->smtp_port,
-										$errno,
-										$errstr,
-										$this->smtp_timeout);
-
-		if( ! is_resource($this->_smtp_connect))
-		{
-			$this->_set_error_message('email_smtp_error', $errno." ".$errstr);
-			return FALSE;
-		}
-
-		$this->_set_error_message($this->_get_smtp_data());
-		return $this->_send_command('hello');
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Send SMTP command
-	 *
-	 * @access	private
-	 * @param	string
-	 * @param	string
-	 * @return	string
-	 */
-	function _send_command($cmd, $data = '')
-	{
-		switch ($cmd)
-		{
-			case 'hello' :
-
-					if ($this->_smtp_auth OR $this->_get_encoding() == '8bit')
-						$this->_send_data('EHLO '.$this->_get_hostname());
-					else
-						$this->_send_data('HELO '.$this->_get_hostname());
-
-						$resp = 250;
-			break;
-			case 'from' :
-
-						$this->_send_data('MAIL FROM:<'.$data.'>');
-
-						$resp = 250;
-			break;
-			case 'to'	:
-
-						$this->_send_data('RCPT TO:<'.$data.'>');
-
-						$resp = 250;
-			break;
-			case 'data'	:
-
-						$this->_send_data('DATA');
-
-						$resp = 354;
-			break;
-			case 'quit'	:
-
-						$this->_send_data('QUIT');
-
-						$resp = 221;
-			break;
-		}
-
-		$reply = $this->_get_smtp_data();
-
-		$this->_debug_msg[] = "<pre>".$cmd.": ".$reply."</pre>";
-
-		if (substr($reply, 0, 3) != $resp)
-		{
-			$this->_set_error_message('email_smtp_error', $reply);
-			return FALSE;
-		}
-
-		if ($cmd == 'quit')
-		{
-			fclose($this->_smtp_connect);
-		}
-
-		return TRUE;
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 *  SMTP Authenticate
-	 *
-	 * @access	private
-	 * @return	bool
-	 */
-	function _smtp_authenticate()
-	{
-		if ( ! $this->_smtp_auth)
-		{
-			return TRUE;
-		}
-
-		if ($this->smtp_user == ""  AND  $this->smtp_pass == "")
-		{
-			$this->_set_error_message('email_no_smtp_unpw');
-			return FALSE;
-		}
-
-		$this->_send_data('AUTH LOGIN');
-
-		$reply = $this->_get_smtp_data();
-
-		if (strncmp($reply, '334', 3) != 0)
-		{
-			$this->_set_error_message('email_failed_smtp_login', $reply);
-			return FALSE;
-		}
-
-		$this->_send_data(base64_encode($this->smtp_user));
-
-		$reply = $this->_get_smtp_data();
-
-		if (strncmp($reply, '334', 3) != 0)
-		{
-			$this->_set_error_message('email_smtp_auth_un', $reply);
-			return FALSE;
-		}
-
-		$this->_send_data(base64_encode($this->smtp_pass));
-
-		$reply = $this->_get_smtp_data();
-
-		if (strncmp($reply, '235', 3) != 0)
-		{
-			$this->_set_error_message('email_smtp_auth_pw', $reply);
-			return FALSE;
-		}
-
-		return TRUE;
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Send SMTP data
-	 *
-	 * @access	private
-	 * @return	bool
-	 */
-	function _send_data($data)
-	{
-		if ( ! fwrite($this->_smtp_connect, $data . $this->newline))
-		{
-			$this->_set_error_message('email_smtp_data_failure', $data);
-			return FALSE;
-		}
-		else
-		{
-			return TRUE;
-		}
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Get SMTP data
-	 *
-	 * @access	private
-	 * @return	string
-	 */
-	function _get_smtp_data()
-	{
-		$data = "";
-
-		while ($str = fgets($this->_smtp_connect, 512))
-		{
-			$data .= $str;
-
-			if (substr($str, 3, 1) == " ")
-			{
-				break;
-			}
-		}
-
-		return $data;
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Get Hostname
-	 *
-	 * @access	private
-	 * @return	string
-	 */
-	function _get_hostname()
-	{
-		return (isset($_SERVER['SERVER_NAME'])) ? $_SERVER['SERVER_NAME'] : 'localhost.localdomain';
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Get IP
-	 *
-	 * @access	private
-	 * @return	string
-	 */
-	function _get_ip()
-	{
-		if ($this->_IP !== FALSE)
-		{
-			return $this->_IP;
-		}
-
-		$cip = (isset($_SERVER['HTTP_CLIENT_IP']) AND $_SERVER['HTTP_CLIENT_IP'] != "") ? $_SERVER['HTTP_CLIENT_IP'] : FALSE;
-		$rip = (isset($_SERVER['REMOTE_ADDR']) AND $_SERVER['REMOTE_ADDR'] != "") ? $_SERVER['REMOTE_ADDR'] : FALSE;
-		$fip = (isset($_SERVER['HTTP_X_FORWARDED_FOR']) AND $_SERVER['HTTP_X_FORWARDED_FOR'] != "") ? $_SERVER['HTTP_X_FORWARDED_FOR'] : FALSE;
-
-		if ($cip && $rip) 	$this->_IP = $cip;
-		elseif ($rip)		$this->_IP = $rip;
-		elseif ($cip)		$this->_IP = $cip;
-		elseif ($fip)		$this->_IP = $fip;
-
-		if (strstr($this->_IP, ','))
-		{
-			$x = explode(',', $this->_IP);
-			$this->_IP = end($x);
-		}
-
-		if ( ! preg_match( "/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/", $this->_IP))
-		{
-			$this->_IP = '0.0.0.0';
-		}
-
-		unset($cip);
-		unset($rip);
-		unset($fip);
-
-		return $this->_IP;
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Get Debug Message
-	 *
-	 * @access	public
-	 * @return	string
-	 */
-	function print_debugger()
-	{
-		$msg = '';
-
-		if (count($this->_debug_msg) > 0)
-		{
-			foreach ($this->_debug_msg as $val)
-			{
-				$msg .= $val;
-			}
-		}
-
-		$msg .= "<pre>".$this->_header_str."\n".htmlspecialchars($this->_subject)."\n".htmlspecialchars($this->_finalbody).'</pre>';
-		return $msg;
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Set Message
-	 *
-	 * @access	private
-	 * @param	string
-	 * @return	string
-	 */
-	function _set_error_message($msg, $val = '')
-	{
-		$CI =& get_instance();
-		$CI->lang->load('email');
-
-		if (FALSE === ($line = $CI->lang->line($msg)))
-		{
-			$this->_debug_msg[] = str_replace('%s', $val, $msg)."<br />";
-		}
-		else
-		{
-			$this->_debug_msg[] = str_replace('%s', $val, $line)."<br />";
-		}
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Mime Types
-	 *
-	 * @access	private
-	 * @param	string
-	 * @return	string
-	 */
-	function _mime_types($ext = "")
-	{
-		$mimes = array(	'hqx'	=>	'application/mac-binhex40',
-						'cpt'	=>	'application/mac-compactpro',
-						'doc'	=>	'application/msword',
-						'bin'	=>	'application/macbinary',
-						'dms'	=>	'application/octet-stream',
-						'lha'	=>	'application/octet-stream',
-						'lzh'	=>	'application/octet-stream',
-						'exe'	=>	'application/octet-stream',
-						'class'	=>	'application/octet-stream',
-						'psd'	=>	'application/octet-stream',
-						'so'	=>	'application/octet-stream',
-						'sea'	=>	'application/octet-stream',
-						'dll'	=>	'application/octet-stream',
-						'oda'	=>	'application/oda',
-						'pdf'	=>	'application/pdf',
-						'ai'	=>	'application/postscript',
-						'eps'	=>	'application/postscript',
-						'ps'	=>	'application/postscript',
-						'smi'	=>	'application/smil',
-						'smil'	=>	'application/smil',
-						'mif'	=>	'application/vnd.mif',
-						'xls'	=>	'application/vnd.ms-excel',
-						'ppt'	=>	'application/vnd.ms-powerpoint',
-						'wbxml'	=>	'application/vnd.wap.wbxml',
-						'wmlc'	=>	'application/vnd.wap.wmlc',
-						'dcr'	=>	'application/x-director',
-						'dir'	=>	'application/x-director',
-						'dxr'	=>	'application/x-director',
-						'dvi'	=>	'application/x-dvi',
-						'gtar'	=>	'application/x-gtar',
-						'php'	=>	'application/x-httpd-php',
-						'php4'	=>	'application/x-httpd-php',
-						'php3'	=>	'application/x-httpd-php',
-						'phtml'	=>	'application/x-httpd-php',
-						'phps'	=>	'application/x-httpd-php-source',
-						'js'	=>	'application/x-javascript',
-						'swf'	=>	'application/x-shockwave-flash',
-						'sit'	=>	'application/x-stuffit',
-						'tar'	=>	'application/x-tar',
-						'tgz'	=>	'application/x-tar',
-						'xhtml'	=>	'application/xhtml+xml',
-						'xht'	=>	'application/xhtml+xml',
-						'zip'	=>	'application/zip',
-						'mid'	=>	'audio/midi',
-						'midi'	=>	'audio/midi',
-						'mpga'	=>	'audio/mpeg',
-						'mp2'	=>	'audio/mpeg',
-						'mp3'	=>	'audio/mpeg',
-						'aif'	=>	'audio/x-aiff',
-						'aiff'	=>	'audio/x-aiff',
-						'aifc'	=>	'audio/x-aiff',
-						'ram'	=>	'audio/x-pn-realaudio',
-						'rm'	=>	'audio/x-pn-realaudio',
-						'rpm'	=>	'audio/x-pn-realaudio-plugin',
-						'ra'	=>	'audio/x-realaudio',
-						'rv'	=>	'video/vnd.rn-realvideo',
-						'wav'	=>	'audio/x-wav',
-						'bmp'	=>	'image/bmp',
-						'gif'	=>	'image/gif',
-						'jpeg'	=>	'image/jpeg',
-						'jpg'	=>	'image/jpeg',
-						'jpe'	=>	'image/jpeg',
-						'png'	=>	'image/png',
-						'tiff'	=>	'image/tiff',
-						'tif'	=>	'image/tiff',
-						'css'	=>	'text/css',
-						'html'	=>	'text/html',
-						'htm'	=>	'text/html',
-						'shtml'	=>	'text/html',
-						'txt'	=>	'text/plain',
-						'text'	=>	'text/plain',
-						'log'	=>	'text/plain',
-						'rtx'	=>	'text/richtext',
-						'rtf'	=>	'text/rtf',
-						'xml'	=>	'text/xml',
-						'xsl'	=>	'text/xml',
-						'mpeg'	=>	'video/mpeg',
-						'mpg'	=>	'video/mpeg',
-						'mpe'	=>	'video/mpeg',
-						'qt'	=>	'video/quicktime',
-						'mov'	=>	'video/quicktime',
-						'avi'	=>	'video/x-msvideo',
-						'movie'	=>	'video/x-sgi-movie',
-						'doc'	=>	'application/msword',
-						'word'	=>	'application/msword',
-						'xl'	=>	'application/excel',
-						'eml'	=>	'message/rfc822'
-					);
-
-		return ( ! isset($mimes[strtolower($ext)])) ? "application/x-unknown-content-type" : $mimes[strtolower($ext)];
-	}
-
-}
-// END CI_Email class
-
-/* End of file Email.php */
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

+/**

+ * CodeIgniter

+ *

+ * An open source application development framework for PHP 4.3.2 or newer

+ *

+ * @package		CodeIgniter

+ * @author		ExpressionEngine Dev Team

+ * @copyright	Copyright (c) 2008, EllisLab, Inc.

+ * @license		http://codeigniter.com/user_guide/license.html

+ * @link		http://codeigniter.com

+ * @since		Version 1.0

+ * @filesource

+ */

+

+// ------------------------------------------------------------------------

+

+/**

+ * CodeIgniter Email Class

+ *

+ * Permits email to be sent using Mail, Sendmail, or SMTP.

+ *

+ * @package		CodeIgniter

+ * @subpackage	Libraries

+ * @category	Libraries

+ * @author		ExpressionEngine Dev Team

+ * @link		http://codeigniter.com/user_guide/libraries/email.html

+ */

+class CI_Email {

+

+	var	$useragent		= "CodeIgniter";

+	var	$mailpath		= "/usr/sbin/sendmail";	// Sendmail path

+	var	$protocol		= "mail";	// mail/sendmail/smtp

+	var	$smtp_host		= "";		// SMTP Server.  Example: mail.earthlink.net

+	var	$smtp_user		= "";		// SMTP Username

+	var	$smtp_pass		= "";		// SMTP Password

+	var	$smtp_port		= "25";		// SMTP Port

+	var	$smtp_timeout	= 5;		// SMTP Timeout in seconds

+	var	$wordwrap		= TRUE;		// TRUE/FALSE  Turns word-wrap on/off

+	var	$wrapchars		= "76";		// Number of characters to wrap at.

+	var	$mailtype		= "text";	// text/html  Defines email formatting

+	var	$charset		= "utf-8";	// Default char set: iso-8859-1 or us-ascii

+	var	$multipart		= "mixed";	// "mixed" (in the body) or "related" (separate)

+	var $alt_message	= '';		// Alternative message for HTML emails

+	var	$validate		= FALSE;	// TRUE/FALSE.  Enables email validation

+	var	$priority		= "3";		// Default priority (1 - 5)

+	var	$newline		= "\n";		// Default newline. "\r\n" or "\n" (Use "\r\n" to comply with RFC 822)

+	var $crlf			= "\n";		// The RFC 2045 compliant CRLF for quoted-printable is "\r\n".  Apparently some servers,

+									// even on the receiving end think they need to muck with CRLFs, so using "\n", while

+									// distasteful, is the only thing that seems to work for all environments.

+	var $send_multipart	= TRUE;		// TRUE/FALSE - Yahoo does not like multipart alternative, so this is an override.  Set to FALSE for Yahoo.

+	var	$bcc_batch_mode	= FALSE;	// TRUE/FALSE  Turns on/off Bcc batch feature

+	var	$bcc_batch_size	= 200;		// If bcc_batch_mode = TRUE, sets max number of Bccs in each batch

+	var $_safe_mode		= FALSE;

+	var	$_subject		= "";

+	var	$_body			= "";

+	var	$_finalbody		= "";

+	var	$_alt_boundary	= "";

+	var	$_atc_boundary	= "";

+	var	$_header_str	= "";

+	var	$_smtp_connect	= "";

+	var	$_encoding		= "8bit";

+	var $_IP			= FALSE;

+	var	$_smtp_auth		= FALSE;

+	var $_replyto_flag	= FALSE;

+	var	$_debug_msg		= array();

+	var	$_recipients	= array();

+	var	$_cc_array		= array();

+	var	$_bcc_array		= array();

+	var	$_headers		= array();

+	var	$_attach_name	= array();

+	var	$_attach_type	= array();

+	var	$_attach_disp	= array();

+	var	$_protocols		= array('mail', 'sendmail', 'smtp');

+	var	$_base_charsets	= array('us-ascii', 'iso-2022-');	// 7-bit charsets (excluding language suffix)

+	var	$_bit_depths	= array('7bit', '8bit');

+	var	$_priorities	= array('1 (Highest)', '2 (High)', '3 (Normal)', '4 (Low)', '5 (Lowest)');

+

+

+	/**

+	 * Constructor - Sets Email Preferences

+	 *

+	 * The constructor can be passed an array of config values

+	 */

+	function CI_Email($config = array())

+	{

+		if (count($config) > 0)

+		{

+			$this->initialize($config);

+		}

+		else

+		{

+			$this->_smtp_auth = ($this->smtp_user == '' AND $this->smtp_pass == '') ? FALSE : TRUE;

+			$this->_safe_mode = ((boolean)@ini_get("safe_mode") === FALSE) ? FALSE : TRUE;

+		}

+

+		log_message('debug', "Email Class Initialized");

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Initialize preferences

+	 *

+	 * @access	public

+	 * @param	array

+	 * @return	void

+	 */

+	function initialize($config = array())

+	{

+		$this->clear();

+		foreach ($config as $key => $val)

+		{

+			if (isset($this->$key))

+			{

+				$method = 'set_'.$key;

+

+				if (method_exists($this, $method))

+				{

+					$this->$method($val);

+				}

+				else

+				{

+					$this->$key = $val;

+				}

+			}

+		}

+

+		$this->_smtp_auth = ($this->smtp_user == '' AND $this->smtp_pass == '') ? FALSE : TRUE;

+		$this->_safe_mode = ((boolean)@ini_get("safe_mode") === FALSE) ? FALSE : TRUE;

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Initialize the Email Data

+	 *

+	 * @access	public

+	 * @return	void

+	 */

+	function clear($clear_attachments = FALSE)

+	{

+		$this->_subject		= "";

+		$this->_body		= "";

+		$this->_finalbody	= "";

+		$this->_header_str	= "";

+		$this->_replyto_flag = FALSE;

+		$this->_recipients	= array();

+		$this->_headers		= array();

+		$this->_debug_msg	= array();

+

+		$this->_set_header('User-Agent', $this->useragent);

+		$this->_set_header('Date', $this->_set_date());

+

+		if ($clear_attachments !== FALSE)

+		{

+			$this->_attach_name = array();

+			$this->_attach_type = array();

+			$this->_attach_disp = array();

+		}

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Set FROM

+	 *

+	 * @access	public

+	 * @param	string

+	 * @param	string

+	 * @return	void

+	 */

+	function from($from, $name = '')

+	{

+		if (preg_match( '/\<(.*)\>/', $from, $match))

+		{

+			$from = $match['1'];

+		}

+

+		if ($this->validate)

+		{

+			$this->validate_email($this->_str_to_array($from));

+		}

+

+		if ($name != '' && strncmp($name, '"', 1) != 0)

+		{

+			$name = '"'.$name.'"';

+		}

+

+		$this->_set_header('From', $name.' <'.$from.'>');

+		$this->_set_header('Return-Path', '<'.$from.'>');

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Set Reply-to

+	 *

+	 * @access	public

+	 * @param	string

+	 * @param	string

+	 * @return	void

+	 */

+	function reply_to($replyto, $name = '')

+	{

+		if (preg_match( '/\<(.*)\>/', $replyto, $match))

+		{

+			$replyto = $match['1'];

+		}

+

+		if ($this->validate)

+		{

+			$this->validate_email($this->_str_to_array($replyto));

+		}

+

+		if ($name == '')

+		{

+			$name = $replyto;

+		}

+

+		if (strncmp($name, '"', 1) != 0)

+		{

+			$name = '"'.$name.'"';

+		}

+

+		$this->_set_header('Reply-To', $name.' <'.$replyto.'>');

+		$this->_replyto_flag = TRUE;

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Set Recipients

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	void

+	 */

+	function to($to)

+	{

+		$to = $this->_str_to_array($to);

+		$to = $this->clean_email($to);

+

+		if ($this->validate)

+		{

+			$this->validate_email($to);

+		}

+

+		if ($this->_get_protocol() != 'mail')

+		{

+			$this->_set_header('To', implode(", ", $to));

+		}

+

+		switch ($this->_get_protocol())

+		{

+			case 'smtp'		: $this->_recipients = $to;

+			break;

+			case 'sendmail'	: $this->_recipients = implode(", ", $to);

+			break;

+			case 'mail'		: $this->_recipients = implode(", ", $to);

+			break;

+		}

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Set CC

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	void

+	 */

+	function cc($cc)

+	{

+		$cc = $this->_str_to_array($cc);

+		$cc = $this->clean_email($cc);

+

+		if ($this->validate)

+		{

+			$this->validate_email($cc);

+		}

+

+		$this->_set_header('Cc', implode(", ", $cc));

+

+		if ($this->_get_protocol() == "smtp")

+		{

+			$this->_cc_array = $cc;

+		}

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Set BCC

+	 *

+	 * @access	public

+	 * @param	string

+	 * @param	string

+	 * @return	void

+	 */

+	function bcc($bcc, $limit = '')

+	{

+		if ($limit != '' && is_numeric($limit))

+		{

+			$this->bcc_batch_mode = TRUE;

+			$this->bcc_batch_size = $limit;

+		}

+

+		$bcc = $this->_str_to_array($bcc);

+		$bcc = $this->clean_email($bcc);

+

+		if ($this->validate)

+		{

+			$this->validate_email($bcc);

+		}

+

+		if (($this->_get_protocol() == "smtp") OR ($this->bcc_batch_mode && count($bcc) > $this->bcc_batch_size))

+		{

+			$this->_bcc_array = $bcc;

+		}

+		else

+		{

+			$this->_set_header('Bcc', implode(", ", $bcc));

+		}

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Set Email Subject

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	void

+	 */

+	function subject($subject)

+	{

+		if (strpos($subject, "\r") !== FALSE OR strpos($subject, "\n") !== FALSE)

+		{

+			$subject = str_replace(array("\r\n", "\r", "\n"), '', $subject);

+		}

+

+		if (strpos($subject, "\t"))

+		{

+			$subject = str_replace("\t", ' ', $subject);

+		}

+

+		$this->_set_header('Subject', trim($subject));

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Set Body

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	void

+	 */

+	function message($body)

+	{

+		$this->_body = stripslashes(rtrim(str_replace("\r", "", $body)));

+	}

+ 

+	// --------------------------------------------------------------------

+

+	/**

+	 * Assign file attachments

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	void

+	 */

+	function attach($filename, $disposition = 'attachment')

+	{

+		$this->_attach_name[] = $filename;

+		$this->_attach_type[] = $this->_mime_types(next(explode('.', basename($filename))));

+		$this->_attach_disp[] = $disposition; // Can also be 'inline'  Not sure if it matters

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Add a Header Item

+	 *

+	 * @access	private

+	 * @param	string

+	 * @param	string

+	 * @return	void

+	 */

+	function _set_header($header, $value)

+	{

+		$this->_headers[$header] = $value;

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Convert a String to an Array

+	 *

+	 * @access	private

+	 * @param	string

+	 * @return	array

+	 */

+	function _str_to_array($email)

+	{

+		if ( ! is_array($email))

+		{

+			if (strpos($email, ',') !== FALSE)

+			{

+				$email = preg_split('/[\s,]/', $email, -1, PREG_SPLIT_NO_EMPTY);

+			}

+			else

+			{

+				$email = trim($email);

+				settype($email, "array");

+			}

+		}

+		return $email;

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Set Multipart Value

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	void

+	 */

+	function set_alt_message($str = '')

+	{

+		$this->alt_message = ($str == '') ? '' : $str;

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Set Mailtype

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	void

+	 */

+	function set_mailtype($type = 'text')

+	{

+		$this->mailtype = ($type == 'html') ? 'html' : 'text';

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Set Wordwrap

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	void

+	 */

+	function set_wordwrap($wordwrap = TRUE)

+	{

+		$this->wordwrap = ($wordwrap === FALSE) ? FALSE : TRUE;

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Set Protocol

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	void

+	 */

+	function set_protocol($protocol = 'mail')

+	{

+		$this->protocol = ( ! in_array($protocol, $this->_protocols, TRUE)) ? 'mail' : strtolower($protocol);

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Set Priority

+	 *

+	 * @access	public

+	 * @param	integer

+	 * @return	void

+	 */

+	function set_priority($n = 3)

+	{

+		if ( ! is_numeric($n))

+		{

+			$this->priority = 3;

+			return;

+		}

+

+		if ($n < 1 OR $n > 5)

+		{

+			$this->priority = 3;

+			return;

+		}

+

+		$this->priority = $n;

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Set Newline Character

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	void

+	 */

+	function set_newline($newline = "\n")

+	{

+		if ($newline != "\n" AND $newline != "\r\n" AND $newline != "\r")

+		{

+			$this->newline	= "\n";

+			return;

+		}

+

+		$this->newline	= $newline;

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Set CRLF

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	void

+	 */

+	function set_crlf($crlf = "\n")

+	{

+		if ($crlf != "\n" AND $crlf != "\r\n" AND $crlf != "\r")

+		{

+			$this->crlf	= "\n";

+			return;

+		}

+

+		$this->crlf	= $crlf;

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Set Message Boundary

+	 *

+	 * @access	private

+	 * @return	void

+	 */

+	function _set_boundaries()

+	{

+		$this->_alt_boundary = "B_ALT_".uniqid(''); // multipart/alternative

+		$this->_atc_boundary = "B_ATC_".uniqid(''); // attachment boundary

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Get the Message ID

+	 *

+	 * @access	private

+	 * @return	string

+	 */

+	function _get_message_id()

+	{

+		$from = $this->_headers['Return-Path'];

+		$from = str_replace(">", "", $from);

+		$from = str_replace("<", "", $from);

+

+		return  "<".uniqid('').strstr($from, '@').">";

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Get Mail Protocol

+	 *

+	 * @access	private

+	 * @param	bool

+	 * @return	string

+	 */

+	function _get_protocol($return = TRUE)

+	{

+		$this->protocol = strtolower($this->protocol);

+		$this->protocol = ( ! in_array($this->protocol, $this->_protocols, TRUE)) ? 'mail' : $this->protocol;

+

+		if ($return == TRUE)

+		{

+			return $this->protocol;

+		}

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Get Mail Encoding

+	 *

+	 * @access	private

+	 * @param	bool

+	 * @return	string

+	 */

+	function _get_encoding($return = TRUE)

+	{

+		$this->_encoding = ( ! in_array($this->_encoding, $this->_bit_depths)) ? '8bit' : $this->_encoding;

+

+		foreach ($this->_base_charsets as $charset)

+		{

+			if (strncmp($charset, $this->charset, strlen($charset)) == 0)

+			{

+				$this->_encoding = '7bit';

+			}

+		}

+

+		if ($return == TRUE)

+		{

+			return $this->_encoding;

+		}

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Get content type (text/html/attachment)

+	 *

+	 * @access	private

+	 * @return	string

+	 */

+	function _get_content_type()

+	{

+		if	($this->mailtype == 'html' &&  count($this->_attach_name) == 0)

+		{

+			return 'html';

+		}

+		elseif	($this->mailtype == 'html' &&  count($this->_attach_name)  > 0)

+		{

+			return 'html-attach';

+		}

+		elseif	($this->mailtype == 'text' &&  count($this->_attach_name)  > 0)

+		{

+			return 'plain-attach';

+		}

+		else

+		{

+			return 'plain';

+		}

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Set RFC 822 Date

+	 *

+	 * @access	private

+	 * @return	string

+	 */

+	function _set_date()

+	{

+		$timezone = date("Z");

+		$operator = (strncmp($timezone, '-', 1) == 0) ? '-' : '+';

+		$timezone = abs($timezone);

+		$timezone = floor($timezone/3600) * 100 + ($timezone % 3600 ) / 60;

+

+		return sprintf("%s %s%04d", date("D, j M Y H:i:s"), $operator, $timezone);

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Mime message

+	 *

+	 * @access	private

+	 * @return	string

+	 */

+	function _get_mime_message()

+	{

+		return "This is a multi-part message in MIME format.".$this->newline."Your email application may not support this format.";

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Validate Email Address

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	bool

+	 */

+	function validate_email($email)

+	{

+		if ( ! is_array($email))

+		{

+			$this->_set_error_message('email_must_be_array');

+			return FALSE;

+		}

+

+		foreach ($email as $val)

+		{

+			if ( ! $this->valid_email($val))

+			{

+				$this->_set_error_message('email_invalid_address', $val);

+				return FALSE;

+			}

+		}

+

+		return TRUE;

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Email Validation

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	bool

+	 */

+	function valid_email($address)

+	{

+		return ( ! preg_match("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix", $address)) ? FALSE : TRUE;

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Clean Extended Email Address: Joe Smith <joe@smith.com>

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	string

+	 */

+	function clean_email($email)

+	{

+		if ( ! is_array($email))

+		{

+			if (preg_match('/\<(.*)\>/', $email, $match))

+			{

+		   		return $match['1'];

+			}

+		   	else

+			{

+		   		return $email;

+			}

+		}

+

+		$clean_email = array();

+

+		foreach ($email as $addy)

+		{

+			if (preg_match( '/\<(.*)\>/', $addy, $match))

+			{

+		   		$clean_email[] = $match['1'];

+			}

+		   	else

+			{

+		   		$clean_email[] = $addy;

+			}

+		}

+

+		return $clean_email;

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Build alternative plain text message

+	 *

+	 * This function provides the raw message for use

+	 * in plain-text headers of HTML-formatted emails.

+	 * If the user hasn't specified his own alternative message

+	 * it creates one by stripping the HTML

+	 *

+	 * @access	private

+	 * @return	string

+	 */

+	function _get_alt_message()

+	{

+		if ($this->alt_message != "")

+		{

+			return $this->word_wrap($this->alt_message, '76');

+		}

+

+		if (preg_match('/\<body.*?\>(.*)\<\/body\>/si', $this->_body, $match))

+		{

+			$body = $match['1'];

+		}

+		else

+		{

+			$body = $this->_body;

+		}

+

+		$body = trim(strip_tags($body));

+		$body = preg_replace( '#<!--(.*)--\>#', "", $body);

+		$body = str_replace("\t", "", $body);

+

+		for ($i = 20; $i >= 3; $i--)

+		{

+			$n = "";

+

+			for ($x = 1; $x <= $i; $x ++)

+			{

+				 $n .= "\n";

+			}

+

+			$body = str_replace($n, "\n\n", $body);

+		}

+

+		return $this->word_wrap($body, '76');

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Word Wrap

+	 *

+	 * @access	public

+	 * @param	string

+	 * @param	integer

+	 * @return	string

+	 */

+	function word_wrap($str, $charlim = '')

+	{

+		// Se the character limit

+		if ($charlim == '')

+		{

+			$charlim = ($this->wrapchars == "") ? "76" : $this->wrapchars;

+		}

+

+		// Reduce multiple spaces

+		$str = preg_replace("| +|", " ", $str);

+

+		// Standardize newlines

+		if (strpos($str, "\r") !== FALSE)

+		{

+			$str = str_replace(array("\r\n", "\r"), "\n", $str);

+		}

+

+		// If the current word is surrounded by {unwrap} tags we'll

+		// strip the entire chunk and replace it with a marker.

+		$unwrap = array();

+		if (preg_match_all("|(\{unwrap\}.+?\{/unwrap\})|s", $str, $matches))

+		{

+			for ($i = 0; $i < count($matches['0']); $i++)

+			{

+				$unwrap[] = $matches['1'][$i];

+				$str = str_replace($matches['1'][$i], "{{unwrapped".$i."}}", $str);

+			}

+		}

+

+		// Use PHP's native function to do the initial wordwrap.

+		// We set the cut flag to FALSE so that any individual words that are

+		// too long get left alone.  In the next step we'll deal with them.

+		$str = wordwrap($str, $charlim, "\n", FALSE);

+

+		// Split the string into individual lines of text and cycle through them

+		$output = "";

+		foreach (explode("\n", $str) as $line)

+		{

+			// Is the line within the allowed character count?

+			// If so we'll join it to the output and continue

+			if (strlen($line) <= $charlim)

+			{

+				$output .= $line.$this->newline;

+				continue;

+			}

+

+			$temp = '';

+			while((strlen($line)) > $charlim)

+			{

+				// If the over-length word is a URL we won't wrap it

+				if (preg_match("!\[url.+\]|://|wwww.!", $line))

+				{

+					break;

+				}

+

+				// Trim the word down

+				$temp .= substr($line, 0, $charlim-1);

+				$line = substr($line, $charlim-1);

+			}

+

+			// If $temp contains data it means we had to split up an over-length

+			// word into smaller chunks so we'll add it back to our current line

+			if ($temp != '')

+			{

+				$output .= $temp.$this->newline.$line;

+			}

+			else

+			{

+				$output .= $line;

+			}

+

+			$output .= $this->newline;

+		}

+

+		// Put our markers back

+		if (count($unwrap) > 0)

+		{

+			foreach ($unwrap as $key => $val)

+			{

+				$output = str_replace("{{unwrapped".$key."}}", $val, $output);

+			}

+		}

+

+		return $output;

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Build final headers

+	 *

+	 * @access	private

+	 * @param	string

+	 * @return	string

+	 */

+	function _build_headers()

+	{

+		$this->_set_header('X-Sender', $this->clean_email($this->_headers['From']));

+		$this->_set_header('X-Mailer', $this->useragent);

+		$this->_set_header('X-Priority', $this->_priorities[$this->priority - 1]);

+		$this->_set_header('Message-ID', $this->_get_message_id());

+		$this->_set_header('Mime-Version', '1.0');

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Write Headers as a string

+	 *

+	 * @access	private

+	 * @return	void

+	 */

+	function _write_headers()

+	{

+		if ($this->protocol == 'mail')

+		{

+			$this->_subject = $this->_headers['Subject'];

+			unset($this->_headers['Subject']);

+		}

+

+		reset($this->_headers);

+		$this->_header_str = "";

+

+		foreach($this->_headers as $key => $val)

+		{

+			$val = trim($val);

+

+			if ($val != "")

+			{

+				$this->_header_str .= $key.": ".$val.$this->newline;

+			}

+		}

+

+		if ($this->_get_protocol() == 'mail')

+		{

+			$this->_header_str = substr($this->_header_str, 0, -1);

+		}

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Build Final Body and attachments

+	 *

+	 * @access	private

+	 * @return	void

+	 */

+	function _build_message()

+	{

+		if ($this->wordwrap === TRUE  AND  $this->mailtype != 'html')

+		{

+			$this->_body = $this->word_wrap($this->_body);

+		}

+

+		$this->_set_boundaries();

+		$this->_write_headers();

+

+		$hdr = ($this->_get_protocol() == 'mail') ? $this->newline : '';

+

+		switch ($this->_get_content_type())

+		{

+			case 'plain' :

+

+				$hdr .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline;

+				$hdr .= "Content-Transfer-Encoding: " . $this->_get_encoding();

+

+				if ($this->_get_protocol() == 'mail')

+				{

+					$this->_header_str .= $hdr;

+					$this->_finalbody = $this->_body;

+

+					return;

+				}

+

+				$hdr .= $this->newline . $this->newline . $this->_body;

+

+				$this->_finalbody = $hdr;

+				return;

+

+			break;

+			case 'html' :

+

+				if ($this->send_multipart === FALSE)

+				{

+					$hdr .= "Content-Type: text/html; charset=" . $this->charset . $this->newline;

+					$hdr .= "Content-Transfer-Encoding: quoted-printable";

+				}

+				else

+				{

+					$hdr .= "Content-Type: multipart/alternative; boundary=\"" . $this->_alt_boundary . "\"" . $this->newline;

+					$hdr .= $this->_get_mime_message() . $this->newline . $this->newline;

+					$hdr .= "--" . $this->_alt_boundary . $this->newline;

+

+					$hdr .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline;

+					$hdr .= "Content-Transfer-Encoding: " . $this->_get_encoding() . $this->newline . $this->newline;

+					$hdr .= $this->_get_alt_message() . $this->newline . $this->newline . "--" . $this->_alt_boundary . $this->newline;

+

+					$hdr .= "Content-Type: text/html; charset=" . $this->charset . $this->newline;

+					$hdr .= "Content-Transfer-Encoding: quoted-printable";

+				}

+

+				$this->_body = $this->_prep_quoted_printable($this->_body);

+

+				if ($this->_get_protocol() == 'mail')

+				{

+					$this->_header_str .= $hdr;

+					$this->_finalbody = $this->_body . $this->newline . $this->newline;

+

+					if ($this->send_multipart !== FALSE)

+					{

+						$this->_finalbody .= "--" . $this->_alt_boundary . "--";

+					}

+

+					return;

+				}

+

+				$hdr .= $this->newline . $this->newline;

+				$hdr .= $this->_body . $this->newline . $this->newline;

+

+				if ($this->send_multipart !== FALSE)

+				{

+					$hdr .= "--" . $this->_alt_boundary . "--";

+				}

+

+				$this->_finalbody = $hdr;

+				return;

+

+			break;

+			case 'plain-attach' :

+

+				$hdr .= "Content-Type: multipart/".$this->multipart."; boundary=\"" . $this->_atc_boundary."\"" . $this->newline;

+				$hdr .= $this->_get_mime_message() . $this->newline . $this->newline;

+				$hdr .= "--" . $this->_atc_boundary . $this->newline;

+

+				$hdr .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline;

+				$hdr .= "Content-Transfer-Encoding: " . $this->_get_encoding();

+

+				if ($this->_get_protocol() == 'mail')

+				{

+					$this->_header_str .= $hdr;

+

+					$body  = $this->_body . $this->newline . $this->newline;

+				}

+

+				$hdr .= $this->newline . $this->newline;

+				$hdr .= $this->_body . $this->newline . $this->newline;

+

+			break;

+			case 'html-attach' :

+

+				$hdr .= "Content-Type: multipart/".$this->multipart."; boundary=\"" . $this->_atc_boundary."\"" . $this->newline;

+				$hdr .= $this->_get_mime_message() . $this->newline . $this->newline;

+				$hdr .= "--" . $this->_atc_boundary . $this->newline;

+

+				$hdr .= "Content-Type: multipart/alternative; boundary=\"" . $this->_alt_boundary . "\"" . $this->newline .$this->newline;

+				$hdr .= "--" . $this->_alt_boundary . $this->newline;

+

+				$hdr .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline;

+				$hdr .= "Content-Transfer-Encoding: " . $this->_get_encoding() . $this->newline . $this->newline;

+				$hdr .= $this->_get_alt_message() . $this->newline . $this->newline . "--" . $this->_alt_boundary . $this->newline;

+

+				$hdr .= "Content-Type: text/html; charset=" . $this->charset . $this->newline;

+				$hdr .= "Content-Transfer-Encoding: quoted-printable";

+

+				$this->_body = $this->_prep_quoted_printable($this->_body);

+

+				if ($this->_get_protocol() == 'mail')

+				{

+					$this->_header_str .= $hdr;

+

+					$body  = $this->_body . $this->newline . $this->newline;

+					$body .= "--" . $this->_alt_boundary . "--" . $this->newline . $this->newline;

+				}

+

+				$hdr .= $this->newline . $this->newline;

+				$hdr .= $this->_body . $this->newline . $this->newline;

+				$hdr .= "--" . $this->_alt_boundary . "--" . $this->newline . $this->newline;

+

+			break;

+		}

+

+		$attachment = array();

+

+		$z = 0;

+

+		for ($i=0; $i < count($this->_attach_name); $i++)

+		{

+			$filename = $this->_attach_name[$i];

+			$basename = basename($filename);

+			$ctype = $this->_attach_type[$i];

+

+			if ( ! file_exists($filename))

+			{

+				$this->_set_error_message('email_attachment_missing', $filename);

+				return FALSE;

+			}

+

+			$h  = "--".$this->_atc_boundary.$this->newline;

+			$h .= "Content-type: ".$ctype."; ";

+			$h .= "name=\"".$basename."\"".$this->newline;

+			$h .= "Content-Disposition: ".$this->_attach_disp[$i].";".$this->newline;

+			$h .= "Content-Transfer-Encoding: base64".$this->newline;

+

+			$attachment[$z++] = $h;

+			$file = filesize($filename) +1;

+

+			if ( ! $fp = fopen($filename, FOPEN_READ))

+			{

+				$this->_set_error_message('email_attachment_unreadable', $filename);

+				return FALSE;

+			}

+

+			$attachment[$z++] = chunk_split(base64_encode(fread($fp, $file)));

+			fclose($fp);

+		}

+

+		if ($this->_get_protocol() == 'mail')

+		{

+			$this->_finalbody = $body . implode($this->newline, $attachment).$this->newline."--".$this->_atc_boundary."--";

+

+			return;

+		}

+

+		$this->_finalbody = $hdr.implode($this->newline, $attachment).$this->newline."--".$this->_atc_boundary."--";

+

+		return;

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Prep Quoted Printable

+	 *

+	 * Prepares string for Quoted-Printable Content-Transfer-Encoding

+	 * Refer to RFC 2045 http://www.ietf.org/rfc/rfc2045.txt

+	 *

+	 * @access	private

+	 * @param	string

+	 * @param	integer

+	 * @return	string

+	 */

+	function _prep_quoted_printable($str, $charlim = '')

+	{

+		// Set the character limit

+		// Don't allow over 76, as that will make servers and MUAs barf

+		// all over quoted-printable data

+		if ($charlim == '' OR $charlim > '76')

+		{

+			$charlim = '76';

+		}

+

+		// Reduce multiple spaces

+		$str = preg_replace("| +|", " ", $str);

+

+		// kill nulls

+		$str = preg_replace('/\x00+/', '', $str);

+

+		// Standardize newlines

+		if (strpos($str, "\r") !== FALSE)

+		{

+			$str = str_replace(array("\r\n", "\r"), "\n", $str);

+		}

+

+		// We are intentionally wrapping so mail servers will encode characters

+		// properly and MUAs will behave, so {unwrap} must go!

+		$str = str_replace(array('{unwrap}', '{/unwrap}'), '', $str);

+

+		// Break into an array of lines

+		$lines = explode("\n", $str);

+

+		$escape = '=';

+		$output = '';

+

+		foreach ($lines as $line)

+		{

+			$length = strlen($line);

+			$temp = '';

+

+			// Loop through each character in the line to add soft-wrap

+			// characters at the end of a line " =\r\n" and add the newly

+			// processed line(s) to the output (see comment on $crlf class property)

+			for ($i = 0; $i < $length; $i++)

+			{

+				// Grab the next character

+				$char = substr($line, $i, 1);

+				$ascii = ord($char);

+

+				// Convert spaces and tabs but only if it's the end of the line

+				if ($i == ($length - 1))

+				{

+					$char = ($ascii == '32' OR $ascii == '9') ? $escape.sprintf('%02s', dechex($ascii)) : $char;

+				}

+

+				// encode = signs

+				if ($ascii == '61')

+				{

+					$char = $escape.strtoupper(sprintf('%02s', dechex($ascii)));  // =3D

+				}

+

+				// If we're at the character limit, add the line to the output,

+				// reset our temp variable, and keep on chuggin'

+				if ((strlen($temp) + strlen($char)) >= $charlim)

+				{

+					$output .= $temp.$escape.$this->crlf;

+					$temp = '';

+				}

+

+				// Add the character to our temporary line

+				$temp .= $char;

+			}

+

+			// Add our completed line to the output

+			$output .= $temp.$this->crlf;

+		}

+

+		// get rid of extra CRLF tacked onto the end

+		$output = substr($output, 0, strlen($this->crlf) * -1);

+

+		return $output;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Send Email

+	 *

+	 * @access	public

+	 * @return	bool

+	 */

+	function send()

+	{

+		if ($this->_replyto_flag == FALSE)

+		{

+			$this->reply_to($this->_headers['From']);

+		}

+

+		if (( ! isset($this->_recipients) AND ! isset($this->_headers['To']))  AND

+			( ! isset($this->_bcc_array) AND ! isset($this->_headers['Bcc'])) AND

+			( ! isset($this->_headers['Cc'])))

+		{

+			$this->_set_error_message('email_no_recipients');

+			return FALSE;

+		}

+

+		$this->_build_headers();

+

+		if ($this->bcc_batch_mode  AND  count($this->_bcc_array) > 0)

+		{

+			if (count($this->_bcc_array) > $this->bcc_batch_size)

+				return $this->batch_bcc_send();

+		}

+

+		$this->_build_message();

+

+		if ( ! $this->_spool_email())

+		{

+			return FALSE;

+		}

+		else

+		{

+			return TRUE;

+		}

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Batch Bcc Send.  Sends groups of BCCs in batches

+	 *

+	 * @access	public

+	 * @return	bool

+	 */

+	function batch_bcc_send()

+	{

+		$float = $this->bcc_batch_size -1;

+

+		$set = "";

+

+		$chunk = array();

+

+		for ($i = 0; $i < count($this->_bcc_array); $i++)

+		{

+			if (isset($this->_bcc_array[$i]))

+			{

+				$set .= ", ".$this->_bcc_array[$i];

+			}

+

+			if ($i == $float)

+			{

+				$chunk[] = substr($set, 1);

+				$float = $float + $this->bcc_batch_size;

+				$set = "";

+			}

+

+			if ($i == count($this->_bcc_array)-1)

+			{

+				$chunk[] = substr($set, 1);

+			}

+		}

+

+		for ($i = 0; $i < count($chunk); $i++)

+		{

+			unset($this->_headers['Bcc']);

+			unset($bcc);

+

+			$bcc = $this->_str_to_array($chunk[$i]);

+			$bcc = $this->clean_email($bcc);

+

+			if ($this->protocol != 'smtp')

+			{

+				$this->_set_header('Bcc', implode(", ", $bcc));

+			}

+			else

+			{

+				$this->_bcc_array = $bcc;

+			}

+

+			$this->_build_message();

+			$this->_spool_email();

+		}

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Unwrap special elements

+	 *

+	 * @access	private

+	 * @return	void

+	 */

+	function _unwrap_specials()

+	{

+		$this->_finalbody = preg_replace_callback("/\{unwrap\}(.*?)\{\/unwrap\}/si", array($this, '_remove_nl_callback'), $this->_finalbody);

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Strip line-breaks via callback

+	 *

+	 * @access	private

+	 * @return	string

+	 */

+	function _remove_nl_callback($matches)

+	{

+		if (strpos($matches[1], "\r") !== FALSE OR strpos($matches[1], "\n") !== FALSE)

+		{

+			$matches[1] = str_replace(array("\r\n", "\r", "\n"), '', $matches[1]);

+		}

+

+		return $matches[1];

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Spool mail to the mail server

+	 *

+	 * @access	private

+	 * @return	bool

+	 */

+	function _spool_email()

+	{

+		$this->_unwrap_specials();

+

+		switch ($this->_get_protocol())

+		{

+			case 'mail'	:

+

+					if ( ! $this->_send_with_mail())

+					{

+						$this->_set_error_message('email_send_failure_phpmail');

+						return FALSE;

+					}

+			break;

+			case 'sendmail'	:

+

+					if ( ! $this->_send_with_sendmail())

+					{

+						$this->_set_error_message('email_send_failure_sendmail');

+						return FALSE;

+					}

+			break;

+			case 'smtp'	:

+

+					if ( ! $this->_send_with_smtp())

+					{

+						$this->_set_error_message('email_send_failure_smtp');

+						return FALSE;

+					}

+			break;

+

+		}

+

+		$this->_set_error_message('email_sent', $this->_get_protocol());

+		return TRUE;

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Send using mail()

+	 *

+	 * @access	private

+	 * @return	bool

+	 */

+	function _send_with_mail()

+	{

+		if ($this->_safe_mode == TRUE)

+		{

+			if ( ! mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str))

+			{

+				return FALSE;

+			}

+			else

+			{

+				return TRUE;

+			}

+		}

+		else

+		{

+			// most documentation of sendmail using the "-f" flag lacks a space after it, however

+			// we've encountered servers that seem to require it to be in place.

+			if ( ! mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str, "-f ".$this->clean_email($this->_headers['From'])))

+			{

+				return FALSE;

+			}

+			else

+			{

+				return TRUE;

+			}

+		}

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Send using Sendmail

+	 *

+	 * @access	private

+	 * @return	bool

+	 */

+	function _send_with_sendmail()

+	{

+		$fp = @popen($this->mailpath . " -oi -f ".$this->clean_email($this->_headers['From'])." -t", 'w');

+

+		if ( ! is_resource($fp))

+		{

+			$this->_set_error_message('email_no_socket');

+			return FALSE;

+		}

+

+		fputs($fp, $this->_header_str);

+		fputs($fp, $this->_finalbody);

+		pclose($fp) >> 8 & 0xFF;

+

+		return TRUE;

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Send using SMTP

+	 *

+	 * @access	private

+	 * @return	bool

+	 */

+	function _send_with_smtp()

+	{

+		if ($this->smtp_host == '')

+		{

+			$this->_set_error_message('email_no_hostname');

+			return FALSE;

+		}

+

+		$this->_smtp_connect();

+		$this->_smtp_authenticate();

+

+		$this->_send_command('from', $this->clean_email($this->_headers['From']));

+

+		foreach($this->_recipients as $val)

+		{

+			$this->_send_command('to', $val);

+		}

+

+		if (count($this->_cc_array) > 0)

+		{

+			foreach($this->_cc_array as $val)

+			{

+				if ($val != "")

+				{

+					$this->_send_command('to', $val);

+				}

+			}

+		}

+

+		if (count($this->_bcc_array) > 0)

+		{

+			foreach($this->_bcc_array as $val)

+			{

+				if ($val != "")

+				{

+					$this->_send_command('to', $val);

+				}

+			}

+		}

+

+		$this->_send_command('data');

+

+		// perform dot transformation on any lines that begin with a dot

+		$this->_send_data($this->_header_str . preg_replace('/^\./m', '..$1', $this->_finalbody));

+

+		$this->_send_data('.');

+

+		$reply = $this->_get_smtp_data();

+

+		$this->_set_error_message($reply);

+

+		if (strncmp($reply, '250', 3) != 0)

+		{

+			$this->_set_error_message('email_smtp_error', $reply);

+			return FALSE;

+		}

+

+		$this->_send_command('quit');

+		return TRUE;

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * SMTP Connect

+	 *

+	 * @access	private

+	 * @param	string

+	 * @return	string

+	 */

+	function _smtp_connect()

+	{

+		$this->_smtp_connect = fsockopen($this->smtp_host,

+										$this->smtp_port,

+										$errno,

+										$errstr,

+										$this->smtp_timeout);

+

+		if( ! is_resource($this->_smtp_connect))

+		{

+			$this->_set_error_message('email_smtp_error', $errno." ".$errstr);

+			return FALSE;

+		}

+

+		$this->_set_error_message($this->_get_smtp_data());

+		return $this->_send_command('hello');

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Send SMTP command

+	 *

+	 * @access	private

+	 * @param	string

+	 * @param	string

+	 * @return	string

+	 */

+	function _send_command($cmd, $data = '')

+	{

+		switch ($cmd)

+		{

+			case 'hello' :

+

+					if ($this->_smtp_auth OR $this->_get_encoding() == '8bit')

+						$this->_send_data('EHLO '.$this->_get_hostname());

+					else

+						$this->_send_data('HELO '.$this->_get_hostname());

+

+						$resp = 250;

+			break;

+			case 'from' :

+

+						$this->_send_data('MAIL FROM:<'.$data.'>');

+

+						$resp = 250;

+			break;

+			case 'to'	:

+

+						$this->_send_data('RCPT TO:<'.$data.'>');

+

+						$resp = 250;

+			break;

+			case 'data'	:

+

+						$this->_send_data('DATA');

+

+						$resp = 354;

+			break;

+			case 'quit'	:

+

+						$this->_send_data('QUIT');

+

+						$resp = 221;

+			break;

+		}

+

+		$reply = $this->_get_smtp_data();

+

+		$this->_debug_msg[] = "<pre>".$cmd.": ".$reply."</pre>";

+

+		if (substr($reply, 0, 3) != $resp)

+		{

+			$this->_set_error_message('email_smtp_error', $reply);

+			return FALSE;

+		}

+

+		if ($cmd == 'quit')

+		{

+			fclose($this->_smtp_connect);

+		}

+

+		return TRUE;

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 *  SMTP Authenticate

+	 *

+	 * @access	private

+	 * @return	bool

+	 */

+	function _smtp_authenticate()

+	{

+		if ( ! $this->_smtp_auth)

+		{

+			return TRUE;

+		}

+

+		if ($this->smtp_user == ""  AND  $this->smtp_pass == "")

+		{

+			$this->_set_error_message('email_no_smtp_unpw');

+			return FALSE;

+		}

+

+		$this->_send_data('AUTH LOGIN');

+

+		$reply = $this->_get_smtp_data();

+

+		if (strncmp($reply, '334', 3) != 0)

+		{

+			$this->_set_error_message('email_failed_smtp_login', $reply);

+			return FALSE;

+		}

+

+		$this->_send_data(base64_encode($this->smtp_user));

+

+		$reply = $this->_get_smtp_data();

+

+		if (strncmp($reply, '334', 3) != 0)

+		{

+			$this->_set_error_message('email_smtp_auth_un', $reply);

+			return FALSE;

+		}

+

+		$this->_send_data(base64_encode($this->smtp_pass));

+

+		$reply = $this->_get_smtp_data();

+

+		if (strncmp($reply, '235', 3) != 0)

+		{

+			$this->_set_error_message('email_smtp_auth_pw', $reply);

+			return FALSE;

+		}

+

+		return TRUE;

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Send SMTP data

+	 *

+	 * @access	private

+	 * @return	bool

+	 */

+	function _send_data($data)

+	{

+		if ( ! fwrite($this->_smtp_connect, $data . $this->newline))

+		{

+			$this->_set_error_message('email_smtp_data_failure', $data);

+			return FALSE;

+		}

+		else

+		{

+			return TRUE;

+		}

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Get SMTP data

+	 *

+	 * @access	private

+	 * @return	string

+	 */

+	function _get_smtp_data()

+	{

+		$data = "";

+

+		while ($str = fgets($this->_smtp_connect, 512))

+		{

+			$data .= $str;

+

+			if (substr($str, 3, 1) == " ")

+			{

+				break;

+			}

+		}

+

+		return $data;

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Get Hostname

+	 *

+	 * @access	private

+	 * @return	string

+	 */

+	function _get_hostname()

+	{

+		return (isset($_SERVER['SERVER_NAME'])) ? $_SERVER['SERVER_NAME'] : 'localhost.localdomain';

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Get IP

+	 *

+	 * @access	private

+	 * @return	string

+	 */

+	function _get_ip()

+	{

+		if ($this->_IP !== FALSE)

+		{

+			return $this->_IP;

+		}

+

+		$cip = (isset($_SERVER['HTTP_CLIENT_IP']) AND $_SERVER['HTTP_CLIENT_IP'] != "") ? $_SERVER['HTTP_CLIENT_IP'] : FALSE;

+		$rip = (isset($_SERVER['REMOTE_ADDR']) AND $_SERVER['REMOTE_ADDR'] != "") ? $_SERVER['REMOTE_ADDR'] : FALSE;

+		$fip = (isset($_SERVER['HTTP_X_FORWARDED_FOR']) AND $_SERVER['HTTP_X_FORWARDED_FOR'] != "") ? $_SERVER['HTTP_X_FORWARDED_FOR'] : FALSE;

+

+		if ($cip && $rip) 	$this->_IP = $cip;

+		elseif ($rip)		$this->_IP = $rip;

+		elseif ($cip)		$this->_IP = $cip;

+		elseif ($fip)		$this->_IP = $fip;

+

+		if (strstr($this->_IP, ','))

+		{

+			$x = explode(',', $this->_IP);

+			$this->_IP = end($x);

+		}

+

+		if ( ! preg_match( "/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/", $this->_IP))

+		{

+			$this->_IP = '0.0.0.0';

+		}

+

+		unset($cip);

+		unset($rip);

+		unset($fip);

+

+		return $this->_IP;

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Get Debug Message

+	 *

+	 * @access	public

+	 * @return	string

+	 */

+	function print_debugger()

+	{

+		$msg = '';

+

+		if (count($this->_debug_msg) > 0)

+		{

+			foreach ($this->_debug_msg as $val)

+			{

+				$msg .= $val;

+			}

+		}

+

+		$msg .= "<pre>".$this->_header_str."\n".htmlspecialchars($this->_subject)."\n".htmlspecialchars($this->_finalbody).'</pre>';

+		return $msg;

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Set Message

+	 *

+	 * @access	private

+	 * @param	string

+	 * @return	string

+	 */

+	function _set_error_message($msg, $val = '')

+	{

+		$CI =& get_instance();

+		$CI->lang->load('email');

+

+		if (FALSE === ($line = $CI->lang->line($msg)))

+		{

+			$this->_debug_msg[] = str_replace('%s', $val, $msg)."<br />";

+		}

+		else

+		{

+			$this->_debug_msg[] = str_replace('%s', $val, $line)."<br />";

+		}

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Mime Types

+	 *

+	 * @access	private

+	 * @param	string

+	 * @return	string

+	 */

+	function _mime_types($ext = "")

+	{

+		$mimes = array(	'hqx'	=>	'application/mac-binhex40',

+						'cpt'	=>	'application/mac-compactpro',

+						'doc'	=>	'application/msword',

+						'bin'	=>	'application/macbinary',

+						'dms'	=>	'application/octet-stream',

+						'lha'	=>	'application/octet-stream',

+						'lzh'	=>	'application/octet-stream',

+						'exe'	=>	'application/octet-stream',

+						'class'	=>	'application/octet-stream',

+						'psd'	=>	'application/octet-stream',

+						'so'	=>	'application/octet-stream',

+						'sea'	=>	'application/octet-stream',

+						'dll'	=>	'application/octet-stream',

+						'oda'	=>	'application/oda',

+						'pdf'	=>	'application/pdf',

+						'ai'	=>	'application/postscript',

+						'eps'	=>	'application/postscript',

+						'ps'	=>	'application/postscript',

+						'smi'	=>	'application/smil',

+						'smil'	=>	'application/smil',

+						'mif'	=>	'application/vnd.mif',

+						'xls'	=>	'application/vnd.ms-excel',

+						'ppt'	=>	'application/vnd.ms-powerpoint',

+						'wbxml'	=>	'application/vnd.wap.wbxml',

+						'wmlc'	=>	'application/vnd.wap.wmlc',

+						'dcr'	=>	'application/x-director',

+						'dir'	=>	'application/x-director',

+						'dxr'	=>	'application/x-director',

+						'dvi'	=>	'application/x-dvi',

+						'gtar'	=>	'application/x-gtar',

+						'php'	=>	'application/x-httpd-php',

+						'php4'	=>	'application/x-httpd-php',

+						'php3'	=>	'application/x-httpd-php',

+						'phtml'	=>	'application/x-httpd-php',

+						'phps'	=>	'application/x-httpd-php-source',

+						'js'	=>	'application/x-javascript',

+						'swf'	=>	'application/x-shockwave-flash',

+						'sit'	=>	'application/x-stuffit',

+						'tar'	=>	'application/x-tar',

+						'tgz'	=>	'application/x-tar',

+						'xhtml'	=>	'application/xhtml+xml',

+						'xht'	=>	'application/xhtml+xml',

+						'zip'	=>	'application/zip',

+						'mid'	=>	'audio/midi',

+						'midi'	=>	'audio/midi',

+						'mpga'	=>	'audio/mpeg',

+						'mp2'	=>	'audio/mpeg',

+						'mp3'	=>	'audio/mpeg',

+						'aif'	=>	'audio/x-aiff',

+						'aiff'	=>	'audio/x-aiff',

+						'aifc'	=>	'audio/x-aiff',

+						'ram'	=>	'audio/x-pn-realaudio',

+						'rm'	=>	'audio/x-pn-realaudio',

+						'rpm'	=>	'audio/x-pn-realaudio-plugin',

+						'ra'	=>	'audio/x-realaudio',

+						'rv'	=>	'video/vnd.rn-realvideo',

+						'wav'	=>	'audio/x-wav',

+						'bmp'	=>	'image/bmp',

+						'gif'	=>	'image/gif',

+						'jpeg'	=>	'image/jpeg',

+						'jpg'	=>	'image/jpeg',

+						'jpe'	=>	'image/jpeg',

+						'png'	=>	'image/png',

+						'tiff'	=>	'image/tiff',

+						'tif'	=>	'image/tiff',

+						'css'	=>	'text/css',

+						'html'	=>	'text/html',

+						'htm'	=>	'text/html',

+						'shtml'	=>	'text/html',

+						'txt'	=>	'text/plain',

+						'text'	=>	'text/plain',

+						'log'	=>	'text/plain',

+						'rtx'	=>	'text/richtext',

+						'rtf'	=>	'text/rtf',

+						'xml'	=>	'text/xml',

+						'xsl'	=>	'text/xml',

+						'mpeg'	=>	'video/mpeg',

+						'mpg'	=>	'video/mpeg',

+						'mpe'	=>	'video/mpeg',

+						'qt'	=>	'video/quicktime',

+						'mov'	=>	'video/quicktime',

+						'avi'	=>	'video/x-msvideo',

+						'movie'	=>	'video/x-sgi-movie',

+						'doc'	=>	'application/msword',

+						'word'	=>	'application/msword',

+						'xl'	=>	'application/excel',

+						'eml'	=>	'message/rfc822'

+					);

+

+		return ( ! isset($mimes[strtolower($ext)])) ? "application/x-unknown-content-type" : $mimes[strtolower($ext)];

+	}

+

+}

+// END CI_Email class

+

+/* End of file Email.php */

 /* Location: ./system/libraries/Email.php */
\ No newline at end of file
diff --git a/system/libraries/Ftp.php b/system/libraries/Ftp.php
index ec84eb0..1a3ab18 100644
--- a/system/libraries/Ftp.php
+++ b/system/libraries/Ftp.php
@@ -1,618 +1,618 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
-/**
- * CodeIgniter
- *
- * An open source application development framework for PHP 4.3.2 or newer
- *
- * @package		CodeIgniter
- * @author		ExpressionEngine Dev Team
- * @copyright	Copyright (c) 2008, EllisLab, Inc.
- * @license		http://codeigniter.com/user_guide/license.html
- * @link		http://codeigniter.com
- * @since		Version 1.0
- * @filesource
- */
-
-// ------------------------------------------------------------------------
-
-/**
- * FTP Class
- *
- * @package		CodeIgniter
- * @subpackage	Libraries
- * @category	Libraries
- * @author		ExpressionEngine Dev Team
- * @link		http://codeigniter.com/user_guide/libraries/ftp.html
- */
-class CI_FTP {
-
-	var $hostname	= '';
-	var $username	= '';
-	var $password	= '';
-	var $port		= 21;
-	var $passive	= TRUE;
-	var $debug		= FALSE;
-	var $conn_id	= FALSE;
-
-
-	/**
-	 * Constructor - Sets Preferences
-	 *
-	 * The constructor can be passed an array of config values
-	 */
-	function CI_FTP($config = array())
-	{
-		if (count($config) > 0)
-		{
-			$this->initialize($config);
-		}
-
-		log_message('debug', "FTP Class Initialized");
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Initialize preferences
-	 *
-	 * @access	public
-	 * @param	array
-	 * @return	void
-	 */
-	function initialize($config = array())
-	{
-		foreach ($config as $key => $val)
-		{
-			if (isset($this->$key))
-			{
-				$this->$key = $val;
-			}
-		}
-
-		// Prep the hostname
-		$this->hostname = preg_replace('|.+?://|', '', $this->hostname);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * FTP Connect
-	 *
-	 * @access	public
-	 * @param	array	 the connection values
-	 * @return	bool
-	 */
-	function connect($config = array())
-	{
-		if (count($config) > 0)
-		{
-			$this->initialize($config);
-		}
-
-		if (FALSE === ($this->conn_id = @ftp_connect($this->hostname, $this->port)))
-		{
-			if ($this->debug == TRUE)
-			{
-				$this->_error('ftp_unable_to_connect');
-			}
-			return FALSE;
-		}
-
-		if ( ! $this->_login())
-		{
-			if ($this->debug == TRUE)
-			{
-				$this->_error('ftp_unable_to_login');
-			}
-			return FALSE;
-		}
-
-		// Set passive mode if needed
-		if ($this->passive == TRUE)
-		{
-			ftp_pasv($this->conn_id, TRUE);
-		}
-
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * FTP Login
-	 *
-	 * @access	private
-	 * @return	bool
-	 */
-	function _login()
-	{
-		return @ftp_login($this->conn_id, $this->username, $this->password);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Validates the connection ID
-	 *
-	 * @access	private
-	 * @return	bool
-	 */
-	function _is_conn()
-	{
-		if ( ! is_resource($this->conn_id))
-		{
-			if ($this->debug == TRUE)
-			{
-				$this->_error('ftp_no_connection');
-			}
-			return FALSE;
-		}
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-
-	/**
-	 * Change direcotry
-	 *
-	 * The second parameter lets us momentarily turn off debugging so that
-	 * this function can be used to test for the existance of a folder
-	 * without throwing an error.  There's no FTP equivalent to is_dir()
-	 * so we do it by trying to change to a particular directory.
-	 * Internally, this paramter is only used by the "mirror" function below.
-	 *
-	 * @access	public
-	 * @param	string
-	 * @param	bool
-	 * @return	bool
-	 */
-	function changedir($path = '', $supress_debug = FALSE)
-	{
-		if ($path == '' OR ! $this->_is_conn())
-		{
-			return FALSE;
-		}
-
-		$result = @ftp_chdir($this->conn_id, $path);
-
-		if ($result === FALSE)
-		{
-			if ($this->debug == TRUE AND $supress_debug == FALSE)
-			{
-				$this->_error('ftp_unable_to_changedir');
-			}
-			return FALSE;
-		}
-
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Create a directory
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	bool
-	 */
-	function mkdir($path = '', $permissions = NULL)
-	{
-		if ($path == '' OR ! $this->_is_conn())
-		{
-			return FALSE;
-		}
-
-		$result = @ftp_mkdir($this->conn_id, $path);
-
-		if ($result === FALSE)
-		{
-			if ($this->debug == TRUE)
-			{
-				$this->_error('ftp_unable_to_makdir');
-			}
-			return FALSE;
-		}
-
-		// Set file permissions if needed
-		if ( ! is_null($permissions))
-		{
-			$this->chmod($path, (int)$permissions);
-		}
-
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Upload a file to the server
-	 *
-	 * @access	public
-	 * @param	string
-	 * @param	string
-	 * @param	string
-	 * @return	bool
-	 */
-	function upload($locpath, $rempath, $mode = 'auto', $permissions = NULL)
-	{
-		if ( ! $this->_is_conn())
-		{
-			return FALSE;
-		}
-
-		if ( ! file_exists($locpath))
-		{
-			$this->_error('ftp_no_source_file');
-			return FALSE;
-		}
-
-		// Set the mode if not specified
-		if ($mode == 'auto')
-		{
-			// Get the file extension so we can set the upload type
-			$ext = $this->_getext($locpath);
-			$mode = $this->_settype($ext);
-		}
-
-		$mode = ($mode == 'ascii') ? FTP_ASCII : FTP_BINARY;
-
-		$result = @ftp_put($this->conn_id, $rempath, $locpath, $mode);
-
-		if ($result === FALSE)
-		{
-			if ($this->debug == TRUE)
-			{
-				$this->_error('ftp_unable_to_upload');
-			}
-			return FALSE;
-		}
-
-		// Set file permissions if needed
-		if ( ! is_null($permissions))
-		{
-			$this->chmod($rempath, (int)$permissions);
-		}
-
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Rename (or move) a file
-	 *
-	 * @access	public
-	 * @param	string
-	 * @param	string
-	 * @param	bool
-	 * @return	bool
-	 */
-	function rename($old_file, $new_file, $move = FALSE)
-	{
-		if ( ! $this->_is_conn())
-		{
-			return FALSE;
-		}
-
-		$result = @ftp_rename($this->conn_id, $old_file, $new_file);
-
-		if ($result === FALSE)
-		{
-			if ($this->debug == TRUE)
-			{
-				$msg = ($move == FALSE) ? 'ftp_unable_to_rename' : 'ftp_unable_to_move';
-
-				$this->_error($msg);
-			}
-			return FALSE;
-		}
-
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Move a file
-	 *
-	 * @access	public
-	 * @param	string
-	 * @param	string
-	 * @return	bool
-	 */
-	function move($old_file, $new_file)
-	{
-		return $this->rename($old_file, $new_file, TRUE);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Rename (or move) a file
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	bool
-	 */
-	function delete_file($filepath)
-	{
-		if ( ! $this->_is_conn())
-		{
-			return FALSE;
-		}
-
-		$result = @ftp_delete($this->conn_id, $filepath);
-
-		if ($result === FALSE)
-		{
-			if ($this->debug == TRUE)
-			{
-				$this->_error('ftp_unable_to_delete');
-			}
-			return FALSE;
-		}
-
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Delete a folder and recursively delete everything (including sub-folders)
-	 * containted within it.
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	bool
-	 */
-	function delete_dir($filepath)
-	{
-		if ( ! $this->_is_conn())
-		{
-			return FALSE;
-		}
-
-		// Add a trailing slash to the file path if needed
-		$filepath = preg_replace("/(.+?)\/*$/", "\\1/",  $filepath);
-
-		$list = $this->list_files($filepath);
-
-		if ($list !== FALSE AND count($list) > 0)
-		{
-			foreach ($list as $item)
-			{
-				// If we can't delete the item it's probaly a folder so
-				// we'll recursively call delete_dir()
-				if ( ! @ftp_delete($this->conn_id, $item))
-				{
-					$this->delete_dir($item);
-				}
-			}
-		}
-
-		$result = @ftp_rmdir($this->conn_id, $filepath);
-
-		if ($result === FALSE)
-		{
-			if ($this->debug == TRUE)
-			{
-				$this->_error('ftp_unable_to_delete');
-			}
-			return FALSE;
-		}
-
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Set file permissions
-	 *
-	 * @access	public
-	 * @param	string 	the file path
-	 * @param	string	the permissions
-	 * @return	bool
-	 */
-	function chmod($path, $perm)
-	{
-		if ( ! $this->_is_conn())
-		{
-			return FALSE;
-		}
-
-		// Permissions can only be set when running PHP 5
-		if ( ! function_exists('ftp_chmod'))
-		{
-			if ($this->debug == TRUE)
-			{
-				$this->_error('ftp_unable_to_chmod');
-			}
-			return FALSE;
-		}
-
-		$result = @ftp_chmod($this->conn_id, $perm, $path);
-
-		if ($result === FALSE)
-		{
-			if ($this->debug == TRUE)
-			{
-				$this->_error('ftp_unable_to_chmod');
-			}
-			return FALSE;
-		}
-
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * FTP List files in the specified directory
-	 *
-	 * @access	public
-	 * @return	array
-	 */
-	function list_files($path = '.')
-	{
-		if ( ! $this->_is_conn())
-		{
-			return FALSE;
-		}
-
-		return ftp_nlist($this->conn_id, $path);
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Read a directory and recreate it remotely
-	 *
-	 * This function recursively reads a folder and everything it contains (including
-	 * sub-folders) and creates a mirror via FTP based on it.  Whatever the directory structure
-	 * of the original file path will be recreated on the server.
-	 *
-	 * @access	public
-	 * @param	string	path to source with trailing slash
-	 * @param	string	path to destination - include the base folder with trailing slash
-	 * @return	bool
-	 */
-	function mirror($locpath, $rempath)
-	{
-		if ( ! $this->_is_conn())
-		{
-			return FALSE;
-		}
-
-		// Open the local file path
-		if ($fp = @opendir($locpath))
-		{
-			// Attempt to open the remote file path.
-			if ( ! $this->changedir($rempath, TRUE))
-			{
-				// If it doesn't exist we'll attempt to create the direcotory
-				if ( ! $this->mkdir($rempath) OR ! $this->changedir($rempath))
-				{
-					return FALSE;
-				}
-			}
-
-			// Recursively read the local directory
-			while (FALSE !== ($file = readdir($fp)))
-			{
-				if (@is_dir($locpath.$file) && substr($file, 0, 1) != '.')
-				{
-					$this->mirror($locpath.$file."/", $rempath.$file."/");
-				}
-				elseif (substr($file, 0, 1) != ".")
-				{
-					// Get the file extension so we can se the upload type
-					$ext = $this->_getext($file);
-					$mode = $this->_settype($ext);
-
-					$this->upload($locpath.$file, $rempath.$file, $mode);
-				}
-			}
-			return TRUE;
-		}
-
-		return FALSE;
-	}
-
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Extract the file extension
-	 *
-	 * @access	private
-	 * @param	string
-	 * @return	string
-	 */
-	function _getext($filename)
-	{
-		if (FALSE === strpos($filename, '.'))
-		{
-			return 'txt';
-		}
-
-		$x = explode('.', $filename);
-		return end($x);
-	}
-
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Set the upload type
-	 *
-	 * @access	private
-	 * @param	string
-	 * @return	string
-	 */
-	function _settype($ext)
-	{
-		$text_types = array(
-							'txt',
-							'text',
-							'php',
-							'phps',
-							'php4',
-							'js',
-							'css',
-							'htm',
-							'html',
-							'phtml',
-							'shtml',
-							'log',
-							'xml'
-							);
-
-
-		return (in_array($ext, $text_types)) ? 'ascii' : 'binary';
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Close the connection
-	 *
-	 * @access	public
-	 * @param	string	path to source
-	 * @param	string	path to destination
-	 * @return	bool
-	 */
-	function close()
-	{
-		if ( ! $this->_is_conn())
-		{
-			return FALSE;
-		}
-
-		@ftp_close($this->conn_id);
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Display error message
-	 *
-	 * @access	private
-	 * @param	string
-	 * @return	bool
-	 */
-	function _error($line)
-	{
-		$CI =& get_instance();
-		$CI->lang->load('ftp');
-		show_error($CI->lang->line($line));
-	}
-
-
-}
-// END FTP Class
-
-/* End of file Ftp.php */
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

+/**

+ * CodeIgniter

+ *

+ * An open source application development framework for PHP 4.3.2 or newer

+ *

+ * @package		CodeIgniter

+ * @author		ExpressionEngine Dev Team

+ * @copyright	Copyright (c) 2008, EllisLab, Inc.

+ * @license		http://codeigniter.com/user_guide/license.html

+ * @link		http://codeigniter.com

+ * @since		Version 1.0

+ * @filesource

+ */

+

+// ------------------------------------------------------------------------

+

+/**

+ * FTP Class

+ *

+ * @package		CodeIgniter

+ * @subpackage	Libraries

+ * @category	Libraries

+ * @author		ExpressionEngine Dev Team

+ * @link		http://codeigniter.com/user_guide/libraries/ftp.html

+ */

+class CI_FTP {

+

+	var $hostname	= '';

+	var $username	= '';

+	var $password	= '';

+	var $port		= 21;

+	var $passive	= TRUE;

+	var $debug		= FALSE;

+	var $conn_id	= FALSE;

+

+

+	/**

+	 * Constructor - Sets Preferences

+	 *

+	 * The constructor can be passed an array of config values

+	 */

+	function CI_FTP($config = array())

+	{

+		if (count($config) > 0)

+		{

+			$this->initialize($config);

+		}

+

+		log_message('debug', "FTP Class Initialized");

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Initialize preferences

+	 *

+	 * @access	public

+	 * @param	array

+	 * @return	void

+	 */

+	function initialize($config = array())

+	{

+		foreach ($config as $key => $val)

+		{

+			if (isset($this->$key))

+			{

+				$this->$key = $val;

+			}

+		}

+

+		// Prep the hostname

+		$this->hostname = preg_replace('|.+?://|', '', $this->hostname);

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * FTP Connect

+	 *

+	 * @access	public

+	 * @param	array	 the connection values

+	 * @return	bool

+	 */

+	function connect($config = array())

+	{

+		if (count($config) > 0)

+		{

+			$this->initialize($config);

+		}

+

+		if (FALSE === ($this->conn_id = @ftp_connect($this->hostname, $this->port)))

+		{

+			if ($this->debug == TRUE)

+			{

+				$this->_error('ftp_unable_to_connect');

+			}

+			return FALSE;

+		}

+

+		if ( ! $this->_login())

+		{

+			if ($this->debug == TRUE)

+			{

+				$this->_error('ftp_unable_to_login');

+			}

+			return FALSE;

+		}

+

+		// Set passive mode if needed

+		if ($this->passive == TRUE)

+		{

+			ftp_pasv($this->conn_id, TRUE);

+		}

+

+		return TRUE;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * FTP Login

+	 *

+	 * @access	private

+	 * @return	bool

+	 */

+	function _login()

+	{

+		return @ftp_login($this->conn_id, $this->username, $this->password);

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Validates the connection ID

+	 *

+	 * @access	private

+	 * @return	bool

+	 */

+	function _is_conn()

+	{

+		if ( ! is_resource($this->conn_id))

+		{

+			if ($this->debug == TRUE)

+			{

+				$this->_error('ftp_no_connection');

+			}

+			return FALSE;

+		}

+		return TRUE;

+	}

+

+	// --------------------------------------------------------------------

+

+

+	/**

+	 * Change direcotry

+	 *

+	 * The second parameter lets us momentarily turn off debugging so that

+	 * this function can be used to test for the existance of a folder

+	 * without throwing an error.  There's no FTP equivalent to is_dir()

+	 * so we do it by trying to change to a particular directory.

+	 * Internally, this paramter is only used by the "mirror" function below.

+	 *

+	 * @access	public

+	 * @param	string

+	 * @param	bool

+	 * @return	bool

+	 */

+	function changedir($path = '', $supress_debug = FALSE)

+	{

+		if ($path == '' OR ! $this->_is_conn())

+		{

+			return FALSE;

+		}

+

+		$result = @ftp_chdir($this->conn_id, $path);

+

+		if ($result === FALSE)

+		{

+			if ($this->debug == TRUE AND $supress_debug == FALSE)

+			{

+				$this->_error('ftp_unable_to_changedir');

+			}

+			return FALSE;

+		}

+

+		return TRUE;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Create a directory

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	bool

+	 */

+	function mkdir($path = '', $permissions = NULL)

+	{

+		if ($path == '' OR ! $this->_is_conn())

+		{

+			return FALSE;

+		}

+

+		$result = @ftp_mkdir($this->conn_id, $path);

+

+		if ($result === FALSE)

+		{

+			if ($this->debug == TRUE)

+			{

+				$this->_error('ftp_unable_to_makdir');

+			}

+			return FALSE;

+		}

+

+		// Set file permissions if needed

+		if ( ! is_null($permissions))

+		{

+			$this->chmod($path, (int)$permissions);

+		}

+

+		return TRUE;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Upload a file to the server

+	 *

+	 * @access	public

+	 * @param	string

+	 * @param	string

+	 * @param	string

+	 * @return	bool

+	 */

+	function upload($locpath, $rempath, $mode = 'auto', $permissions = NULL)

+	{

+		if ( ! $this->_is_conn())

+		{

+			return FALSE;

+		}

+

+		if ( ! file_exists($locpath))

+		{

+			$this->_error('ftp_no_source_file');

+			return FALSE;

+		}

+

+		// Set the mode if not specified

+		if ($mode == 'auto')

+		{

+			// Get the file extension so we can set the upload type

+			$ext = $this->_getext($locpath);

+			$mode = $this->_settype($ext);

+		}

+

+		$mode = ($mode == 'ascii') ? FTP_ASCII : FTP_BINARY;

+

+		$result = @ftp_put($this->conn_id, $rempath, $locpath, $mode);

+

+		if ($result === FALSE)

+		{

+			if ($this->debug == TRUE)

+			{

+				$this->_error('ftp_unable_to_upload');

+			}

+			return FALSE;

+		}

+

+		// Set file permissions if needed

+		if ( ! is_null($permissions))

+		{

+			$this->chmod($rempath, (int)$permissions);

+		}

+

+		return TRUE;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Rename (or move) a file

+	 *

+	 * @access	public

+	 * @param	string

+	 * @param	string

+	 * @param	bool

+	 * @return	bool

+	 */

+	function rename($old_file, $new_file, $move = FALSE)

+	{

+		if ( ! $this->_is_conn())

+		{

+			return FALSE;

+		}

+

+		$result = @ftp_rename($this->conn_id, $old_file, $new_file);

+

+		if ($result === FALSE)

+		{

+			if ($this->debug == TRUE)

+			{

+				$msg = ($move == FALSE) ? 'ftp_unable_to_rename' : 'ftp_unable_to_move';

+

+				$this->_error($msg);

+			}

+			return FALSE;

+		}

+

+		return TRUE;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Move a file

+	 *

+	 * @access	public

+	 * @param	string

+	 * @param	string

+	 * @return	bool

+	 */

+	function move($old_file, $new_file)

+	{

+		return $this->rename($old_file, $new_file, TRUE);

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Rename (or move) a file

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	bool

+	 */

+	function delete_file($filepath)

+	{

+		if ( ! $this->_is_conn())

+		{

+			return FALSE;

+		}

+

+		$result = @ftp_delete($this->conn_id, $filepath);

+

+		if ($result === FALSE)

+		{

+			if ($this->debug == TRUE)

+			{

+				$this->_error('ftp_unable_to_delete');

+			}

+			return FALSE;

+		}

+

+		return TRUE;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Delete a folder and recursively delete everything (including sub-folders)

+	 * containted within it.

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	bool

+	 */

+	function delete_dir($filepath)

+	{

+		if ( ! $this->_is_conn())

+		{

+			return FALSE;

+		}

+

+		// Add a trailing slash to the file path if needed

+		$filepath = preg_replace("/(.+?)\/*$/", "\\1/",  $filepath);

+

+		$list = $this->list_files($filepath);

+

+		if ($list !== FALSE AND count($list) > 0)

+		{

+			foreach ($list as $item)

+			{

+				// If we can't delete the item it's probaly a folder so

+				// we'll recursively call delete_dir()

+				if ( ! @ftp_delete($this->conn_id, $item))

+				{

+					$this->delete_dir($item);

+				}

+			}

+		}

+

+		$result = @ftp_rmdir($this->conn_id, $filepath);

+

+		if ($result === FALSE)

+		{

+			if ($this->debug == TRUE)

+			{

+				$this->_error('ftp_unable_to_delete');

+			}

+			return FALSE;

+		}

+

+		return TRUE;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Set file permissions

+	 *

+	 * @access	public

+	 * @param	string 	the file path

+	 * @param	string	the permissions

+	 * @return	bool

+	 */

+	function chmod($path, $perm)

+	{

+		if ( ! $this->_is_conn())

+		{

+			return FALSE;

+		}

+

+		// Permissions can only be set when running PHP 5

+		if ( ! function_exists('ftp_chmod'))

+		{

+			if ($this->debug == TRUE)

+			{

+				$this->_error('ftp_unable_to_chmod');

+			}

+			return FALSE;

+		}

+

+		$result = @ftp_chmod($this->conn_id, $perm, $path);

+

+		if ($result === FALSE)

+		{

+			if ($this->debug == TRUE)

+			{

+				$this->_error('ftp_unable_to_chmod');

+			}

+			return FALSE;

+		}

+

+		return TRUE;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * FTP List files in the specified directory

+	 *

+	 * @access	public

+	 * @return	array

+	 */

+	function list_files($path = '.')

+	{

+		if ( ! $this->_is_conn())

+		{

+			return FALSE;

+		}

+

+		return ftp_nlist($this->conn_id, $path);

+	}

+

+	// ------------------------------------------------------------------------

+

+	/**

+	 * Read a directory and recreate it remotely

+	 *

+	 * This function recursively reads a folder and everything it contains (including

+	 * sub-folders) and creates a mirror via FTP based on it.  Whatever the directory structure

+	 * of the original file path will be recreated on the server.

+	 *

+	 * @access	public

+	 * @param	string	path to source with trailing slash

+	 * @param	string	path to destination - include the base folder with trailing slash

+	 * @return	bool

+	 */

+	function mirror($locpath, $rempath)

+	{

+		if ( ! $this->_is_conn())

+		{

+			return FALSE;

+		}

+

+		// Open the local file path

+		if ($fp = @opendir($locpath))

+		{

+			// Attempt to open the remote file path.

+			if ( ! $this->changedir($rempath, TRUE))

+			{

+				// If it doesn't exist we'll attempt to create the direcotory

+				if ( ! $this->mkdir($rempath) OR ! $this->changedir($rempath))

+				{

+					return FALSE;

+				}

+			}

+

+			// Recursively read the local directory

+			while (FALSE !== ($file = readdir($fp)))

+			{

+				if (@is_dir($locpath.$file) && substr($file, 0, 1) != '.')

+				{

+					$this->mirror($locpath.$file."/", $rempath.$file."/");

+				}

+				elseif (substr($file, 0, 1) != ".")

+				{

+					// Get the file extension so we can se the upload type

+					$ext = $this->_getext($file);

+					$mode = $this->_settype($ext);

+

+					$this->upload($locpath.$file, $rempath.$file, $mode);

+				}

+			}

+			return TRUE;

+		}

+

+		return FALSE;

+	}

+

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Extract the file extension

+	 *

+	 * @access	private

+	 * @param	string

+	 * @return	string

+	 */

+	function _getext($filename)

+	{

+		if (FALSE === strpos($filename, '.'))

+		{

+			return 'txt';

+		}

+

+		$x = explode('.', $filename);

+		return end($x);

+	}

+

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Set the upload type

+	 *

+	 * @access	private

+	 * @param	string

+	 * @return	string

+	 */

+	function _settype($ext)

+	{

+		$text_types = array(

+							'txt',

+							'text',

+							'php',

+							'phps',

+							'php4',

+							'js',

+							'css',

+							'htm',

+							'html',

+							'phtml',

+							'shtml',

+							'log',

+							'xml'

+							);

+

+

+		return (in_array($ext, $text_types)) ? 'ascii' : 'binary';

+	}

+

+	// ------------------------------------------------------------------------

+

+	/**

+	 * Close the connection

+	 *

+	 * @access	public

+	 * @param	string	path to source

+	 * @param	string	path to destination

+	 * @return	bool

+	 */

+	function close()

+	{

+		if ( ! $this->_is_conn())

+		{

+			return FALSE;

+		}

+

+		@ftp_close($this->conn_id);

+	}

+

+	// ------------------------------------------------------------------------

+

+	/**

+	 * Display error message

+	 *

+	 * @access	private

+	 * @param	string

+	 * @return	bool

+	 */

+	function _error($line)

+	{

+		$CI =& get_instance();

+		$CI->lang->load('ftp');

+		show_error($CI->lang->line($line));

+	}

+

+

+}

+// END FTP Class

+

+/* End of file Ftp.php */

 /* Location: ./system/libraries/Ftp.php */
\ No newline at end of file
diff --git a/system/libraries/Hooks.php b/system/libraries/Hooks.php
index 46f3ac4..55019e4 100644
--- a/system/libraries/Hooks.php
+++ b/system/libraries/Hooks.php
@@ -1,226 +1,226 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
-/**
- * CodeIgniter
- *
- * An open source application development framework for PHP 4.3.2 or newer
- *
- * @package		CodeIgniter
- * @author		ExpressionEngine Dev Team
- * @copyright	Copyright (c) 2008, EllisLab, Inc.
- * @license		http://codeigniter.com/user_guide/license.html
- * @link		http://codeigniter.com
- * @since		Version 1.0
- * @filesource
- */
-
-// ------------------------------------------------------------------------
-
-/**
- * CodeIgniter Hooks Class
- *
- * Provides a mechanism to extend the base system without hacking.  Most of
- * this class is borrowed from Paul's Extension class in ExpressionEngine.
- *
- * @package		CodeIgniter
- * @subpackage	Libraries
- * @category	Libraries
- * @author		ExpressionEngine Dev Team
- * @link		http://codeigniter.com/user_guide/libraries/encryption.html
- */
-class CI_Hooks {
-
-	var $enabled 		= FALSE;
-	var $hooks   		= array();
-	var $in_progress	= FALSE;
-
-	/**
-	 * Constructor
-	 *
-	 */
-	function CI_Hooks()
-	{
-		$this->_initialize();
-		log_message('debug', "Hooks Class Initialized");
-	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Initialize the Hooks Preferences
-	 *
-	 * @access	private
-	 * @return	void
-	 */  
-  	function _initialize()
-  	{
-		$CFG =& load_class('Config');
-
-		// If hooks are not enabled in the config file
-		// there is nothing else to do
-
-		if ($CFG->item('enable_hooks') == FALSE)
-		{
-			return;
-		}
-
-		// Grab the "hooks" definition file.
-		// If there are no hooks, we're done.
-
-		@include(APPPATH.'config/hooks'.EXT);
-
-		if ( ! isset($hook) OR ! is_array($hook))
-		{
-			return;
-		}
-
-		$this->hooks =& $hook;
-		$this->enabled = TRUE;
-  	}
-  
-	// --------------------------------------------------------------------
-
-	/**
-	 * Call Hook
-	 *
-	 * Calls a particular hook
-	 *
-	 * @access	private
-	 * @param	string	the hook name
-	 * @return	mixed
-	 */
-	function _call_hook($which = '')
-	{
-		if ( ! $this->enabled OR ! isset($this->hooks[$which]))
-		{
-			return FALSE;
-		}
-
-		if (isset($this->hooks[$which][0]) AND is_array($this->hooks[$which][0]))
-		{
-			foreach ($this->hooks[$which] as $val)
-			{
-				$this->_run_hook($val);
-			}
-		}
-		else
-		{
-			$this->_run_hook($this->hooks[$which]);
-		}
-
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Run Hook
-	 *
-	 * Runs a particular hook
-	 *
-	 * @access	private
-	 * @param	array	the hook details
-	 * @return	bool
-	 */
-	function _run_hook($data)
-	{
-		if ( ! is_array($data))
-		{
-			return FALSE;
-		}
-
-		// -----------------------------------
-		// Safety - Prevents run-away loops
-		// -----------------------------------
-
-		// If the script being called happens to have the same
-		// hook call within it a loop can happen
-
-		if ($this->in_progress == TRUE)
-		{
-			return;
-		}
-
-		// -----------------------------------
-		// Set file path
-		// -----------------------------------
-
-		if ( ! isset($data['filepath']) OR ! isset($data['filename']))
-		{
-			return FALSE;
-		}
-
-		$filepath = APPPATH.$data['filepath'].'/'.$data['filename'];
-
-		if ( ! file_exists($filepath))
-		{
-			return FALSE;
-		}
-
-		// -----------------------------------
-		// Set class/function name
-		// -----------------------------------
-
-		$class		= FALSE;
-		$function	= FALSE;
-		$params		= '';
-
-		if (isset($data['class']) AND $data['class'] != '')
-		{
-			$class = $data['class'];
-		}
-
-		if (isset($data['function']))
-		{
-			$function = $data['function'];
-		}
-
-		if (isset($data['params']))
-		{
-			$params = $data['params'];
-		}
-
-		if ($class === FALSE AND $function === FALSE)
-		{
-			return FALSE;
-		}
-
-		// -----------------------------------
-		// Set the in_progress flag
-		// -----------------------------------
-
-		$this->in_progress = TRUE;
-
-		// -----------------------------------
-		// Call the requested class and/or function
-		// -----------------------------------
-
-		if ($class !== FALSE)
-		{
-			if ( ! class_exists($class))
-			{
-				require($filepath);
-			}
-
-			$HOOK = new $class;
-			$HOOK->$function($params);
-		}
-		else
-		{
-			if ( ! function_exists($function))
-			{
-				require($filepath);
-			}
-
-			$function($params);
-		}
-
-		$this->in_progress = FALSE;
-		return TRUE;
-	}
-
-}
-
-// END CI_Hooks class
-
-/* End of file Hooks.php */
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

+/**

+ * CodeIgniter

+ *

+ * An open source application development framework for PHP 4.3.2 or newer

+ *

+ * @package		CodeIgniter

+ * @author		ExpressionEngine Dev Team

+ * @copyright	Copyright (c) 2008, EllisLab, Inc.

+ * @license		http://codeigniter.com/user_guide/license.html

+ * @link		http://codeigniter.com

+ * @since		Version 1.0

+ * @filesource

+ */

+

+// ------------------------------------------------------------------------

+

+/**

+ * CodeIgniter Hooks Class

+ *

+ * Provides a mechanism to extend the base system without hacking.  Most of

+ * this class is borrowed from Paul's Extension class in ExpressionEngine.

+ *

+ * @package		CodeIgniter

+ * @subpackage	Libraries

+ * @category	Libraries

+ * @author		ExpressionEngine Dev Team

+ * @link		http://codeigniter.com/user_guide/libraries/encryption.html

+ */

+class CI_Hooks {

+

+	var $enabled 		= FALSE;

+	var $hooks   		= array();

+	var $in_progress	= FALSE;

+

+	/**

+	 * Constructor

+	 *

+	 */

+	function CI_Hooks()

+	{

+		$this->_initialize();

+		log_message('debug', "Hooks Class Initialized");

+	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Initialize the Hooks Preferences

+	 *

+	 * @access	private

+	 * @return	void

+	 */  

+  	function _initialize()

+  	{

+		$CFG =& load_class('Config');

+

+		// If hooks are not enabled in the config file

+		// there is nothing else to do

+

+		if ($CFG->item('enable_hooks') == FALSE)

+		{

+			return;

+		}

+

+		// Grab the "hooks" definition file.

+		// If there are no hooks, we're done.

+

+		@include(APPPATH.'config/hooks'.EXT);

+

+		if ( ! isset($hook) OR ! is_array($hook))

+		{

+			return;

+		}

+

+		$this->hooks =& $hook;

+		$this->enabled = TRUE;

+  	}

+  

+	// --------------------------------------------------------------------

+

+	/**

+	 * Call Hook

+	 *

+	 * Calls a particular hook

+	 *

+	 * @access	private

+	 * @param	string	the hook name

+	 * @return	mixed

+	 */

+	function _call_hook($which = '')

+	{

+		if ( ! $this->enabled OR ! isset($this->hooks[$which]))

+		{

+			return FALSE;

+		}

+

+		if (isset($this->hooks[$which][0]) AND is_array($this->hooks[$which][0]))

+		{

+			foreach ($this->hooks[$which] as $val)

+			{

+				$this->_run_hook($val);

+			}

+		}

+		else

+		{

+			$this->_run_hook($this->hooks[$which]);

+		}

+

+		return TRUE;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Run Hook

+	 *

+	 * Runs a particular hook

+	 *

+	 * @access	private

+	 * @param	array	the hook details

+	 * @return	bool

+	 */

+	function _run_hook($data)

+	{

+		if ( ! is_array($data))

+		{

+			return FALSE;

+		}

+

+		// -----------------------------------

+		// Safety - Prevents run-away loops

+		// -----------------------------------

+

+		// If the script being called happens to have the same

+		// hook call within it a loop can happen

+

+		if ($this->in_progress == TRUE)

+		{

+			return;

+		}

+

+		// -----------------------------------

+		// Set file path

+		// -----------------------------------

+

+		if ( ! isset($data['filepath']) OR ! isset($data['filename']))

+		{

+			return FALSE;

+		}

+

+		$filepath = APPPATH.$data['filepath'].'/'.$data['filename'];

+

+		if ( ! file_exists($filepath))

+		{

+			return FALSE;

+		}

+

+		// -----------------------------------

+		// Set class/function name

+		// -----------------------------------

+

+		$class		= FALSE;

+		$function	= FALSE;

+		$params		= '';

+

+		if (isset($data['class']) AND $data['class'] != '')

+		{

+			$class = $data['class'];

+		}

+

+		if (isset($data['function']))

+		{

+			$function = $data['function'];

+		}

+

+		if (isset($data['params']))

+		{

+			$params = $data['params'];

+		}

+

+		if ($class === FALSE AND $function === FALSE)

+		{

+			return FALSE;

+		}

+

+		// -----------------------------------

+		// Set the in_progress flag

+		// -----------------------------------

+

+		$this->in_progress = TRUE;

+

+		// -----------------------------------

+		// Call the requested class and/or function

+		// -----------------------------------

+

+		if ($class !== FALSE)

+		{

+			if ( ! class_exists($class))

+			{

+				require($filepath);

+			}

+

+			$HOOK = new $class;

+			$HOOK->$function($params);

+		}

+		else

+		{

+			if ( ! function_exists($function))

+			{

+				require($filepath);

+			}

+

+			$function($params);

+		}

+

+		$this->in_progress = FALSE;

+		return TRUE;

+	}

+

+}

+

+// END CI_Hooks class

+

+/* End of file Hooks.php */

 /* Location: ./system/libraries/Hooks.php */
\ No newline at end of file
diff --git a/system/libraries/Image_lib.php b/system/libraries/Image_lib.php
index 16201ee..f260e76 100644
--- a/system/libraries/Image_lib.php
+++ b/system/libraries/Image_lib.php
@@ -1,1548 +1,1548 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
-/**
- * CodeIgniter
- *
- * An open source application development framework for PHP 4.3.2 or newer
- *
- * @package		CodeIgniter
- * @author		ExpressionEngine Dev Team
- * @copyright	Copyright (c) 2008, EllisLab, Inc.
- * @license		http://codeigniter.com/user_guide/license.html
- * @link		http://codeigniter.com
- * @since		Version 1.0
- * @filesource
- */
-
-// ------------------------------------------------------------------------
-
-/**
- * Image Manipulation class
- *
- * @package		CodeIgniter
- * @subpackage	Libraries
- * @category	Image_lib
- * @author		ExpressionEngine Dev Team
- * @link		http://codeigniter.com/user_guide/libraries/image_lib.html
- */
-class CI_Image_lib {
-
-	var $image_library		= 'gd2';  	// Can be:  imagemagick, netpbm, gd, gd2
-	var $library_path		= '';
-	var $dynamic_output		= FALSE;	// Whether to send to browser or write to disk
-	var $source_image		= '';
-	var $new_image			= '';
-	var $width				= '';
-	var $height				= '';
-	var $quality			= '90';
-	var $create_thumb		= FALSE;
-	var $thumb_marker		= '_thumb';
-	var $maintain_ratio		= TRUE;  	// Whether to maintain aspect ratio when resizing or use hard values
-	var $master_dim			= 'auto';	// auto, height, or width.  Determines what to use as the master dimension
-	var $rotation_angle		= '';
-	var $x_axis				= '';
-	var	$y_axis				= '';
-
-	// Watermark Vars
-	var $wm_text			= '';			// Watermark text if graphic is not used
-	var $wm_type			= 'text';		// Type of watermarking.  Options:  text/overlay
-	var $wm_x_transp		= 4;
-	var $wm_y_transp		= 4;
-	var $wm_overlay_path	= '';			// Watermark image path
-	var $wm_font_path		= '';			// TT font
-	var $wm_font_size		= 17;			// Font size (different versions of GD will either use points or pixels)
-	var $wm_vrt_alignment	= 'B';			// Vertical alignment:   T M B
-	var $wm_hor_alignment	= 'C';			// Horizontal alignment: L R C
-	var $wm_padding			= 0;			// Padding around text
-	var $wm_hor_offset		= 0;			// Lets you push text to the right
-	var $wm_vrt_offset		= 0;			 // Lets you push  text down
-	var $wm_font_color		= '#ffffff';	// Text color
-	var $wm_shadow_color	= '';			// Dropshadow color
-	var $wm_shadow_distance	= 2;			// Dropshadow distance
-	var $wm_opacity			= 50; 			// Image opacity: 1 - 100  Only works with image
-
-	// Private Vars
-	var $source_folder		= '';
-	var $dest_folder		= '';
-	var $mime_type			= '';
-	var $orig_width			= '';
-	var $orig_height		= '';
-	var $image_type			= '';
-	var $size_str			= '';
-	var $full_src_path		= '';
-	var $full_dst_path		= '';
-	var $create_fnc			= 'imagecreatetruecolor';
-	var $copy_fnc			= 'imagecopyresampled';
-	var $error_msg			= array();
-	var $wm_use_drop_shadow	= FALSE;
-	var $wm_use_truetype	= FALSE;
-
-	/**
-	 * Constructor
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	void
-	 */
-	function CI_Image_lib($props = array())
-	{
-		if (count($props) > 0)
-		{
-			$this->initialize($props);
-		}
-
-		log_message('debug', "Image Lib Class Initialized");
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Initialize image properties
-	 *
-	 * Resets values in case this class is used in a loop
-	 *
-	 * @access	public
-	 * @return	void
-	 */
-	function clear()
-	{
-		$props = array('source_folder', 'dest_folder', 'source_image', 'full_src_path', 'full_dst_path', 'new_image', 'image_type', 'size_str', 'quality', 'orig_width', 'orig_height', 'rotation_angle', 'x_axis', 'y_axis', 'create_fnc', 'copy_fnc', 'wm_overlay_path', 'wm_use_truetype', 'dynamic_output', 'wm_font_size', 'wm_text', 'wm_vrt_alignment', 'wm_hor_alignment', 'wm_padding', 'wm_hor_offset', 'wm_vrt_offset', 'wm_font_color', 'wm_use_drop_shadow', 'wm_shadow_color', 'wm_shadow_distance', 'wm_opacity');
-
-		foreach ($props as $val)
-		{
-			$this->$val = '';
-		}
-
-		// special consideration for master_dim
-		$this->master_dim = 'auto';
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * initialize image preferences
-	 *
-	 * @access	public
-	 * @param	array
-	 * @return	bool
-	 */
-	function initialize($props = array())
-	{
-		/*
-		 * Convert array elements into class variables
-		 */
-		if (count($props) > 0)
-		{
-			foreach ($props as $key => $val)
-			{
-				$this->$key = $val;
-			}
-		}
-
-		/*
-		 * Is there a source image?
-		 *
-		 * If not, there's no reason to continue
-		 *
-		 */
-		if ($this->source_image == '')
-		{
-			$this->set_error('imglib_source_image_required');
-			return FALSE;	   
-		}
-
-		/*
-		 * Is getimagesize() Available?
-		 *
-		 * We use it to determine the image properties (width/height).
-		 * Note:  We need to figure out how to determine image
-		 * properties using ImageMagick and NetPBM
-		 *
-		 */
-		if ( ! function_exists('getimagesize'))
-		{
-			$this->set_error('imglib_gd_required_for_props');
-			return FALSE;
-		}
-
-		$this->image_library = strtolower($this->image_library);
-
-		/*
-		 * Set the full server path
-		 *
-		 * The source image may or may not contain a path.
-		 * Either way, we'll try use realpath to generate the
-		 * full server path in order to more reliably read it.
-		 *
-		 */
-		if (function_exists('realpath') AND @realpath($this->source_image) !== FALSE)
-		{
-			$full_source_path = str_replace("\\", "/", realpath($this->source_image));
-		}
-		else
-		{
-			$full_source_path = $this->source_image;
-		}
-
-		$x = explode('/', $full_source_path);
-		$this->source_image = end($x);
-		$this->source_folder = str_replace($this->source_image, '', $full_source_path);
-
-		// Set the Image Properties
-		if ( ! $this->get_image_properties($this->source_folder.$this->source_image))
-		{
-			return FALSE;	   
-		}
-
-		/*
-		 * Assign the "new" image name/path
-		 *
-		 * If the user has set a "new_image" name it means
-		 * we are making a copy of the source image. If not
-		 * it means we are altering the original.  We'll
-		 * set the destination filename and path accordingly.
-		 *
-		 */
-		if ($this->new_image == '')
-		{
-			$this->dest_image = $this->source_image;
-			$this->dest_folder = $this->source_folder;
-		}
-		else
-		{
-			if (strpos($this->new_image, '/') === FALSE)
-			{
-				$this->dest_folder = $this->source_folder;
-				$this->dest_image = $this->new_image;
-			}
-			else
-			{
-				if (function_exists('realpath') AND @realpath($this->new_image) !== FALSE)
-				{
-					$full_dest_path = str_replace("\\", "/", realpath($this->new_image));
-				}
-				else
-				{
-					$full_dest_path = $this->new_image;
-				}
-
-				// Is there a file name?
-				if ( ! preg_match("#\.(jpg|jpeg|gif|png)$#i", $full_dest_path))
-				{
-					$this->dest_folder = $full_dest_path.'/';
-					$this->dest_image = $this->source_image;
-				}
-				else
-				{
-					$x = explode('/', $full_dest_path);
-					$this->dest_image = end($x);
-					$this->dest_folder = str_replace($this->dest_image, '', $full_dest_path);
-				}
-			}
-		}
-
-		/*
-		 * Compile the finalized filenames/paths
-		 *
-		 * We'll create two master strings containing the
-		 * full server path to the source image and the
-		 * full server path to the destination image.
-		 * We'll also split the destination image name
-		 * so we can insert the thumbnail marker if needed.
-		 *
-		 */
-		if ($this->create_thumb === FALSE OR $this->thumb_marker == '')
-		{
-			$this->thumb_marker = '';
-		}
-
-		$xp	= $this->explode_name($this->dest_image);
-
-		$filename = $xp['name'];
-		$file_ext = $xp['ext'];
-
-		$this->full_src_path = $this->source_folder.$this->source_image;
-		$this->full_dst_path = $this->dest_folder.$filename.$this->thumb_marker.$file_ext;
-
-		/*
-		 * Should we maintain image proportions?
-		 *
-		 * When creating thumbs or copies, the target width/height
-		 * might not be in correct proportion with the source
-		 * image's width/height.  We'll recalculate it here.
-		 *
-		 */
-		if ($this->maintain_ratio === TRUE && ($this->width != '' AND $this->height != ''))
-		{
-			$this->image_reproportion();
-		}
-
-		/*
-		 * Was a width and height specified?
-		 *
-		 * If the destination width/height was
-		 * not submitted we will use the values
-		 * from the actual file
-		 *
-		 */
-		if ($this->width == '')
-			$this->width = $this->orig_width;
-
-		if ($this->height == '')
-			$this->height = $this->orig_height;
-
-		// Set the quality
-		$this->quality = trim(str_replace("%", "", $this->quality));
-
-		if ($this->quality == '' OR $this->quality == 0 OR ! is_numeric($this->quality))
-			$this->quality = 90;
-
-		// Set the x/y coordinates
-		$this->x_axis = ($this->x_axis == '' OR ! is_numeric($this->x_axis)) ? 0 : $this->x_axis;
-		$this->y_axis = ($this->y_axis == '' OR ! is_numeric($this->y_axis)) ? 0 : $this->y_axis;
-
-		// Watermark-related Stuff...
-		if ($this->wm_font_color != '')
-		{
-			if (strlen($this->wm_font_color) == 6)
-			{
-				$this->wm_font_color = '#'.$this->wm_font_color;
-			}
-		}
-
-		if ($this->wm_shadow_color != '')
-		{
-			if (strlen($this->wm_shadow_color) == 6)
-			{
-				$this->wm_shadow_color = '#'.$this->wm_shadow_color;
-			}
-		}
-
-		if ($this->wm_overlay_path != '')
-		{
-			$this->wm_overlay_path = str_replace("\\", "/", realpath($this->wm_overlay_path));
-		}
-
-		if ($this->wm_shadow_color != '')
-		{
-			$this->wm_use_drop_shadow = TRUE;
-		}
-
-		if ($this->wm_font_path != '')
-		{
-			$this->wm_use_truetype = TRUE;
-		}
-
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Image Resize
-	 *
-	 * This is a wrapper function that chooses the proper
-	 * resize function based on the protocol specified
-	 *
-	 * @access	public
-	 * @return	bool
-	 */
-	function resize()
-	{
-		$protocol = 'image_process_'.$this->image_library;
-
-		if (eregi("gd2$", $protocol))
-		{
-			$protocol = 'image_process_gd';
-		}
-
-		return $this->$protocol('resize');
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Image Crop
-	 *
-	 * This is a wrapper function that chooses the proper
-	 * cropping function based on the protocol specified
-	 *
-	 * @access	public
-	 * @return	bool
-	 */
-	function crop()
-	{
-		$protocol = 'image_process_'.$this->image_library;
-
-		if (eregi("gd2$", $protocol))
-		{
-			$protocol = 'image_process_gd';
-		}
-
-		return $this->$protocol('crop');
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Image Rotate
-	 *
-	 * This is a wrapper function that chooses the proper
-	 * rotation function based on the protocol specified
-	 *
-	 * @access	public
-	 * @return	bool
-	 */
-	function rotate()
-	{
-		// Allowed rotation values
-		$degs = array(90, 180, 270, 'vrt', 'hor');
-
-		if ($this->rotation_angle == '' OR ! in_array($this->rotation_angle, $degs, TRUE))
-		{
-			$this->set_error('imglib_rotation_angle_required');
-			return FALSE;	   
-		}
-
-		// Reassign the width and height
-		if ($this->rotation_angle == 90 OR $this->rotation_angle == 270)
-		{
-			$this->width	= $this->orig_height;
-			$this->height	= $this->orig_width;
-		}
-		else
-		{
-			$this->width	= $this->orig_width;
-			$this->height	= $this->orig_height;
-		}
-
-
-		// Choose resizing function
-		if ($this->image_library == 'imagemagick' OR $this->image_library == 'netpbm')
-		{
-			$protocol = 'image_process_'.$this->image_library;
-
-			return $this->$protocol('rotate');
-		}
-
-		if ($this->rotation_angle == 'hor' OR $this->rotation_angle == 'vrt')
-		{
-			return $this->image_mirror_gd();
-		}
-		else
-		{
-			return $this->image_rotate_gd();
-		}
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Image Process Using GD/GD2
-	 *
-	 * This function will resize or crop
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	bool
-	 */
-	function image_process_gd($action = 'resize')
-	{
-		$v2_override = FALSE;
-
-		// If the target width/height match the source, AND if the new file name is not equal to the old file name
-		// we'll simply make a copy of the original with the new name... assuming dynamic rendering is off.
-		if ($this->dynamic_output === FALSE)
-		{
-			if ($this->orig_width == $this->width AND $this->orig_height == $this->height)
-			{
- 				if ($this->source_image != $this->new_image)
- 				{
-					if (@copy($this->full_src_path, $this->full_dst_path))
-					{
-						@chmod($this->full_dst_path, DIR_WRITE_MODE);
-					}
-				}
-
-				return TRUE;
-			}
-		}
-
-		// Let's set up our values based on the action
-		if ($action == 'crop')
-		{
-			//  Reassign the source width/height if cropping
-			$this->orig_width  = $this->width;
-			$this->orig_height = $this->height;
-
-			// GD 2.0 has a cropping bug so we'll test for it
-			if ($this->gd_version() !== FALSE)
-			{
-				$gd_version = str_replace('0', '', $this->gd_version());
-				$v2_override = ($gd_version == 2) ? TRUE : FALSE;
-			}
-		}
-		else
-		{
-			// If resizing the x/y axis must be zero
-			$this->x_axis = 0;
-			$this->y_axis = 0;
-		}
-
-		//  Create the image handle
-		if ( ! ($src_img = $this->image_create_gd()))
-		{
-			return FALSE;
-		}
-
- 		//  Create The Image
-		//
-		//  old conditional which users report cause problems with shared GD libs who report themselves as "2.0 or greater"
-		//  it appears that this is no longer the issue that it was in 2004, so we've removed it, retaining it in the comment
-		//  below should that ever prove inaccurate.
-		//
-		//  if ($this->image_library == 'gd2' AND function_exists('imagecreatetruecolor') AND $v2_override == FALSE)
- 		if ($this->image_library == 'gd2' AND function_exists('imagecreatetruecolor'))
-		{
-			$create	= 'imagecreatetruecolor';
-			$copy	= 'imagecopyresampled';
-		}
-		else
-		{
-			$create	= 'imagecreate';
-			$copy	= 'imagecopyresized';
-		}
-
-		$dst_img = $create($this->width, $this->height);
-		$copy($dst_img, $src_img, 0, 0, $this->x_axis, $this->y_axis, $this->width, $this->height, $this->orig_width, $this->orig_height);
-
-		//  Show the image
-		if ($this->dynamic_output == TRUE)
-		{
-			$this->image_display_gd($dst_img);
-		}
-		else
-		{
-			// Or save it
-			if ( ! $this->image_save_gd($dst_img))
-			{
-				return FALSE;
-			}
-		}
-
-		//  Kill the file handles
-		imagedestroy($dst_img);
-		imagedestroy($src_img);
-
-		// Set the file to 777
-		@chmod($this->full_dst_path, DIR_WRITE_MODE);
-
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Image Process Using ImageMagick
-	 *
-	 * This function will resize, crop or rotate
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	bool
-	 */
-	function image_process_imagemagick($action = 'resize')
-	{
-		//  Do we have a vaild library path?
-		if ($this->library_path == '')
-		{
-			$this->set_error('imglib_libpath_invalid');
-			return FALSE;
-		}
-
-		if ( ! eregi("convert$", $this->library_path))
-		{
-			if ( ! eregi("/$", $this->library_path)) $this->library_path .= "/";
-
-			$this->library_path .= 'convert';
-		}
-
-		// Execute the command
-		$cmd = $this->library_path." -quality ".$this->quality;
-
-		if ($action == 'crop')
-		{
-			$cmd .= " -crop ".$this->width."x".$this->height."+".$this->x_axis."+".$this->y_axis." \"$this->full_src_path\" \"$this->full_dst_path\" 2>&1";
-		}
-		elseif ($action == 'rotate')
-		{
-			switch ($this->rotation_angle)
-			{
-				case 'hor' 	: $angle = '-flop';
-					break;
-				case 'vrt' 	: $angle = '-flip';
-					break;
-				default		: $angle = '-rotate '.$this->rotation_angle;
-					break;
-			}
-
-			$cmd .= " ".$angle." \"$this->full_src_path\" \"$this->full_dst_path\" 2>&1";
-		}
-		else  // Resize
-		{
-			$cmd .= " -resize ".$this->width."x".$this->height." \"$this->full_src_path\" \"$this->full_dst_path\" 2>&1";
-		}
-
-		$retval = 1;
-
-		@exec($cmd, $output, $retval);
-
-		//	Did it work?
-		if ($retval > 0)
-		{
-			$this->set_error('imglib_image_process_failed');
-			return FALSE;
-		}
-
-		// Set the file to 777
-		@chmod($this->full_dst_path, DIR_WRITE_MODE);
-
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Image Process Using NetPBM
-	 *
-	 * This function will resize, crop or rotate
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	bool
-	 */
-	function image_process_netpbm($action = 'resize')
-	{
-		if ($this->library_path == '')
-		{
-			$this->set_error('imglib_libpath_invalid');
-			return FALSE;
-		}
-
-		//  Build the resizing command
-		switch ($this->image_type)
-		{
-			case 1 :
-						$cmd_in		= 'giftopnm';
-						$cmd_out	= 'ppmtogif';
-				break;
-			case 2 :
-						$cmd_in		= 'jpegtopnm';
-						$cmd_out	= 'ppmtojpeg';
-				break;
-			case 3 :
-						$cmd_in		= 'pngtopnm';
-						$cmd_out	= 'ppmtopng';
-				break;
-		}
-
-		if ($action == 'crop')
-		{
-			$cmd_inner = 'pnmcut -left '.$this->x_axis.' -top '.$this->y_axis.' -width '.$this->width.' -height '.$this->height;
-		}
-		elseif ($action == 'rotate')
-		{
-			switch ($this->rotation_angle)
-			{
-				case 90		:	$angle = 'r270';
-					break;
-				case 180	:	$angle = 'r180';
-					break;
-				case 270 	:	$angle = 'r90';
-					break;
-				case 'vrt'	:	$angle = 'tb';
-					break;
-				case 'hor'	:	$angle = 'lr';
-					break;
-			}
-
-			$cmd_inner = 'pnmflip -'.$angle.' ';
-		}
-		else // Resize
-		{
-			$cmd_inner = 'pnmscale -xysize '.$this->width.' '.$this->height;
-		}
-
-		$cmd = $this->library_path.$cmd_in.' '.$this->full_src_path.' | '.$cmd_inner.' | '.$cmd_out.' > '.$this->dest_folder.'netpbm.tmp';
-
-		$retval = 1;
-
-		@exec($cmd, $output, $retval);
-
-		//  Did it work?
-		if ($retval > 0)
-		{
-			$this->set_error('imglib_image_process_failed');
-			return FALSE;
-		}
-
-		// With NetPBM we have to create a temporary image.
-		// If you try manipulating the original it fails so
-		// we have to rename the temp file.
-		copy ($this->dest_folder.'netpbm.tmp', $this->full_dst_path);
-		unlink ($this->dest_folder.'netpbm.tmp');
-		@chmod($this->full_dst_path, DIR_WRITE_MODE);
-
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Image Rotate Using GD
-	 *
-	 * @access	public
-	 * @return	bool
-	 */
-	function image_rotate_gd()
-	{
-		// Is Image Rotation Supported?
-		// this function is only supported as of PHP 4.3
-		if ( ! function_exists('imagerotate'))
-		{
-			$this->set_error('imglib_rotate_unsupported');
-			return FALSE;
-		}
-
-		//  Create the image handle
-		if ( ! ($src_img = $this->image_create_gd()))
-		{
-			return FALSE;
-		}
-
-		// Set the background color
-		// This won't work with transparent PNG files so we are
-		// going to have to figure out how to determine the color
-		// of the alpha channel in a future release.
-
-		$white	= imagecolorallocate($src_img, 255, 255, 255);
-
-		//  Rotate it!
-		$dst_img = imagerotate($src_img, $this->rotation_angle, $white);
-
-		//  Save the Image
-		if ($this->dynamic_output == TRUE)
-		{
-			$this->image_display_gd($dst_img);
-		}
-		else
-		{
-			// Or save it
-			if ( ! $this->image_save_gd($dst_img))
-			{
-				return FALSE;
-			}
-		}
-
-		//  Kill the file handles
-		imagedestroy($dst_img);
-		imagedestroy($src_img);
-
-		// Set the file to 777
-
-		@chmod($this->full_dst_path, DIR_WRITE_MODE);
-
-		return true;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Create Mirror Image using GD
-	 *
-	 * This function will flip horizontal or vertical
-	 *
-	 * @access	public
-	 * @return	bool
-	 */
-	function image_mirror_gd()
-	{
-		if ( ! $src_img = $this->image_create_gd())
-		{
-			return FALSE;
-		}
-
-		$width  = $this->orig_width;
-		$height = $this->orig_height;
-
-		if ($this->rotation_angle == 'hor')
-		{
-			for ($i = 0; $i < $height; $i++)
-			{
-				$left  = 0;
-				$right = $width-1;
-
-				while ($left < $right)
-				{
-					$cl = imagecolorat($src_img, $left, $i);
-					$cr = imagecolorat($src_img, $right, $i);
-
-					imagesetpixel($src_img, $left, $i, $cr);
-					imagesetpixel($src_img, $right, $i, $cl);
-
-					$left++;
-					$right--;
-				}
-			}
-		}
-		else
-		{
-			for ($i = 0; $i < $width; $i++)
-			{
-				$top = 0;
-				$bot = $height-1;
-
-				while ($top < $bot)
-				{
-					$ct = imagecolorat($src_img, $i, $top);
-					$cb = imagecolorat($src_img, $i, $bot);
-
-					imagesetpixel($src_img, $i, $top, $cb);
-					imagesetpixel($src_img, $i, $bot, $ct);
-
-					$top++;
-					$bot--;
-				}
-			}
-		}
-
-		//  Show the image
-		if ($this->dynamic_output == TRUE)
-		{
-			$this->image_display_gd($src_img);
-		}
-		else
-		{
-			// Or save it
-			if ( ! $this->image_save_gd($src_img))
-			{
-				return FALSE;
-			}
-		}
-
-		//  Kill the file handles
-		imagedestroy($src_img);
-
-		// Set the file to 777
-		@chmod($this->full_dst_path, DIR_WRITE_MODE);
-
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Image Watermark
-	 *
-	 * This is a wrapper function that chooses the type
-	 * of watermarking based on the specified preference.
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	bool
-	 */
-	function watermark()
-	{
-		if ($this->wm_type == 'overlay')
-		{
-			return $this->overlay_watermark();
-		}
-		else
-		{
-			return $this->text_watermark();
-		}
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Watermark - Graphic Version
-	 *
-	 * @access	public
-	 * @return	bool
-	 */
-	function overlay_watermark()
-	{
-		if ( ! function_exists('imagecolortransparent'))
-		{
-			$this->set_error('imglib_gd_required');
-			return FALSE;
-		}
-
-		//  Fetch source image properties
-		$this->get_image_properties();
-
-		//  Fetch watermark image properties
-		$props 			= $this->get_image_properties($this->wm_overlay_path, TRUE);
-		$wm_img_type	= $props['image_type'];
-		$wm_width		= $props['width'];
-		$wm_height		= $props['height'];
-
-		//  Create two image resources
-		$wm_img  = $this->image_create_gd($this->wm_overlay_path, $wm_img_type);
-		$src_img = $this->image_create_gd($this->full_src_path);
-
-		// Reverse the offset if necessary
-		// When the image is positioned at the bottom
-		// we don't want the vertical offset to push it
-		// further down.  We want the reverse, so we'll
-		// invert the offset.  Same with the horizontal
-		// offset when the image is at the right
-
-		$this->wm_vrt_alignment = strtoupper(substr($this->wm_vrt_alignment, 0, 1));
-		$this->wm_hor_alignment = strtoupper(substr($this->wm_hor_alignment, 0, 1));
-
-		if ($this->wm_vrt_alignment == 'B')
-			$this->wm_vrt_offset = $this->wm_vrt_offset * -1;
-
-		if ($this->wm_hor_alignment == 'R')
-			$this->wm_hor_offset = $this->wm_hor_offset * -1;
-
-		//  Set the base x and y axis values
-		$x_axis = $this->wm_hor_offset + $this->wm_padding;
-		$y_axis = $this->wm_vrt_offset + $this->wm_padding;
-
-		//  Set the vertical position
-		switch ($this->wm_vrt_alignment)
-		{
-			case 'T':
-				break;
-			case 'M':	$y_axis += ($this->orig_height / 2) - ($wm_height / 2);
-				break;
-			case 'B':	$y_axis += $this->orig_height - $wm_height;
-				break;
-		}
-
-		//  Set the horizontal position
-		switch ($this->wm_hor_alignment)
-		{
-			case 'L':
-				break;
-			case 'C':	$x_axis += ($this->orig_width / 2) - ($wm_width / 2);
-				break;
-			case 'R':	$x_axis += $this->orig_width - $wm_width;
-				break;
-		}
-
-		//  Build the finalized image
-		if ($wm_img_type == 3 AND function_exists('imagealphablending'))
-		{
-			@imagealphablending($src_img, TRUE);
-		} 
-
-		// Set RGB values for text and shadow
-		$rgba = imagecolorat($wm_img, $this->wm_x_transp, $this->wm_y_transp);
-		$alpha = ($rgba & 0x7F000000) >> 24;
-
-		// make a best guess as to whether we're dealing with an image with alpha transparency or no/binary transparency
-		if ($alpha > 0)
-		{
-			// copy the image directly, the image's alpha transparency being the sole determinant of blending
-			imagecopy($src_img, $wm_img, $x_axis, $y_axis, 0, 0, $wm_width, $wm_height);
-		}
-		else
-		{
-			// set our RGB value from above to be transparent and merge the images with the specified opacity
-			imagecolortransparent($wm_img, imagecolorat($wm_img, $this->wm_x_transp, $this->wm_y_transp));
-			imagecopymerge($src_img, $wm_img, $x_axis, $y_axis, 0, 0, $wm_width, $wm_height, $this->wm_opacity);
-		}
-
-		//  Output the image
-		if ($this->dynamic_output == TRUE)
-		{
-			$this->image_display_gd($src_img);
-		}
-		else
-		{
-			if ( ! $this->image_save_gd($src_img))
-			{
-				return FALSE;
-			}
-		}
-
-		imagedestroy($src_img);
-		imagedestroy($wm_img);
-
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Watermark - Text Version
-	 *
-	 * @access	public
-	 * @return	bool
-	 */
-	function text_watermark()
-	{
-		if ( ! ($src_img = $this->image_create_gd()))
-		{
-			return FALSE;
-		}
-
-		if ($this->wm_use_truetype == TRUE AND ! file_exists($this->wm_font_path))
-		{
-			$this->set_error('imglib_missing_font');
-			return FALSE;
-		}
-
-		//  Fetch source image properties
-		$this->get_image_properties();
-
-		// Set RGB values for text and shadow
-		$this->wm_font_color	= str_replace('#', '', $this->wm_font_color);
-		$this->wm_shadow_color	= str_replace('#', '', $this->wm_shadow_color);
-
-		$R1 = hexdec(substr($this->wm_font_color, 0, 2));
-		$G1 = hexdec(substr($this->wm_font_color, 2, 2));
-		$B1 = hexdec(substr($this->wm_font_color, 4, 2));
-
-		$R2 = hexdec(substr($this->wm_shadow_color, 0, 2));
-		$G2 = hexdec(substr($this->wm_shadow_color, 2, 2));
-		$B2 = hexdec(substr($this->wm_shadow_color, 4, 2));
-
-		$txt_color	= imagecolorclosest($src_img, $R1, $G1, $B1);
-		$drp_color	= imagecolorclosest($src_img, $R2, $G2, $B2);
-
-		// Reverse the vertical offset
-		// When the image is positioned at the bottom
-		// we don't want the vertical offset to push it
-		// further down.  We want the reverse, so we'll
-		// invert the offset.  Note: The horizontal
-		// offset flips itself automatically
-
-		if ($this->wm_vrt_alignment == 'B')
-			$this->wm_vrt_offset = $this->wm_vrt_offset * -1;
-
-		if ($this->wm_hor_alignment == 'R')
-			$this->wm_hor_offset = $this->wm_hor_offset * -1;
-
-		// Set font width and height
-		// These are calculated differently depending on
-		// whether we are using the true type font or not
-		if ($this->wm_use_truetype == TRUE)
-		{
-			if ($this->wm_font_size == '')
-				$this->wm_font_size = '17';
-
-			$fontwidth  = $this->wm_font_size-($this->wm_font_size/4);
-			$fontheight = $this->wm_font_size;
-			$this->wm_vrt_offset += $this->wm_font_size;
-		}
-		else
-		{
-			$fontwidth  = imagefontwidth($this->wm_font_size);
-			$fontheight = imagefontheight($this->wm_font_size);
-		}
-
-		// Set base X and Y axis values
-		$x_axis = $this->wm_hor_offset + $this->wm_padding;
-		$y_axis = $this->wm_vrt_offset + $this->wm_padding;
-
-		// Set verticle alignment
-		if ($this->wm_use_drop_shadow == FALSE)
-			$this->wm_shadow_distance = 0;
-
-		$this->wm_vrt_alignment = strtoupper(substr($this->wm_vrt_alignment, 0, 1));
-		$this->wm_hor_alignment = strtoupper(substr($this->wm_hor_alignment, 0, 1));
-
-		switch ($this->wm_vrt_alignment)
-		{
-			case	 "T" :
-				break;
-			case "M":	$y_axis += ($this->orig_height/2)+($fontheight/2);
-				break;
-			case "B":	$y_axis += ($this->orig_height - $fontheight - $this->wm_shadow_distance - ($fontheight/2));
-				break;
-		}
-
-		$x_shad = $x_axis + $this->wm_shadow_distance;
-		$y_shad = $y_axis + $this->wm_shadow_distance;
-
-		// Set horizontal alignment
-		switch ($this->wm_hor_alignment)
-		{
-			case "L":
-				break;
-			case "R":
-						if ($this->wm_use_drop_shadow)
-							$x_shad += ($this->orig_width - $fontwidth*strlen($this->wm_text));
-							$x_axis += ($this->orig_width - $fontwidth*strlen($this->wm_text));
-				break;
-			case "C":
-						if ($this->wm_use_drop_shadow)
-							$x_shad += floor(($this->orig_width - $fontwidth*strlen($this->wm_text))/2);
-							$x_axis += floor(($this->orig_width  -$fontwidth*strlen($this->wm_text))/2);
-				break;
-		}
-
-		//  Add the text to the source image
-		if ($this->wm_use_truetype)
-		{
-			if ($this->wm_use_drop_shadow)
-				imagettftext($src_img, $this->wm_font_size, 0, $x_shad, $y_shad, $drp_color, $this->wm_font_path, $this->wm_text);
-				imagettftext($src_img, $this->wm_font_size, 0, $x_axis, $y_axis, $txt_color, $this->wm_font_path, $this->wm_text);
-		}
-		else
-		{
-			if ($this->wm_use_drop_shadow)
-				imagestring($src_img, $this->wm_font_size, $x_shad, $y_shad, $this->wm_text, $drp_color);
-				imagestring($src_img, $this->wm_font_size, $x_axis, $y_axis, $this->wm_text, $txt_color);
-		}
-
-		//  Output the final image
-		if ($this->dynamic_output == TRUE)
-		{
-			$this->image_display_gd($src_img);
-		}
-		else
-		{
-			$this->image_save_gd($src_img);
-		}
-
-		imagedestroy($src_img);
-
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Create Image - GD
-	 *
-	 * This simply creates an image resource handle
-	 * based on the type of image being processed
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	resource
-	 */
-	function image_create_gd($path = '', $image_type = '')
-	{
-		if ($path == '')
-			$path = $this->full_src_path;
-
-		if ($image_type == '')
-			$image_type = $this->image_type;
-
-
-		switch ($image_type)
-		{
-			case	 1 :
-						if ( ! function_exists('imagecreatefromgif'))
-						{
-							$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_gif_not_supported'));
-							return FALSE;
-						}
-
-						return imagecreatefromgif($path);
-				break;
-			case 2 :
-						if ( ! function_exists('imagecreatefromjpeg'))
-						{
-							$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_jpg_not_supported'));
-							return FALSE;
-						}
-
-						return imagecreatefromjpeg($path);
-				break;
-			case 3 :
-						if ( ! function_exists('imagecreatefrompng'))
-						{
-							$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_png_not_supported'));
-							return FALSE;
-						}
-
-						return imagecreatefrompng($path);
-				break;
-
-		}
-
-		$this->set_error(array('imglib_unsupported_imagecreate'));
-		return FALSE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Write image file to disk - GD
-	 *
-	 * Takes an image resource as input and writes the file
-	 * to the specified destination
-	 *
-	 * @access	public
-	 * @param	resource
-	 * @return	bool
-	 */
-	function image_save_gd($resource)
-	{
-		switch ($this->image_type)
-		{
-			case 1 :
-						if ( ! function_exists('imagegif'))
-						{
-							$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_gif_not_supported'));
-							return FALSE;
-						}
-
-						@imagegif($resource, $this->full_dst_path);
-				break;
-			case 2	:
-						if ( ! function_exists('imagejpeg'))
-						{
-							$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_jpg_not_supported'));
-							return FALSE;
-						}
-
-						if (phpversion() == '4.4.1')
-						{
-							@touch($this->full_dst_path); // PHP 4.4.1 bug #35060 - workaround
-						}
-
-						@imagejpeg($resource, $this->full_dst_path, $this->quality);
-				break;
-			case 3	:
-						if ( ! function_exists('imagepng'))
-						{
-							$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_png_not_supported'));
-							return FALSE;
-						}
-
-						@imagepng($resource, $this->full_dst_path);
-				break;
-			default		:
-							$this->set_error(array('imglib_unsupported_imagecreate'));
-							return FALSE;
-				break;
-		}
-
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Dynamically outputs an image
-	 *
-	 * @access	public
-	 * @param	resource
-	 * @return	void
-	 */
-	function image_display_gd($resource)
-	{
-		header("Content-Disposition: filename={$this->source_image};");
-		header("Content-Type: {$this->mime_type}");
-		header('Content-Transfer-Encoding: binary');
-		header('Last-Modified: '.gmdate('D, d M Y H:i:s', time()).' GMT');
-
-		switch ($this->image_type)
-		{
-			case 1 		:	imagegif($resource);
-				break;
-			case 2		:	imagejpeg($resource, '', $this->quality);
-				break;
-			case 3		:	imagepng($resource);
-				break;
-			default		:	echo 'Unable to display the image';
-				break;
-		}
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Re-proportion Image Width/Height
-	 *
-	 * When creating thumbs, the desired width/height
-	 * can end up warping the image due to an incorrect
-	 * ratio between the full-sized image and the thumb.
-	 *
-	 * This function lets us re-proportion the width/height
-	 * if users choose to maintain the aspect ratio when resizing.
-	 *
-	 * @access	public
-	 * @return	void
-	 */
-	function image_reproportion()
-	{
-		if ( ! is_numeric($this->width) OR ! is_numeric($this->height) OR $this->width == 0 OR $this->height == 0)
-			return;
-
-		if ( ! is_numeric($this->orig_width) OR ! is_numeric($this->orig_height) OR $this->orig_width == 0 OR $this->orig_height == 0)
-			return;
-
-		$new_width	= ceil($this->orig_width*$this->height/$this->orig_height);
-		$new_height	= ceil($this->width*$this->orig_height/$this->orig_width);
-
-		$ratio = (($this->orig_height/$this->orig_width) - ($this->height/$this->width));
-
-		if ($this->master_dim != 'width' AND $this->master_dim != 'height')
-		{
-			$this->master_dim = ($ratio < 0) ? 'width' : 'height';
-		}
-
-		if (($this->width != $new_width) AND ($this->height != $new_height))
-		{
-			if ($this->master_dim == 'height')
-			{
-				$this->width = $new_width;
-			}
-			else
-			{
-				$this->height = $new_height;
-			}
-		}
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Get image properties
-	 *
-	 * A helper function that gets info about the file
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	mixed
-	 */
-	function get_image_properties($path = '', $return = FALSE)
-	{
-		// For now we require GD but we should
-		// find a way to determine this using IM or NetPBM
-
-		if ($path == '')
-			$path = $this->full_src_path;
-
-		if ( ! file_exists($path))
-		{
-			$this->set_error('imglib_invalid_path');
-			return FALSE;
-		}
-
-		$vals = @getimagesize($path);
-
-		$types = array(1 => 'gif', 2 => 'jpeg', 3 => 'png');
-
-		$mime = (isset($types[$vals['2']])) ? 'image/'.$types[$vals['2']] : 'image/jpg';
-
-		if ($return == TRUE)
-		{
-			$v['width']			= $vals['0'];
-			$v['height']		= $vals['1'];
-			$v['image_type']	= $vals['2'];
-			$v['size_str']		= $vals['3'];
-			$v['mime_type']		= $mime;
-
-			return $v;
-		}
-
-		$this->orig_width	= $vals['0'];
-		$this->orig_height	= $vals['1'];
-		$this->image_type	= $vals['2'];
-		$this->size_str		= $vals['3'];
-		$this->mime_type	= $mime;
-
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Size calculator
-	 *
-	 * This function takes a known width x height and
-	 * recalculates it to a new size.  Only one
-	 * new variable needs to be known
-	 *
-	 *	$props = array(
-	 *					'width' 		=> $width,
-	 *					'height' 		=> $height,
-	 *					'new_width'		=> 40,
-	 *					'new_height'	=> ''
-	 *				  );
-	 *
-	 * @access	public
-	 * @param	array
-	 * @return	array
-	 */
-	function size_calculator($vals)
-	{
-		if ( ! is_array($vals))
-		{
-			return;
-		}
-
-		$allowed = array('new_width', 'new_height', 'width', 'height');
-
-		foreach ($allowed as $item)
-		{
-			if ( ! isset($vals[$item]) OR $vals[$item] == '')
-				$vals[$item] = 0;
-		}
-
-		if ($vals['width'] == 0 OR $vals['height'] == 0)
-		{
-			return $vals;
-		}
-
-		if ($vals['new_width'] == 0)
-		{
-			$vals['new_width'] = ceil($vals['width']*$vals['new_height']/$vals['height']);
-		}
-		elseif ($vals['new_height'] == 0)
-		{
-			$vals['new_height'] = ceil($vals['new_width']*$vals['height']/$vals['width']);
-		}
-
-		return $vals;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Explode source_image
-	 *
-	 * This is a helper function that extracts the extension
-	 * from the source_image.  This function lets us deal with
-	 * source_images with multiple periods, like:  my.cool.jpg
-	 * It returns an associative array with two elements:
-	 * $array['ext']  = '.jpg';
-	 * $array['name'] = 'my.cool';
-	 *
-	 * @access	public
-	 * @param	array
-	 * @return	array
-	 */
-	function explode_name($source_image)
-	{
-		$x = explode('.', $source_image);
-		$ret['ext'] = '.'.end($x);
-
-		$name = '';
-
-		$ct = count($x)-1;
-
-		for ($i = 0; $i < $ct; $i++)
-		{
-			$name .= $x[$i];
-
-			if ($i < ($ct - 1))
-			{
-				$name .= '.';
-			}
-		}
-
-		$ret['name'] = $name;
-
-		return $ret;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Is GD Installed?
-	 *
-	 * @access	public
-	 * @return	bool
-	 */
-	function gd_loaded()
-	{
-		if ( ! extension_loaded('gd'))
-		{
-			if ( ! dl('gd.so'))
-			{
-				return FALSE;
-			}
-		}
-
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Get GD version
-	 *
-	 * @access	public
-	 * @return	mixed
-	 */
-	function gd_version()
-	{
-		if (function_exists('gd_info'))
-		{
-			$gd_version = @gd_info();
-			$gd_version = preg_replace("/\D/", "", $gd_version['GD Version']);
-
-			return $gd_version;
-		}
-
-		return FALSE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Set error message
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	void
-	 */
-	function set_error($msg)
-	{
-		$CI =& get_instance();
-		$CI->lang->load('imglib');
-
-		if (is_array($msg))
-		{
-			foreach ($msg as $val)
-			{
-
-				$msg = ($CI->lang->line($val) == FALSE) ? $val : $CI->lang->line($val);
-				$this->error_msg[] = $msg;
-				log_message('error', $msg);
-			}
-		}
-		else
-		{
-			$msg = ($CI->lang->line($msg) == FALSE) ? $msg : $CI->lang->line($msg);
-			$this->error_msg[] = $msg;
-			log_message('error', $msg);
-		}
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Show error messages
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	string
-	 */
-	function display_errors($open = '<p>', $close = '</p>')
-	{
-		$str = '';
-		foreach ($this->error_msg as $val)
-		{
-			$str .= $open.$val.$close;
-		}
-
-		return $str;
-	}
-
-}
-// END Image_lib Class
-
-/* End of file Image_lib.php */
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

+/**

+ * CodeIgniter

+ *

+ * An open source application development framework for PHP 4.3.2 or newer

+ *

+ * @package		CodeIgniter

+ * @author		ExpressionEngine Dev Team

+ * @copyright	Copyright (c) 2008, EllisLab, Inc.

+ * @license		http://codeigniter.com/user_guide/license.html

+ * @link		http://codeigniter.com

+ * @since		Version 1.0

+ * @filesource

+ */

+

+// ------------------------------------------------------------------------

+

+/**

+ * Image Manipulation class

+ *

+ * @package		CodeIgniter

+ * @subpackage	Libraries

+ * @category	Image_lib

+ * @author		ExpressionEngine Dev Team

+ * @link		http://codeigniter.com/user_guide/libraries/image_lib.html

+ */

+class CI_Image_lib {

+

+	var $image_library		= 'gd2';  	// Can be:  imagemagick, netpbm, gd, gd2

+	var $library_path		= '';

+	var $dynamic_output		= FALSE;	// Whether to send to browser or write to disk

+	var $source_image		= '';

+	var $new_image			= '';

+	var $width				= '';

+	var $height				= '';

+	var $quality			= '90';

+	var $create_thumb		= FALSE;

+	var $thumb_marker		= '_thumb';

+	var $maintain_ratio		= TRUE;  	// Whether to maintain aspect ratio when resizing or use hard values

+	var $master_dim			= 'auto';	// auto, height, or width.  Determines what to use as the master dimension

+	var $rotation_angle		= '';

+	var $x_axis				= '';

+	var	$y_axis				= '';

+

+	// Watermark Vars

+	var $wm_text			= '';			// Watermark text if graphic is not used

+	var $wm_type			= 'text';		// Type of watermarking.  Options:  text/overlay

+	var $wm_x_transp		= 4;

+	var $wm_y_transp		= 4;

+	var $wm_overlay_path	= '';			// Watermark image path

+	var $wm_font_path		= '';			// TT font

+	var $wm_font_size		= 17;			// Font size (different versions of GD will either use points or pixels)

+	var $wm_vrt_alignment	= 'B';			// Vertical alignment:   T M B

+	var $wm_hor_alignment	= 'C';			// Horizontal alignment: L R C

+	var $wm_padding			= 0;			// Padding around text

+	var $wm_hor_offset		= 0;			// Lets you push text to the right

+	var $wm_vrt_offset		= 0;			 // Lets you push  text down

+	var $wm_font_color		= '#ffffff';	// Text color

+	var $wm_shadow_color	= '';			// Dropshadow color

+	var $wm_shadow_distance	= 2;			// Dropshadow distance

+	var $wm_opacity			= 50; 			// Image opacity: 1 - 100  Only works with image

+

+	// Private Vars

+	var $source_folder		= '';

+	var $dest_folder		= '';

+	var $mime_type			= '';

+	var $orig_width			= '';

+	var $orig_height		= '';

+	var $image_type			= '';

+	var $size_str			= '';

+	var $full_src_path		= '';

+	var $full_dst_path		= '';

+	var $create_fnc			= 'imagecreatetruecolor';

+	var $copy_fnc			= 'imagecopyresampled';

+	var $error_msg			= array();

+	var $wm_use_drop_shadow	= FALSE;

+	var $wm_use_truetype	= FALSE;

+

+	/**

+	 * Constructor

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	void

+	 */

+	function CI_Image_lib($props = array())

+	{

+		if (count($props) > 0)

+		{

+			$this->initialize($props);

+		}

+

+		log_message('debug', "Image Lib Class Initialized");

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Initialize image properties

+	 *

+	 * Resets values in case this class is used in a loop

+	 *

+	 * @access	public

+	 * @return	void

+	 */

+	function clear()

+	{

+		$props = array('source_folder', 'dest_folder', 'source_image', 'full_src_path', 'full_dst_path', 'new_image', 'image_type', 'size_str', 'quality', 'orig_width', 'orig_height', 'rotation_angle', 'x_axis', 'y_axis', 'create_fnc', 'copy_fnc', 'wm_overlay_path', 'wm_use_truetype', 'dynamic_output', 'wm_font_size', 'wm_text', 'wm_vrt_alignment', 'wm_hor_alignment', 'wm_padding', 'wm_hor_offset', 'wm_vrt_offset', 'wm_font_color', 'wm_use_drop_shadow', 'wm_shadow_color', 'wm_shadow_distance', 'wm_opacity');

+

+		foreach ($props as $val)

+		{

+			$this->$val = '';

+		}

+

+		// special consideration for master_dim

+		$this->master_dim = 'auto';

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * initialize image preferences

+	 *

+	 * @access	public

+	 * @param	array

+	 * @return	bool

+	 */

+	function initialize($props = array())

+	{

+		/*

+		 * Convert array elements into class variables

+		 */

+		if (count($props) > 0)

+		{

+			foreach ($props as $key => $val)

+			{

+				$this->$key = $val;

+			}

+		}

+

+		/*

+		 * Is there a source image?

+		 *

+		 * If not, there's no reason to continue

+		 *

+		 */

+		if ($this->source_image == '')

+		{

+			$this->set_error('imglib_source_image_required');

+			return FALSE;	   

+		}

+

+		/*

+		 * Is getimagesize() Available?

+		 *

+		 * We use it to determine the image properties (width/height).

+		 * Note:  We need to figure out how to determine image

+		 * properties using ImageMagick and NetPBM

+		 *

+		 */

+		if ( ! function_exists('getimagesize'))

+		{

+			$this->set_error('imglib_gd_required_for_props');

+			return FALSE;

+		}

+

+		$this->image_library = strtolower($this->image_library);

+

+		/*

+		 * Set the full server path

+		 *

+		 * The source image may or may not contain a path.

+		 * Either way, we'll try use realpath to generate the

+		 * full server path in order to more reliably read it.

+		 *

+		 */

+		if (function_exists('realpath') AND @realpath($this->source_image) !== FALSE)

+		{

+			$full_source_path = str_replace("\\", "/", realpath($this->source_image));

+		}

+		else

+		{

+			$full_source_path = $this->source_image;

+		}

+

+		$x = explode('/', $full_source_path);

+		$this->source_image = end($x);

+		$this->source_folder = str_replace($this->source_image, '', $full_source_path);

+

+		// Set the Image Properties

+		if ( ! $this->get_image_properties($this->source_folder.$this->source_image))

+		{

+			return FALSE;	   

+		}

+

+		/*

+		 * Assign the "new" image name/path

+		 *

+		 * If the user has set a "new_image" name it means

+		 * we are making a copy of the source image. If not

+		 * it means we are altering the original.  We'll

+		 * set the destination filename and path accordingly.

+		 *

+		 */

+		if ($this->new_image == '')

+		{

+			$this->dest_image = $this->source_image;

+			$this->dest_folder = $this->source_folder;

+		}

+		else

+		{

+			if (strpos($this->new_image, '/') === FALSE)

+			{

+				$this->dest_folder = $this->source_folder;

+				$this->dest_image = $this->new_image;

+			}

+			else

+			{

+				if (function_exists('realpath') AND @realpath($this->new_image) !== FALSE)

+				{

+					$full_dest_path = str_replace("\\", "/", realpath($this->new_image));

+				}

+				else

+				{

+					$full_dest_path = $this->new_image;

+				}

+

+				// Is there a file name?

+				if ( ! preg_match("#\.(jpg|jpeg|gif|png)$#i", $full_dest_path))

+				{

+					$this->dest_folder = $full_dest_path.'/';

+					$this->dest_image = $this->source_image;

+				}

+				else

+				{

+					$x = explode('/', $full_dest_path);

+					$this->dest_image = end($x);

+					$this->dest_folder = str_replace($this->dest_image, '', $full_dest_path);

+				}

+			}

+		}

+

+		/*

+		 * Compile the finalized filenames/paths

+		 *

+		 * We'll create two master strings containing the

+		 * full server path to the source image and the

+		 * full server path to the destination image.

+		 * We'll also split the destination image name

+		 * so we can insert the thumbnail marker if needed.

+		 *

+		 */

+		if ($this->create_thumb === FALSE OR $this->thumb_marker == '')

+		{

+			$this->thumb_marker = '';

+		}

+

+		$xp	= $this->explode_name($this->dest_image);

+

+		$filename = $xp['name'];

+		$file_ext = $xp['ext'];

+

+		$this->full_src_path = $this->source_folder.$this->source_image;

+		$this->full_dst_path = $this->dest_folder.$filename.$this->thumb_marker.$file_ext;

+

+		/*

+		 * Should we maintain image proportions?

+		 *

+		 * When creating thumbs or copies, the target width/height

+		 * might not be in correct proportion with the source

+		 * image's width/height.  We'll recalculate it here.

+		 *

+		 */

+		if ($this->maintain_ratio === TRUE && ($this->width != '' AND $this->height != ''))

+		{

+			$this->image_reproportion();

+		}

+

+		/*

+		 * Was a width and height specified?

+		 *

+		 * If the destination width/height was

+		 * not submitted we will use the values

+		 * from the actual file

+		 *

+		 */

+		if ($this->width == '')

+			$this->width = $this->orig_width;

+

+		if ($this->height == '')

+			$this->height = $this->orig_height;

+

+		// Set the quality

+		$this->quality = trim(str_replace("%", "", $this->quality));

+

+		if ($this->quality == '' OR $this->quality == 0 OR ! is_numeric($this->quality))

+			$this->quality = 90;

+

+		// Set the x/y coordinates

+		$this->x_axis = ($this->x_axis == '' OR ! is_numeric($this->x_axis)) ? 0 : $this->x_axis;

+		$this->y_axis = ($this->y_axis == '' OR ! is_numeric($this->y_axis)) ? 0 : $this->y_axis;

+

+		// Watermark-related Stuff...

+		if ($this->wm_font_color != '')

+		{

+			if (strlen($this->wm_font_color) == 6)

+			{

+				$this->wm_font_color = '#'.$this->wm_font_color;

+			}

+		}

+

+		if ($this->wm_shadow_color != '')

+		{

+			if (strlen($this->wm_shadow_color) == 6)

+			{

+				$this->wm_shadow_color = '#'.$this->wm_shadow_color;

+			}

+		}

+

+		if ($this->wm_overlay_path != '')

+		{

+			$this->wm_overlay_path = str_replace("\\", "/", realpath($this->wm_overlay_path));

+		}

+

+		if ($this->wm_shadow_color != '')

+		{

+			$this->wm_use_drop_shadow = TRUE;

+		}

+

+		if ($this->wm_font_path != '')

+		{

+			$this->wm_use_truetype = TRUE;

+		}

+

+		return TRUE;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Image Resize

+	 *

+	 * This is a wrapper function that chooses the proper

+	 * resize function based on the protocol specified

+	 *

+	 * @access	public

+	 * @return	bool

+	 */

+	function resize()

+	{

+		$protocol = 'image_process_'.$this->image_library;

+

+		if (eregi("gd2$", $protocol))

+		{

+			$protocol = 'image_process_gd';

+		}

+

+		return $this->$protocol('resize');

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Image Crop

+	 *

+	 * This is a wrapper function that chooses the proper

+	 * cropping function based on the protocol specified

+	 *

+	 * @access	public

+	 * @return	bool

+	 */

+	function crop()

+	{

+		$protocol = 'image_process_'.$this->image_library;

+

+		if (eregi("gd2$", $protocol))

+		{

+			$protocol = 'image_process_gd';

+		}

+

+		return $this->$protocol('crop');

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Image Rotate

+	 *

+	 * This is a wrapper function that chooses the proper

+	 * rotation function based on the protocol specified

+	 *

+	 * @access	public

+	 * @return	bool

+	 */

+	function rotate()

+	{

+		// Allowed rotation values

+		$degs = array(90, 180, 270, 'vrt', 'hor');

+

+		if ($this->rotation_angle == '' OR ! in_array($this->rotation_angle, $degs, TRUE))

+		{

+			$this->set_error('imglib_rotation_angle_required');

+			return FALSE;	   

+		}

+

+		// Reassign the width and height

+		if ($this->rotation_angle == 90 OR $this->rotation_angle == 270)

+		{

+			$this->width	= $this->orig_height;

+			$this->height	= $this->orig_width;

+		}

+		else

+		{

+			$this->width	= $this->orig_width;

+			$this->height	= $this->orig_height;

+		}

+

+

+		// Choose resizing function

+		if ($this->image_library == 'imagemagick' OR $this->image_library == 'netpbm')

+		{

+			$protocol = 'image_process_'.$this->image_library;

+

+			return $this->$protocol('rotate');

+		}

+

+		if ($this->rotation_angle == 'hor' OR $this->rotation_angle == 'vrt')

+		{

+			return $this->image_mirror_gd();

+		}

+		else

+		{

+			return $this->image_rotate_gd();

+		}

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Image Process Using GD/GD2

+	 *

+	 * This function will resize or crop

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	bool

+	 */

+	function image_process_gd($action = 'resize')

+	{

+		$v2_override = FALSE;

+

+		// If the target width/height match the source, AND if the new file name is not equal to the old file name

+		// we'll simply make a copy of the original with the new name... assuming dynamic rendering is off.

+		if ($this->dynamic_output === FALSE)

+		{

+			if ($this->orig_width == $this->width AND $this->orig_height == $this->height)

+			{

+ 				if ($this->source_image != $this->new_image)

+ 				{

+					if (@copy($this->full_src_path, $this->full_dst_path))

+					{

+						@chmod($this->full_dst_path, DIR_WRITE_MODE);

+					}

+				}

+

+				return TRUE;

+			}

+		}

+

+		// Let's set up our values based on the action

+		if ($action == 'crop')

+		{

+			//  Reassign the source width/height if cropping

+			$this->orig_width  = $this->width;

+			$this->orig_height = $this->height;

+

+			// GD 2.0 has a cropping bug so we'll test for it

+			if ($this->gd_version() !== FALSE)

+			{

+				$gd_version = str_replace('0', '', $this->gd_version());

+				$v2_override = ($gd_version == 2) ? TRUE : FALSE;

+			}

+		}

+		else

+		{

+			// If resizing the x/y axis must be zero

+			$this->x_axis = 0;

+			$this->y_axis = 0;

+		}

+

+		//  Create the image handle

+		if ( ! ($src_img = $this->image_create_gd()))

+		{

+			return FALSE;

+		}

+

+ 		//  Create The Image

+		//

+		//  old conditional which users report cause problems with shared GD libs who report themselves as "2.0 or greater"

+		//  it appears that this is no longer the issue that it was in 2004, so we've removed it, retaining it in the comment

+		//  below should that ever prove inaccurate.

+		//

+		//  if ($this->image_library == 'gd2' AND function_exists('imagecreatetruecolor') AND $v2_override == FALSE)

+ 		if ($this->image_library == 'gd2' AND function_exists('imagecreatetruecolor'))

+		{

+			$create	= 'imagecreatetruecolor';

+			$copy	= 'imagecopyresampled';

+		}

+		else

+		{

+			$create	= 'imagecreate';

+			$copy	= 'imagecopyresized';

+		}

+

+		$dst_img = $create($this->width, $this->height);

+		$copy($dst_img, $src_img, 0, 0, $this->x_axis, $this->y_axis, $this->width, $this->height, $this->orig_width, $this->orig_height);

+

+		//  Show the image

+		if ($this->dynamic_output == TRUE)

+		{

+			$this->image_display_gd($dst_img);

+		}

+		else

+		{

+			// Or save it

+			if ( ! $this->image_save_gd($dst_img))

+			{

+				return FALSE;

+			}

+		}

+

+		//  Kill the file handles

+		imagedestroy($dst_img);

+		imagedestroy($src_img);

+

+		// Set the file to 777

+		@chmod($this->full_dst_path, DIR_WRITE_MODE);

+

+		return TRUE;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Image Process Using ImageMagick

+	 *

+	 * This function will resize, crop or rotate

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	bool

+	 */

+	function image_process_imagemagick($action = 'resize')

+	{

+		//  Do we have a vaild library path?

+		if ($this->library_path == '')

+		{

+			$this->set_error('imglib_libpath_invalid');

+			return FALSE;

+		}

+

+		if ( ! eregi("convert$", $this->library_path))

+		{

+			if ( ! eregi("/$", $this->library_path)) $this->library_path .= "/";

+

+			$this->library_path .= 'convert';

+		}

+

+		// Execute the command

+		$cmd = $this->library_path." -quality ".$this->quality;

+

+		if ($action == 'crop')

+		{

+			$cmd .= " -crop ".$this->width."x".$this->height."+".$this->x_axis."+".$this->y_axis." \"$this->full_src_path\" \"$this->full_dst_path\" 2>&1";

+		}

+		elseif ($action == 'rotate')

+		{

+			switch ($this->rotation_angle)

+			{

+				case 'hor' 	: $angle = '-flop';

+					break;

+				case 'vrt' 	: $angle = '-flip';

+					break;

+				default		: $angle = '-rotate '.$this->rotation_angle;

+					break;

+			}

+

+			$cmd .= " ".$angle." \"$this->full_src_path\" \"$this->full_dst_path\" 2>&1";

+		}

+		else  // Resize

+		{

+			$cmd .= " -resize ".$this->width."x".$this->height." \"$this->full_src_path\" \"$this->full_dst_path\" 2>&1";

+		}

+

+		$retval = 1;

+

+		@exec($cmd, $output, $retval);

+

+		//	Did it work?

+		if ($retval > 0)

+		{

+			$this->set_error('imglib_image_process_failed');

+			return FALSE;

+		}

+

+		// Set the file to 777

+		@chmod($this->full_dst_path, DIR_WRITE_MODE);

+

+		return TRUE;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Image Process Using NetPBM

+	 *

+	 * This function will resize, crop or rotate

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	bool

+	 */

+	function image_process_netpbm($action = 'resize')

+	{

+		if ($this->library_path == '')

+		{

+			$this->set_error('imglib_libpath_invalid');

+			return FALSE;

+		}

+

+		//  Build the resizing command

+		switch ($this->image_type)

+		{

+			case 1 :

+						$cmd_in		= 'giftopnm';

+						$cmd_out	= 'ppmtogif';

+				break;

+			case 2 :

+						$cmd_in		= 'jpegtopnm';

+						$cmd_out	= 'ppmtojpeg';

+				break;

+			case 3 :

+						$cmd_in		= 'pngtopnm';

+						$cmd_out	= 'ppmtopng';

+				break;

+		}

+

+		if ($action == 'crop')

+		{

+			$cmd_inner = 'pnmcut -left '.$this->x_axis.' -top '.$this->y_axis.' -width '.$this->width.' -height '.$this->height;

+		}

+		elseif ($action == 'rotate')

+		{

+			switch ($this->rotation_angle)

+			{

+				case 90		:	$angle = 'r270';

+					break;

+				case 180	:	$angle = 'r180';

+					break;

+				case 270 	:	$angle = 'r90';

+					break;

+				case 'vrt'	:	$angle = 'tb';

+					break;

+				case 'hor'	:	$angle = 'lr';

+					break;

+			}

+

+			$cmd_inner = 'pnmflip -'.$angle.' ';

+		}

+		else // Resize

+		{

+			$cmd_inner = 'pnmscale -xysize '.$this->width.' '.$this->height;

+		}

+

+		$cmd = $this->library_path.$cmd_in.' '.$this->full_src_path.' | '.$cmd_inner.' | '.$cmd_out.' > '.$this->dest_folder.'netpbm.tmp';

+

+		$retval = 1;

+

+		@exec($cmd, $output, $retval);

+

+		//  Did it work?

+		if ($retval > 0)

+		{

+			$this->set_error('imglib_image_process_failed');

+			return FALSE;

+		}

+

+		// With NetPBM we have to create a temporary image.

+		// If you try manipulating the original it fails so

+		// we have to rename the temp file.

+		copy ($this->dest_folder.'netpbm.tmp', $this->full_dst_path);

+		unlink ($this->dest_folder.'netpbm.tmp');

+		@chmod($this->full_dst_path, DIR_WRITE_MODE);

+

+		return TRUE;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Image Rotate Using GD

+	 *

+	 * @access	public

+	 * @return	bool

+	 */

+	function image_rotate_gd()

+	{

+		// Is Image Rotation Supported?

+		// this function is only supported as of PHP 4.3

+		if ( ! function_exists('imagerotate'))

+		{

+			$this->set_error('imglib_rotate_unsupported');

+			return FALSE;

+		}

+

+		//  Create the image handle

+		if ( ! ($src_img = $this->image_create_gd()))

+		{

+			return FALSE;

+		}

+

+		// Set the background color

+		// This won't work with transparent PNG files so we are

+		// going to have to figure out how to determine the color

+		// of the alpha channel in a future release.

+

+		$white	= imagecolorallocate($src_img, 255, 255, 255);

+

+		//  Rotate it!

+		$dst_img = imagerotate($src_img, $this->rotation_angle, $white);

+

+		//  Save the Image

+		if ($this->dynamic_output == TRUE)

+		{

+			$this->image_display_gd($dst_img);

+		}

+		else

+		{

+			// Or save it

+			if ( ! $this->image_save_gd($dst_img))

+			{

+				return FALSE;

+			}

+		}

+

+		//  Kill the file handles

+		imagedestroy($dst_img);

+		imagedestroy($src_img);

+

+		// Set the file to 777

+

+		@chmod($this->full_dst_path, DIR_WRITE_MODE);

+

+		return true;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Create Mirror Image using GD

+	 *

+	 * This function will flip horizontal or vertical

+	 *

+	 * @access	public

+	 * @return	bool

+	 */

+	function image_mirror_gd()

+	{

+		if ( ! $src_img = $this->image_create_gd())

+		{

+			return FALSE;

+		}

+

+		$width  = $this->orig_width;

+		$height = $this->orig_height;

+

+		if ($this->rotation_angle == 'hor')

+		{

+			for ($i = 0; $i < $height; $i++)

+			{

+				$left  = 0;

+				$right = $width-1;

+

+				while ($left < $right)

+				{

+					$cl = imagecolorat($src_img, $left, $i);

+					$cr = imagecolorat($src_img, $right, $i);

+

+					imagesetpixel($src_img, $left, $i, $cr);

+					imagesetpixel($src_img, $right, $i, $cl);

+

+					$left++;

+					$right--;

+				}

+			}

+		}

+		else

+		{

+			for ($i = 0; $i < $width; $i++)

+			{

+				$top = 0;

+				$bot = $height-1;

+

+				while ($top < $bot)

+				{

+					$ct = imagecolorat($src_img, $i, $top);

+					$cb = imagecolorat($src_img, $i, $bot);

+

+					imagesetpixel($src_img, $i, $top, $cb);

+					imagesetpixel($src_img, $i, $bot, $ct);

+

+					$top++;

+					$bot--;

+				}

+			}

+		}

+

+		//  Show the image

+		if ($this->dynamic_output == TRUE)

+		{

+			$this->image_display_gd($src_img);

+		}

+		else

+		{

+			// Or save it

+			if ( ! $this->image_save_gd($src_img))

+			{

+				return FALSE;

+			}

+		}

+

+		//  Kill the file handles

+		imagedestroy($src_img);

+

+		// Set the file to 777

+		@chmod($this->full_dst_path, DIR_WRITE_MODE);

+

+		return TRUE;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Image Watermark

+	 *

+	 * This is a wrapper function that chooses the type

+	 * of watermarking based on the specified preference.

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	bool

+	 */

+	function watermark()

+	{

+		if ($this->wm_type == 'overlay')

+		{

+			return $this->overlay_watermark();

+		}

+		else

+		{

+			return $this->text_watermark();

+		}

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Watermark - Graphic Version

+	 *

+	 * @access	public

+	 * @return	bool

+	 */

+	function overlay_watermark()

+	{

+		if ( ! function_exists('imagecolortransparent'))

+		{

+			$this->set_error('imglib_gd_required');

+			return FALSE;

+		}

+

+		//  Fetch source image properties

+		$this->get_image_properties();

+

+		//  Fetch watermark image properties

+		$props 			= $this->get_image_properties($this->wm_overlay_path, TRUE);

+		$wm_img_type	= $props['image_type'];

+		$wm_width		= $props['width'];

+		$wm_height		= $props['height'];

+

+		//  Create two image resources

+		$wm_img  = $this->image_create_gd($this->wm_overlay_path, $wm_img_type);

+		$src_img = $this->image_create_gd($this->full_src_path);

+

+		// Reverse the offset if necessary

+		// When the image is positioned at the bottom

+		// we don't want the vertical offset to push it

+		// further down.  We want the reverse, so we'll

+		// invert the offset.  Same with the horizontal

+		// offset when the image is at the right

+

+		$this->wm_vrt_alignment = strtoupper(substr($this->wm_vrt_alignment, 0, 1));

+		$this->wm_hor_alignment = strtoupper(substr($this->wm_hor_alignment, 0, 1));

+

+		if ($this->wm_vrt_alignment == 'B')

+			$this->wm_vrt_offset = $this->wm_vrt_offset * -1;

+

+		if ($this->wm_hor_alignment == 'R')

+			$this->wm_hor_offset = $this->wm_hor_offset * -1;

+

+		//  Set the base x and y axis values

+		$x_axis = $this->wm_hor_offset + $this->wm_padding;

+		$y_axis = $this->wm_vrt_offset + $this->wm_padding;

+

+		//  Set the vertical position

+		switch ($this->wm_vrt_alignment)

+		{

+			case 'T':

+				break;

+			case 'M':	$y_axis += ($this->orig_height / 2) - ($wm_height / 2);

+				break;

+			case 'B':	$y_axis += $this->orig_height - $wm_height;

+				break;

+		}

+

+		//  Set the horizontal position

+		switch ($this->wm_hor_alignment)

+		{

+			case 'L':

+				break;

+			case 'C':	$x_axis += ($this->orig_width / 2) - ($wm_width / 2);

+				break;

+			case 'R':	$x_axis += $this->orig_width - $wm_width;

+				break;

+		}

+

+		//  Build the finalized image

+		if ($wm_img_type == 3 AND function_exists('imagealphablending'))

+		{

+			@imagealphablending($src_img, TRUE);

+		} 

+

+		// Set RGB values for text and shadow

+		$rgba = imagecolorat($wm_img, $this->wm_x_transp, $this->wm_y_transp);

+		$alpha = ($rgba & 0x7F000000) >> 24;

+

+		// make a best guess as to whether we're dealing with an image with alpha transparency or no/binary transparency

+		if ($alpha > 0)

+		{

+			// copy the image directly, the image's alpha transparency being the sole determinant of blending

+			imagecopy($src_img, $wm_img, $x_axis, $y_axis, 0, 0, $wm_width, $wm_height);

+		}

+		else

+		{

+			// set our RGB value from above to be transparent and merge the images with the specified opacity

+			imagecolortransparent($wm_img, imagecolorat($wm_img, $this->wm_x_transp, $this->wm_y_transp));

+			imagecopymerge($src_img, $wm_img, $x_axis, $y_axis, 0, 0, $wm_width, $wm_height, $this->wm_opacity);

+		}

+

+		//  Output the image

+		if ($this->dynamic_output == TRUE)

+		{

+			$this->image_display_gd($src_img);

+		}

+		else

+		{

+			if ( ! $this->image_save_gd($src_img))

+			{

+				return FALSE;

+			}

+		}

+

+		imagedestroy($src_img);

+		imagedestroy($wm_img);

+

+		return TRUE;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Watermark - Text Version

+	 *

+	 * @access	public

+	 * @return	bool

+	 */

+	function text_watermark()

+	{

+		if ( ! ($src_img = $this->image_create_gd()))

+		{

+			return FALSE;

+		}

+

+		if ($this->wm_use_truetype == TRUE AND ! file_exists($this->wm_font_path))

+		{

+			$this->set_error('imglib_missing_font');

+			return FALSE;

+		}

+

+		//  Fetch source image properties

+		$this->get_image_properties();

+

+		// Set RGB values for text and shadow

+		$this->wm_font_color	= str_replace('#', '', $this->wm_font_color);

+		$this->wm_shadow_color	= str_replace('#', '', $this->wm_shadow_color);

+

+		$R1 = hexdec(substr($this->wm_font_color, 0, 2));

+		$G1 = hexdec(substr($this->wm_font_color, 2, 2));

+		$B1 = hexdec(substr($this->wm_font_color, 4, 2));

+

+		$R2 = hexdec(substr($this->wm_shadow_color, 0, 2));

+		$G2 = hexdec(substr($this->wm_shadow_color, 2, 2));

+		$B2 = hexdec(substr($this->wm_shadow_color, 4, 2));

+

+		$txt_color	= imagecolorclosest($src_img, $R1, $G1, $B1);

+		$drp_color	= imagecolorclosest($src_img, $R2, $G2, $B2);

+

+		// Reverse the vertical offset

+		// When the image is positioned at the bottom

+		// we don't want the vertical offset to push it

+		// further down.  We want the reverse, so we'll

+		// invert the offset.  Note: The horizontal

+		// offset flips itself automatically

+

+		if ($this->wm_vrt_alignment == 'B')

+			$this->wm_vrt_offset = $this->wm_vrt_offset * -1;

+

+		if ($this->wm_hor_alignment == 'R')

+			$this->wm_hor_offset = $this->wm_hor_offset * -1;

+

+		// Set font width and height

+		// These are calculated differently depending on

+		// whether we are using the true type font or not

+		if ($this->wm_use_truetype == TRUE)

+		{

+			if ($this->wm_font_size == '')

+				$this->wm_font_size = '17';

+

+			$fontwidth  = $this->wm_font_size-($this->wm_font_size/4);

+			$fontheight = $this->wm_font_size;

+			$this->wm_vrt_offset += $this->wm_font_size;

+		}

+		else

+		{

+			$fontwidth  = imagefontwidth($this->wm_font_size);

+			$fontheight = imagefontheight($this->wm_font_size);

+		}

+

+		// Set base X and Y axis values

+		$x_axis = $this->wm_hor_offset + $this->wm_padding;

+		$y_axis = $this->wm_vrt_offset + $this->wm_padding;

+

+		// Set verticle alignment

+		if ($this->wm_use_drop_shadow == FALSE)

+			$this->wm_shadow_distance = 0;

+

+		$this->wm_vrt_alignment = strtoupper(substr($this->wm_vrt_alignment, 0, 1));

+		$this->wm_hor_alignment = strtoupper(substr($this->wm_hor_alignment, 0, 1));

+

+		switch ($this->wm_vrt_alignment)

+		{

+			case	 "T" :

+				break;

+			case "M":	$y_axis += ($this->orig_height/2)+($fontheight/2);

+				break;

+			case "B":	$y_axis += ($this->orig_height - $fontheight - $this->wm_shadow_distance - ($fontheight/2));

+				break;

+		}

+

+		$x_shad = $x_axis + $this->wm_shadow_distance;

+		$y_shad = $y_axis + $this->wm_shadow_distance;

+

+		// Set horizontal alignment

+		switch ($this->wm_hor_alignment)

+		{

+			case "L":

+				break;

+			case "R":

+						if ($this->wm_use_drop_shadow)

+							$x_shad += ($this->orig_width - $fontwidth*strlen($this->wm_text));

+							$x_axis += ($this->orig_width - $fontwidth*strlen($this->wm_text));

+				break;

+			case "C":

+						if ($this->wm_use_drop_shadow)

+							$x_shad += floor(($this->orig_width - $fontwidth*strlen($this->wm_text))/2);

+							$x_axis += floor(($this->orig_width  -$fontwidth*strlen($this->wm_text))/2);

+				break;

+		}

+

+		//  Add the text to the source image

+		if ($this->wm_use_truetype)

+		{

+			if ($this->wm_use_drop_shadow)

+				imagettftext($src_img, $this->wm_font_size, 0, $x_shad, $y_shad, $drp_color, $this->wm_font_path, $this->wm_text);

+				imagettftext($src_img, $this->wm_font_size, 0, $x_axis, $y_axis, $txt_color, $this->wm_font_path, $this->wm_text);

+		}

+		else

+		{

+			if ($this->wm_use_drop_shadow)

+				imagestring($src_img, $this->wm_font_size, $x_shad, $y_shad, $this->wm_text, $drp_color);

+				imagestring($src_img, $this->wm_font_size, $x_axis, $y_axis, $this->wm_text, $txt_color);

+		}

+

+		//  Output the final image

+		if ($this->dynamic_output == TRUE)

+		{

+			$this->image_display_gd($src_img);

+		}

+		else

+		{

+			$this->image_save_gd($src_img);

+		}

+

+		imagedestroy($src_img);

+

+		return TRUE;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Create Image - GD

+	 *

+	 * This simply creates an image resource handle

+	 * based on the type of image being processed

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	resource

+	 */

+	function image_create_gd($path = '', $image_type = '')

+	{

+		if ($path == '')

+			$path = $this->full_src_path;

+

+		if ($image_type == '')

+			$image_type = $this->image_type;

+

+

+		switch ($image_type)

+		{

+			case	 1 :

+						if ( ! function_exists('imagecreatefromgif'))

+						{

+							$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_gif_not_supported'));

+							return FALSE;

+						}

+

+						return imagecreatefromgif($path);

+				break;

+			case 2 :

+						if ( ! function_exists('imagecreatefromjpeg'))

+						{

+							$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_jpg_not_supported'));

+							return FALSE;

+						}

+

+						return imagecreatefromjpeg($path);

+				break;

+			case 3 :

+						if ( ! function_exists('imagecreatefrompng'))

+						{

+							$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_png_not_supported'));

+							return FALSE;

+						}

+

+						return imagecreatefrompng($path);

+				break;

+

+		}

+

+		$this->set_error(array('imglib_unsupported_imagecreate'));

+		return FALSE;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Write image file to disk - GD

+	 *

+	 * Takes an image resource as input and writes the file

+	 * to the specified destination

+	 *

+	 * @access	public

+	 * @param	resource

+	 * @return	bool

+	 */

+	function image_save_gd($resource)

+	{

+		switch ($this->image_type)

+		{

+			case 1 :

+						if ( ! function_exists('imagegif'))

+						{

+							$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_gif_not_supported'));

+							return FALSE;

+						}

+

+						@imagegif($resource, $this->full_dst_path);

+				break;

+			case 2	:

+						if ( ! function_exists('imagejpeg'))

+						{

+							$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_jpg_not_supported'));

+							return FALSE;

+						}

+

+						if (phpversion() == '4.4.1')

+						{

+							@touch($this->full_dst_path); // PHP 4.4.1 bug #35060 - workaround

+						}

+

+						@imagejpeg($resource, $this->full_dst_path, $this->quality);

+				break;

+			case 3	:

+						if ( ! function_exists('imagepng'))

+						{

+							$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_png_not_supported'));

+							return FALSE;

+						}

+

+						@imagepng($resource, $this->full_dst_path);

+				break;

+			default		:

+							$this->set_error(array('imglib_unsupported_imagecreate'));

+							return FALSE;

+				break;

+		}

+

+		return TRUE;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Dynamically outputs an image

+	 *

+	 * @access	public

+	 * @param	resource

+	 * @return	void

+	 */

+	function image_display_gd($resource)

+	{

+		header("Content-Disposition: filename={$this->source_image};");

+		header("Content-Type: {$this->mime_type}");

+		header('Content-Transfer-Encoding: binary');

+		header('Last-Modified: '.gmdate('D, d M Y H:i:s', time()).' GMT');

+

+		switch ($this->image_type)

+		{

+			case 1 		:	imagegif($resource);

+				break;

+			case 2		:	imagejpeg($resource, '', $this->quality);

+				break;

+			case 3		:	imagepng($resource);

+				break;

+			default		:	echo 'Unable to display the image';

+				break;

+		}

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Re-proportion Image Width/Height

+	 *

+	 * When creating thumbs, the desired width/height

+	 * can end up warping the image due to an incorrect

+	 * ratio between the full-sized image and the thumb.

+	 *

+	 * This function lets us re-proportion the width/height

+	 * if users choose to maintain the aspect ratio when resizing.

+	 *

+	 * @access	public

+	 * @return	void

+	 */

+	function image_reproportion()

+	{

+		if ( ! is_numeric($this->width) OR ! is_numeric($this->height) OR $this->width == 0 OR $this->height == 0)

+			return;

+

+		if ( ! is_numeric($this->orig_width) OR ! is_numeric($this->orig_height) OR $this->orig_width == 0 OR $this->orig_height == 0)

+			return;

+

+		$new_width	= ceil($this->orig_width*$this->height/$this->orig_height);

+		$new_height	= ceil($this->width*$this->orig_height/$this->orig_width);

+

+		$ratio = (($this->orig_height/$this->orig_width) - ($this->height/$this->width));

+

+		if ($this->master_dim != 'width' AND $this->master_dim != 'height')

+		{

+			$this->master_dim = ($ratio < 0) ? 'width' : 'height';

+		}

+

+		if (($this->width != $new_width) AND ($this->height != $new_height))

+		{

+			if ($this->master_dim == 'height')

+			{

+				$this->width = $new_width;

+			}

+			else

+			{

+				$this->height = $new_height;

+			}

+		}

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Get image properties

+	 *

+	 * A helper function that gets info about the file

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	mixed

+	 */

+	function get_image_properties($path = '', $return = FALSE)

+	{

+		// For now we require GD but we should

+		// find a way to determine this using IM or NetPBM

+

+		if ($path == '')

+			$path = $this->full_src_path;

+

+		if ( ! file_exists($path))

+		{

+			$this->set_error('imglib_invalid_path');

+			return FALSE;

+		}

+

+		$vals = @getimagesize($path);

+

+		$types = array(1 => 'gif', 2 => 'jpeg', 3 => 'png');

+

+		$mime = (isset($types[$vals['2']])) ? 'image/'.$types[$vals['2']] : 'image/jpg';

+

+		if ($return == TRUE)

+		{

+			$v['width']			= $vals['0'];

+			$v['height']		= $vals['1'];

+			$v['image_type']	= $vals['2'];

+			$v['size_str']		= $vals['3'];

+			$v['mime_type']		= $mime;

+

+			return $v;

+		}

+

+		$this->orig_width	= $vals['0'];

+		$this->orig_height	= $vals['1'];

+		$this->image_type	= $vals['2'];

+		$this->size_str		= $vals['3'];

+		$this->mime_type	= $mime;

+

+		return TRUE;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Size calculator

+	 *

+	 * This function takes a known width x height and

+	 * recalculates it to a new size.  Only one

+	 * new variable needs to be known

+	 *

+	 *	$props = array(

+	 *					'width' 		=> $width,

+	 *					'height' 		=> $height,

+	 *					'new_width'		=> 40,

+	 *					'new_height'	=> ''

+	 *				  );

+	 *

+	 * @access	public

+	 * @param	array

+	 * @return	array

+	 */

+	function size_calculator($vals)

+	{

+		if ( ! is_array($vals))

+		{

+			return;

+		}

+

+		$allowed = array('new_width', 'new_height', 'width', 'height');

+

+		foreach ($allowed as $item)

+		{

+			if ( ! isset($vals[$item]) OR $vals[$item] == '')

+				$vals[$item] = 0;

+		}

+

+		if ($vals['width'] == 0 OR $vals['height'] == 0)

+		{

+			return $vals;

+		}

+

+		if ($vals['new_width'] == 0)

+		{

+			$vals['new_width'] = ceil($vals['width']*$vals['new_height']/$vals['height']);

+		}

+		elseif ($vals['new_height'] == 0)

+		{

+			$vals['new_height'] = ceil($vals['new_width']*$vals['height']/$vals['width']);

+		}

+

+		return $vals;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Explode source_image

+	 *

+	 * This is a helper function that extracts the extension

+	 * from the source_image.  This function lets us deal with

+	 * source_images with multiple periods, like:  my.cool.jpg

+	 * It returns an associative array with two elements:

+	 * $array['ext']  = '.jpg';

+	 * $array['name'] = 'my.cool';

+	 *

+	 * @access	public

+	 * @param	array

+	 * @return	array

+	 */

+	function explode_name($source_image)

+	{

+		$x = explode('.', $source_image);

+		$ret['ext'] = '.'.end($x);

+

+		$name = '';

+

+		$ct = count($x)-1;

+

+		for ($i = 0; $i < $ct; $i++)

+		{

+			$name .= $x[$i];

+

+			if ($i < ($ct - 1))

+			{

+				$name .= '.';

+			}

+		}

+

+		$ret['name'] = $name;

+

+		return $ret;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Is GD Installed?

+	 *

+	 * @access	public

+	 * @return	bool

+	 */

+	function gd_loaded()

+	{

+		if ( ! extension_loaded('gd'))

+		{

+			if ( ! dl('gd.so'))

+			{

+				return FALSE;

+			}

+		}

+

+		return TRUE;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Get GD version

+	 *

+	 * @access	public

+	 * @return	mixed

+	 */

+	function gd_version()

+	{

+		if (function_exists('gd_info'))

+		{

+			$gd_version = @gd_info();

+			$gd_version = preg_replace("/\D/", "", $gd_version['GD Version']);

+

+			return $gd_version;

+		}

+

+		return FALSE;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Set error message

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	void

+	 */

+	function set_error($msg)

+	{

+		$CI =& get_instance();

+		$CI->lang->load('imglib');

+

+		if (is_array($msg))

+		{

+			foreach ($msg as $val)

+			{

+

+				$msg = ($CI->lang->line($val) == FALSE) ? $val : $CI->lang->line($val);

+				$this->error_msg[] = $msg;

+				log_message('error', $msg);

+			}

+		}

+		else

+		{

+			$msg = ($CI->lang->line($msg) == FALSE) ? $msg : $CI->lang->line($msg);

+			$this->error_msg[] = $msg;

+			log_message('error', $msg);

+		}

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Show error messages

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	string

+	 */

+	function display_errors($open = '<p>', $close = '</p>')

+	{

+		$str = '';

+		foreach ($this->error_msg as $val)

+		{

+			$str .= $open.$val.$close;

+		}

+

+		return $str;

+	}

+

+}

+// END Image_lib Class

+

+/* End of file Image_lib.php */

 /* Location: ./system/libraries/Image_lib.php */
\ No newline at end of file
diff --git a/system/libraries/Input.php b/system/libraries/Input.php
index f26df75..fe76559 100644
--- a/system/libraries/Input.php
+++ b/system/libraries/Input.php
@@ -1,1059 +1,1059 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
-/**
- * CodeIgniter
- *
- * An open source application development framework for PHP 4.3.2 or newer
- *
- * @package		CodeIgniter
- * @author		ExpressionEngine Dev Team
- * @copyright	Copyright (c) 2008, EllisLab, Inc.
- * @license		http://codeigniter.com/user_guide/license.html
- * @link		http://codeigniter.com
- * @since		Version 1.0
- * @filesource
- */
-
-// ------------------------------------------------------------------------
-
-/**
- * Input Class
- *
- * Pre-processes global input data for security
- *
- * @package		CodeIgniter
- * @subpackage	Libraries
- * @category	Input
- * @author		ExpressionEngine Dev Team
- * @link		http://codeigniter.com/user_guide/libraries/input.html
- */
-class CI_Input {
-	var $use_xss_clean		= FALSE;
-	var $xss_hash			= '';
-	var $ip_address			= FALSE;
-	var $user_agent			= FALSE;
-	var $allow_get_array	= FALSE;
-
-	/* never allowed, string replacement */
-	var $never_allowed_str = array(
-									'document.cookie'	=> '[removed]',
-									'document.write'	=> '[removed]',
-									'.parentNode'		=> '[removed]',
-									'.innerHTML'		=> '[removed]',
-									'window.location'	=> '[removed]',
-									'-moz-binding'		=> '[removed]',
-									'<!--'				=> '&lt;!--',
-									'-->'				=> '--&gt;',
-									'<![CDATA['			=> '&lt;![CDATA['
-									);
-	/* never allowed, regex replacement */
-	var $never_allowed_regex = array(
-										"javascript\s*:"	=> '[removed]',
-										"expression\s*\("	=> '[removed]', // CSS and IE
-										"Redirect\s+302"	=> '[removed]'
-									);
-
-	/**
-	* Constructor
-	*
-	* Sets whether to globally enable the XSS processing
-	* and whether to allow the $_GET array
-	*
-	* @access	public
-	*/
-	function CI_Input()
-	{
-		log_message('debug', "Input Class Initialized");
-
-		$CFG =& load_class('Config');
-		$this->use_xss_clean	= ($CFG->item('global_xss_filtering') === TRUE) ? TRUE : FALSE;
-		$this->allow_get_array	= ($CFG->item('enable_query_strings') === TRUE) ? TRUE : FALSE;
-		$this->_sanitize_globals();
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	* Sanitize Globals
-	*
-	* This function does the following:
-	*
-	* Unsets $_GET data (if query strings are not enabled)
-	*
-	* Unsets all globals if register_globals is enabled
-	*
-	* Standardizes newline characters to \n
-	*
-	* @access	private
-	* @return	void
-	*/
-	function _sanitize_globals()
-	{
-		// Would kind of be "wrong" to unset any of these GLOBALS
-		$protected = array('_SERVER', '_GET', '_POST', '_FILES', '_REQUEST', '_SESSION', '_ENV', 'GLOBALS', 'HTTP_RAW_POST_DATA',
-							'system_folder', 'application_folder', 'BM', 'EXT', 'CFG', 'URI', 'RTR', 'OUT', 'IN');
-
-		// Unset globals for security. 
-		// This is effectively the same as register_globals = off
-		foreach (array($_GET, $_POST, $_COOKIE, $_SERVER, $_FILES, $_ENV, (isset($_SESSION) && is_array($_SESSION)) ? $_SESSION : array()) as $global)
-		{
-			if ( ! is_array($global))
-			{
-				if ( ! in_array($global, $protected))
-				{
-					unset($GLOBALS[$global]);
-				}
-			}
-			else
-			{
-				foreach ($global as $key => $val)
-				{
-					if ( ! in_array($key, $protected))
-					{
-						unset($GLOBALS[$key]);
-					}
-
-					if (is_array($val))
-					{
-						foreach($val as $k => $v)
-						{
-							if ( ! in_array($k, $protected))
-							{
-								unset($GLOBALS[$k]);
-							}
-						}
-					}
-				}
-			}
-		}
-
-		// Is $_GET data allowed? If not we'll set the $_GET to an empty array
-		if ($this->allow_get_array == FALSE)
-		{
-			$_GET = array();
-		}
-		else
-		{
-			$_GET = $this->_clean_input_data($_GET);
-		}
-
-		// Clean $_POST Data
-		$_POST = $this->_clean_input_data($_POST);
-
-		// Clean $_COOKIE Data
-		// Also get rid of specially treated cookies that might be set by a server
-		// or silly application, that are of no use to a CI application anyway
-		// but that when present will trip our 'Disallowed Key Characters' alarm
-		// http://www.ietf.org/rfc/rfc2109.txt
-		// note that the key names below are single quoted strings, and are not PHP variables
-		unset($_COOKIE['$Version']);
-		unset($_COOKIE['$Path']);
-		unset($_COOKIE['$Domain']);
-		$_COOKIE = $this->_clean_input_data($_COOKIE);
-
-		log_message('debug', "Global POST and COOKIE data sanitized");
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	* Clean Input Data
-	*
-	* This is a helper function. It escapes data and
-	* standardizes newline characters to \n
-	*
-	* @access	private
-	* @param	string
-	* @return	string
-	*/
-	function _clean_input_data($str)
-	{
-		if (is_array($str))
-		{
-			$new_array = array();
-			foreach ($str as $key => $val)
-			{
-				$new_array[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);
-			}
-			return $new_array;
-		}
-
-		// We strip slashes if magic quotes is on to keep things consistent
-		if (get_magic_quotes_gpc())
-		{
-			$str = stripslashes($str);
-		}
-
-		// Should we filter the input data?
-		if ($this->use_xss_clean === TRUE)
-		{
-			$str = $this->xss_clean($str);
-		}
-
-		// Standardize newlines
-		if (strpos($str, "\r") !== FALSE)
-		{
-			$str = str_replace(array("\r\n", "\r"), "\n", $str);
-		}
-
-		return $str;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	* Clean Keys
-	*
-	* This is a helper function. To prevent malicious users
-	* from trying to exploit keys we make sure that keys are
-	* only named with alpha-numeric text and a few other items.
-	*
-	* @access	private
-	* @param	string
-	* @return	string
-	*/
-	function _clean_input_keys($str)
-	{
-		if ( ! preg_match("/^[a-z0-9:_\/-]+$/i", $str))
-		{
-			exit('Disallowed Key Characters.');
-		}
-
-		return $str;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	* Fetch from array
-	*
-	* This is a helper function to retrieve values from global arrays
-	*
-	* @access	private
-	* @param	array
-	* @param	string
-	* @param	bool
-	* @return	string
-	*/
-	function _fetch_from_array(&$array, $index = '', $xss_clean = FALSE)
-	{
-		if ( ! isset($array[$index]))
-		{
-			return FALSE;
-		}
-
-		if ($xss_clean === TRUE)
-		{
-			return $this->xss_clean($array[$index]);
-		}
-
-		return $array[$index];
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	* Fetch an item from the GET array
-	*
-	* @access	public
-	* @param	string
-	* @param	bool
-	* @return	string
-	*/
-	function get($index = '', $xss_clean = FALSE)
-	{
-		return $this->_fetch_from_array($_GET, $index, $xss_clean);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	* Fetch an item from the POST array
-	*
-	* @access	public
-	* @param	string
-	* @param	bool
-	* @return	string
-	*/
-	function post($index = '', $xss_clean = FALSE)
-	{
-		return $this->_fetch_from_array($_POST, $index, $xss_clean);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	* Fetch an item from either the GET array or the POST
-	*
-	* @access	public
-	* @param	string	The index key
-	* @param	bool	XSS cleaning
-	* @return	string
-	*/
-	function get_post($index = '', $xss_clean = FALSE)
-	{
-		if ( ! isset($_POST[$index]) )
-		{
-			return $this->get($index, $xss_clean);
-		}
-		else
-		{
-			return $this->post($index, $xss_clean);
-		}
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	* Fetch an item from the COOKIE array
-	*
-	* @access	public
-	* @param	string
-	* @param	bool
-	* @return	string
-	*/
-	function cookie($index = '', $xss_clean = FALSE)
-	{
-		return $this->_fetch_from_array($_COOKIE, $index, $xss_clean);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	* Fetch an item from the SERVER array
-	*
-	* @access	public
-	* @param	string
-	* @param	bool
-	* @return	string
-	*/
-	function server($index = '', $xss_clean = FALSE)
-	{
-		return $this->_fetch_from_array($_SERVER, $index, $xss_clean);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	* Fetch the IP Address
-	*
-	* @access	public
-	* @return	string
-	*/
-	function ip_address()
-	{
-		if ($this->ip_address !== FALSE)
-		{
-			return $this->ip_address;
-		}
-
-		if ($this->server('REMOTE_ADDR') AND $this->server('HTTP_CLIENT_IP'))
-		{
-			$this->ip_address = $_SERVER['HTTP_CLIENT_IP'];
-		}
-		elseif ($this->server('REMOTE_ADDR'))
-		{
-			$this->ip_address = $_SERVER['REMOTE_ADDR'];
-		}
-		elseif ($this->server('HTTP_CLIENT_IP'))
-		{
-			$this->ip_address = $_SERVER['HTTP_CLIENT_IP'];
-		}
-		elseif ($this->server('HTTP_X_FORWARDED_FOR'))
-		{
-			$this->ip_address = $_SERVER['HTTP_X_FORWARDED_FOR'];
-		}
-
-		if ($this->ip_address === FALSE)
-		{
-			$this->ip_address = '0.0.0.0';
-			return $this->ip_address;
-		}
-
-		if (strstr($this->ip_address, ','))
-		{
-			$x = explode(',', $this->ip_address);
-			$this->ip_address = end($x);
-		}
-
-		if ( ! $this->valid_ip($this->ip_address))
-		{
-			$this->ip_address = '0.0.0.0';
-		}
-
-		return $this->ip_address;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	* Validate IP Address
-	*
-	* Updated version suggested by Geert De Deckere
-	* 
-	* @access	public
-	* @param	string
-	* @return	string
-	*/
-	function valid_ip($ip)
-	{
-		$ip_segments = explode('.', $ip);
-
-		// Always 4 segments needed
-		if (count($ip_segments) != 4)
-		{
-			return FALSE;
-		}
-		// IP can not start with 0
-		if ($ip_segments[0][0] == '0')
-		{
-			return FALSE;
-		}
-		// Check each segment
-		foreach ($ip_segments as $segment)
-		{
-			// IP segments must be digits and can not be 
-			// longer than 3 digits or greater then 255
-			if ($segment == '' OR preg_match("/[^0-9]/", $segment) OR $segment > 255 OR strlen($segment) > 3)
-			{
-				return FALSE;
-			}
-		}
-
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	* User Agent
-	*
-	* @access	public
-	* @return	string
-	*/
-	function user_agent()
-	{
-		if ($this->user_agent !== FALSE)
-		{
-			return $this->user_agent;
-		}
-
-		$this->user_agent = ( ! isset($_SERVER['HTTP_USER_AGENT'])) ? FALSE : $_SERVER['HTTP_USER_AGENT'];
-
-		return $this->user_agent;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	* Filename Security
-	*
-	* @access	public
-	* @param	string
-	* @return	string
-	*/
-	function filename_security($str)
-	{
-		$bad = array(
-						"../",
-						"./",
-						"<!--",
-						"-->",
-						"<",
-						">",
-						"'",
-						'"',
-						'&',
-						'$',
-						'#',
-						'{',
-						'}',
-						'[',
-						']',
-						'=',
-						';',
-						'?',
-						"%20",
-						"%22",
-						"%3c",		// <
-						"%253c", 	// <
-						"%3e", 		// >
-						"%0e", 		// >
-						"%28", 		// (  
-						"%29", 		// ) 
-						"%2528", 	// (
-						"%26", 		// &
-						"%24", 		// $
-						"%3f", 		// ?
-						"%3b", 		// ;
-						"%3d"		// =
-					);
-
-		return stripslashes(str_replace($bad, '', $str));
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	* XSS Clean
-	*
-	* Sanitizes data so that Cross Site Scripting Hacks can be
-	* prevented.  This function does a fair amount of work but
-	* it is extremely thorough, designed to prevent even the
-	* most obscure XSS attempts.  Nothing is ever 100% foolproof,
-	* of course, but I haven't been able to get anything passed
-	* the filter.
-	*
-	* Note: This function should only be used to deal with data
-	* upon submission.  It's not something that should
-	* be used for general runtime processing.
-	*
-	* This function was based in part on some code and ideas I
-	* got from Bitflux: http://blog.bitflux.ch/wiki/XSS_Prevention
-	*
-	* To help develop this script I used this great list of
-	* vulnerabilities along with a few other hacks I've
-	* harvested from examining vulnerabilities in other programs:
-	* http://ha.ckers.org/xss.html
-	*
-	* @access	public
-	* @param	string
-	* @return	string
-	*/
-	function xss_clean($str, $is_image = FALSE)
-	{
-		/*
-		* Is the string an array?
-		*
-		*/
-		if (is_array($str))
-		{
-			while (list($key) = each($str))
-			{
-				$str[$key] = $this->xss_clean($str[$key]);
-			}
-
-			return $str;
-		}
-
-		/*
-		* Remove Invisible Characters
-		*/
-		$str = $this->_remove_invisible_characters($str);
-
-		/*
-		* Protect GET variables in URLs
-		*/
-
-		// 901119URL5918AMP18930PROTECT8198
-
-		$str = preg_replace('|\&([a-z\_0-9]+)\=([a-z\_0-9]+)|i', $this->xss_hash()."\\1=\\2", $str);
-
-		/*
-		* Validate standard character entities
-		*
-		* Add a semicolon if missing.  We do this to enable
-		* the conversion of entities to ASCII later.
-		*
-		*/
-		$str = preg_replace('#(&\#?[0-9a-z]{2,})[\x00-\x20]*;?#i', "\\1;", $str);
-
-		/*
-		* Validate UTF16 two byte encoding (x00) 
-		*
-		* Just as above, adds a semicolon if missing.
-		*
-		*/
-		$str = preg_replace('#(&\#x?)([0-9A-F]+);?#i',"\\1\\2;",$str);
-
-		/*
-		* Un-Protect GET variables in URLs
-		*/
-		$str = str_replace($this->xss_hash(), '&', $str);
-
-		/*
-		* URL Decode
-		*
-		* Just in case stuff like this is submitted:
-		*
-		* <a href="http://%77%77%77%2E%67%6F%6F%67%6C%65%2E%63%6F%6D">Google</a>
-		*
-		* Note: Use rawurldecode() so it does not remove plus signs
-		*
-		*/
-		$str = rawurldecode($str);
-
-		/*
-		* Convert character entities to ASCII 
-		*
-		* This permits our tests below to work reliably.
-		* We only convert entities that are within tags since
-		* these are the ones that will pose security problems.
-		*
-		*/
-
-		$str = preg_replace_callback("/[a-z]+=([\'\"]).*?\\1/si", array($this, '_convert_attribute'), $str);
-
-		$str = preg_replace_callback("/<\w+.*?(?=>|<|$)/si", array($this, '_html_entity_decode_callback'), $str);
-
-		/*
-		* Remove Invisible Characters Again!
-		*/
-		$str = $this->_remove_invisible_characters($str);
-
-		/*
-		* Convert all tabs to spaces
-		*
-		* This prevents strings like this: ja	vascript
-		* NOTE: we deal with spaces between characters later.
-		* NOTE: preg_replace was found to be amazingly slow here on large blocks of data,
-		* so we use str_replace.
-		*
-		*/
-
- 		if (strpos($str, "\t") !== FALSE)
-		{
-			$str = str_replace("\t", ' ', $str);
-		}
-
-		/*
-		* Capture converted string for later comparison
-		*/
-		$converted_string = $str;
-
-		/*
-		* Not Allowed Under Any Conditions
-		*/
-
-		foreach ($this->never_allowed_str as $key => $val)
-		{
-			$str = str_replace($key, $val, $str);   
-		}
-
-		foreach ($this->never_allowed_regex as $key => $val)
-		{
-			$str = preg_replace("#".$key."#i", $val, $str);   
-		}
-
-		/*
-		* Makes PHP tags safe
-		*
-		*  Note: XML tags are inadvertently replaced too:
-		*
-		*	<?xml
-		*
-		* But it doesn't seem to pose a problem.
-		*
-		*/
-		if ($is_image === TRUE)
-		{
-			// Images have a tendency to have the PHP short opening and closing tags every so often
-			// so we skip those and only do the long opening tags.
-			$str = str_replace(array('<?php', '<?PHP'),  array('&lt;?php', '&lt;?PHP'), $str);
-		}
-		else
-		{
-			$str = str_replace(array('<?php', '<?PHP', '<?', '?'.'>'),  array('&lt;?php', '&lt;?PHP', '&lt;?', '?&gt;'), $str);
-		}
-
-		/*
-		* Compact any exploded words
-		*
-		* This corrects words like:  j a v a s c r i p t
-		* These words are compacted back to their correct state.
-		*
-		*/
-		$words = array('javascript', 'expression', 'vbscript', 'script', 'applet', 'alert', 'document', 'write', 'cookie', 'window');
-		foreach ($words as $word)
-		{
-			$temp = '';
-
-			for ($i = 0, $wordlen = strlen($word); $i < $wordlen; $i++)
-			{
-				$temp .= substr($word, $i, 1)."\s*";
-			}
-
-			// We only want to do this when it is followed by a non-word character
-			// That way valid stuff like "dealer to" does not become "dealerto"
-			$str = preg_replace_callback('#('.substr($temp, 0, -3).')(\W)#is', array($this, '_compact_exploded_words'), $str);
-		}
-
-		/*
-		* Remove disallowed Javascript in links or img tags
-		* We used to do some version comparisons and use of stripos for PHP5, but it is dog slow compared
-		* to these simplified non-capturing preg_match(), especially if the pattern exists in the string
-		*/
-		do
-		{
-			$original = $str;
-
-			if (preg_match("/<a/i", $str))
-			{
-				$str = preg_replace_callback("#<a\s+([^>]*?)(>|$)#si", array($this, '_js_link_removal'), $str);
-			}
-
-			if (preg_match("/<img/i", $str))
-			{
-				$str = preg_replace_callback("#<img\s+([^>]*?)(\s?/?>|$)#si", array($this, '_js_img_removal'), $str);
-			}
-
-			if (preg_match("/script/i", $str) OR preg_match("/xss/i", $str))
-			{
-				$str = preg_replace("#<(/*)(script|xss)(.*?)\>#si", '[removed]', $str);
-			}
-		}
-		while($original != $str);
-
-		unset($original);
-
-		/*
-		* Remove JavaScript Event Handlers
-		*
-		* Note: This code is a little blunt.  It removes
-		* the event handler and anything up to the closing >,
-		* but it's unlikely to be a problem.
-		*
-		*/
-		$event_handlers = array('[^a-z_\-]on\w*','xmlns');
-
-		if ($is_image === TRUE)
-		{
-			/*
-			* Adobe Photoshop puts XML metadata into JFIF images, including namespacing, 
-			* so we have to allow this for images. -Paul
-			*/
-			unset($event_handlers[array_search('xmlns', $event_handlers)]);
-		}
-
-		$str = preg_replace("#<([^><]+?)(".implode('|', $event_handlers).")(\s*=\s*[^><]*)([><]*)#i", "<\\1\\4", $str);
-
-		/*
-		* Sanitize naughty HTML elements
-		*
-		* If a tag containing any of the words in the list
-		* below is found, the tag gets converted to entities.
-		*
-		* So this: <blink>
-		* Becomes: &lt;blink&gt;
-		*
-		*/
-		$naughty = 'alert|applet|audio|basefont|base|behavior|bgsound|blink|body|embed|expression|form|frameset|frame|head|html|ilayer|iframe|input|isindex|layer|link|meta|object|plaintext|style|script|textarea|title|video|xml|xss';
-		$str = preg_replace_callback('#<(/*\s*)('.$naughty.')([^><]*)([><]*)#is', array($this, '_sanitize_naughty_html'), $str);
-
-		/*
-		* Sanitize naughty scripting elements
-		*
-		* Similar to above, only instead of looking for
-		* tags it looks for PHP and JavaScript commands
-		* that are disallowed.  Rather than removing the
-		* code, it simply converts the parenthesis to entities
-		* rendering the code un-executable.
-		*
-		* For example:	eval('some code')
-		* Becomes:		eval&#40;'some code'&#41;
-		*
-		*/
-		$str = preg_replace('#(alert|cmd|passthru|eval|exec|expression|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)#si', "\\1\\2&#40;\\3&#41;", $str);
-
-		/*
-		* Final clean up
-		*
-		* This adds a bit of extra precaution in case
-		* something got through the above filters
-		*
-		*/
-		foreach ($this->never_allowed_str as $key => $val)
-		{
-			$str = str_replace($key, $val, $str);   
-		}
-
-		foreach ($this->never_allowed_regex as $key => $val)
-		{
-			$str = preg_replace("#".$key."#i", $val, $str);
-		}
-
-		/*
-		*  Images are Handled in a Special Way
-		*  - Essentially, we want to know that after all of the character conversion is done whether
-		*  any unwanted, likely XSS, code was found.  If not, we return TRUE, as the image is clean.
-		*  However, if the string post-conversion does not matched the string post-removal of XSS,
-		*  then it fails, as there was unwanted XSS code found and removed/changed during processing.
-		*/
-
-		if ($is_image === TRUE)
-		{
-			if ($str == $converted_string)
-			{
-				return TRUE;
-			}
-			else
-			{
-				return FALSE;
-			}
-		}
-
-		log_message('debug', "XSS Filtering completed");
-		return $str;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	* Random Hash for protecting URLs
-	*
-	* @access	public
-	* @return	string
-	*/
-	function xss_hash()
-	{
-		if ($this->xss_hash == '')
-		{
-			if (phpversion() >= 4.2)
-				mt_srand();
-			else
-				mt_srand(hexdec(substr(md5(microtime()), -8)) & 0x7fffffff);
-
-			$this->xss_hash = md5(time() + mt_rand(0, 1999999999));
-		}
-
-		return $this->xss_hash;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	* Remove Invisible Characters
-	*
-	* This prevents sandwiching null characters
-	* between ascii characters, like Java\0script.
-	*
-	* @access	public
-	* @param	string
-	* @return	string
-	*/
-	function _remove_invisible_characters($str)
-	{
-		static $non_displayables;
-
-		if ( ! isset($non_displayables))
-		{
-			// every control character except newline (dec 10), carriage return (dec 13), and horizontal tab (dec 09),
-			$non_displayables = array(
-										'/%0[0-8bcef]/',			// url encoded 00-08, 11, 12, 14, 15
-										'/%1[0-9a-f]/',				// url encoded 16-31
-										'/[\x00-\x08]/',			// 00-08
-										'/\x0b/', '/\x0c/',			// 11, 12
-										'/[\x0e-\x1f]/'				// 14-31
-									);
-		}
-
-		do
-		{
-			$cleaned = $str;
-			$str = preg_replace($non_displayables, '', $str);
-		}
-		while ($cleaned != $str);
-
-		return $str;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	* Compact Exploded Words
-	*
-	* Callback function for xss_clean() to remove whitespace from
-	* things like j a v a s c r i p t
-	*
-	* @access	public
-	* @param	type
-	* @return	type
-	*/
-	function _compact_exploded_words($matches)
-	{
-		return preg_replace('/\s+/s', '', $matches[1]).$matches[2];
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	* Sanitize Naughty HTML
-	*
-	* Callback function for xss_clean() to remove naughty HTML elements
-	*
-	* @access	private
-	* @param	array
-	* @return	string
-	*/
-	function _sanitize_naughty_html($matches)
-	{
-		// encode opening brace
-		$str = '&lt;'.$matches[1].$matches[2].$matches[3];
-
-		// encode captured opening or closing brace to prevent recursive vectors
-		$str .= str_replace(array('>', '<'), array('&gt;', '&lt;'), $matches[4]);
-
-		return $str;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	* JS Link Removal
-	*
-	* Callback function for xss_clean() to sanitize links
-	* This limits the PCRE backtracks, making it more performance friendly
-	* and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in
-	* PHP 5.2+ on link-heavy strings
-	*
-	* @access	private
-	* @param	array
-	* @return	string
-	*/
-	function _js_link_removal($match)
-	{
-		$attributes = $this->_filter_attributes(str_replace(array('<', '>'), '', $match[1]));
-		return str_replace($match[1], preg_replace("#href=.*?(alert\(|alert&\#40;|javascript\:|charset\=|window\.|document\.|\.cookie|<script|<xss|base64\s*,)#si", "", $attributes), $match[0]);
-	}
-
-	/**
-	* JS Image Removal
-	*
-	* Callback function for xss_clean() to sanitize image tags
-	* This limits the PCRE backtracks, making it more performance friendly
-	* and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in
-	* PHP 5.2+ on image tag heavy strings
-	*
-	* @access	private
-	* @param	array
-	* @return	string
-	*/
-	function _js_img_removal($match)
-	{
-		$attributes = $this->_filter_attributes(str_replace(array('<', '>'), '', $match[1]));
-		return str_replace($match[1], preg_replace("#src=.*?(alert\(|alert&\#40;|javascript\:|charset\=|window\.|document\.|\.cookie|<script|<xss|base64\s*,)#si", "", $attributes), $match[0]);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	* Attribute Conversion
-	*
-	* Used as a callback for XSS Clean
-	*
-	* @access	public
-	* @param	array
-	* @return	string
-	*/
-	function _convert_attribute($match)
-	{
-		return str_replace(array('>', '<'), array('&gt;', '&lt;'), $match[0]);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	* HTML Entity Decode Callback
-	*
-	* Used as a callback for XSS Clean
-	*
-	* @access	public
-	* @param	array
-	* @return	string
-	*/
-	function _html_entity_decode_callback($match)
-	{
-		$CFG =& load_class('Config');
-		$charset = $CFG->item('charset');
-
-		return $this->_html_entity_decode($match[0], strtoupper($charset));
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	* HTML Entities Decode
-	*
-	* This function is a replacement for html_entity_decode()
-	*
-	* In some versions of PHP the native function does not work
-	* when UTF-8 is the specified character set, so this gives us
-	* a work-around.  More info here:
-	* http://bugs.php.net/bug.php?id=25670
-	*
-	* @access	private
-	* @param	string
-	* @param	string
-	* @return	string
-	*/
-	/* -------------------------------------------------
-	/*  Replacement for html_entity_decode()
-	/* -------------------------------------------------*/
-
-	/*
-	NOTE: html_entity_decode() has a bug in some PHP versions when UTF-8 is the
-	character set, and the PHP developers said they were not back porting the
-	fix to versions other than PHP 5.x.
-	*/
-	function _html_entity_decode($str, $charset='UTF-8')
-	{
-		if (stristr($str, '&') === FALSE) return $str;
-
-		// The reason we are not using html_entity_decode() by itself is because
-		// while it is not technically correct to leave out the semicolon
-		// at the end of an entity most browsers will still interpret the entity
-		// correctly.  html_entity_decode() does not convert entities without
-		// semicolons, so we are left with our own little solution here. Bummer.
-
-		if (function_exists('html_entity_decode') && (strtolower($charset) != 'utf-8' OR version_compare(phpversion(), '5.0.0', '>=')))
-		{
-			$str = html_entity_decode($str, ENT_COMPAT, $charset);
-			$str = preg_replace('~&#x(0*[0-9a-f]{2,5})~ei', 'chr(hexdec("\\1"))', $str);
-			return preg_replace('~&#([0-9]{2,4})~e', 'chr(\\1)', $str);
-		}
-
-		// Numeric Entities
-		$str = preg_replace('~&#x(0*[0-9a-f]{2,5});{0,1}~ei', 'chr(hexdec("\\1"))', $str);
-		$str = preg_replace('~&#([0-9]{2,4});{0,1}~e', 'chr(\\1)', $str);
-
-		// Literal Entities - Slightly slow so we do another check
-		if (stristr($str, '&') === FALSE)
-		{
-			$str = strtr($str, array_flip(get_html_translation_table(HTML_ENTITIES)));
-		}
-
-		return $str;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	* Filter Attributes
-	*
-	* Filters tag attributes for consistency and safety
-	*
-	* @access	public
-	* @param	string
-	* @return	string
-	*/
-	function _filter_attributes($str)
-	{
-		$out = '';
-
-		if (preg_match_all('#\s*[a-z\-]+\s*=\s*(\042|\047)([^\\1]*?)\\1#is', $str, $matches))
-		{
-			foreach ($matches[0] as $match)
-			{
-				$out .= "{$match}";
-			}
-		}
-
-		return $out;
-	}
-
-	// --------------------------------------------------------------------
-
-}
-// END Input class
-
-/* End of file Input.php */
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

+/**

+ * CodeIgniter

+ *

+ * An open source application development framework for PHP 4.3.2 or newer

+ *

+ * @package		CodeIgniter

+ * @author		ExpressionEngine Dev Team

+ * @copyright	Copyright (c) 2008, EllisLab, Inc.

+ * @license		http://codeigniter.com/user_guide/license.html

+ * @link		http://codeigniter.com

+ * @since		Version 1.0

+ * @filesource

+ */

+

+// ------------------------------------------------------------------------

+

+/**

+ * Input Class

+ *

+ * Pre-processes global input data for security

+ *

+ * @package		CodeIgniter

+ * @subpackage	Libraries

+ * @category	Input

+ * @author		ExpressionEngine Dev Team

+ * @link		http://codeigniter.com/user_guide/libraries/input.html

+ */

+class CI_Input {

+	var $use_xss_clean		= FALSE;

+	var $xss_hash			= '';

+	var $ip_address			= FALSE;

+	var $user_agent			= FALSE;

+	var $allow_get_array	= FALSE;

+

+	/* never allowed, string replacement */

+	var $never_allowed_str = array(

+									'document.cookie'	=> '[removed]',

+									'document.write'	=> '[removed]',

+									'.parentNode'		=> '[removed]',

+									'.innerHTML'		=> '[removed]',

+									'window.location'	=> '[removed]',

+									'-moz-binding'		=> '[removed]',

+									'<!--'				=> '&lt;!--',

+									'-->'				=> '--&gt;',

+									'<![CDATA['			=> '&lt;![CDATA['

+									);

+	/* never allowed, regex replacement */

+	var $never_allowed_regex = array(

+										"javascript\s*:"	=> '[removed]',

+										"expression\s*\("	=> '[removed]', // CSS and IE

+										"Redirect\s+302"	=> '[removed]'

+									);

+

+	/**

+	* Constructor

+	*

+	* Sets whether to globally enable the XSS processing

+	* and whether to allow the $_GET array

+	*

+	* @access	public

+	*/

+	function CI_Input()

+	{

+		log_message('debug', "Input Class Initialized");

+

+		$CFG =& load_class('Config');

+		$this->use_xss_clean	= ($CFG->item('global_xss_filtering') === TRUE) ? TRUE : FALSE;

+		$this->allow_get_array	= ($CFG->item('enable_query_strings') === TRUE) ? TRUE : FALSE;

+		$this->_sanitize_globals();

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	* Sanitize Globals

+	*

+	* This function does the following:

+	*

+	* Unsets $_GET data (if query strings are not enabled)

+	*

+	* Unsets all globals if register_globals is enabled

+	*

+	* Standardizes newline characters to \n

+	*

+	* @access	private

+	* @return	void

+	*/

+	function _sanitize_globals()

+	{

+		// Would kind of be "wrong" to unset any of these GLOBALS

+		$protected = array('_SERVER', '_GET', '_POST', '_FILES', '_REQUEST', '_SESSION', '_ENV', 'GLOBALS', 'HTTP_RAW_POST_DATA',

+							'system_folder', 'application_folder', 'BM', 'EXT', 'CFG', 'URI', 'RTR', 'OUT', 'IN');

+

+		// Unset globals for security. 

+		// This is effectively the same as register_globals = off

+		foreach (array($_GET, $_POST, $_COOKIE, $_SERVER, $_FILES, $_ENV, (isset($_SESSION) && is_array($_SESSION)) ? $_SESSION : array()) as $global)

+		{

+			if ( ! is_array($global))

+			{

+				if ( ! in_array($global, $protected))

+				{

+					unset($GLOBALS[$global]);

+				}

+			}

+			else

+			{

+				foreach ($global as $key => $val)

+				{

+					if ( ! in_array($key, $protected))

+					{

+						unset($GLOBALS[$key]);

+					}

+

+					if (is_array($val))

+					{

+						foreach($val as $k => $v)

+						{

+							if ( ! in_array($k, $protected))

+							{

+								unset($GLOBALS[$k]);

+							}

+						}

+					}

+				}

+			}

+		}

+

+		// Is $_GET data allowed? If not we'll set the $_GET to an empty array

+		if ($this->allow_get_array == FALSE)

+		{

+			$_GET = array();

+		}

+		else

+		{

+			$_GET = $this->_clean_input_data($_GET);

+		}

+

+		// Clean $_POST Data

+		$_POST = $this->_clean_input_data($_POST);

+

+		// Clean $_COOKIE Data

+		// Also get rid of specially treated cookies that might be set by a server

+		// or silly application, that are of no use to a CI application anyway

+		// but that when present will trip our 'Disallowed Key Characters' alarm

+		// http://www.ietf.org/rfc/rfc2109.txt

+		// note that the key names below are single quoted strings, and are not PHP variables

+		unset($_COOKIE['$Version']);

+		unset($_COOKIE['$Path']);

+		unset($_COOKIE['$Domain']);

+		$_COOKIE = $this->_clean_input_data($_COOKIE);

+

+		log_message('debug', "Global POST and COOKIE data sanitized");

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	* Clean Input Data

+	*

+	* This is a helper function. It escapes data and

+	* standardizes newline characters to \n

+	*

+	* @access	private

+	* @param	string

+	* @return	string

+	*/

+	function _clean_input_data($str)

+	{

+		if (is_array($str))

+		{

+			$new_array = array();

+			foreach ($str as $key => $val)

+			{

+				$new_array[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);

+			}

+			return $new_array;

+		}

+

+		// We strip slashes if magic quotes is on to keep things consistent

+		if (get_magic_quotes_gpc())

+		{

+			$str = stripslashes($str);

+		}

+

+		// Should we filter the input data?

+		if ($this->use_xss_clean === TRUE)

+		{

+			$str = $this->xss_clean($str);

+		}

+

+		// Standardize newlines

+		if (strpos($str, "\r") !== FALSE)

+		{

+			$str = str_replace(array("\r\n", "\r"), "\n", $str);

+		}

+

+		return $str;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	* Clean Keys

+	*

+	* This is a helper function. To prevent malicious users

+	* from trying to exploit keys we make sure that keys are

+	* only named with alpha-numeric text and a few other items.

+	*

+	* @access	private

+	* @param	string

+	* @return	string

+	*/

+	function _clean_input_keys($str)

+	{

+		if ( ! preg_match("/^[a-z0-9:_\/-]+$/i", $str))

+		{

+			exit('Disallowed Key Characters.');

+		}

+

+		return $str;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	* Fetch from array

+	*

+	* This is a helper function to retrieve values from global arrays

+	*

+	* @access	private

+	* @param	array

+	* @param	string

+	* @param	bool

+	* @return	string

+	*/

+	function _fetch_from_array(&$array, $index = '', $xss_clean = FALSE)

+	{

+		if ( ! isset($array[$index]))

+		{

+			return FALSE;

+		}

+

+		if ($xss_clean === TRUE)

+		{

+			return $this->xss_clean($array[$index]);

+		}

+

+		return $array[$index];

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	* Fetch an item from the GET array

+	*

+	* @access	public

+	* @param	string

+	* @param	bool

+	* @return	string

+	*/

+	function get($index = '', $xss_clean = FALSE)

+	{

+		return $this->_fetch_from_array($_GET, $index, $xss_clean);

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	* Fetch an item from the POST array

+	*

+	* @access	public

+	* @param	string

+	* @param	bool

+	* @return	string

+	*/

+	function post($index = '', $xss_clean = FALSE)

+	{

+		return $this->_fetch_from_array($_POST, $index, $xss_clean);

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	* Fetch an item from either the GET array or the POST

+	*

+	* @access	public

+	* @param	string	The index key

+	* @param	bool	XSS cleaning

+	* @return	string

+	*/

+	function get_post($index = '', $xss_clean = FALSE)

+	{

+		if ( ! isset($_POST[$index]) )

+		{

+			return $this->get($index, $xss_clean);

+		}

+		else

+		{

+			return $this->post($index, $xss_clean);

+		}

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	* Fetch an item from the COOKIE array

+	*

+	* @access	public

+	* @param	string

+	* @param	bool

+	* @return	string

+	*/

+	function cookie($index = '', $xss_clean = FALSE)

+	{

+		return $this->_fetch_from_array($_COOKIE, $index, $xss_clean);

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	* Fetch an item from the SERVER array

+	*

+	* @access	public

+	* @param	string

+	* @param	bool

+	* @return	string

+	*/

+	function server($index = '', $xss_clean = FALSE)

+	{

+		return $this->_fetch_from_array($_SERVER, $index, $xss_clean);

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	* Fetch the IP Address

+	*

+	* @access	public

+	* @return	string

+	*/

+	function ip_address()

+	{

+		if ($this->ip_address !== FALSE)

+		{

+			return $this->ip_address;

+		}

+

+		if ($this->server('REMOTE_ADDR') AND $this->server('HTTP_CLIENT_IP'))

+		{

+			$this->ip_address = $_SERVER['HTTP_CLIENT_IP'];

+		}

+		elseif ($this->server('REMOTE_ADDR'))

+		{

+			$this->ip_address = $_SERVER['REMOTE_ADDR'];

+		}

+		elseif ($this->server('HTTP_CLIENT_IP'))

+		{

+			$this->ip_address = $_SERVER['HTTP_CLIENT_IP'];

+		}

+		elseif ($this->server('HTTP_X_FORWARDED_FOR'))

+		{

+			$this->ip_address = $_SERVER['HTTP_X_FORWARDED_FOR'];

+		}

+

+		if ($this->ip_address === FALSE)

+		{

+			$this->ip_address = '0.0.0.0';

+			return $this->ip_address;

+		}

+

+		if (strstr($this->ip_address, ','))

+		{

+			$x = explode(',', $this->ip_address);

+			$this->ip_address = end($x);

+		}

+

+		if ( ! $this->valid_ip($this->ip_address))

+		{

+			$this->ip_address = '0.0.0.0';

+		}

+

+		return $this->ip_address;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	* Validate IP Address

+	*

+	* Updated version suggested by Geert De Deckere

+	* 

+	* @access	public

+	* @param	string

+	* @return	string

+	*/

+	function valid_ip($ip)

+	{

+		$ip_segments = explode('.', $ip);

+

+		// Always 4 segments needed

+		if (count($ip_segments) != 4)

+		{

+			return FALSE;

+		}

+		// IP can not start with 0

+		if ($ip_segments[0][0] == '0')

+		{

+			return FALSE;

+		}

+		// Check each segment

+		foreach ($ip_segments as $segment)

+		{

+			// IP segments must be digits and can not be 

+			// longer than 3 digits or greater then 255

+			if ($segment == '' OR preg_match("/[^0-9]/", $segment) OR $segment > 255 OR strlen($segment) > 3)

+			{

+				return FALSE;

+			}

+		}

+

+		return TRUE;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	* User Agent

+	*

+	* @access	public

+	* @return	string

+	*/

+	function user_agent()

+	{

+		if ($this->user_agent !== FALSE)

+		{

+			return $this->user_agent;

+		}

+

+		$this->user_agent = ( ! isset($_SERVER['HTTP_USER_AGENT'])) ? FALSE : $_SERVER['HTTP_USER_AGENT'];

+

+		return $this->user_agent;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	* Filename Security

+	*

+	* @access	public

+	* @param	string

+	* @return	string

+	*/

+	function filename_security($str)

+	{

+		$bad = array(

+						"../",

+						"./",

+						"<!--",

+						"-->",

+						"<",

+						">",

+						"'",

+						'"',

+						'&',

+						'$',

+						'#',

+						'{',

+						'}',

+						'[',

+						']',

+						'=',

+						';',

+						'?',

+						"%20",

+						"%22",

+						"%3c",		// <

+						"%253c", 	// <

+						"%3e", 		// >

+						"%0e", 		// >

+						"%28", 		// (  

+						"%29", 		// ) 

+						"%2528", 	// (

+						"%26", 		// &

+						"%24", 		// $

+						"%3f", 		// ?

+						"%3b", 		// ;

+						"%3d"		// =

+					);

+

+		return stripslashes(str_replace($bad, '', $str));

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	* XSS Clean

+	*

+	* Sanitizes data so that Cross Site Scripting Hacks can be

+	* prevented.  This function does a fair amount of work but

+	* it is extremely thorough, designed to prevent even the

+	* most obscure XSS attempts.  Nothing is ever 100% foolproof,

+	* of course, but I haven't been able to get anything passed

+	* the filter.

+	*

+	* Note: This function should only be used to deal with data

+	* upon submission.  It's not something that should

+	* be used for general runtime processing.

+	*

+	* This function was based in part on some code and ideas I

+	* got from Bitflux: http://blog.bitflux.ch/wiki/XSS_Prevention

+	*

+	* To help develop this script I used this great list of

+	* vulnerabilities along with a few other hacks I've

+	* harvested from examining vulnerabilities in other programs:

+	* http://ha.ckers.org/xss.html

+	*

+	* @access	public

+	* @param	string

+	* @return	string

+	*/

+	function xss_clean($str, $is_image = FALSE)

+	{

+		/*

+		* Is the string an array?

+		*

+		*/

+		if (is_array($str))

+		{

+			while (list($key) = each($str))

+			{

+				$str[$key] = $this->xss_clean($str[$key]);

+			}

+

+			return $str;

+		}

+

+		/*

+		* Remove Invisible Characters

+		*/

+		$str = $this->_remove_invisible_characters($str);

+

+		/*

+		* Protect GET variables in URLs

+		*/

+

+		// 901119URL5918AMP18930PROTECT8198

+

+		$str = preg_replace('|\&([a-z\_0-9]+)\=([a-z\_0-9]+)|i', $this->xss_hash()."\\1=\\2", $str);

+

+		/*

+		* Validate standard character entities

+		*

+		* Add a semicolon if missing.  We do this to enable

+		* the conversion of entities to ASCII later.

+		*

+		*/

+		$str = preg_replace('#(&\#?[0-9a-z]{2,})[\x00-\x20]*;?#i', "\\1;", $str);

+

+		/*

+		* Validate UTF16 two byte encoding (x00) 

+		*

+		* Just as above, adds a semicolon if missing.

+		*

+		*/

+		$str = preg_replace('#(&\#x?)([0-9A-F]+);?#i',"\\1\\2;",$str);

+

+		/*

+		* Un-Protect GET variables in URLs

+		*/

+		$str = str_replace($this->xss_hash(), '&', $str);

+

+		/*

+		* URL Decode

+		*

+		* Just in case stuff like this is submitted:

+		*

+		* <a href="http://%77%77%77%2E%67%6F%6F%67%6C%65%2E%63%6F%6D">Google</a>

+		*

+		* Note: Use rawurldecode() so it does not remove plus signs

+		*

+		*/

+		$str = rawurldecode($str);

+

+		/*

+		* Convert character entities to ASCII 

+		*

+		* This permits our tests below to work reliably.

+		* We only convert entities that are within tags since

+		* these are the ones that will pose security problems.

+		*

+		*/

+

+		$str = preg_replace_callback("/[a-z]+=([\'\"]).*?\\1/si", array($this, '_convert_attribute'), $str);

+

+		$str = preg_replace_callback("/<\w+.*?(?=>|<|$)/si", array($this, '_html_entity_decode_callback'), $str);

+

+		/*

+		* Remove Invisible Characters Again!

+		*/

+		$str = $this->_remove_invisible_characters($str);

+

+		/*

+		* Convert all tabs to spaces

+		*

+		* This prevents strings like this: ja	vascript

+		* NOTE: we deal with spaces between characters later.

+		* NOTE: preg_replace was found to be amazingly slow here on large blocks of data,

+		* so we use str_replace.

+		*

+		*/

+

+ 		if (strpos($str, "\t") !== FALSE)

+		{

+			$str = str_replace("\t", ' ', $str);

+		}

+

+		/*

+		* Capture converted string for later comparison

+		*/

+		$converted_string = $str;

+

+		/*

+		* Not Allowed Under Any Conditions

+		*/

+

+		foreach ($this->never_allowed_str as $key => $val)

+		{

+			$str = str_replace($key, $val, $str);   

+		}

+

+		foreach ($this->never_allowed_regex as $key => $val)

+		{

+			$str = preg_replace("#".$key."#i", $val, $str);   

+		}

+

+		/*

+		* Makes PHP tags safe

+		*

+		*  Note: XML tags are inadvertently replaced too:

+		*

+		*	<?xml

+		*

+		* But it doesn't seem to pose a problem.

+		*

+		*/

+		if ($is_image === TRUE)

+		{

+			// Images have a tendency to have the PHP short opening and closing tags every so often

+			// so we skip those and only do the long opening tags.

+			$str = str_replace(array('<?php', '<?PHP'),  array('&lt;?php', '&lt;?PHP'), $str);

+		}

+		else

+		{

+			$str = str_replace(array('<?php', '<?PHP', '<?', '?'.'>'),  array('&lt;?php', '&lt;?PHP', '&lt;?', '?&gt;'), $str);

+		}

+

+		/*

+		* Compact any exploded words

+		*

+		* This corrects words like:  j a v a s c r i p t

+		* These words are compacted back to their correct state.

+		*

+		*/

+		$words = array('javascript', 'expression', 'vbscript', 'script', 'applet', 'alert', 'document', 'write', 'cookie', 'window');

+		foreach ($words as $word)

+		{

+			$temp = '';

+

+			for ($i = 0, $wordlen = strlen($word); $i < $wordlen; $i++)

+			{

+				$temp .= substr($word, $i, 1)."\s*";

+			}

+

+			// We only want to do this when it is followed by a non-word character

+			// That way valid stuff like "dealer to" does not become "dealerto"

+			$str = preg_replace_callback('#('.substr($temp, 0, -3).')(\W)#is', array($this, '_compact_exploded_words'), $str);

+		}

+

+		/*

+		* Remove disallowed Javascript in links or img tags

+		* We used to do some version comparisons and use of stripos for PHP5, but it is dog slow compared

+		* to these simplified non-capturing preg_match(), especially if the pattern exists in the string

+		*/

+		do

+		{

+			$original = $str;

+

+			if (preg_match("/<a/i", $str))

+			{

+				$str = preg_replace_callback("#<a\s+([^>]*?)(>|$)#si", array($this, '_js_link_removal'), $str);

+			}

+

+			if (preg_match("/<img/i", $str))

+			{

+				$str = preg_replace_callback("#<img\s+([^>]*?)(\s?/?>|$)#si", array($this, '_js_img_removal'), $str);

+			}

+

+			if (preg_match("/script/i", $str) OR preg_match("/xss/i", $str))

+			{

+				$str = preg_replace("#<(/*)(script|xss)(.*?)\>#si", '[removed]', $str);

+			}

+		}

+		while($original != $str);

+

+		unset($original);

+

+		/*

+		* Remove JavaScript Event Handlers

+		*

+		* Note: This code is a little blunt.  It removes

+		* the event handler and anything up to the closing >,

+		* but it's unlikely to be a problem.

+		*

+		*/

+		$event_handlers = array('[^a-z_\-]on\w*','xmlns');

+

+		if ($is_image === TRUE)

+		{

+			/*

+			* Adobe Photoshop puts XML metadata into JFIF images, including namespacing, 

+			* so we have to allow this for images. -Paul

+			*/

+			unset($event_handlers[array_search('xmlns', $event_handlers)]);

+		}

+

+		$str = preg_replace("#<([^><]+?)(".implode('|', $event_handlers).")(\s*=\s*[^><]*)([><]*)#i", "<\\1\\4", $str);

+

+		/*

+		* Sanitize naughty HTML elements

+		*

+		* If a tag containing any of the words in the list

+		* below is found, the tag gets converted to entities.

+		*

+		* So this: <blink>

+		* Becomes: &lt;blink&gt;

+		*

+		*/

+		$naughty = 'alert|applet|audio|basefont|base|behavior|bgsound|blink|body|embed|expression|form|frameset|frame|head|html|ilayer|iframe|input|isindex|layer|link|meta|object|plaintext|style|script|textarea|title|video|xml|xss';

+		$str = preg_replace_callback('#<(/*\s*)('.$naughty.')([^><]*)([><]*)#is', array($this, '_sanitize_naughty_html'), $str);

+

+		/*

+		* Sanitize naughty scripting elements

+		*

+		* Similar to above, only instead of looking for

+		* tags it looks for PHP and JavaScript commands

+		* that are disallowed.  Rather than removing the

+		* code, it simply converts the parenthesis to entities

+		* rendering the code un-executable.

+		*

+		* For example:	eval('some code')

+		* Becomes:		eval&#40;'some code'&#41;

+		*

+		*/

+		$str = preg_replace('#(alert|cmd|passthru|eval|exec|expression|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)#si', "\\1\\2&#40;\\3&#41;", $str);

+

+		/*

+		* Final clean up

+		*

+		* This adds a bit of extra precaution in case

+		* something got through the above filters

+		*

+		*/

+		foreach ($this->never_allowed_str as $key => $val)

+		{

+			$str = str_replace($key, $val, $str);   

+		}

+

+		foreach ($this->never_allowed_regex as $key => $val)

+		{

+			$str = preg_replace("#".$key."#i", $val, $str);

+		}

+

+		/*

+		*  Images are Handled in a Special Way

+		*  - Essentially, we want to know that after all of the character conversion is done whether

+		*  any unwanted, likely XSS, code was found.  If not, we return TRUE, as the image is clean.

+		*  However, if the string post-conversion does not matched the string post-removal of XSS,

+		*  then it fails, as there was unwanted XSS code found and removed/changed during processing.

+		*/

+

+		if ($is_image === TRUE)

+		{

+			if ($str == $converted_string)

+			{

+				return TRUE;

+			}

+			else

+			{

+				return FALSE;

+			}

+		}

+

+		log_message('debug', "XSS Filtering completed");

+		return $str;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	* Random Hash for protecting URLs

+	*

+	* @access	public

+	* @return	string

+	*/

+	function xss_hash()

+	{

+		if ($this->xss_hash == '')

+		{

+			if (phpversion() >= 4.2)

+				mt_srand();

+			else

+				mt_srand(hexdec(substr(md5(microtime()), -8)) & 0x7fffffff);

+

+			$this->xss_hash = md5(time() + mt_rand(0, 1999999999));

+		}

+

+		return $this->xss_hash;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	* Remove Invisible Characters

+	*

+	* This prevents sandwiching null characters

+	* between ascii characters, like Java\0script.

+	*

+	* @access	public

+	* @param	string

+	* @return	string

+	*/

+	function _remove_invisible_characters($str)

+	{

+		static $non_displayables;

+

+		if ( ! isset($non_displayables))

+		{

+			// every control character except newline (dec 10), carriage return (dec 13), and horizontal tab (dec 09),

+			$non_displayables = array(

+										'/%0[0-8bcef]/',			// url encoded 00-08, 11, 12, 14, 15

+										'/%1[0-9a-f]/',				// url encoded 16-31

+										'/[\x00-\x08]/',			// 00-08

+										'/\x0b/', '/\x0c/',			// 11, 12

+										'/[\x0e-\x1f]/'				// 14-31

+									);

+		}

+

+		do

+		{

+			$cleaned = $str;

+			$str = preg_replace($non_displayables, '', $str);

+		}

+		while ($cleaned != $str);

+

+		return $str;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	* Compact Exploded Words

+	*

+	* Callback function for xss_clean() to remove whitespace from

+	* things like j a v a s c r i p t

+	*

+	* @access	public

+	* @param	type

+	* @return	type

+	*/

+	function _compact_exploded_words($matches)

+	{

+		return preg_replace('/\s+/s', '', $matches[1]).$matches[2];

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	* Sanitize Naughty HTML

+	*

+	* Callback function for xss_clean() to remove naughty HTML elements

+	*

+	* @access	private

+	* @param	array

+	* @return	string

+	*/

+	function _sanitize_naughty_html($matches)

+	{

+		// encode opening brace

+		$str = '&lt;'.$matches[1].$matches[2].$matches[3];

+

+		// encode captured opening or closing brace to prevent recursive vectors

+		$str .= str_replace(array('>', '<'), array('&gt;', '&lt;'), $matches[4]);

+

+		return $str;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	* JS Link Removal

+	*

+	* Callback function for xss_clean() to sanitize links

+	* This limits the PCRE backtracks, making it more performance friendly

+	* and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in

+	* PHP 5.2+ on link-heavy strings

+	*

+	* @access	private

+	* @param	array

+	* @return	string

+	*/

+	function _js_link_removal($match)

+	{

+		$attributes = $this->_filter_attributes(str_replace(array('<', '>'), '', $match[1]));

+		return str_replace($match[1], preg_replace("#href=.*?(alert\(|alert&\#40;|javascript\:|charset\=|window\.|document\.|\.cookie|<script|<xss|base64\s*,)#si", "", $attributes), $match[0]);

+	}

+

+	/**

+	* JS Image Removal

+	*

+	* Callback function for xss_clean() to sanitize image tags

+	* This limits the PCRE backtracks, making it more performance friendly

+	* and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in

+	* PHP 5.2+ on image tag heavy strings

+	*

+	* @access	private

+	* @param	array

+	* @return	string

+	*/

+	function _js_img_removal($match)

+	{

+		$attributes = $this->_filter_attributes(str_replace(array('<', '>'), '', $match[1]));

+		return str_replace($match[1], preg_replace("#src=.*?(alert\(|alert&\#40;|javascript\:|charset\=|window\.|document\.|\.cookie|<script|<xss|base64\s*,)#si", "", $attributes), $match[0]);

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	* Attribute Conversion

+	*

+	* Used as a callback for XSS Clean

+	*

+	* @access	public

+	* @param	array

+	* @return	string

+	*/

+	function _convert_attribute($match)

+	{

+		return str_replace(array('>', '<'), array('&gt;', '&lt;'), $match[0]);

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	* HTML Entity Decode Callback

+	*

+	* Used as a callback for XSS Clean

+	*

+	* @access	public

+	* @param	array

+	* @return	string

+	*/

+	function _html_entity_decode_callback($match)

+	{

+		$CFG =& load_class('Config');

+		$charset = $CFG->item('charset');

+

+		return $this->_html_entity_decode($match[0], strtoupper($charset));

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	* HTML Entities Decode

+	*

+	* This function is a replacement for html_entity_decode()

+	*

+	* In some versions of PHP the native function does not work

+	* when UTF-8 is the specified character set, so this gives us

+	* a work-around.  More info here:

+	* http://bugs.php.net/bug.php?id=25670

+	*

+	* @access	private

+	* @param	string

+	* @param	string

+	* @return	string

+	*/

+	/* -------------------------------------------------

+	/*  Replacement for html_entity_decode()

+	/* -------------------------------------------------*/

+

+	/*

+	NOTE: html_entity_decode() has a bug in some PHP versions when UTF-8 is the

+	character set, and the PHP developers said they were not back porting the

+	fix to versions other than PHP 5.x.

+	*/

+	function _html_entity_decode($str, $charset='UTF-8')

+	{

+		if (stristr($str, '&') === FALSE) return $str;

+

+		// The reason we are not using html_entity_decode() by itself is because

+		// while it is not technically correct to leave out the semicolon

+		// at the end of an entity most browsers will still interpret the entity

+		// correctly.  html_entity_decode() does not convert entities without

+		// semicolons, so we are left with our own little solution here. Bummer.

+

+		if (function_exists('html_entity_decode') && (strtolower($charset) != 'utf-8' OR version_compare(phpversion(), '5.0.0', '>=')))

+		{

+			$str = html_entity_decode($str, ENT_COMPAT, $charset);

+			$str = preg_replace('~&#x(0*[0-9a-f]{2,5})~ei', 'chr(hexdec("\\1"))', $str);

+			return preg_replace('~&#([0-9]{2,4})~e', 'chr(\\1)', $str);

+		}

+

+		// Numeric Entities

+		$str = preg_replace('~&#x(0*[0-9a-f]{2,5});{0,1}~ei', 'chr(hexdec("\\1"))', $str);

+		$str = preg_replace('~&#([0-9]{2,4});{0,1}~e', 'chr(\\1)', $str);

+

+		// Literal Entities - Slightly slow so we do another check

+		if (stristr($str, '&') === FALSE)

+		{

+			$str = strtr($str, array_flip(get_html_translation_table(HTML_ENTITIES)));

+		}

+

+		return $str;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	* Filter Attributes

+	*

+	* Filters tag attributes for consistency and safety

+	*

+	* @access	public

+	* @param	string

+	* @return	string

+	*/

+	function _filter_attributes($str)

+	{

+		$out = '';

+

+		if (preg_match_all('#\s*[a-z\-]+\s*=\s*(\042|\047)([^\\1]*?)\\1#is', $str, $matches))

+		{

+			foreach ($matches[0] as $match)

+			{

+				$out .= "{$match}";

+			}

+		}

+

+		return $out;

+	}

+

+	// --------------------------------------------------------------------

+

+}

+// END Input class

+

+/* End of file Input.php */

 /* Location: ./system/libraries/Input.php */
\ No newline at end of file
diff --git a/system/libraries/Language.php b/system/libraries/Language.php
index 78f4143..bc237e7 100644
--- a/system/libraries/Language.php
+++ b/system/libraries/Language.php
@@ -1,123 +1,123 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
-/**
- * CodeIgniter
- *
- * An open source application development framework for PHP 4.3.2 or newer
- *
- * @package		CodeIgniter
- * @author		ExpressionEngine Dev Team
- * @copyright	Copyright (c) 2008, EllisLab, Inc.
- * @license		http://codeigniter.com/user_guide/license.html
- * @link		http://codeigniter.com
- * @since		Version 1.0
- * @filesource
- */
-
-// ------------------------------------------------------------------------
-
-/**
- * Language Class
- *
- * @package		CodeIgniter
- * @subpackage	Libraries
- * @category	Language
- * @author		ExpressionEngine Dev Team
- * @link		http://codeigniter.com/user_guide/libraries/language.html
- */
-class CI_Language {
-
-	var $language	= array();
-	var $is_loaded	= array();
-
-	/**
-	 * Constructor
-	 *
-	 * @access	public
-	 */
-	function CI_Language()
-	{
-		log_message('debug', "Language Class Initialized");
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Load a language file
-	 *
-	 * @access	public
-	 * @param	mixed	the name of the language file to be loaded. Can be an array
-	 * @param	string	the language (english, etc.)
-	 * @return	mixed
-	 */
-	function load($langfile = '', $idiom = '', $return = FALSE)
-	{
-		$langfile = str_replace(EXT, '', str_replace('_lang.', '', $langfile)).'_lang'.EXT;
-
-		if (in_array($langfile, $this->is_loaded, TRUE))
-		{
-			return;
-		}
-
-		if ($idiom == '')
-		{
-			$CI =& get_instance();
-			$deft_lang = $CI->config->item('language');
-			$idiom = ($deft_lang == '') ? 'english' : $deft_lang;
-		}
-
-		// Determine where the language file is and load it
-		if (file_exists(APPPATH.'language/'.$idiom.'/'.$langfile))
-		{
-			include(APPPATH.'language/'.$idiom.'/'.$langfile);
-		}
-		else
-		{
-			if (file_exists(BASEPATH.'language/'.$idiom.'/'.$langfile))
-			{
-				include(BASEPATH.'language/'.$idiom.'/'.$langfile);
-			}
-			else
-			{
-				show_error('Unable to load the requested language file: language/'.$langfile);
-			}
-		}
-
-		if ( ! isset($lang))
-		{
-			log_message('error', 'Language file contains no data: language/'.$idiom.'/'.$langfile);
-			return;
-		}
-
-		if ($return == TRUE)
-		{
-			return $lang;
-		}
-
-		$this->is_loaded[] = $langfile;
-		$this->language = array_merge($this->language, $lang);
-		unset($lang);
-
-		log_message('debug', 'Language file loaded: language/'.$idiom.'/'.$langfile);
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Fetch a single line of text from the language array
-	 *
-	 * @access	public
-	 * @param	string	$line 	the language line
-	 * @return	string
-	 */
-	function line($line = '')
-	{
-		$line = ($line == '' OR ! isset($this->language[$line])) ? FALSE : $this->language[$line];
-		return $line;
-	}
-
-}
-// END Language Class
-
-/* End of file Language.php */
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

+/**

+ * CodeIgniter

+ *

+ * An open source application development framework for PHP 4.3.2 or newer

+ *

+ * @package		CodeIgniter

+ * @author		ExpressionEngine Dev Team

+ * @copyright	Copyright (c) 2008, EllisLab, Inc.

+ * @license		http://codeigniter.com/user_guide/license.html

+ * @link		http://codeigniter.com

+ * @since		Version 1.0

+ * @filesource

+ */

+

+// ------------------------------------------------------------------------

+

+/**

+ * Language Class

+ *

+ * @package		CodeIgniter

+ * @subpackage	Libraries

+ * @category	Language

+ * @author		ExpressionEngine Dev Team

+ * @link		http://codeigniter.com/user_guide/libraries/language.html

+ */

+class CI_Language {

+

+	var $language	= array();

+	var $is_loaded	= array();

+

+	/**

+	 * Constructor

+	 *

+	 * @access	public

+	 */

+	function CI_Language()

+	{

+		log_message('debug', "Language Class Initialized");

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Load a language file

+	 *

+	 * @access	public

+	 * @param	mixed	the name of the language file to be loaded. Can be an array

+	 * @param	string	the language (english, etc.)

+	 * @return	mixed

+	 */

+	function load($langfile = '', $idiom = '', $return = FALSE)

+	{

+		$langfile = str_replace(EXT, '', str_replace('_lang.', '', $langfile)).'_lang'.EXT;

+

+		if (in_array($langfile, $this->is_loaded, TRUE))

+		{

+			return;

+		}

+

+		if ($idiom == '')

+		{

+			$CI =& get_instance();

+			$deft_lang = $CI->config->item('language');

+			$idiom = ($deft_lang == '') ? 'english' : $deft_lang;

+		}

+

+		// Determine where the language file is and load it

+		if (file_exists(APPPATH.'language/'.$idiom.'/'.$langfile))

+		{

+			include(APPPATH.'language/'.$idiom.'/'.$langfile);

+		}

+		else

+		{

+			if (file_exists(BASEPATH.'language/'.$idiom.'/'.$langfile))

+			{

+				include(BASEPATH.'language/'.$idiom.'/'.$langfile);

+			}

+			else

+			{

+				show_error('Unable to load the requested language file: language/'.$langfile);

+			}

+		}

+

+		if ( ! isset($lang))

+		{

+			log_message('error', 'Language file contains no data: language/'.$idiom.'/'.$langfile);

+			return;

+		}

+

+		if ($return == TRUE)

+		{

+			return $lang;

+		}

+

+		$this->is_loaded[] = $langfile;

+		$this->language = array_merge($this->language, $lang);

+		unset($lang);

+

+		log_message('debug', 'Language file loaded: language/'.$idiom.'/'.$langfile);

+		return TRUE;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Fetch a single line of text from the language array

+	 *

+	 * @access	public

+	 * @param	string	$line 	the language line

+	 * @return	string

+	 */

+	function line($line = '')

+	{

+		$line = ($line == '' OR ! isset($this->language[$line])) ? FALSE : $this->language[$line];

+		return $line;

+	}

+

+}

+// END Language Class

+

+/* End of file Language.php */

 /* Location: ./system/libraries/Language.php */
\ No newline at end of file
diff --git a/system/libraries/Session.php b/system/libraries/Session.php
index 660ce8f..25bf21f 100644
--- a/system/libraries/Session.php
+++ b/system/libraries/Session.php
@@ -1,758 +1,758 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
-/**
- * CodeIgniter
- *
- * An open source application development framework for PHP 4.3.2 or newer
- *
- * @package		CodeIgniter
- * @author		ExpressionEngine Dev Team
- * @copyright	Copyright (c) 2008, EllisLab, Inc.
- * @license		http://codeigniter.com/user_guide/license.html
- * @link		http://codeigniter.com
- * @since		Version 1.0
- * @filesource
- */
-
-// ------------------------------------------------------------------------
-
-/**
- * Session Class
- *
- * @package		CodeIgniter
- * @subpackage	Libraries
- * @category	Sessions
- * @author		ExpressionEngine Dev Team
- * @link		http://codeigniter.com/user_guide/libraries/sessions.html
- */
-class CI_Session {
-
-	var $sess_encrypt_cookie		= FALSE;
-	var $sess_use_database			= FALSE;
-	var $sess_table_name			= '';
-	var $sess_expiration			= 7200;
-	var $sess_match_ip				= FALSE;
-	var $sess_match_useragent		= TRUE;
-	var $sess_cookie_name			= 'ci_session';
-	var $cookie_prefix				= '';
-	var $cookie_path				= '';
-	var $cookie_domain				= '';
-	var $sess_time_to_update		= 300;
-	var $encryption_key				= '';
-	var $flashdata_key 				= 'flash';
-	var $time_reference				= 'time';
-	var $gc_probability				= 5;
-	var $userdata					= array();
-	var $CI;
-	var $now;
-
-	/**
-	 * Session Constructor
-	 *
-	 * The constructor runs the session routines automatically
-	 * whenever the class is instantiated.
-	 */
-	function CI_Session($params = array())
-	{
-		log_message('debug', "Session Class Initialized");
-
-		// Set the super object to a local variable for use throughout the class
-		$this->CI =& get_instance();
-
-		// Set all the session preferences, which can either be set
-		// manually via the $params array above or via the config file
-		foreach (array('sess_encrypt_cookie', 'sess_use_database', 'sess_table_name', 'sess_expiration', 'sess_match_ip', 'sess_match_useragent', 'sess_cookie_name', 'cookie_path', 'cookie_domain', 'sess_time_to_update', 'time_reference', 'cookie_prefix', 'encryption_key') as $key)
-		{
-			$this->$key = (isset($params[$key])) ? $params[$key] : $this->CI->config->item($key);
-		}
-
-		// Load the string helper so we can use the strip_slashes() function
-		$this->CI->load->helper('string');
-
-		// Do we need encryption? If so, load the encryption class
-		if ($this->sess_encrypt_cookie == TRUE)
-		{
-			$this->CI->load->library('encrypt');
-		}
-
-		// Are we using a database?  If so, load it
-		if ($this->sess_use_database === TRUE AND $this->sess_table_name != '')
-		{
-			$this->CI->load->database();
-		}
-
-		// Set the "now" time.  Can either be GMT or server time, based on the
-		// config prefs.  We use this to set the "last activity" time
-		$this->now = $this->_get_time();
-
-		// Set the session length. If the session expiration is
-		// set to zero we'll set the expiration two years from now.
-		if ($this->sess_expiration == 0)
-		{
-			$this->sess_expiration = (60*60*24*365*2);
-		}
-		 
-		// Set the cookie name
-		$this->sess_cookie_name = $this->cookie_prefix.$this->sess_cookie_name;
-
-		// Run the Session routine. If a session doesn't exist we'll
-		// create a new one.  If it does, we'll update it.
-		if ( ! $this->sess_read())
-		{
-			$this->sess_create();
-		}
-		else
-		{
-			$this->sess_update();
-		}
-
-		// Delete 'old' flashdata (from last request)
-	   	$this->_flashdata_sweep();
-
-		// Mark all new flashdata as old (data will be deleted before next request)
-	   	$this->_flashdata_mark();
-
-		// Delete expired sessions if necessary
-		$this->_sess_gc();
-
-		log_message('debug', "Session routines successfully run");
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Fetch the current session data if it exists
-	 *
-	 * @access	public
-	 * @return	bool
-	 */
-	function sess_read()
-	{
-		// Fetch the cookie
-		$session = $this->CI->input->cookie($this->sess_cookie_name);
-
-		// No cookie?  Goodbye cruel world!...
-		if ($session === FALSE)
-		{
-			log_message('debug', 'A session cookie was not found.');
-			return FALSE;
-		}
-
-		// Decrypt the cookie data
-		if ($this->sess_encrypt_cookie == TRUE)
-		{
-			$session = $this->CI->encrypt->decode($session);
-		}
-		else
-		{
-			// encryption was not used, so we need to check the md5 hash
-			$hash	 = substr($session, strlen($session)-32); // get last 32 chars
-			$session = substr($session, 0, strlen($session)-32);
-
-			// Does the md5 hash match?  This is to prevent manipulation of session data in userspace
-			if ($hash !==  md5($session.$this->encryption_key))
-			{
-				log_message('error', 'The session cookie data did not match what was expected. This could be a possible hacking attempt.');
-				$this->sess_destroy();
-				return FALSE;
-			}
-		}
-
-		// Unserialize the session array
-		$session = $this->_unserialize($session);
-
-		// Is the session data we unserialized an array with the correct format?
-		if ( ! is_array($session) OR ! isset($session['session_id']) OR ! isset($session['ip_address']) OR ! isset($session['user_agent']) OR ! isset($session['last_activity']))
-		{
-			$this->sess_destroy();
-			return FALSE;
-		}
-
-		// Is the session current?
-		if (($session['last_activity'] + $this->sess_expiration) < $this->now)
-		{
-			$this->sess_destroy();
-			return FALSE;
-		}
-
-		// Does the IP Match?
-		if ($this->sess_match_ip == TRUE AND $session['ip_address'] != $this->CI->input->ip_address())
-		{
-			$this->sess_destroy();
-			return FALSE;
-		}
-
-		// Does the User Agent Match?
-		if ($this->sess_match_useragent == TRUE AND trim($session['user_agent']) != trim(substr($this->CI->input->user_agent(), 0, 50)))
-		{
-			$this->sess_destroy();
-			return FALSE;
-		}
-
-		// Is there a corresponding session in the DB?
-		if ($this->sess_use_database === TRUE)
-		{
-			$this->CI->db->where('session_id', $session['session_id']);
-
-			if ($this->sess_match_ip == TRUE)
-			{
-				$this->CI->db->where('ip_address', $session['ip_address']);
-			}
-
-			if ($this->sess_match_useragent == TRUE)
-			{
-				$this->CI->db->where('user_agent', $session['user_agent']);
-			}
-
-			$query = $this->CI->db->get($this->sess_table_name);
-
-			// No result?  Kill it!
-			if ($query->num_rows() == 0)
-			{
-				$this->sess_destroy();
-				return FALSE;
-			}
-
-			// Is there custom data?  If so, add it to the main session array
-			$row = $query->row();
-			if (isset($row->user_data) AND $row->user_data != '')
-			{
-				$custom_data = $this->_unserialize($row->user_data);
-
-				if (is_array($custom_data))
-				{
-					foreach ($custom_data as $key => $val)
-					{
-						$session[$key] = $val;
-					}
-				}
-			}
-		}
-
-		// Session is valid!
-		$this->userdata = $session;
-		unset($session);
-
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Write the session data
-	 *
-	 * @access	public
-	 * @return	void
-	 */
-	function sess_write()
-	{
-		// Are we saving custom data to the DB?  If not, all we do is update the cookie
-		if ($this->sess_use_database === FALSE)
-		{
-			$this->_set_cookie();
-			return;
-		}
-
-		// set the custom userdata, the session data we will set in a second
-		$custom_userdata = $this->userdata;
-		$cookie_userdata = array();
-
-		// Before continuing, we need to determine if there is any custom data to deal with.
-		// Let's determine this by removing the default indexes to see if there's anything left in the array
-		// and set the session data while we're at it
-		foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
-		{
-			unset($custom_userdata[$val]);
-			$cookie_userdata[$val] = $this->userdata[$val];
-		}
-
-		// Did we find any custom data?  If not, we turn the empty array into a string
-		// since there's no reason to serialize and store an empty array in the DB
-		if (count($custom_userdata) === 0)
-		{
-			$custom_userdata = '';
-		}
-		else
-		{
-			// Serialize the custom data array so we can store it
-			$custom_userdata = $this->_serialize($custom_userdata);
-		}
-
-		// Run the update query
-		$this->CI->db->where('session_id', $this->userdata['session_id']);
-		$this->CI->db->update($this->sess_table_name, array('last_activity' => $this->userdata['last_activity'], 'user_data' => $custom_userdata));
-
-		// Write the cookie.  Notice that we manually pass the cookie data array to the
-		// _set_cookie() function. Normally that function will store $this->userdata, but
-		// in this case that array contains custom data, which we do not want in the cookie.
-		$this->_set_cookie($cookie_userdata);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Create a new session
-	 *
-	 * @access	public
-	 * @return	void
-	 */
-	function sess_create()
-	{
-		$sessid = '';
-		while (strlen($sessid) < 32)
-		{
-			$sessid .= mt_rand(0, mt_getrandmax());
-		}
-
-		// To make the session ID even more secure we'll combine it with the user's IP
-		$sessid .= $this->CI->input->ip_address();
-
-		$this->userdata = array(
-							'session_id' 	=> md5(uniqid($sessid, TRUE)),
-							'ip_address' 	=> $this->CI->input->ip_address(),
-							'user_agent' 	=> substr($this->CI->input->user_agent(), 0, 50),
-							'last_activity'	=> $this->now
-							);
-
-
-		// Save the data to the DB if needed
-		if ($this->sess_use_database === TRUE)
-		{
-			$this->CI->db->query($this->CI->db->insert_string($this->sess_table_name, $this->userdata));
-		}
-
-		// Write the cookie
-		$this->_set_cookie();
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Update an existing session
-	 *
-	 * @access	public
-	 * @return	void
-	 */
-	function sess_update()
-	{
-		// We only update the session every five minutes by default
-		if (($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now)
-		{
-			return;
-		}
-
-		// Save the old session id so we know which record to
-		// update in the database if we need it
-		$old_sessid = $this->userdata['session_id'];
-		$new_sessid = '';
-		while (strlen($new_sessid) < 32)
-		{
-			$new_sessid .= mt_rand(0, mt_getrandmax());
-		}
-
-		// To make the session ID even more secure we'll combine it with the user's IP
-		$new_sessid .= $this->CI->input->ip_address();
-
-		// Turn it into a hash
-		$new_sessid = md5(uniqid($new_sessid, TRUE));
-
-		// Update the session data in the session data array
-		$this->userdata['session_id'] = $new_sessid;
-		$this->userdata['last_activity'] = $this->now;
-
-		// _set_cookie() will handle this for us if we aren't using database sessions
-		// by pushing all userdata to the cookie.
-		$cookie_data = NULL;
-
-		// Update the session ID and last_activity field in the DB if needed
-		if ($this->sess_use_database === TRUE)
-		{
-			// set cookie explicitly to only have our session data
-			$cookie_data = array();
-			foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
-			{
-				$cookie_data[$val] = $this->userdata[$val];
-			}
-
-			$this->CI->db->query($this->CI->db->update_string($this->sess_table_name, array('last_activity' => $this->now, 'session_id' => $new_sessid), array('session_id' => $old_sessid)));
-		}
-
-		// Write the cookie
-		$this->_set_cookie($cookie_data);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Destroy the current session
-	 *
-	 * @access	public
-	 * @return	void
-	 */
-	function sess_destroy()
-	{
-		// Kill the session DB row
-		if ($this->sess_use_database === TRUE AND isset($this->userdata['session_id']))
-		{
-			$this->CI->db->where('session_id', $this->userdata['session_id']);
-			$this->CI->db->delete($this->sess_table_name);
-		}
-
-		// Kill the cookie
-		setcookie(
-					$this->sess_cookie_name,
-					addslashes(serialize(array())),
-					($this->now - 31500000),
-					$this->cookie_path,
-					$this->cookie_domain,
-					0
-				);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Fetch a specific item from the session array
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	string
-	 */
-	function userdata($item)
-	{
-		return ( ! isset($this->userdata[$item])) ? FALSE : $this->userdata[$item];
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Fetch all session data
-	 *
-	 * @access	public
-	 * @return	mixed
-	 */
-	function all_userdata()
-	{
-		return ( ! isset($this->userdata)) ? FALSE : $this->userdata;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Add or change data in the "userdata" array
-	 *
-	 * @access	public
-	 * @param	mixed
-	 * @param	string
-	 * @return	void
-	 */
-	function set_userdata($newdata = array(), $newval = '')
-	{
-		if (is_string($newdata))
-		{
-			$newdata = array($newdata => $newval);
-		}
-
-		if (count($newdata) > 0)
-		{
-			foreach ($newdata as $key => $val)
-			{
-				$this->userdata[$key] = $val;
-			}
-		}
-
-		$this->sess_write();
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Delete a session variable from the "userdata" array
-	 *
-	 * @access	array
-	 * @return	void
-	 */
-	function unset_userdata($newdata = array())
-	{
-		if (is_string($newdata))
-		{
-			$newdata = array($newdata => '');
-		}
-
-		if (count($newdata) > 0)
-		{
-			foreach ($newdata as $key => $val)
-			{
-				unset($this->userdata[$key]);
-			}
-		}
-
-		$this->sess_write();
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Add or change flashdata, only available
-	 * until the next request
-	 *
-	 * @access	public
-	 * @param	mixed
-	 * @param	string
-	 * @return	void
-	 */
-	function set_flashdata($newdata = array(), $newval = '')
-	{
-		if (is_string($newdata))
-		{
-			$newdata = array($newdata => $newval);
-		}
-
-		if (count($newdata) > 0)
-		{
-			foreach ($newdata as $key => $val)
-			{
-				$flashdata_key = $this->flashdata_key.':new:'.$key;
-				$this->set_userdata($flashdata_key, $val);
-			}
-		}
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Keeps existing flashdata available to next request.
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	void
-	 */
-	function keep_flashdata($key)
-	{
-		// 'old' flashdata gets removed.  Here we mark all
-		// flashdata as 'new' to preserve it from _flashdata_sweep()
-		// Note the function will return FALSE if the $key
-		// provided cannot be found
-		$old_flashdata_key = $this->flashdata_key.':old:'.$key;
-		$value = $this->userdata($old_flashdata_key);
-
-		$new_flashdata_key = $this->flashdata_key.':new:'.$key;
-		$this->set_userdata($new_flashdata_key, $value);
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Fetch a specific flashdata item from the session array
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	string
-	 */
-	function flashdata($key)
-	{
-		$flashdata_key = $this->flashdata_key.':old:'.$key;
-		return $this->userdata($flashdata_key);
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Identifies flashdata as 'old' for removal
-	 * when _flashdata_sweep() runs.
-	 *
-	 * @access	private
-	 * @return	void
-	 */
-	function _flashdata_mark()
-	{
-		$userdata = $this->all_userdata();
-		foreach ($userdata as $name => $value)
-		{
-			$parts = explode(':new:', $name);
-			if (is_array($parts) && count($parts) === 2)
-			{
-				$new_name = $this->flashdata_key.':old:'.$parts[1];
-				$this->set_userdata($new_name, $value);
-				$this->unset_userdata($name);
-			}
-		}
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Removes all flashdata marked as 'old'
-	 *
-	 * @access	private
-	 * @return	void
-	 */
-
-	function _flashdata_sweep()
-	{
-		$userdata = $this->all_userdata();
-		foreach ($userdata as $key => $value)
-		{
-			if (strpos($key, ':old:'))
-			{
-				$this->unset_userdata($key);
-			}
-		}
-
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Get the "now" time
-	 *
-	 * @access	private
-	 * @return	string
-	 */
-	function _get_time()
-	{
-		if (strtolower($this->time_reference) == 'gmt')
-		{
-			$now = time();
-			$time = mktime(gmdate("H", $now), gmdate("i", $now), gmdate("s", $now), gmdate("m", $now), gmdate("d", $now), gmdate("Y", $now));
-		}
-		else
-		{
-			$time = time();
-		}
-
-		return $time;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Write the session cookie
-	 *
-	 * @access	public
-	 * @return	void
-	 */
-	function _set_cookie($cookie_data = NULL)
-	{
-		if (is_null($cookie_data))
-		{
-			$cookie_data = $this->userdata;
-		}
-
-		// Serialize the userdata for the cookie
-		$cookie_data = $this->_serialize($cookie_data);
-
-		if ($this->sess_encrypt_cookie == TRUE)
-		{
-			$cookie_data = $this->CI->encrypt->encode($cookie_data);
-		}
-		else
-		{
-			// if encryption is not used, we provide an md5 hash to prevent userside tampering
-			$cookie_data = $cookie_data.md5($cookie_data.$this->encryption_key);
-		}
-
-		// Set the cookie
-		setcookie(
-					$this->sess_cookie_name,
-					$cookie_data,
-					$this->sess_expiration + time(),
-					$this->cookie_path,
-					$this->cookie_domain,
-					0
-				);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Serialize an array
-	 *
-	 * This function first converts any slashes found in the array to a temporary
-	 * marker, so when it gets unserialized the slashes will be preserved
-	 *
-	 * @access	private
-	 * @param	array
-	 * @return	string
-	 */
-	function _serialize($data)
-	{
-		if (is_array($data))
-		{
-			foreach ($data as $key => $val)
-			{
-				$data[$key] = str_replace('\\', '{{slash}}', $val);
-			}
-		}
-		else
-		{
-			$data = str_replace('\\', '{{slash}}', $data);
-		}
-
-		return serialize($data);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Unserialize
-	 *
-	 * This function unserializes a data string, then converts any
-	 * temporary slash markers back to actual slashes
-	 *
-	 * @access	private
-	 * @param	array
-	 * @return	string
-	 */
-	function _unserialize($data)
-	{
-		$data = @unserialize(strip_slashes($data));
-
-		if (is_array($data))
-		{
-			foreach ($data as $key => $val)
-			{
-				$data[$key] = str_replace('{{slash}}', '\\', $val);
-			}
-
-			return $data;
-		}
-
-		return str_replace('{{slash}}', '\\', $data);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Garbage collection
-	 *
-	 * This deletes expired session rows from database
-	 * if the probability percentage is met
-	 *
-	 * @access	public
-	 * @return	void
-	 */
-	function _sess_gc()
-	{
-		if ($this->sess_use_database != TRUE)
-		{
-			return;
-		}
-
-		srand(time());
-		if ((rand() % 100) < $this->gc_probability)
-		{
-			$expire = $this->now - $this->sess_expiration;
-
-			$this->CI->db->where("last_activity < {$expire}");
-			$this->CI->db->delete($this->sess_table_name);
-
-			log_message('debug', 'Session garbage collection performed.');
-		}
-	}
-
-
-}
-// END Session Class
-
-/* End of file Session.php */
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

+/**

+ * CodeIgniter

+ *

+ * An open source application development framework for PHP 4.3.2 or newer

+ *

+ * @package		CodeIgniter

+ * @author		ExpressionEngine Dev Team

+ * @copyright	Copyright (c) 2008, EllisLab, Inc.

+ * @license		http://codeigniter.com/user_guide/license.html

+ * @link		http://codeigniter.com

+ * @since		Version 1.0

+ * @filesource

+ */

+

+// ------------------------------------------------------------------------

+

+/**

+ * Session Class

+ *

+ * @package		CodeIgniter

+ * @subpackage	Libraries

+ * @category	Sessions

+ * @author		ExpressionEngine Dev Team

+ * @link		http://codeigniter.com/user_guide/libraries/sessions.html

+ */

+class CI_Session {

+

+	var $sess_encrypt_cookie		= FALSE;

+	var $sess_use_database			= FALSE;

+	var $sess_table_name			= '';

+	var $sess_expiration			= 7200;

+	var $sess_match_ip				= FALSE;

+	var $sess_match_useragent		= TRUE;

+	var $sess_cookie_name			= 'ci_session';

+	var $cookie_prefix				= '';

+	var $cookie_path				= '';

+	var $cookie_domain				= '';

+	var $sess_time_to_update		= 300;

+	var $encryption_key				= '';

+	var $flashdata_key 				= 'flash';

+	var $time_reference				= 'time';

+	var $gc_probability				= 5;

+	var $userdata					= array();

+	var $CI;

+	var $now;

+

+	/**

+	 * Session Constructor

+	 *

+	 * The constructor runs the session routines automatically

+	 * whenever the class is instantiated.

+	 */

+	function CI_Session($params = array())

+	{

+		log_message('debug', "Session Class Initialized");

+

+		// Set the super object to a local variable for use throughout the class

+		$this->CI =& get_instance();

+

+		// Set all the session preferences, which can either be set

+		// manually via the $params array above or via the config file

+		foreach (array('sess_encrypt_cookie', 'sess_use_database', 'sess_table_name', 'sess_expiration', 'sess_match_ip', 'sess_match_useragent', 'sess_cookie_name', 'cookie_path', 'cookie_domain', 'sess_time_to_update', 'time_reference', 'cookie_prefix', 'encryption_key') as $key)

+		{

+			$this->$key = (isset($params[$key])) ? $params[$key] : $this->CI->config->item($key);

+		}

+

+		// Load the string helper so we can use the strip_slashes() function

+		$this->CI->load->helper('string');

+

+		// Do we need encryption? If so, load the encryption class

+		if ($this->sess_encrypt_cookie == TRUE)

+		{

+			$this->CI->load->library('encrypt');

+		}

+

+		// Are we using a database?  If so, load it

+		if ($this->sess_use_database === TRUE AND $this->sess_table_name != '')

+		{

+			$this->CI->load->database();

+		}

+

+		// Set the "now" time.  Can either be GMT or server time, based on the

+		// config prefs.  We use this to set the "last activity" time

+		$this->now = $this->_get_time();

+

+		// Set the session length. If the session expiration is

+		// set to zero we'll set the expiration two years from now.

+		if ($this->sess_expiration == 0)

+		{

+			$this->sess_expiration = (60*60*24*365*2);

+		}

+		 

+		// Set the cookie name

+		$this->sess_cookie_name = $this->cookie_prefix.$this->sess_cookie_name;

+

+		// Run the Session routine. If a session doesn't exist we'll

+		// create a new one.  If it does, we'll update it.

+		if ( ! $this->sess_read())

+		{

+			$this->sess_create();

+		}

+		else

+		{

+			$this->sess_update();

+		}

+

+		// Delete 'old' flashdata (from last request)

+	   	$this->_flashdata_sweep();

+

+		// Mark all new flashdata as old (data will be deleted before next request)

+	   	$this->_flashdata_mark();

+

+		// Delete expired sessions if necessary

+		$this->_sess_gc();

+

+		log_message('debug', "Session routines successfully run");

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Fetch the current session data if it exists

+	 *

+	 * @access	public

+	 * @return	bool

+	 */

+	function sess_read()

+	{

+		// Fetch the cookie

+		$session = $this->CI->input->cookie($this->sess_cookie_name);

+

+		// No cookie?  Goodbye cruel world!...

+		if ($session === FALSE)

+		{

+			log_message('debug', 'A session cookie was not found.');

+			return FALSE;

+		}

+

+		// Decrypt the cookie data

+		if ($this->sess_encrypt_cookie == TRUE)

+		{

+			$session = $this->CI->encrypt->decode($session);

+		}

+		else

+		{

+			// encryption was not used, so we need to check the md5 hash

+			$hash	 = substr($session, strlen($session)-32); // get last 32 chars

+			$session = substr($session, 0, strlen($session)-32);

+

+			// Does the md5 hash match?  This is to prevent manipulation of session data in userspace

+			if ($hash !==  md5($session.$this->encryption_key))

+			{

+				log_message('error', 'The session cookie data did not match what was expected. This could be a possible hacking attempt.');

+				$this->sess_destroy();

+				return FALSE;

+			}

+		}

+

+		// Unserialize the session array

+		$session = $this->_unserialize($session);

+

+		// Is the session data we unserialized an array with the correct format?

+		if ( ! is_array($session) OR ! isset($session['session_id']) OR ! isset($session['ip_address']) OR ! isset($session['user_agent']) OR ! isset($session['last_activity']))

+		{

+			$this->sess_destroy();

+			return FALSE;

+		}

+

+		// Is the session current?

+		if (($session['last_activity'] + $this->sess_expiration) < $this->now)

+		{

+			$this->sess_destroy();

+			return FALSE;

+		}

+

+		// Does the IP Match?

+		if ($this->sess_match_ip == TRUE AND $session['ip_address'] != $this->CI->input->ip_address())

+		{

+			$this->sess_destroy();

+			return FALSE;

+		}

+

+		// Does the User Agent Match?

+		if ($this->sess_match_useragent == TRUE AND trim($session['user_agent']) != trim(substr($this->CI->input->user_agent(), 0, 50)))

+		{

+			$this->sess_destroy();

+			return FALSE;

+		}

+

+		// Is there a corresponding session in the DB?

+		if ($this->sess_use_database === TRUE)

+		{

+			$this->CI->db->where('session_id', $session['session_id']);

+

+			if ($this->sess_match_ip == TRUE)

+			{

+				$this->CI->db->where('ip_address', $session['ip_address']);

+			}

+

+			if ($this->sess_match_useragent == TRUE)

+			{

+				$this->CI->db->where('user_agent', $session['user_agent']);

+			}

+

+			$query = $this->CI->db->get($this->sess_table_name);

+

+			// No result?  Kill it!

+			if ($query->num_rows() == 0)

+			{

+				$this->sess_destroy();

+				return FALSE;

+			}

+

+			// Is there custom data?  If so, add it to the main session array

+			$row = $query->row();

+			if (isset($row->user_data) AND $row->user_data != '')

+			{

+				$custom_data = $this->_unserialize($row->user_data);

+

+				if (is_array($custom_data))

+				{

+					foreach ($custom_data as $key => $val)

+					{

+						$session[$key] = $val;

+					}

+				}

+			}

+		}

+

+		// Session is valid!

+		$this->userdata = $session;

+		unset($session);

+

+		return TRUE;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Write the session data

+	 *

+	 * @access	public

+	 * @return	void

+	 */

+	function sess_write()

+	{

+		// Are we saving custom data to the DB?  If not, all we do is update the cookie

+		if ($this->sess_use_database === FALSE)

+		{

+			$this->_set_cookie();

+			return;

+		}

+

+		// set the custom userdata, the session data we will set in a second

+		$custom_userdata = $this->userdata;

+		$cookie_userdata = array();

+

+		// Before continuing, we need to determine if there is any custom data to deal with.

+		// Let's determine this by removing the default indexes to see if there's anything left in the array

+		// and set the session data while we're at it

+		foreach (array('session_id','ip_address','user_agent','last_activity') as $val)

+		{

+			unset($custom_userdata[$val]);

+			$cookie_userdata[$val] = $this->userdata[$val];

+		}

+

+		// Did we find any custom data?  If not, we turn the empty array into a string

+		// since there's no reason to serialize and store an empty array in the DB

+		if (count($custom_userdata) === 0)

+		{

+			$custom_userdata = '';

+		}

+		else

+		{

+			// Serialize the custom data array so we can store it

+			$custom_userdata = $this->_serialize($custom_userdata);

+		}

+

+		// Run the update query

+		$this->CI->db->where('session_id', $this->userdata['session_id']);

+		$this->CI->db->update($this->sess_table_name, array('last_activity' => $this->userdata['last_activity'], 'user_data' => $custom_userdata));

+

+		// Write the cookie.  Notice that we manually pass the cookie data array to the

+		// _set_cookie() function. Normally that function will store $this->userdata, but

+		// in this case that array contains custom data, which we do not want in the cookie.

+		$this->_set_cookie($cookie_userdata);

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Create a new session

+	 *

+	 * @access	public

+	 * @return	void

+	 */

+	function sess_create()

+	{

+		$sessid = '';

+		while (strlen($sessid) < 32)

+		{

+			$sessid .= mt_rand(0, mt_getrandmax());

+		}

+

+		// To make the session ID even more secure we'll combine it with the user's IP

+		$sessid .= $this->CI->input->ip_address();

+

+		$this->userdata = array(

+							'session_id' 	=> md5(uniqid($sessid, TRUE)),

+							'ip_address' 	=> $this->CI->input->ip_address(),

+							'user_agent' 	=> substr($this->CI->input->user_agent(), 0, 50),

+							'last_activity'	=> $this->now

+							);

+

+

+		// Save the data to the DB if needed

+		if ($this->sess_use_database === TRUE)

+		{

+			$this->CI->db->query($this->CI->db->insert_string($this->sess_table_name, $this->userdata));

+		}

+

+		// Write the cookie

+		$this->_set_cookie();

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Update an existing session

+	 *

+	 * @access	public

+	 * @return	void

+	 */

+	function sess_update()

+	{

+		// We only update the session every five minutes by default

+		if (($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now)

+		{

+			return;

+		}

+

+		// Save the old session id so we know which record to

+		// update in the database if we need it

+		$old_sessid = $this->userdata['session_id'];

+		$new_sessid = '';

+		while (strlen($new_sessid) < 32)

+		{

+			$new_sessid .= mt_rand(0, mt_getrandmax());

+		}

+

+		// To make the session ID even more secure we'll combine it with the user's IP

+		$new_sessid .= $this->CI->input->ip_address();

+

+		// Turn it into a hash

+		$new_sessid = md5(uniqid($new_sessid, TRUE));

+

+		// Update the session data in the session data array

+		$this->userdata['session_id'] = $new_sessid;

+		$this->userdata['last_activity'] = $this->now;

+

+		// _set_cookie() will handle this for us if we aren't using database sessions

+		// by pushing all userdata to the cookie.

+		$cookie_data = NULL;

+

+		// Update the session ID and last_activity field in the DB if needed

+		if ($this->sess_use_database === TRUE)

+		{

+			// set cookie explicitly to only have our session data

+			$cookie_data = array();

+			foreach (array('session_id','ip_address','user_agent','last_activity') as $val)

+			{

+				$cookie_data[$val] = $this->userdata[$val];

+			}

+

+			$this->CI->db->query($this->CI->db->update_string($this->sess_table_name, array('last_activity' => $this->now, 'session_id' => $new_sessid), array('session_id' => $old_sessid)));

+		}

+

+		// Write the cookie

+		$this->_set_cookie($cookie_data);

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Destroy the current session

+	 *

+	 * @access	public

+	 * @return	void

+	 */

+	function sess_destroy()

+	{

+		// Kill the session DB row

+		if ($this->sess_use_database === TRUE AND isset($this->userdata['session_id']))

+		{

+			$this->CI->db->where('session_id', $this->userdata['session_id']);

+			$this->CI->db->delete($this->sess_table_name);

+		}

+

+		// Kill the cookie

+		setcookie(

+					$this->sess_cookie_name,

+					addslashes(serialize(array())),

+					($this->now - 31500000),

+					$this->cookie_path,

+					$this->cookie_domain,

+					0

+				);

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Fetch a specific item from the session array

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	string

+	 */

+	function userdata($item)

+	{

+		return ( ! isset($this->userdata[$item])) ? FALSE : $this->userdata[$item];

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Fetch all session data

+	 *

+	 * @access	public

+	 * @return	mixed

+	 */

+	function all_userdata()

+	{

+		return ( ! isset($this->userdata)) ? FALSE : $this->userdata;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Add or change data in the "userdata" array

+	 *

+	 * @access	public

+	 * @param	mixed

+	 * @param	string

+	 * @return	void

+	 */

+	function set_userdata($newdata = array(), $newval = '')

+	{

+		if (is_string($newdata))

+		{

+			$newdata = array($newdata => $newval);

+		}

+

+		if (count($newdata) > 0)

+		{

+			foreach ($newdata as $key => $val)

+			{

+				$this->userdata[$key] = $val;

+			}

+		}

+

+		$this->sess_write();

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Delete a session variable from the "userdata" array

+	 *

+	 * @access	array

+	 * @return	void

+	 */

+	function unset_userdata($newdata = array())

+	{

+		if (is_string($newdata))

+		{

+			$newdata = array($newdata => '');

+		}

+

+		if (count($newdata) > 0)

+		{

+			foreach ($newdata as $key => $val)

+			{

+				unset($this->userdata[$key]);

+			}

+		}

+

+		$this->sess_write();

+	}

+

+	// ------------------------------------------------------------------------

+

+	/**

+	 * Add or change flashdata, only available

+	 * until the next request

+	 *

+	 * @access	public

+	 * @param	mixed

+	 * @param	string

+	 * @return	void

+	 */

+	function set_flashdata($newdata = array(), $newval = '')

+	{

+		if (is_string($newdata))

+		{

+			$newdata = array($newdata => $newval);

+		}

+

+		if (count($newdata) > 0)

+		{

+			foreach ($newdata as $key => $val)

+			{

+				$flashdata_key = $this->flashdata_key.':new:'.$key;

+				$this->set_userdata($flashdata_key, $val);

+			}

+		}

+	}

+

+	// ------------------------------------------------------------------------

+

+	/**

+	 * Keeps existing flashdata available to next request.

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	void

+	 */

+	function keep_flashdata($key)

+	{

+		// 'old' flashdata gets removed.  Here we mark all

+		// flashdata as 'new' to preserve it from _flashdata_sweep()

+		// Note the function will return FALSE if the $key

+		// provided cannot be found

+		$old_flashdata_key = $this->flashdata_key.':old:'.$key;

+		$value = $this->userdata($old_flashdata_key);

+

+		$new_flashdata_key = $this->flashdata_key.':new:'.$key;

+		$this->set_userdata($new_flashdata_key, $value);

+	}

+

+	// ------------------------------------------------------------------------

+

+	/**

+	 * Fetch a specific flashdata item from the session array

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	string

+	 */

+	function flashdata($key)

+	{

+		$flashdata_key = $this->flashdata_key.':old:'.$key;

+		return $this->userdata($flashdata_key);

+	}

+

+	// ------------------------------------------------------------------------

+

+	/**

+	 * Identifies flashdata as 'old' for removal

+	 * when _flashdata_sweep() runs.

+	 *

+	 * @access	private

+	 * @return	void

+	 */

+	function _flashdata_mark()

+	{

+		$userdata = $this->all_userdata();

+		foreach ($userdata as $name => $value)

+		{

+			$parts = explode(':new:', $name);

+			if (is_array($parts) && count($parts) === 2)

+			{

+				$new_name = $this->flashdata_key.':old:'.$parts[1];

+				$this->set_userdata($new_name, $value);

+				$this->unset_userdata($name);

+			}

+		}

+	}

+

+	// ------------------------------------------------------------------------

+

+	/**

+	 * Removes all flashdata marked as 'old'

+	 *

+	 * @access	private

+	 * @return	void

+	 */

+

+	function _flashdata_sweep()

+	{

+		$userdata = $this->all_userdata();

+		foreach ($userdata as $key => $value)

+		{

+			if (strpos($key, ':old:'))

+			{

+				$this->unset_userdata($key);

+			}

+		}

+

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Get the "now" time

+	 *

+	 * @access	private

+	 * @return	string

+	 */

+	function _get_time()

+	{

+		if (strtolower($this->time_reference) == 'gmt')

+		{

+			$now = time();

+			$time = mktime(gmdate("H", $now), gmdate("i", $now), gmdate("s", $now), gmdate("m", $now), gmdate("d", $now), gmdate("Y", $now));

+		}

+		else

+		{

+			$time = time();

+		}

+

+		return $time;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Write the session cookie

+	 *

+	 * @access	public

+	 * @return	void

+	 */

+	function _set_cookie($cookie_data = NULL)

+	{

+		if (is_null($cookie_data))

+		{

+			$cookie_data = $this->userdata;

+		}

+

+		// Serialize the userdata for the cookie

+		$cookie_data = $this->_serialize($cookie_data);

+

+		if ($this->sess_encrypt_cookie == TRUE)

+		{

+			$cookie_data = $this->CI->encrypt->encode($cookie_data);

+		}

+		else

+		{

+			// if encryption is not used, we provide an md5 hash to prevent userside tampering

+			$cookie_data = $cookie_data.md5($cookie_data.$this->encryption_key);

+		}

+

+		// Set the cookie

+		setcookie(

+					$this->sess_cookie_name,

+					$cookie_data,

+					$this->sess_expiration + time(),

+					$this->cookie_path,

+					$this->cookie_domain,

+					0

+				);

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Serialize an array

+	 *

+	 * This function first converts any slashes found in the array to a temporary

+	 * marker, so when it gets unserialized the slashes will be preserved

+	 *

+	 * @access	private

+	 * @param	array

+	 * @return	string

+	 */

+	function _serialize($data)

+	{

+		if (is_array($data))

+		{

+			foreach ($data as $key => $val)

+			{

+				$data[$key] = str_replace('\\', '{{slash}}', $val);

+			}

+		}

+		else

+		{

+			$data = str_replace('\\', '{{slash}}', $data);

+		}

+

+		return serialize($data);

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Unserialize

+	 *

+	 * This function unserializes a data string, then converts any

+	 * temporary slash markers back to actual slashes

+	 *

+	 * @access	private

+	 * @param	array

+	 * @return	string

+	 */

+	function _unserialize($data)

+	{

+		$data = @unserialize(strip_slashes($data));

+

+		if (is_array($data))

+		{

+			foreach ($data as $key => $val)

+			{

+				$data[$key] = str_replace('{{slash}}', '\\', $val);

+			}

+

+			return $data;

+		}

+

+		return str_replace('{{slash}}', '\\', $data);

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Garbage collection

+	 *

+	 * This deletes expired session rows from database

+	 * if the probability percentage is met

+	 *

+	 * @access	public

+	 * @return	void

+	 */

+	function _sess_gc()

+	{

+		if ($this->sess_use_database != TRUE)

+		{

+			return;

+		}

+

+		srand(time());

+		if ((rand() % 100) < $this->gc_probability)

+		{

+			$expire = $this->now - $this->sess_expiration;

+

+			$this->CI->db->where("last_activity < {$expire}");

+			$this->CI->db->delete($this->sess_table_name);

+

+			log_message('debug', 'Session garbage collection performed.');

+		}

+	}

+

+

+}

+// END Session Class

+

+/* End of file Session.php */

 /* Location: ./system/libraries/Session.php */
\ No newline at end of file
diff --git a/system/libraries/Typography.php b/system/libraries/Typography.php
index 6a0f2ec..3ff0d2f 100644
--- a/system/libraries/Typography.php
+++ b/system/libraries/Typography.php
@@ -1,386 +1,385 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
-/**
- * CodeIgniter
- *
- * An open source application development framework for PHP 4.3.2 or newer
- *
- * @package		CodeIgniter
- * @author		ExpressionEngine Dev Team
- * @copyright	Copyright (c) 2008, EllisLab, Inc.
- * @license		http://codeigniter.com/user_guide/license.html
- * @link		http://codeigniter.com
- * @since		Version 1.0
- * @filesource
- */
-
-// ------------------------------------------------------------------------
-
-/**
- * Typography Class
- *
- *
- * @access		private
- * @category	Helpers
- * @author		ExpressionEngine Dev Team
- * @link		http://codeigniter.com/user_guide/helpers/
- */
-class CI_Typography {
-
-	// Block level elements that should not be wrapped inside <p> tags
-	var $block_elements = 'address|blockquote|div|dl|fieldset|form|h\d|hr|noscript|object|ol|p|pre|script|table|ul';
-	
-	// Elements that should not have <p> and <br /> tags within them.
-	var $skip_elements	= 'p|pre|ol|ul|dl|object|table';
-	
-	// Tags we want the parser to completely ignore when splitting the string.
-	var $inline_elements = 'a|abbr|acronym|b|bdo|big|br|button|cite|code|del|dfn|em|i|img|ins|input|label|map|kbd|q|samp|select|small|span|strong|sub|sup|textarea|tt|var';
-
-	// whether or not to protect quotes within { curly braces }
-	var $protect_braced_quotes = FALSE;
-	
-	/**
-	 * Nothing to do here...
-	 *
-	 */
-	function CI_Typography()
-	{
-	}
-
-	/**
-	 * Auto Typography
-	 *
-	 * This function converts text, making it typographically correct:
-	 * 	- Converts double spaces into paragraphs.
-	 * 	- Converts single line breaks into <br /> tags
-	 * 	- Converts single and double quotes into correctly facing curly quote entities.
-	 * 	- Converts three dots into ellipsis.
-	 * 	- Converts double dashes into em-dashes.
-	 *  - Converts two spaces into entities
-	 *
-	 * @access	public
-	 * @param	string
-	 * @param	bool	whether to reduce more then two consecutive newlines to two
-	 * @return	string
-	 */
-	function auto_typography($str, $reduce_linebreaks = FALSE)
-	{
-		if ($str == '')
-		{
-			return '';
-		}
-
-		// Standardize Newlines to make matching easier
-		if (strpos($str, "\r") !== FALSE)
-		{
-			$str = str_replace(array("\r\n", "\r"), "\n", $str);			
-		}
-			
-		// Reduce line breaks.  If there are more than two consecutive linebreaks
-		// we'll compress them down to a maximum of two since there's no benefit to more.
-		if ($reduce_linebreaks === TRUE)
-		{
-			$str = preg_replace("/\n\n+/", "\n\n", $str);
-		} 
-
-		// Convert quotes within tags to temporary markers. We don't want quotes converted 
-		// within tags so we'll temporarily convert them to {@DQ} and {@SQ}
-		// and we don't want double dashes converted to emdash entities, so they are marked with {@DD}
-		// likewise double spaces are converted to {@NBS} to prevent entity conversion
-		if (preg_match_all("#\<.+?>#si", $str, $matches))
-		{
-			for ($i = 0, $total = count($matches[0]); $i < $total; $i++)
-			{
-				$str = str_replace($matches[0][$i],
-									str_replace(array("'",'"','--','  '), array('{@SQ}', '{@DQ}', '{@DD}', '{@NBS}'), $matches[0][$i]),
-									$str);
-			}
-		}
-		
-		if ($this->protect_braced_quotes === TRUE)
-		{
-			if (preg_match_all("#\{.+?}#si", $str, $matches))
-			{
-				for ($i = 0, $total = count($matches[0]); $i < $total; $i++)
-				{
-					$str = str_replace($matches[0][$i],
-										str_replace(array("'",'"'), array('{@SQ}', '{@DQ}'), $matches[0][$i]),
-										$str);
-				}
-			}			
-		}
-		
-		// Convert "ignore" tags to temporary marker.  The parser splits out the string at every tag 
-		// it encounters.  Certain inline tags, like image tags, links, span tags, etc. will be 
-		// adversely affected if they are split out so we'll convert the opening bracket < temporarily to: {@TAG}
-		$str = preg_replace("#<(/*)(".$this->inline_elements.")([ >])#i", "{@TAG}\\1\\2\\3", $str);
-
-		// Split the string at every tag.  This expression creates an array with this prototype:
-		// 
-		// 	[array]
-		// 	{
-		// 		[0] = <opening tag>
-		// 		[1] = Content...
-		// 		[2] = <closing tag>
-		// 		Etc...
-		// 	}	
-		$chunks = preg_split('/(<(?:[^<>]+(?:"[^"]*"|\'[^\']*\')?)+>)/', $str, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
-		
-		// Build our finalized string.  We cycle through the array, skipping tags, and processing the contained text	
-		$str = '';
-		$process = TRUE;
-		$paragraph = FALSE;
-		foreach ($chunks as $chunk)
-		{
-			// Are we dealing with a tag? If so, we'll skip the processing for this cycle.
-			// Well also set the "process" flag which allows us to skip <pre> tags and a few other things.
-			if (preg_match("#<(/*)(".$this->block_elements.").*?\>#", $chunk, $match))
-			{
-				if (preg_match("#".$this->skip_elements."#", $match[2]))
-				{
-					$process =  ($match[1] == '/') ? TRUE : FALSE;
-				}
-				
-				$str .= $chunk;
-				continue;
-			}
-			elseif (preg_match('/<(\/?)([a-z]*).*?>/s', $chunk, $tagmatch))
-			{
-				if ($tagmatch[1] == '/' && $tagmatch[2] == $this->last_tag)
-				{
-					$process = FALSE;
-				}
-				else
-				{
-					$process = TRUE;
-					$this->last_tag = $tagmatch[2];					
-				}
-			}
-
-			if ($process == FALSE)
-			{
-				$str .= $chunk;
-				continue;
-			}
-			
-			//  Convert Newlines into <p> and <br /> tags
-			$str .= $this->format_characters($this->_format_newlines($chunk));			
-		}
-
-		// is the whole of the content inside a block level element?
-		if ( ! preg_match("/^<(?:".$this->block_elements.")/i", $str, $match))
-		{
-			$str = "<p>{$str}</p>";
-		}
-
-
-		// some special linebreak cleanup
-		$str = preg_replace_callback('#<(?!/|'.$this->block_elements.')([^>]*)><p>(.*?)</p><(\w*)#si', array($this, '_linebreak_cleanup'), $str);
-		
-		// and cleanup empty paragraph tags sitting between two closing tags
-		$str = preg_replace('#(</\w+>)<p>(\s*)</p>(</\w+>)#si', '$1$2$3', $str);
-		
-		// Final clean up
-		$table = array(
-		
-						// If the user submitted their own paragraph tags within the text
-						// we will retain them instead of using our tags.
-						'/(<p[^>*?]>)<p>/'	=> '$1', // <?php BBEdit syntax coloring bug fix
-						
-						// Reduce multiple instances of opening/closing paragraph tags to a single one
-						'#(</p>)+#'			=> '</p>',
-						'/(<p><p>)+/'		=> '<p>',
-						'/(<p>\W+<p>)+/'	=> '<p>',
-						
-						// Clean up stray paragraph tags that appear before block level elements
-						'#<p></p><('.$this->block_elements.')#'	=> '<$1',
-						
-						// Clean up open paragraph tags that appear before block level elements
-						'#<p>(\W)<('.$this->block_elements.')#'	=> '<p></p>$1<$2',
-
-						// Clean up stray non-breaking spaces preceeding block elements
-						'#[&nbsp; ]+<('.$this->block_elements.')#'	=> '  <$1',
-			
-						// Replace the temporary markers we added earlier
-						'/\{@TAG\}/'		=> '<',
-						'/\{@DQ\}/'			=> '"',
-						'/\{@SQ\}/'			=> "'",
-						'/\{@DD\}/'			=> '--',
-						'/\{@NBS\}/'		=> '  '
-
-						);
-
-		// Do we need to reduce empty lines?
-		if ($reduce_linebreaks === TRUE)
-		{
-			$table['#<p>\n*</p>#'] = '';
-		}
-		else
-		{
-			// If we have empty paragraph tags we add a non-breaking space
-			// otherwise most browsers won't treat them as true paragraphs
-			$table['#<p></p>#'] = '<p>&nbsp;</p>';
-		}
-	
-		return preg_replace(array_keys($table), $table, $str);
-
-	}
-	
-	// --------------------------------------------------------------------
-	
-	/**
-	 * Linebreak Cleanup
-	 *
-	 * Removes paragraph and line break tags inserted inbetween
-	 * inline content and a new opening block level element
-	 *
-	 * @access	private
-	 * @param	array
-	 * @return	string
-	 */
-	function _linebreak_cleanup($match)
-	{
-		if (in_array($match[3], explode('|', $this->block_elements)))
-		{
-			return "<{$match[1]}>".str_replace('<br />', '', $match[2])."<{$match[3]}";
-		}
-		else
-		{
-			return $match[0];
-		}
-	}
-
-	// --------------------------------------------------------------------
-	
-	/**
-	 * Format Characters
-	 *
-	 * This function mainly converts double and single quotes
-	 * to curly entities, but it also converts em-dashes,
-	 * double spaces, and ampersands
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	string
-	 */
-	function format_characters($str)
-	{
-		static $table;
-		
-		if ( ! isset($table))
-		{
-	        $table = array(					
-							// nested smart quotes, opening and closing
-							// note that rules for grammar (English) allow only for two levels deep
-							// and that single quotes are _supposed_ to always be on the outside
-							// but we'll accommodate both
-							'/(^|\W|\s)\'"/'				=> '$1&#8216;&#8220;',
-							'/\'"(\s|\W|$)/'				=> '&#8217;&#8221;$1',
-							'/(^|\W|\s)"\'/'				=> '$1&#8220;&#8216;',
-							'/"\'(\s|\W|$)/'				=> '&#8221;&#8217;$1',
-
-							// single quote smart quotes
-							'/\'(\s|\W|$)/'					=> '&#8217;$1',
-							'/(^|\W|\s)\'/'					=> '$1&#8216;',
-
-							// double quote smart quotes
-							'/"(\s|\W|$)/'					=> '&#8221;$1',
-							'/(^|\W|\s)"/'					=> '$1&#8220;',
-
-							// apostrophes
-							"/(\w)'(\w)/"       	    	=> '$1&#8217;$2',
-
-							// Em dash and ellipses dots
-							'/\s?\-\-\s?/'					=> '&#8212;',
-							'/(\w)\.{3}/'					=> '$1&#8230;',
-
-							// double space after sentences
-							'/(\W)  /'						=> '$1&nbsp; ',
-
-							// ampersands, if not a character entity
-							'/&(?!#?[a-zA-Z0-9]{2,};)/'		=> '&amp;'
-	        			);			
-		}	
-
-		return preg_replace(array_keys($table), $table, $str);
-	}
-	
-	// --------------------------------------------------------------------
-
-	/**
-	 * Format Newlines
-	 *
-	 * Converts newline characters into either <p> tags or <br />
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	string
-	 */	
-	function _format_newlines($str)
-	{
-		if ($str == '')
-		{
-			return $str;
-		}
-
-		if (strpos($str, "\n") === FALSE)
-		{
-			return $str;
-		}
-		
-		// Convert two consecutive newlines to paragraphs
-		$str = str_replace("\n\n", "</p>\n\n<p>", $str);
-		
-		// Convert single spaces to <br /> tags
-		$str = preg_replace("/([^\n])(\n)([^\n])/", "\\1<br />\\2\\3", $str);
-		
-		// Wrap the whole enchilada in enclosing paragraphs
-		if ($str != "\n")
-		{
-			$str =  '<p>'.$str.'</p>';
-		}
-
-		// Remove empty paragraphs if they are on the first line, as this
-		// is a potential unintended consequence of the previous code
-		$str = preg_replace("/<p><\/p>(.*)/", "\\1", $str, 1);
-		
-		return $str;
-	}
-	
-	// ------------------------------------------------------------------------
-	
-	/**
-	 * Convert newlines to HTML line breaks except within PRE tags
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	string
-	 */		
-	function nl2br_except_pre($str)
-	{
-		$ex = explode("pre>",$str);
-		$ct = count($ex);
-	
-		$newstr = "";
-		for ($i = 0; $i < $ct; $i++)
-		{
-			if (($i % 2) == 0)
-			{
-				$newstr .= nl2br($ex[$i]);
-			}
-			else
-			{
-				$newstr .= $ex[$i];
-			}
-		
-			if ($ct - 1 != $i)
-				$newstr .= "pre>";
-		}
-	
-		return $newstr;
-	}
-	
-}
-// END Typography Class
-
-/* End of file Typography.php */
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

+/**

+ * CodeIgniter

+ *

+ * An open source application development framework for PHP 4.3.2 or newer

+ *

+ * @package		CodeIgniter

+ * @author		ExpressionEngine Dev Team

+ * @copyright	Copyright (c) 2008, EllisLab, Inc.

+ * @license		http://codeigniter.com/user_guide/license.html

+ * @link		http://codeigniter.com

+ * @since		Version 1.0

+ * @filesource

+ */

+

+// ------------------------------------------------------------------------

+

+/**

+ * Typography Class

+ *

+ *

+ * @access		private

+ * @category	Helpers

+ * @author		ExpressionEngine Dev Team

+ * @link		http://codeigniter.com/user_guide/helpers/

+ */

+class CI_Typography {

+

+	// Block level elements that should not be wrapped inside <p> tags

+	var $block_elements = 'address|blockquote|div|dl|fieldset|form|h\d|hr|noscript|object|ol|p|pre|script|table|ul';

+	

+	// Elements that should not have <p> and <br /> tags within them.

+	var $skip_elements	= 'p|pre|ol|ul|dl|object|table';

+	

+	// Tags we want the parser to completely ignore when splitting the string.

+	var $inline_elements = 'a|abbr|acronym|b|bdo|big|br|button|cite|code|del|dfn|em|i|img|ins|input|label|map|kbd|q|samp|select|small|span|strong|sub|sup|textarea|tt|var';

+

+	// whether or not to protect quotes within { curly braces }

+	var $protect_braced_quotes = FALSE;

+	

+	/**

+	 * Nothing to do here...

+	 *

+	 */

+	function CI_Typography()

+	{

+	}

+

+	/**

+	 * Auto Typography

+	 *

+	 * This function converts text, making it typographically correct:

+	 * 	- Converts double spaces into paragraphs.

+	 * 	- Converts single line breaks into <br /> tags

+	 * 	- Converts single and double quotes into correctly facing curly quote entities.

+	 * 	- Converts three dots into ellipsis.

+	 * 	- Converts double dashes into em-dashes.

+	 *  - Converts two spaces into entities

+	 *

+	 * @access	public

+	 * @param	string

+	 * @param	bool	whether to reduce more then two consecutive newlines to two

+	 * @return	string

+	 */

+	function auto_typography($str, $reduce_linebreaks = FALSE)

+	{

+		if ($str == '')

+		{

+			return '';

+		}

+

+		// Standardize Newlines to make matching easier

+		if (strpos($str, "\r") !== FALSE)

+		{

+			$str = str_replace(array("\r\n", "\r"), "\n", $str);			

+		}

+			

+		// Reduce line breaks.  If there are more than two consecutive linebreaks

+		// we'll compress them down to a maximum of two since there's no benefit to more.

+		if ($reduce_linebreaks === TRUE)

+		{

+			$str = preg_replace("/\n\n+/", "\n\n", $str);

+		} 

+

+		// Convert quotes within tags to temporary markers. We don't want quotes converted 

+		// within tags so we'll temporarily convert them to {@DQ} and {@SQ}

+		// and we don't want double dashes converted to emdash entities, so they are marked with {@DD}

+		// likewise double spaces are converted to {@NBS} to prevent entity conversion

+		if (preg_match_all("#\<.+?>#si", $str, $matches))

+		{

+			for ($i = 0, $total = count($matches[0]); $i < $total; $i++)

+			{

+				$str = str_replace($matches[0][$i],

+									str_replace(array("'",'"','--','  '), array('{@SQ}', '{@DQ}', '{@DD}', '{@NBS}'), $matches[0][$i]),

+									$str);

+			}

+		}

+		

+		if ($this->protect_braced_quotes === TRUE)

+		{

+			if (preg_match_all("#\{.+?}#si", $str, $matches))

+			{

+				for ($i = 0, $total = count($matches[0]); $i < $total; $i++)

+				{

+					$str = str_replace($matches[0][$i],

+										str_replace(array("'",'"'), array('{@SQ}', '{@DQ}'), $matches[0][$i]),

+										$str);

+				}

+			}			

+		}

+		

+		// Convert "ignore" tags to temporary marker.  The parser splits out the string at every tag 

+		// it encounters.  Certain inline tags, like image tags, links, span tags, etc. will be 

+		// adversely affected if they are split out so we'll convert the opening bracket < temporarily to: {@TAG}

+		$str = preg_replace("#<(/*)(".$this->inline_elements.")([ >])#i", "{@TAG}\\1\\2\\3", $str);

+

+		// Split the string at every tag.  This expression creates an array with this prototype:

+		// 

+		// 	[array]

+		// 	{

+		// 		[0] = <opening tag>

+		// 		[1] = Content...

+		// 		[2] = <closing tag>

+		// 		Etc...

+		// 	}	

+		$chunks = preg_split('/(<(?:[^<>]+(?:"[^"]*"|\'[^\']*\')?)+>)/', $str, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);

+		

+		// Build our finalized string.  We cycle through the array, skipping tags, and processing the contained text	

+		$str = '';

+		$process = TRUE;

+		$paragraph = FALSE;

+		foreach ($chunks as $chunk)

+		{

+			// Are we dealing with a tag? If so, we'll skip the processing for this cycle.

+			// Well also set the "process" flag which allows us to skip <pre> tags and a few other things.

+			if (preg_match("#<(/*)(".$this->block_elements.").*?>#", $chunk, $match))

+			{

+				if (preg_match("#".$this->skip_elements."#", $match[2]))

+				{

+					$process =  ($match[1] == '/') ? TRUE : FALSE;

+				}

+				

+				$str .= $chunk;

+				continue;

+			}

+			elseif (preg_match('/<(\/?)([a-z]*).*?>/s', $chunk, $tagmatch))

+			{

+				if ($tagmatch[1] == '/' && $tagmatch[2] == $this->last_tag)

+				{

+					$process = FALSE;

+				}

+				else

+				{

+					$process = TRUE;

+					$this->last_tag = $tagmatch[2];					

+				}

+			}

+

+			if ($process == FALSE)

+			{

+				$str .= $chunk;

+				continue;

+			}

+			

+			//  Convert Newlines into <p> and <br /> tags

+			$str .= $this->format_characters($this->_format_newlines($chunk));			

+		}

+

+		// is the whole of the content inside a block level element?

+		if ( ! preg_match("/^<(?:".$this->block_elements.")/i", $str, $match))

+		{

+			$str = "<p>{$str}</p>";

+		}

+

+

+		// some special linebreak cleanup

+		$str = preg_replace_callback('#<(?!/|'.$this->block_elements.')([^>]*)><p>(.*?)</p><(\w*)#si', array($this, '_linebreak_cleanup'), $str);

+		

+		// and cleanup empty paragraph tags sitting between two closing tags

+		$str = preg_replace('#(</\w+>)<p>(\s*)</p>(</\w+>)#si', '$1$2$3', $str);

+		

+		// Final clean up

+		$table = array(

+		

+						// If the user submitted their own paragraph tags within the text

+						// we will retain them instead of using our tags.

+						'/(<p[^>*?]>)<p>/'	=> '$1', // <?php BBEdit syntax coloring bug fix

+						

+						// Reduce multiple instances of opening/closing paragraph tags to a single one

+						'#(</p>)+#'			=> '</p>',

+						'/(<p>\W*<p>)+/'	=> '<p>',

+						

+						// Clean up stray paragraph tags that appear before block level elements

+						'#<p></p><('.$this->block_elements.')#'	=> '<$1',

+						

+						// Clean up open paragraph tags that appear before block level elements

+						'#<p>(\W)<('.$this->block_elements.')#'	=> '<p></p>$1<$2',

+

+						// Clean up stray non-breaking spaces preceeding block elements

+						'#[&nbsp; ]+<('.$this->block_elements.')#'	=> '  <$1',

+			

+						// Replace the temporary markers we added earlier

+						'/\{@TAG\}/'		=> '<',

+						'/\{@DQ\}/'			=> '"',

+						'/\{@SQ\}/'			=> "'",

+						'/\{@DD\}/'			=> '--',

+						'/\{@NBS\}/'		=> '  '

+

+						);

+

+		// Do we need to reduce empty lines?

+		if ($reduce_linebreaks === TRUE)

+		{

+			$table['#<p>\n*</p>#'] = '';

+		}

+		else

+		{

+			// If we have empty paragraph tags we add a non-breaking space

+			// otherwise most browsers won't treat them as true paragraphs

+			$table['#<p></p>#'] = '<p>&nbsp;</p>';

+		}

+	

+		return preg_replace(array_keys($table), $table, $str);

+

+	}

+	

+	// --------------------------------------------------------------------

+	

+	/**

+	 * Linebreak Cleanup

+	 *

+	 * Removes paragraph and line break tags inserted inbetween

+	 * inline content and a new opening block level element

+	 *

+	 * @access	private

+	 * @param	array

+	 * @return	string

+	 */

+	function _linebreak_cleanup($match)

+	{

+		if (in_array($match[3], explode('|', $this->block_elements)))

+		{

+			return "<{$match[1]}>".str_replace('<br />', '', $match[2])."<{$match[3]}";

+		}

+		else

+		{

+			return $match[0];

+		}

+	}

+

+	// --------------------------------------------------------------------

+	

+	/**

+	 * Format Characters

+	 *

+	 * This function mainly converts double and single quotes

+	 * to curly entities, but it also converts em-dashes,

+	 * double spaces, and ampersands

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	string

+	 */

+	function format_characters($str)

+	{

+		static $table;

+		

+		if ( ! isset($table))

+		{

+	        $table = array(					

+							// nested smart quotes, opening and closing

+							// note that rules for grammar (English) allow only for two levels deep

+							// and that single quotes are _supposed_ to always be on the outside

+							// but we'll accommodate both

+							'/(^|\W|\s)\'"/'				=> '$1&#8216;&#8220;',

+							'/\'"(\s|\W|$)/'				=> '&#8217;&#8221;$1',

+							'/(^|\W|\s)"\'/'				=> '$1&#8220;&#8216;',

+							'/"\'(\s|\W|$)/'				=> '&#8221;&#8217;$1',

+

+							// single quote smart quotes

+							'/\'(\s|\W|$)/'					=> '&#8217;$1',

+							'/(^|\W|\s)\'/'					=> '$1&#8216;',

+

+							// double quote smart quotes

+							'/"(\s|\W|$)/'					=> '&#8221;$1',

+							'/(^|\W|\s)"/'					=> '$1&#8220;',

+

+							// apostrophes

+							"/(\w)'(\w)/"       	    	=> '$1&#8217;$2',

+

+							// Em dash and ellipses dots

+							'/\s?\-\-\s?/'					=> '&#8212;',

+							'/(\w)\.{3}/'					=> '$1&#8230;',

+

+							// double space after sentences

+							'/(\W)  /'						=> '$1&nbsp; ',

+

+							// ampersands, if not a character entity

+							'/&(?!#?[a-zA-Z0-9]{2,};)/'		=> '&amp;'

+	        			);			

+		}	

+

+		return preg_replace(array_keys($table), $table, $str);

+	}

+	

+	// --------------------------------------------------------------------

+

+	/**

+	 * Format Newlines

+	 *

+	 * Converts newline characters into either <p> tags or <br />

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	string

+	 */	

+	function _format_newlines($str)

+	{

+		if ($str == '')

+		{

+			return $str;

+		}

+

+		if (strpos($str, "\n") === FALSE)

+		{

+			return $str;

+		}

+		

+		// Convert two consecutive newlines to paragraphs

+		$str = str_replace("\n\n", "</p>\n\n<p>", $str);

+		

+		// Convert single spaces to <br /> tags

+		$str = preg_replace("/([^\n])(\n)([^\n])/", "\\1<br />\\2\\3", $str);

+		

+		// Wrap the whole enchilada in enclosing paragraphs

+		if ($str != "\n")

+		{

+			$str =  '<p>'.$str.'</p>';

+		}

+

+		// Remove empty paragraphs if they are on the first line, as this

+		// is a potential unintended consequence of the previous code

+		$str = preg_replace("/<p><\/p>(.*)/", "\\1", $str, 1);

+		

+		return $str;

+	}

+	

+	// ------------------------------------------------------------------------

+	

+	/**

+	 * Convert newlines to HTML line breaks except within PRE tags

+	 *

+	 * @access	public

+	 * @param	string

+	 * @return	string

+	 */		

+	function nl2br_except_pre($str)

+	{

+		$ex = explode("pre>",$str);

+		$ct = count($ex);

+	

+		$newstr = "";

+		for ($i = 0; $i < $ct; $i++)

+		{

+			if (($i % 2) == 0)

+			{

+				$newstr .= nl2br($ex[$i]);

+			}

+			else

+			{

+				$newstr .= $ex[$i];

+			}

+		

+			if ($ct - 1 != $i)

+				$newstr .= "pre>";

+		}

+	

+		return $newstr;

+	}

+	

+}

+// END Typography Class

+

+/* End of file Typography.php */

 /* Location: ./system/libraries/Typography.php */
\ No newline at end of file
diff --git a/system/libraries/URI.php b/system/libraries/URI.php
index aa2d71e..b27dfa3 100644
--- a/system/libraries/URI.php
+++ b/system/libraries/URI.php
@@ -1,585 +1,585 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
-/**
- * CodeIgniter
- *
- * An open source application development framework for PHP 4.3.2 or newer
- *
- * @package		CodeIgniter
- * @author		ExpressionEngine Dev Team
- * @copyright	Copyright (c) 2008, EllisLab, Inc.
- * @license		http://codeigniter.com/user_guide/license.html
- * @link		http://codeigniter.com
- * @since		Version 1.0
- * @filesource
- */
-
-// ------------------------------------------------------------------------
-
-/**
- * URI Class
- *
- * Parses URIs and determines routing
- *
- * @package		CodeIgniter
- * @subpackage	Libraries
- * @category	URI
- * @author		ExpressionEngine Dev Team
- * @link		http://codeigniter.com/user_guide/libraries/uri.html
- */
-class CI_URI {
-
-	var	$keyval	= array();
-	var $uri_string;
-	var $segments		= array();
-	var $rsegments		= array();
-
-	/**
-	 * Constructor
-	 *
-	 * Simply globalizes the $RTR object.  The front
-	 * loads the Router class early on so it's not available
-	 * normally as other classes are.
-	 *
-	 * @access	public
-	 */
-	function CI_URI()
-	{
-		$this->config =& load_class('Config');
-		log_message('debug', "URI Class Initialized");
-	}
-
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Get the URI String
-	 *
-	 * @access	private
-	 * @return	string
-	 */
-	function _fetch_uri_string()
-	{
-		if (strtoupper($this->config->item('uri_protocol')) == 'AUTO')
-		{
-			// If the URL has a question mark then it's simplest to just
-			// build the URI string from the zero index of the $_GET array.
-			// This avoids having to deal with $_SERVER variables, which
-			// can be unreliable in some environments
-			if (is_array($_GET) && count($_GET) == 1 && trim(key($_GET), '/') != '')
-			{
-				$this->uri_string = key($_GET);
-				return;
-			}
-
-			// Is there a PATH_INFO variable?
-			// Note: some servers seem to have trouble with getenv() so we'll test it two ways
-			$path = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : @getenv('PATH_INFO');
-			if (trim($path, '/') != '' && $path != "/".SELF)
-			{
-				$this->uri_string = $path;
-				return;
-			}
-
-			// No PATH_INFO?... What about QUERY_STRING?
-			$path =  (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING');
-			if (trim($path, '/') != '')
-			{
-				$this->uri_string = $path;
-				return;
-			}
-
-			// No QUERY_STRING?... Maybe the ORIG_PATH_INFO variable exists?
-			$path = (isset($_SERVER['ORIG_PATH_INFO'])) ? $_SERVER['ORIG_PATH_INFO'] : @getenv('ORIG_PATH_INFO');
-			if (trim($path, '/') != '' && $path != "/".SELF)
-			{
-				// remove path and script information so we have good URI data
-				$this->uri_string = str_replace($_SERVER['SCRIPT_NAME'], '', $path);
-				return;
-			}
-
-			// We've exhausted all our options...
-			$this->uri_string = '';
-		}
-		else
-		{
-			$uri = strtoupper($this->config->item('uri_protocol'));
-
-			if ($uri == 'REQUEST_URI')
-			{
-				$this->uri_string = $this->_parse_request_uri();
-				return;
-			}
-
-			$this->uri_string = (isset($_SERVER[$uri])) ? $_SERVER[$uri] : @getenv($uri);
-		}
-
-		// If the URI contains only a slash we'll kill it
-		if ($this->uri_string == '/')
-		{
-			$this->uri_string = '';
-		}
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Parse the REQUEST_URI
-	 *
-	 * Due to the way REQUEST_URI works it usually contains path info
-	 * that makes it unusable as URI data.  We'll trim off the unnecessary
-	 * data, hopefully arriving at a valid URI that we can use.
-	 *
-	 * @access	private
-	 * @return	string
-	 */
-	function _parse_request_uri()
-	{
-		if ( ! isset($_SERVER['REQUEST_URI']) OR $_SERVER['REQUEST_URI'] == '')
-		{
-			return '';
-		}
-
-		$request_uri = preg_replace("|/(.*)|", "\\1", str_replace("\\", "/", $_SERVER['REQUEST_URI']));
-
-		if ($request_uri == '' OR $request_uri == SELF)
-		{
-			return '';
-		}
-
-		$fc_path = FCPATH;
-		if (strpos($request_uri, '?') !== FALSE)
-		{
-			$fc_path .= '?';
-		}
-
-		$parsed_uri = explode("/", $request_uri);
-
-		$i = 0;
-		foreach(explode("/", $fc_path) as $segment)
-		{
-			if (isset($parsed_uri[$i]) && $segment == $parsed_uri[$i])
-			{
-				$i++;
-			}
-		}
-
-		$parsed_uri = implode("/", array_slice($parsed_uri, $i));
-
-		if ($parsed_uri != '')
-		{
-			$parsed_uri = '/'.$parsed_uri;
-		}
-
-		return $parsed_uri;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Filter segments for malicious characters
-	 *
-	 * @access	private
-	 * @param	string
-	 * @return	string
-	 */
-	function _filter_uri($str)
-	{
-		if ($str != '' && $this->config->item('permitted_uri_chars') != '' && $this->config->item('enable_query_strings') == FALSE)
-		{
-			if ( ! preg_match("|^[".preg_quote($this->config->item('permitted_uri_chars'))."]+$|i", $str))
-			{
-				header('HTTP/1.1 400 Bad Request');
-				exit('The URI you submitted has disallowed characters.');
-			}
-		}
-
-		// Convert programatic characters to entities
-		$bad	= array('$', 		'(', 		')',	 	'%28', 		'%29');
-		$good	= array('&#36;',	'&#40;',	'&#41;',	'&#40;',	'&#41;');
-
-		return str_replace($bad, $good, $str);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Remove the suffix from the URL if needed
-	 *
-	 * @access	private
-	 * @return	void
-	 */
-	function _remove_url_suffix()
-	{
-		if  ($this->config->item('url_suffix') != "")
-		{
-			$this->uri_string = preg_replace("|".preg_quote($this->config->item('url_suffix'))."$|", "", $this->uri_string);
-		}
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Explode the URI Segments. The individual segments will
-	 * be stored in the $this->segments array.
-	 *
-	 * @access	private
-	 * @return	void
-	 */
-	function _explode_segments()
-	{
-		foreach(explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string)) as $val)
-		{
-			// Filter segments for security
-			$val = trim($this->_filter_uri($val));
-
-			if ($val != '')
-			{
-				$this->segments[] = $val;
-			}
-		}
-	}
-
-	// --------------------------------------------------------------------
-	/**
-	 * Re-index Segments
-	 *
-	 * This function re-indexes the $this->segment array so that it
-	 * starts at 1 rather than 0.  Doing so makes it simpler to
-	 * use functions like $this->uri->segment(n) since there is
-	 * a 1:1 relationship between the segment array and the actual segments.
-	 *
-	 * @access	private
-	 * @return	void
-	 */
-	function _reindex_segments()
-	{
-		array_unshift($this->segments, NULL);
-		array_unshift($this->rsegments, NULL);
-		unset($this->segments[0]);
-		unset($this->rsegments[0]);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Fetch a URI Segment
-	 *
-	 * This function returns the URI segment based on the number provided.
-	 *
-	 * @access	public
-	 * @param	integer
-	 * @param	bool
-	 * @return	string
-	 */
-	function segment($n, $no_result = FALSE)
-	{
-		return ( ! isset($this->segments[$n])) ? $no_result : $this->segments[$n];
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Fetch a URI "routed" Segment
-	 *
-	 * This function returns the re-routed URI segment (assuming routing rules are used)
-	 * based on the number provided.  If there is no routing this function returns the
-	 * same result as $this->segment()
-	 *
-	 * @access	public
-	 * @param	integer
-	 * @param	bool
-	 * @return	string
-	 */
-	function rsegment($n, $no_result = FALSE)
-	{
-		return ( ! isset($this->rsegments[$n])) ? $no_result : $this->rsegments[$n];
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Generate a key value pair from the URI string
-	 *
-	 * This function generates and associative array of URI data starting
-	 * at the supplied segment. For example, if this is your URI:
-	 *
-	 *	example.com/user/search/name/joe/location/UK/gender/male
-	 *
-	 * You can use this function to generate an array with this prototype:
-	 *
-	 * array (
-	 *			name => joe
-	 *			location => UK
-	 *			gender => male
-	 *		 )
-	 *
-	 * @access	public
-	 * @param	integer	the starting segment number
-	 * @param	array	an array of default values
-	 * @return	array
-	 */
-	function uri_to_assoc($n = 3, $default = array())
-	{
-	 	return $this->_uri_to_assoc($n, $default, 'segment');
-	}
-	/**
-	 * Identical to above only it uses the re-routed segment array
-	 *
-	 */
-	function ruri_to_assoc($n = 3, $default = array())
-	{
-	 	return $this->_uri_to_assoc($n, $default, 'rsegment');
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Generate a key value pair from the URI string or Re-routed URI string
-	 *
-	 * @access	private
-	 * @param	integer	the starting segment number
-	 * @param	array	an array of default values
-	 * @param	string	which array we should use
-	 * @return	array
-	 */
-	function _uri_to_assoc($n = 3, $default = array(), $which = 'segment')
-	{
-		if ($which == 'segment')
-		{
-			$total_segments = 'total_segments';
-			$segment_array = 'segment_array';
-		}
-		else
-		{
-			$total_segments = 'total_rsegments';
-			$segment_array = 'rsegment_array';
-		}
-
-		if ( ! is_numeric($n))
-		{
-			return $default;
-		}
-
-		if (isset($this->keyval[$n]))
-		{
-			return $this->keyval[$n];
-		}
-
-		if ($this->$total_segments() < $n)
-		{
-			if (count($default) == 0)
-			{
-				return array();
-			}
-
-			$retval = array();
-			foreach ($default as $val)
-			{
-				$retval[$val] = FALSE;
-			}
-			return $retval;
-		}
-
-		$segments = array_slice($this->$segment_array(), ($n - 1));
-
-		$i = 0;
-		$lastval = '';
-		$retval  = array();
-		foreach ($segments as $seg)
-		{
-			if ($i % 2)
-			{
-				$retval[$lastval] = $seg;
-			}
-			else
-			{
-				$retval[$seg] = FALSE;
-				$lastval = $seg;
-			}
-
-			$i++;
-		}
-
-		if (count($default) > 0)
-		{
-			foreach ($default as $val)
-			{
-				if ( ! array_key_exists($val, $retval))
-				{
-					$retval[$val] = FALSE;
-				}
-			}
-		}
-
-		// Cache the array for reuse
-		$this->keyval[$n] = $retval;
-		return $retval;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Generate a URI string from an associative array
-	 *
-	 *
-	 * @access	public
-	 * @param	array	an associative array of key/values
-	 * @return	array
-	 */
-	function assoc_to_uri($array)
-	{
-		$temp = array();
-		foreach ((array)$array as $key => $val)
-		{
-			$temp[] = $key;
-			$temp[] = $val;
-		}
-
-		return implode('/', $temp);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Fetch a URI Segment and add a trailing slash
-	 *
-	 * @access	public
-	 * @param	integer
-	 * @param	string
-	 * @return	string
-	 */
-	function slash_segment($n, $where = 'trailing')
-	{
-		return $this->_slash_segment($n, $where, 'segment');
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Fetch a URI Segment and add a trailing slash
-	 *
-	 * @access	public
-	 * @param	integer
-	 * @param	string
-	 * @return	string
-	 */
-	function slash_rsegment($n, $where = 'trailing')
-	{
-		return $this->_slash_segment($n, $where, 'rsegment');
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Fetch a URI Segment and add a trailing slash - helper function
-	 *
-	 * @access	private
-	 * @param	integer
-	 * @param	string
-	 * @param	string
-	 * @return	string
-	 */
-	function _slash_segment($n, $where = 'trailing', $which = 'segment')
-	{
-		if ($where == 'trailing')
-		{
-			$trailing	= '/';
-			$leading	= '';
-		}
-		elseif ($where == 'leading')
-		{
-			$leading	= '/';
-			$trailing	= '';
-		}
-		else
-		{
-			$leading	= '/';
-			$trailing	= '/';
-		}
-		return $leading.$this->$which($n).$trailing;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Segment Array
-	 *
-	 * @access	public
-	 * @return	array
-	 */
-	function segment_array()
-	{
-		return $this->segments;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Routed Segment Array
-	 *
-	 * @access	public
-	 * @return	array
-	 */
-	function rsegment_array()
-	{
-		return $this->rsegments;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Total number of segments
-	 *
-	 * @access	public
-	 * @return	integer
-	 */
-	function total_segments()
-	{
-		return count($this->segments);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Total number of routed segments
-	 *
-	 * @access	public
-	 * @return	integer
-	 */
-	function total_rsegments()
-	{
-		return count($this->rsegments);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Fetch the entire URI string
-	 *
-	 * @access	public
-	 * @return	string
-	 */
-	function uri_string()
-	{
-		return $this->uri_string;
-	}
-
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Fetch the entire Re-routed URI string
-	 *
-	 * @access	public
-	 * @return	string
-	 */
-	function ruri_string()
-	{
-		return '/'.implode('/', $this->rsegment_array()).'/';
-	}
-
-}
-// END URI Class
-
-/* End of file URI.php */
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

+/**

+ * CodeIgniter

+ *

+ * An open source application development framework for PHP 4.3.2 or newer

+ *

+ * @package		CodeIgniter

+ * @author		ExpressionEngine Dev Team

+ * @copyright	Copyright (c) 2008, EllisLab, Inc.

+ * @license		http://codeigniter.com/user_guide/license.html

+ * @link		http://codeigniter.com

+ * @since		Version 1.0

+ * @filesource

+ */

+

+// ------------------------------------------------------------------------

+

+/**

+ * URI Class

+ *

+ * Parses URIs and determines routing

+ *

+ * @package		CodeIgniter

+ * @subpackage	Libraries

+ * @category	URI

+ * @author		ExpressionEngine Dev Team

+ * @link		http://codeigniter.com/user_guide/libraries/uri.html

+ */

+class CI_URI {

+

+	var	$keyval	= array();

+	var $uri_string;

+	var $segments		= array();

+	var $rsegments		= array();

+

+	/**

+	 * Constructor

+	 *

+	 * Simply globalizes the $RTR object.  The front

+	 * loads the Router class early on so it's not available

+	 * normally as other classes are.

+	 *

+	 * @access	public

+	 */

+	function CI_URI()

+	{

+		$this->config =& load_class('Config');

+		log_message('debug', "URI Class Initialized");

+	}

+

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Get the URI String

+	 *

+	 * @access	private

+	 * @return	string

+	 */

+	function _fetch_uri_string()

+	{

+		if (strtoupper($this->config->item('uri_protocol')) == 'AUTO')

+		{

+			// If the URL has a question mark then it's simplest to just

+			// build the URI string from the zero index of the $_GET array.

+			// This avoids having to deal with $_SERVER variables, which

+			// can be unreliable in some environments

+			if (is_array($_GET) && count($_GET) == 1 && trim(key($_GET), '/') != '')

+			{

+				$this->uri_string = key($_GET);

+				return;

+			}

+

+			// Is there a PATH_INFO variable?

+			// Note: some servers seem to have trouble with getenv() so we'll test it two ways

+			$path = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : @getenv('PATH_INFO');

+			if (trim($path, '/') != '' && $path != "/".SELF)

+			{

+				$this->uri_string = $path;

+				return;

+			}

+

+			// No PATH_INFO?... What about QUERY_STRING?

+			$path =  (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING');

+			if (trim($path, '/') != '')

+			{

+				$this->uri_string = $path;

+				return;

+			}

+

+			// No QUERY_STRING?... Maybe the ORIG_PATH_INFO variable exists?

+			$path = (isset($_SERVER['ORIG_PATH_INFO'])) ? $_SERVER['ORIG_PATH_INFO'] : @getenv('ORIG_PATH_INFO');

+			if (trim($path, '/') != '' && $path != "/".SELF)

+			{

+				// remove path and script information so we have good URI data

+				$this->uri_string = str_replace($_SERVER['SCRIPT_NAME'], '', $path);

+				return;

+			}

+

+			// We've exhausted all our options...

+			$this->uri_string = '';

+		}

+		else

+		{

+			$uri = strtoupper($this->config->item('uri_protocol'));

+

+			if ($uri == 'REQUEST_URI')

+			{

+				$this->uri_string = $this->_parse_request_uri();

+				return;

+			}

+

+			$this->uri_string = (isset($_SERVER[$uri])) ? $_SERVER[$uri] : @getenv($uri);

+		}

+

+		// If the URI contains only a slash we'll kill it

+		if ($this->uri_string == '/')

+		{

+			$this->uri_string = '';

+		}

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Parse the REQUEST_URI

+	 *

+	 * Due to the way REQUEST_URI works it usually contains path info

+	 * that makes it unusable as URI data.  We'll trim off the unnecessary

+	 * data, hopefully arriving at a valid URI that we can use.

+	 *

+	 * @access	private

+	 * @return	string

+	 */

+	function _parse_request_uri()

+	{

+		if ( ! isset($_SERVER['REQUEST_URI']) OR $_SERVER['REQUEST_URI'] == '')

+		{

+			return '';

+		}

+

+		$request_uri = preg_replace("|/(.*)|", "\\1", str_replace("\\", "/", $_SERVER['REQUEST_URI']));

+

+		if ($request_uri == '' OR $request_uri == SELF)

+		{

+			return '';

+		}

+

+		$fc_path = FCPATH;

+		if (strpos($request_uri, '?') !== FALSE)

+		{

+			$fc_path .= '?';

+		}

+

+		$parsed_uri = explode("/", $request_uri);

+

+		$i = 0;

+		foreach(explode("/", $fc_path) as $segment)

+		{

+			if (isset($parsed_uri[$i]) && $segment == $parsed_uri[$i])

+			{

+				$i++;

+			}

+		}

+

+		$parsed_uri = implode("/", array_slice($parsed_uri, $i));

+

+		if ($parsed_uri != '')

+		{

+			$parsed_uri = '/'.$parsed_uri;

+		}

+

+		return $parsed_uri;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Filter segments for malicious characters

+	 *

+	 * @access	private

+	 * @param	string

+	 * @return	string

+	 */

+	function _filter_uri($str)

+	{

+		if ($str != '' && $this->config->item('permitted_uri_chars') != '' && $this->config->item('enable_query_strings') == FALSE)

+		{

+			if ( ! preg_match("|^[".preg_quote($this->config->item('permitted_uri_chars'))."]+$|i", $str))

+			{

+				header('HTTP/1.1 400 Bad Request');

+				exit('The URI you submitted has disallowed characters.');

+			}

+		}

+

+		// Convert programatic characters to entities

+		$bad	= array('$', 		'(', 		')',	 	'%28', 		'%29');

+		$good	= array('&#36;',	'&#40;',	'&#41;',	'&#40;',	'&#41;');

+

+		return str_replace($bad, $good, $str);

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Remove the suffix from the URL if needed

+	 *

+	 * @access	private

+	 * @return	void

+	 */

+	function _remove_url_suffix()

+	{

+		if  ($this->config->item('url_suffix') != "")

+		{

+			$this->uri_string = preg_replace("|".preg_quote($this->config->item('url_suffix'))."$|", "", $this->uri_string);

+		}

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Explode the URI Segments. The individual segments will

+	 * be stored in the $this->segments array.

+	 *

+	 * @access	private

+	 * @return	void

+	 */

+	function _explode_segments()

+	{

+		foreach(explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string)) as $val)

+		{

+			// Filter segments for security

+			$val = trim($this->_filter_uri($val));

+

+			if ($val != '')

+			{

+				$this->segments[] = $val;

+			}

+		}

+	}

+

+	// --------------------------------------------------------------------

+	/**

+	 * Re-index Segments

+	 *

+	 * This function re-indexes the $this->segment array so that it

+	 * starts at 1 rather than 0.  Doing so makes it simpler to

+	 * use functions like $this->uri->segment(n) since there is

+	 * a 1:1 relationship between the segment array and the actual segments.

+	 *

+	 * @access	private

+	 * @return	void

+	 */

+	function _reindex_segments()

+	{

+		array_unshift($this->segments, NULL);

+		array_unshift($this->rsegments, NULL);

+		unset($this->segments[0]);

+		unset($this->rsegments[0]);

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Fetch a URI Segment

+	 *

+	 * This function returns the URI segment based on the number provided.

+	 *

+	 * @access	public

+	 * @param	integer

+	 * @param	bool

+	 * @return	string

+	 */

+	function segment($n, $no_result = FALSE)

+	{

+		return ( ! isset($this->segments[$n])) ? $no_result : $this->segments[$n];

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Fetch a URI "routed" Segment

+	 *

+	 * This function returns the re-routed URI segment (assuming routing rules are used)

+	 * based on the number provided.  If there is no routing this function returns the

+	 * same result as $this->segment()

+	 *

+	 * @access	public

+	 * @param	integer

+	 * @param	bool

+	 * @return	string

+	 */

+	function rsegment($n, $no_result = FALSE)

+	{

+		return ( ! isset($this->rsegments[$n])) ? $no_result : $this->rsegments[$n];

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Generate a key value pair from the URI string

+	 *

+	 * This function generates and associative array of URI data starting

+	 * at the supplied segment. For example, if this is your URI:

+	 *

+	 *	example.com/user/search/name/joe/location/UK/gender/male

+	 *

+	 * You can use this function to generate an array with this prototype:

+	 *

+	 * array (

+	 *			name => joe

+	 *			location => UK

+	 *			gender => male

+	 *		 )

+	 *

+	 * @access	public

+	 * @param	integer	the starting segment number

+	 * @param	array	an array of default values

+	 * @return	array

+	 */

+	function uri_to_assoc($n = 3, $default = array())

+	{

+	 	return $this->_uri_to_assoc($n, $default, 'segment');

+	}

+	/**

+	 * Identical to above only it uses the re-routed segment array

+	 *

+	 */

+	function ruri_to_assoc($n = 3, $default = array())

+	{

+	 	return $this->_uri_to_assoc($n, $default, 'rsegment');

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Generate a key value pair from the URI string or Re-routed URI string

+	 *

+	 * @access	private

+	 * @param	integer	the starting segment number

+	 * @param	array	an array of default values

+	 * @param	string	which array we should use

+	 * @return	array

+	 */

+	function _uri_to_assoc($n = 3, $default = array(), $which = 'segment')

+	{

+		if ($which == 'segment')

+		{

+			$total_segments = 'total_segments';

+			$segment_array = 'segment_array';

+		}

+		else

+		{

+			$total_segments = 'total_rsegments';

+			$segment_array = 'rsegment_array';

+		}

+

+		if ( ! is_numeric($n))

+		{

+			return $default;

+		}

+

+		if (isset($this->keyval[$n]))

+		{

+			return $this->keyval[$n];

+		}

+

+		if ($this->$total_segments() < $n)

+		{

+			if (count($default) == 0)

+			{

+				return array();

+			}

+

+			$retval = array();

+			foreach ($default as $val)

+			{

+				$retval[$val] = FALSE;

+			}

+			return $retval;

+		}

+

+		$segments = array_slice($this->$segment_array(), ($n - 1));

+

+		$i = 0;

+		$lastval = '';

+		$retval  = array();

+		foreach ($segments as $seg)

+		{

+			if ($i % 2)

+			{

+				$retval[$lastval] = $seg;

+			}

+			else

+			{

+				$retval[$seg] = FALSE;

+				$lastval = $seg;

+			}

+

+			$i++;

+		}

+

+		if (count($default) > 0)

+		{

+			foreach ($default as $val)

+			{

+				if ( ! array_key_exists($val, $retval))

+				{

+					$retval[$val] = FALSE;

+				}

+			}

+		}

+

+		// Cache the array for reuse

+		$this->keyval[$n] = $retval;

+		return $retval;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Generate a URI string from an associative array

+	 *

+	 *

+	 * @access	public

+	 * @param	array	an associative array of key/values

+	 * @return	array

+	 */

+	function assoc_to_uri($array)

+	{

+		$temp = array();

+		foreach ((array)$array as $key => $val)

+		{

+			$temp[] = $key;

+			$temp[] = $val;

+		}

+

+		return implode('/', $temp);

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Fetch a URI Segment and add a trailing slash

+	 *

+	 * @access	public

+	 * @param	integer

+	 * @param	string

+	 * @return	string

+	 */

+	function slash_segment($n, $where = 'trailing')

+	{

+		return $this->_slash_segment($n, $where, 'segment');

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Fetch a URI Segment and add a trailing slash

+	 *

+	 * @access	public

+	 * @param	integer

+	 * @param	string

+	 * @return	string

+	 */

+	function slash_rsegment($n, $where = 'trailing')

+	{

+		return $this->_slash_segment($n, $where, 'rsegment');

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Fetch a URI Segment and add a trailing slash - helper function

+	 *

+	 * @access	private

+	 * @param	integer

+	 * @param	string

+	 * @param	string

+	 * @return	string

+	 */

+	function _slash_segment($n, $where = 'trailing', $which = 'segment')

+	{

+		if ($where == 'trailing')

+		{

+			$trailing	= '/';

+			$leading	= '';

+		}

+		elseif ($where == 'leading')

+		{

+			$leading	= '/';

+			$trailing	= '';

+		}

+		else

+		{

+			$leading	= '/';

+			$trailing	= '/';

+		}

+		return $leading.$this->$which($n).$trailing;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Segment Array

+	 *

+	 * @access	public

+	 * @return	array

+	 */

+	function segment_array()

+	{

+		return $this->segments;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Routed Segment Array

+	 *

+	 * @access	public

+	 * @return	array

+	 */

+	function rsegment_array()

+	{

+		return $this->rsegments;

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Total number of segments

+	 *

+	 * @access	public

+	 * @return	integer

+	 */

+	function total_segments()

+	{

+		return count($this->segments);

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Total number of routed segments

+	 *

+	 * @access	public

+	 * @return	integer

+	 */

+	function total_rsegments()

+	{

+		return count($this->rsegments);

+	}

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Fetch the entire URI string

+	 *

+	 * @access	public

+	 * @return	string

+	 */

+	function uri_string()

+	{

+		return $this->uri_string;

+	}

+

+

+	// --------------------------------------------------------------------

+

+	/**

+	 * Fetch the entire Re-routed URI string

+	 *

+	 * @access	public

+	 * @return	string

+	 */

+	function ruri_string()

+	{

+		return '/'.implode('/', $this->rsegment_array()).'/';

+	}

+

+}

+// END URI Class

+

+/* End of file URI.php */

 /* Location: ./system/libraries/URI.php */
\ No newline at end of file