Location: PHPKode > projects > v-creator > v-creator_1.3-pre3/modules/text.php
<?php
	/*
	 * Copyright (c) 2003 gencon Ltd, all rights reserved.
	 *
	 * This file is part of v-creator.
	 *
   * v-creator is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
	 *
   * v-creator is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
	 *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
	 */

	/**
	 * @ingroup VCmodules
	 * @brief Class for processing text.
	 *
	 * $Revision: 1.5 $  $Date: 2006-01-20 14:42:04 $
	 *
	 * @author Andrew 'Diddymus' Rolfe
	 *
	 * This module provides functionality for processing text. Included are
	 * methods for translating meta markup codes:
	 *
	 * @code
	 *	b[ something nice and bold ]b 
	 * @endcode
	 *
	 * becomes
	 *
	 * @code
	 *  <b> something nice and bold </b>
	 * @endcode
	 *
	 * This is so that users can have limited formatting capabilities within text
	 * entered via forms. If we were to allow any HTML to be entered directly
	 * this would pose a security risk as Javascript and other malicious content
	 * could be entered.
	 */
	class text {

		/**
		 * @brief Function to setup defines.
		 *
		 * When called this function sets up the following
		 * defines for use with the text module:
		 *
		 * <dl>
		 *	<dt>TEXT_LF2BR</dt>
		 *	<dd>Used to format linefeeds as  &lt;br /&gt;</dt>
		 *	<dt>TEXT_BOLD</dt>
		 *	<dd>Used to format b[...]b as bold text</dd>
		 *	<dt>TEXT_ITALIC</dt>
		 *	<dd>Used to format i[...]i as italic text</dd>
		 *	<dt>TEXT_UNDERLINE</dt>
		 *	<dd>Used to format u[...]u as underlined text</dd>
		 *	<dt>TEXT_PREFORMAT</dt>
		 *	<dd>Used to format p[...]p as preformatted text</dd>
		 *	<dt>TEXT_SUB</dt>
		 *	<dd>Used to format s[...]s as subscript text</dd>
		 *	<dt>TEXT_SUP</dt>
		 *	<dd>Used to format S[...]S as superscript text</dd>
		 *	<dt>TEXT_STRIKE</dt>
		 *	<dd>Used to format -[...]- as strikethough text</dd>
		 *	<dt>TEXT_LINK</dt>
		 *	<dd>Used to format a[...]a as hyperlinks</dd>
		 *	<dt>TEXT_IMAGE</dt>
		 *	<dd>Used to format g[...]g as image ('g'raphics) links</dd>
		 *	<dt>TEXT_MAIL</dt>
		 *	<dd>Used to format m[...]m as a mailto hyperlink</dd>
		 *	<dt>TEXT_HTML</dt>
		 *	<dd>Used to convert HTML entities so arbitirary HTML
		 *			cannot be rendered</dd>
		 *	<dt>TEXT_ALL</dt>
		 *	<dd>Performs all of the available formatting options</dd>
		 *	<dt>TEXT_FIXSMART</dt>
		 *	<dd>Translates Microsoft's "smart quotes" to regular quotes</dd>
		 *	<dt>TEXT_LIST</dt>
		 *	<dd>Creates unordered lists by identifying lines beginning with
		 *      only whitespace and then an asterisk.</dd>
		 * </dl>
		 *
		 * @static
		 */
		function defines() {
			if (!defined('TEXT_LF2BR')) {
				define('TEXT_LF2BR',      'lf2br');
				define('TEXT_BOLD',       'bold');
				define('TEXT_ITALIC',     'ital');
				define('TEXT_UNDERLINE',  'under');
				define('TEXT_PREFORMAT',  'pre');
				define("TEXT_SUB",  			"subscript");
				define("TEXT_SUPER",  		"superscript");
				define("TEXT_STRIKE",  		"strikethough");				
				define('TEXT_LINK',       'www');
				define('TEXT_IMAGE',      'image');
				define('TEXT_MAIL',  			'mail');
				define('TEXT_HTML',  			'html');
				define('TEXT_ALL',  			'all');
				define('TEXT_FIXSMART',  	'fixsmart');
				define('TEXT_LIST',  			'list');
			}
		}

		/**
		 * @brief Function to apply formatting to some text.
		 *
		 * This function is used to provide text formatting functions. The
		 * specific type of formatting to carry out is specified in text_format.
		 * The values returned in VC_data are:
		 *
		 * <dl>
		 *	<dt>text_out</dt>
		 *	<dd>This is set to the formatted text result</dd>
		 * </dl>
		 *
		 * The following values from VC_data will be used if available:
		 *
		 * <dl>
		 *	<dt>text_in</dt>
		 *	<dd>The input text to be formatted</dd>
		 *	<dt>text_format</dt>
		 *	<dd>The formatting type to perform</dd>
		 * </dl>
		 *
		 * @static
		 */
		function format() {
			global $VC_data;

			$format = VCPage::getVC_data('text_format');
			$textIn = VCPage::getVC_data('text_in');

			if (!$format) return;

			switch ($format) {
				case TEXT_LF2BR:
					$textOut = text::_i_lf2br($textIn);
					break;
				case TEXT_BOLD:
					$textOut = text::_i_replaceTags($textIn, 'b');
					break;
				case TEXT_ITALIC:
					$textOut = text::_i_replaceTags($textIn, 'i');
					break;
				case TEXT_UNDERLINE:
					$textOut = text::_i_replaceTags($textIn, 'u');
					break;
				case TEXT_PREFORMAT:
					$textOut = text::_i_replaceTags($textIn, 'p', 'pre', true);
					break;
				case TEXT_SUB:
					$textOut = text::_i_replaceTags($textIn, 's', 'sub');
					break;
				case TEXT_SUPER:
					$textOut = text::_i_replaceTags($textIn, 'S', 'sup');
					break;
				case TEXT_STRIKE:
					$textOut = text::_i_replaceTags($textIn, '-', 'strike');
					break;
				case TEXT_LINK:
					$textOut = text::_i_convertToLink($textIn,'a','http://','_blank');
					$textOut = text::_i_convertToLink($textIn,'A','http://');
					break;
				case TEXT_IMAGE:
					$textOut = text::_i_convertToImage($textIn,'g');
					break;
				case TEXT_MAIL:
					$textOut = text::_i_convertToLink($textIn,'m','mailto:');
					break;
				case TEXT_HTML:
					$textOut = htmlentities($textIn);
					break;
				case TEXT_FIXSMART:
					$textOut = text::_i_fixSmartQuotes($textIn);
					break;
				case TEXT_LIST:
					$textOut = text::_i_buildList($textIn);
					break;
				case TEXT_ALL:
					$textOut = text::_i_fixSmartQuotes($textIn);
					$textOut = htmlentities($textOut);
					$textOut = text::_i_lf2br($textOut);
					$textOut = text::_i_replaceTags($textOut, 'b');
					$textOut = text::_i_replaceTags($textOut, 'i');
					$textOut = text::_i_replaceTags($textOut, 'u');
					$textOut = text::_i_replaceTags($textOut, 'p', 'pre', true);
					$textOut = text::_i_replaceTags($textOut, 's', 'sub');
					$textOut = text::_i_replaceTags($textOut, 'S', 'sup');
					$textOut = text::_i_replaceTags($textOut, '-', 'strike');
					$textOut = text::_i_convertToLink($textOut,'a','http://','_blank');
					$textOut = text::_i_convertToLink($textOut,'A','http://');
					$textOut = text::_i_convertToLink($textOut,'m','mailto:');
					//$textOut = text::_i_convertToImage($textOut,'g');
					$textOut = text::_i_buildList($textOut);
					break;
			}

			$VC_data['text_out'] = $textOut;
			
		}

		/**
		 * @internal
		 * @brief Function to convert cr/lf to &lt;br /&gt;.
		 *
		 * This function takes the text specified and removes any carridge return
		 * characters. It then changes and linefeed characters into HTML &lt;br
		 * /&gt; tags.
		 *
		 * @param $text The text to be formatted.
		 *
		 * @static
		 */
		function _i_lf2br($text) {
			$textOut = str_replace("\r",'',$text);
			$textOut = str_replace("\n",'<br />',$textOut);
			return $textOut;
		}

		/**
		 * @internal
		 *
		 * @brief Function to convert embeded text formatting codes and build
		 * hyperlinks.
		 *
		 * This function is used to format text containing basic markup
		 * codes for links. The basic markup codes are in the form x[...]x
		 * where x represents the type of formatting. The common types are:
		 *
		 * <dl>
		 * 	<dt>a</dt>
		 * 	<dd>Make a URL link around the enclosed text that open in another window.</dd>
		 * 	<dt>A</dt>
		 * 	<dd>Make a URL link around the enclosed text that opens in the same window.</dd>
		 * 	<dt>m</dt>
		 * 	<dd>Make a mailto link around the enclosed text</dd>
		 * </dl>
		 *
		 * Text surrounded as "a[link]a" will be formatted as
		 * @code
		 *	<a href="http://link" target="_blank">link</a>
		 *
		 *  Example:
		 *	a[www.example.com]a
		 *
		 *	<a href="http://www.example.com" target="_blank">www.example.com</a>
		 * @endcode
		 *
		 * An optional description may be placed after the link:
		 * @code
		 *  Example:
		 *	a[www.example.com A description]a
		 *
		 *	<a href="http://www.example.com" target="_blank">A description</a>
		 * @endcode
		 *
		 * Text surrounded as "m[email]m" will be formatted as
		 * @code
		 *	<a href="mailto:email">email</a>
		 *
		 *  Example:
		 *	m[hide@address.com]m
		 *
		 *	<a href="mailto:hide@address.com">hide@address.com</a>
		 * @endcode
		 *
		 * An optional description may be placed after the email as well:
		 * @code
		 *
		 *  Example:
		 *	m[hide@address.com Anybody]m
		 *
		 *	<a href="mailto:hide@address.com">Anybody</a>
		 * @endcode
		 *
		 * This can be used to provide limited text formatting to a website
		 * user, for example in dynamic news items, without allowing them
		 * to enter any arbitary HTML code.
     *
     * @param $text The text to be formatted
     * @param $linkTag The letter for the replacement to perform
     * @param $linkProtocol The protocol to use (EG: http:// or mailto:)
		 * @param $linkTarget The frame target for the link.
		 *
		 * @static
		 *
		 */
		function _i_convertToLink($text, $linkTag, $linkProtocol, $linkTarget=null) {
			
			$findStart = $linkTag.'[';
			$findEnd = ']'.$linkTag;

			$linkStart = strpos($text, $findStart);
			while ($linkStart !== false) {
				$linkEnd = strpos($text, $findEnd, $linkStart);
				if ($linkEnd === false) break;

				$textBeforeLink = substr($text,0,$linkStart);
				$textForLink = substr($text,$linkStart+2,$linkEnd-$linkStart-2);
				
				// If link contains spaces everythin before the space is the link and
				// everything after is used as the links description. If there are no
				// spaces the link is also the description.
				$spaceCheck = strpos($textForLink, ' ');
				if ($spaceCheck) {
					$textForDescription = substr($textForLink, $spaceCheck+1);
					$textForLink = substr($textForLink, 0, $spaceCheck);
				} else {
					$textForDescription = $textForLink;
				}

				// If we have a bare link for passed for http, i.e. a[]a or A[]A tags, prefix with current hostname.
				if ($textForLink[0] == '/' && $linkProtocol == 'http://') {
					$textForLink = VCEngine::getSiteReference(false,false,false).$textForLink;
				}
				
				$textAfterLink = substr($text,$linkEnd+2);

				$text = $textBeforeLink.'<a href="'.$linkProtocol.$textForLink.'"';
				if ($linkTarget) $text .= ' target="'.$linkTarget.'"';
				$text .= '>'.$textForDescription.'</a>'.$textAfterLink;
			
				$linkStart = strpos($text, $findStart, $linkEnd);
			}

			return $text;
		}
		
		/**
		 * @internal
		 *
		 * @brief Function to convert embeded text formatting codes and build
		 * image links with options ALT text attributes.
		 *
		 * Text surrounded as "g[link]g" will be formatted as
		 * @code
		 *	<img href="link" />
		 *
		 *  Example:
		 *	g[/images/sample.gif]g
		 *
		 *	<img src="/images/sample.gif" />
		 * @endcode
		 *
		 * An optional description may be placed after the link which will be used to
		 * construct the ALT text attribute:
		 * @code
		 *  Example:
		 *	g[/image/sample.gif Sample Image]g
		 *
		 *	<img src="/images/sample.gif" alt="Sample Image" />
		 * @endcode
		 *
		 * This can be used to provide limited HTML formatting to a website
		 * user, for example in dynamic news items, without allowing them
		 * to enter any arbitary HTML code.
     *
     * @param $text The text to be formatted
     * @param $imageTag The letter for the replacement to perform
		 *
		 * @static
		 *
		 */
		function _i_convertToImage($text, $imageTag) {
			
			$findStart = $imageTag.'[';
			$findEnd = ']'.$imageTag;

			$linkStart = strpos($text, $findStart);
			while ($linkStart !== false) {
				$linkEnd = strpos($text, $findEnd, $linkStart);
				if ($linkEnd === false) break;

				$textBeforeLink = substr($text,0,$linkStart);
				$textForLink = substr($text,$linkStart+2,$linkEnd-$linkStart-2);
				
				// If link contains spaces everythin before the space is the link and
				// everything after is used as the links ALT description.
				$spaceCheck = strpos($textForLink, ' ');
				if ($spaceCheck) {
					$textForDescription = substr($textForLink, $spaceCheck+1);
					$textForLink = substr($textForLink, 0, $spaceCheck);
				} else {
					$textForDescription = null;
				}
				
				$textAfterLink = substr($text,$linkEnd+2);

				$text = $textBeforeLink.'<img src="'.$textForLink.'"';
				if ($textForDescription) $text .= ' alt="'.$textForDescription.'"';
				$text .= ' />'.$textAfterLink;
			
				$linkStart = strpos($text, $findStart, $linkEnd);
			}

			return $text;
		}

		/**
		 * @internal
		 *
		 * @brief Function to convert embeded text formatting codes.
		 *
		 * This function is used to format text containing basic markup
		 * codes. The basic markup codes are in the form x[...]x where
		 * x represents the type of formatting. The common types are:
		 *
		 * <dl>
		 * 	<dt>b</dt>
		 * 	<dd>Bold text</dd>
		 * 	<dt>u</dt>
		 * 	<dd>Underlined text</dd>
		 * 	<dt>i</dt>
		 * 	<dd>Italic text</dd>
		 * 	<dt>p</dt>
		 * 	<dd>Pre-formatted text</dd>
		 * 	<dt>s</dt>
		 * 	<dd>Subscript text</dd>
		 * 	<dt>S</dt>
		 * 	<dd>Superscript text</dd>
		 * 	<dt>-</dt>
		 * 	<dd>Strike through text</dd>
		 * </dl>
		 *
		 * Each occurance of "x[" will be replaced by "<x>". Each
		 * occurance of "]x" will be replaced by "</x>". For example
		 * "b[some text]b" will be formatted as "<b>some text</b>".
		 *
		 * If a substitute tag is specified that will be used instead of "x". For
		 * example "p[some text]p" will become "<pre>some text</pre>".
		 *
		 * This can be used to provide limited text formatting to a website
		 * user, for example in dynamic news items, without allowing them
		 * to enter any arbitary HTML code.
		 *
		 * The optional reblock parameter should be used when the text is within
		 * paragraph tags and the replacement HTML tags should not be within
		 * paragraph tags, for example "<pre></pre>". If set the paragraph will be
		 * ended and restarted or 'reblocked':
		 *
		 * @code
		 * Example:
		 * a p[text]p b
		 *
		 * Becomes:
		 * </p>a <pre>text</pre> b<p>
		 *
		 * This assumes the text will be placed inside a paragraph such as:
		 *
		 *	<p>|{DATA:text_out}|</p>
		 * @endcode
     *
     * @param $text The text to be formatted
     * @param $replaceTag The letter for the replacement to perform
     * @param $substituteTag The replacement tag to use, defaults to $replaceTag
     * @param $reblock Should the replacement tags end and start a paragraph block?
		 *
		 * @static
		 *
		 */
		function _i_replaceTags($text, $replaceTag, $substituteTag = null, $reblock = false) {
			
			if (!$substituteTag) $substituteTag = $replaceTag;

			$findStart = $replaceTag.'[';
			$replaceStart = '<'.$substituteTag.'>';
			if ($reblock) $replaceStart	=	'</p>'.$replaceStart;
			$findEnd = ']'.$replaceTag;
			$replaceEnd = '</'.$substituteTag.'>';
			if ($reblock) $replaceEnd	=	$replaceEnd.'<p>';

			$textOut = str_replace($findStart,$replaceStart,$text);
			$textOut = str_replace($findEnd,$replaceEnd,$textOut);

      $start_count  = substr_count($textOut, $replaceStart);
      $end_count    = substr_count($textOut, $replaceEnd);

			if ($start_count > $end_count) $textOut = $textOut.$replaceEnd;
			if ($start_count < $end_count) $textOut = $replaceStart.$textOut;

			return $textOut;
		}

		/**
		 * @brief Function to check if a string represents a numeric value.
		 *
		 * This function is used to validate a string to see if it represents an
		 * integer value (IE only contains the characters 0 through 9). This is useful
		 * when validating form data. The values returned in VC_data are:
		 *
		 * <dl>
		 *	<dt>text_is_integer</dt>
		 *	<dd>This is set to true if text_integer represents an integer else false</dd>
		 * </dl>
		 *
		 * The following values from VC_data will be used if available:
		 *
		 * <dl>
		 *	<dt>text_integer</dt>
		 *	<dd>The input text to be checked</dd>
		 * </dl>
		 *
		 * @static
		 */
		function checkInteger() {
			global $VC_data;
			
			$textInteger = VCPage::getVC_data('text_integer');
			$VC_data['text_is_integer'] = ctype_digit($textInteger);
		}

		/**
		 * @brief Function to convert Microsoft's "smart quotes" to regular quotes.
		 *
		 * This function will convert Microsoft's non-standard single and double
		 * "smart quotes" located between ASCII 145-148 dec, 91-94 hex and convert
		 * them to regular/standard single and double quotes (' and ").
		 *
		 * @param $text The text to be formatted.
		 *
		 * @static
		 */
		function _i_fixSmartQuotes($text) {
			
			$text = str_replace("\x91",'\'',$text);
			$text = str_replace("\x92",'\'',$text);
			$text = str_replace("\x93",'"',$text);
			$text = str_replace("\x94",'"',$text);
			
			return $text;
		}
		
		/**
		 * @brief Function to apply list formatting to some text.
		 *
		 * This function is used to provide list formatting functions. Lists
		 * should be specified in the text using an asterisk with only whitespace
		 * characters preceding it. Each line will then be wrapped in li tags with
		 * consecutive groups of such lines wrapped in ul tags. 
		 *
		 * @static
		 */
		function _i_buildList($text) {
			global $VC_data;
						
			if (substr($text,-1) != "\n") $text .= "\n";
			$text = str_replace("\r",'',$text);
			$text = str_replace('<br />',"\n",$text);
			$list	= '';
			
			$blockStart = 0;
			
			$startPos 	= strpos($text, '*');
			$blockStart = $startPos;
			$list .= substr($text, 0, $startPos);
			$blockEnd = false;

			while (strpos($text, '*', $blockStart) !== false) {
				$offset = strpos($text, '*', $blockStart);
				$list .= substr($text, $blockStart, $offset-$blockStart);
				$blockStart = $offset;

				// Find a CR/FL with no * after it...
				$pos = $blockStart;
				$blockEnd = false;
				if ($blockStart !== false) {
					while ($pos < strlen($text) && !$blockEnd) {
						$posLF = strpos($text, "\n", $pos);
						if ($posLF === false) {
							$blockEnd = strlen($text);
							break;
						}
						$posA = strpos($text, '*', $posLF);
						if ($posA === false) {
							$blockEnd = $posLF;
							break;
						}
						if (trim(substr($text, $posLF, $posA - $posLF))) {
						 $blockEnd = $posLF;
						 break;
						}
						$pos = $posA;
					}
				}

				// We now have out block start and end positions
				// so we can now apply the formatting...
				if ($blockStart !== false && $blockEnd !== false) {
					$list .= '</p><ul>';
					$block = substr($text, $blockStart, $blockEnd - $blockStart);
					$block = str_replace('*','<li>',$block);
					$block = str_replace("\n",'</li>',$block);
					$block = trim($block);
					if (substr($block,strlen($block)-5,5) != '</li>') {
						$block .= '</li>';
					}
					$list .= $block;
					$list .= '</ul><p>';
				}

				$blockStart = $blockEnd;
			}

			if (!$blockEnd) {
				$list .= $text;
			} else {
				$tempText = substr($text,$blockEnd);
				$list .= $tempText;
			}

			$list = trim($list);
			$list = str_replace("\n",'<br />',$list);
			$list = str_replace('<p><br />','<p>', $list);
			$list = str_replace('<br /></p>','</p>', $list);
		
			return $list;	
    }
	}

?>
Return current item: v-creator