<?php
/**
*
* YapBB's Bulletin Board Tags class v2.18
*
* YapBB's Tags class has functionality typically found in discussion board
* systems ('forums'). YBBtags originates from the YapBB forum system. Class
* objects can easily process text by specifying the actions to perform on the
* represented text. These include PHP code highlighting (both PHP3 and PHP4),
* lists, simple formatting, IRC-style schizophrenia, division of the
* represented text into quote/code blocks, handling of smilies, and more.
* Actions can be specified at run time, e.g. depending on variables defined
* in the calling script.
*
* http://yapbb.sourceforge.net/YBBtags/
*
*
* <code>--------------
* Example Usage:
* --------------</code>
*
* # We assume that $text already contains a text, $smiles is
* # an array in the proper format (see constructor), $sessionUser
* # contains a description of the person who made the
* # HTTP request and that this file has already been included
* # into the project somewhere.
*
* <code>
* $YBB = new YBBtags($text, $smiles, "./images/", $sessionUser);
*
* $operations = "";
* if ($useHTML == 0) $operations .= $YBB->OP_NOHTML;
* if ($highlightcode == 1) $operations .= $YBB->OP_PHP;
* $operations .= $YBB->OP_SIMPLE;
* $operations .= $YBB->OP_SMILIES;
* $operations .= $YBB->OP_QUOTE;
*
* $text = $YBB->pgetText($operations);
* </code>
*
* # Done! $text now contains the parsed version of the
* # original $text.
*
*
* <code>------
* Notes:
* ------</code>
*
* o In order to alter the resulting HTML produced by <code>[code], [php],
* [quote] and [img2]</code> tags, please alter the <code>encapsulate()</code> method
* of this class.
* By default it assumes presence of a style sheet with elements
* named <code>'code', 'quote' and 'image'</code> (which can be applied to <code><tr></code>
* elements), which would be used for decoration.
*
* o The <code>[me=XYZ]</code> and <code>[you]</code> tags assume that style sheet elements
* with the names 'me' and 'you' respectively, are availlable
* and can be applied to <code><span></code> elements. Look for
* <code>"case $this->OP_PERSONAL:"</code> in this class and change the
* appropriate code.
*
* o YBBtags has been succesfully tested on PHP4.0.6 and PHP3.0.17
* on Windows platform and on PHP4.0.3pl1 on Linux platform.
*
* o The NL2BR and NBSP operarators are always handled last (if present) and
* the NOHTML or SAFEHTML operators are always handled first (if present).
*
* o In order to add the original '/me' capability, use the following regular expression
* before passing text to instances of this class:
* <code>
* // Me function by hide@address.com :
* $expression = "!(^|[ \t])/me (.*)$!im";
* $replacement = "\\1[me=" . $userNickName . "]\\2[/me]";
* $text = preg_replace($expression, $replacement, $text);
* </code>
* In the context of a forum system, <code>$userNickName</code> should contain the username of
* the person who posted the message that is being processed.
*
* o Processing of string highlighting in PHP3 is VERY CPU intensive and should probably not
* not be enabled when used with large text fragments.
*
*
* <code>------------
* Limitations:
* ------------</code>
*
* o The appearance of a code, php or quote segment inside a list
* segment does not give the desired effect, because of the way
* these segments are split up.
*
* o The same limitation does *NOT* go for a code or php segment
* inside a quote segment.
*
* o In general, segments inside another segment of the same kind
* do not function.
*
*
* <code>--------
* Changes:
* --------</code>
*
* o New in 2.18:
* x Changed the constructor to now check if PHP is running in
* safe mode or not, before attempting to reset the time out
* x Changed the resulting HTML of the <code>[edit]</code> tag
*
* o New in 2.17:
* x Bug fix in <code>processTypes()</code>. Now <code>$operations</code> is first inspected for types,
* *then* individual actions are taken in a predefined sequence. Altering this sequence
* could cause problems
* x Bug fix: now &&nbsp;'s are added based on the <code>$OP_NBSP</code> operator,
* not the <code>$OP_NL2BR</code> operator
* x Bug fix in the simple markup tags for PHP3
*
* o New in 2.16:
* x Bug fix in the <code>[edit]</code> tag (language array was not properly used)
* x Bug fix in the <code>[list]</code> tag ('variables' were not handled properly, ie such sequences: $aVar)
*
* o New in 2.15:
* x Documentation changes
* x Bug fix for the <code>[rev]</code> tag-processor - the PHP3 and PHP4 blocks were mistakenly swapped
* x Split <code>$OP_CODE</code> into <code>$OP_CODE</code> (for normal <code>[code]</code>) and <code>$OP_PHP</code> (for <code>[php]</code> code)
* (now the example finally is 100% accurate as well ;))
*
* o New in 2.14:
* x Documentation changes
* x Added new <code>[rev]</code> markup tag to reverse the contents of its body
* x Previously, the <code>$OP_NL2BR</code> operator was handled at the point it was encountered,
* but now it's always handled last in line. Same goes for <code>$OP_NOHTML</code> and
* <code>$OP_SAFEHTML</code> (which are both handled first). Now the order in which the operators
* appear, that are passed to <code>parse()</code>, does not matter anymore.
* x Now all operators are 2-char strings, to allow for easier future expansion
* (of course this does not interfere with normal operation in any way)
* x Added the OP_NBSP operator.
* x Changed code for locating operators in <code>$operations</code>, since operators are now 2-char strings
*
* o New in 2.13:
* x Insignificant documentation changes
* x Bug fix when using upper case tags for code, php or quote
* x Added simple markup tags: <code>[sub]</code> and <code>[sup]</code>
*
* o New in 2.12:
* x Small typo in documentation corrected
* x Added more documentation on how to use the supported tags
* x Fixed some more documentation
* x Added more links and cross references
* x When code is encapsulated, it's nolonger wrapped (see <code>_encapsulate()</code>)
* (The prefered way is to add the nowrap style to the code element in
* the CSS.)
* x Bug fix when "reversing" <code>&amp;amp;#code;</code> back to <code>&#code;</code> (with HTML disabled)
*
* o New in 2.11:
* x Bug fix: [me=XYZ] now works correctly
* x Small documentation changes
* x Removed redundant <code>_generate_ereg()</code>
* x Other small code changes
*
* o New in 2.10:
* x Re-instated array_values and array_keys emulation
* x [list] now finally works on PHP3
* x Optimized the code a bit
* x PHP highlighting now fully functional for PHP3 (though
* VERY slow)
* x YBBtags now tries to disable the script-timeout setting
* x Made the $smilies array a required parameter to the
* constructor. (For the sake of the PHPDoc system.)
* Previously $smilies was an optional argument
*
* o New in 2.9:
* x Added highlight functionality for PHP3 (buggy, so disabled)
* x Removed array_values and array_keys emulation
*
* o New in 2.8:
* x Started keeping changelog
* x Added the OP_APPEARANCE operator (derived from OP_SIMPLE)
* x Some code cleanup
* x Cleaned up the documentation as well as adding new ones
*
*
* <code>-----------------
* Integral part of:
* -----------------</code>
*
* YapBB, a fully functional bulletin board system
* Copyright (C) 2001 Arno van der Kolk, Sven Vintges
* http://yapbb.sourceforge.net/
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* @author Arno van der Kolk <hide@address.com>
* @copyright © 2001 Arno van der Kolk
* @link http://yapbb.sourceforge.net/YBBtags/ YBBtags Home Page
* @link http://yapbb.sourceforge.net/ YapBB Website
* @link http://freshmeat.net/projects/YBBtags/ YBBtags on freshmeat.net
* @link http://yapbb.sourceforge.net/article.php?sid=3&mode=threaded?menu=13 GNU Public License
* @link http://yapbb.sourceforge.net/forum/faq.php#ybb Full list of supported tags
* @version 2.18
* @access public
*
*/
class YBBtags
{
/**
* Information for serialization
*
* @access public
* @static
* @final
* @var string $classname
* @link http://www.yapbb.net/serialize
* @since 2.0
*/
var $classname = "YBBtags";
/**
* For keeping track if this instance has already been parsed (instances won't parse more than once)
*
* @access private
* @var boolean $_hasparsed
* @since 2.0
*/
var $_hasparsed = false;
/**
* For keeping track of all the text segments
*
* This array is automatically filled in <code>_split</code>.
*
* @access private
* @var array $_segments
* @see _split()
* @since 2.0
*/
var $_segments = array();
/**
* For keeping track of the types of all the text segments
*
* This array is automatically filled in <code>_split</code>.
*
* @access private
* @var array $_types
* @see _split()
* @since 2.0
*/
var $_types = array();
/**
* Are we dealing with some anitique PHP3 system? ;)
*
* This is automatically set in constructor.
* (In previous 2.x versions this was called <code>_isPHP4</code>.)
*
* @access private
* @static
* @var boolean $_isPHP3
* @see YBBtags()
* @since 2.8
*/
var $_isPHP3;
/**
* Pointer to the array that contains the smilies
*
* This is set through a constructor parameter.
*
* @access private
* @var array $_smilies
* @see YBBtags()
* @since 2.0
*/
var $_smilies;
/**
* Should contain the URI where the supporting images can be located
*
* This is set through a constructor parameter.
*
* @access private
* @var string $_imgURL
* @see YBBtags()
* @since 2.0
*/
var $_imgURL;
/**
* Should contain a string identifying the reader of the represented text
*
* This is set through a constructor parameter.
*
* @access private
* @var string $_reader
* @see YBBtags()
* @since 2.0
*/
var $_reader;
/**
* Used to mark segment as normal (plain text)
*
* @access private
* @static
* @final
* @var integer $_TYPE_NORMAL
* @since 2.0
*/
var $_TYPE_NORMAL = 1;
/**
* Used to mark segment as code
*
* @access private
* @static
* @final
* @var integer $_TYPE_CODE
* @since 2.0
*/
var $_TYPE_CODE = 2;
/**
* Used to mark segment as PHP code
*
* @access private
* @static
* @final
* @var integer $_TYPE_PHP
* @since 2.0
*/
var $_TYPE_PHP = 3;
/**
* Used to mark segment as quote
*
* @access private
* @static
* @final
* @var integer $_TYPE_QUOTE
* @since 2.3
*/
var $_TYPE_QUOTE = 4;
/**
* Operator: Disable all HTML by converting <, > and & to &amp;lt;, &amp;gt; and &amp;amp; respectively
*
* Note that all occurances of <code>&amp;#code;</code> and <code>&amp;XYZ;</code> are converted back for added flexibility.
*
* @access public
* @static
* @final
* @var string $OP_NOHTML
* @since 2.0
*/
var $OP_NOHTML = "NH";
/**
* Operator: Only disable dangerous HTML (has no effect when <code>$OP_NOHTML</code> is also set)
*
* This includes <code><td>, <tr>, <table>, <th>, <script>, <meta>, <xmp>, <html>, <body>, <head>, <textarea></code>.
* Also, the <code>style</code> attribute for all elements has been disabled.
*
* @access public
* @static
* @final
* @var string $OP_SAFEHTML
* @see $OP_NOHTML
* @since 2.0
*/
var $OP_SAFEHTML = "SH";
/**
* Operator: Process smilies (replace smile-codes with their pictures)
*
* See constructor for format of the smilies array.
*
* @access public
* @static
* @final
* @var string $OP_SMILIES
* @see YBBtags()
* @since 2.0
*/
var $OP_SMILIES = "EM";
/**
* Operator: Process [list] tags
*
* The proper format is:
* <code>
* [list]
* [*]Text 1
* [*]Text 2
* [*]Text 3
* [/list]
* </code>
* Result is:
* <code>
* <ul>
* <li>Text 1</li>
* <li>Text 2</li>
* <li>Text 3</li>
* </ul>
* </code>
* @access public
* @static
* @final
* @var string $OP_LIST
* @see _create_listitems()
* @since 2.0
*/
var $OP_LIST = "LI";
/**
* Operator: Process simple markup tags
*
* This includes:
* <code>
* [b]bold[/b] --> <b>bold</b>
* [i]italic[/i] --> <i>italic</i>
* [u]underline[/u] --> <u>underline</u>
* [s]strike-through[/s] --> <s>strike-through</s>
* [tt]teletype font[/tt] --> <tt>teletype font</tt>
* [sub]subscript[/sub] --> <sub>subscript</sub>
* [sup]superscript[/sup] --> <sup>superscript</sup>
* [hr] --> <hr>
* </code>
* @access public
* @static
* @final
* @var string $OP_SIMPLE
* @since 2.0
*/
var $OP_SIMPLE = "SM";
/**
* Operator: Process color and size of text
*
* This includes:
* <code>
* [color=XYZ]text[/color] --> <font color="XYZ">text</font>
* [size=XYZ]text[/size] --> <font size="XYZ">text</font>
* </code>
* @access public
* @static
* @final
* @var string $OP_APPEARANCE
* @since 2.8
*/
var $OP_APPEARANCE = "AP";
/**
* Operator: Treat code segments as code (in stead of plain text segments)
*
* This includes:
*
* <code>[code]text[/code]</code>
*
* (see <code>_encapsulate()</code> for resulting HTML)
*
* @access public
* @static
* @final
* @var string $OP_CODE
* @see _encapsulate()
* @since 2.0
*/
var $OP_CODE = "CO";
/**
* Operator: Treat PHP code segments as code (in stead of plain text segments)
*
* This includes:
*
* <code>[php]text[/php]</code>
*
* (see <code>_encapsulate()</code> for resulting HTML)
*
* @access public
* @static
* @final
* @var string $OP_PHP
* @see _encapsulate()
* @since 2.15
*/
var $OP_PHP = "PC";
/**
* Operator: Process [quote]
*
* This includes:
*
* <code>[quote]text[/quote]</code>
*
* (see <code>_encapsulate()</code> for resulting HTML)
*
* @access public
* @static
* @final
* @var string $OP_QUOTE
* @see _encapsulate()
* @since 2.0
*/
var $OP_QUOTE = "QU";
/**
* Operator: Process [email], [url] and make links clickable
*
* This includes:
* <code>
* [email]XYZ[/email] --> <a href="mailto:XYZ">XYZ</a>
*
* [email=ABC]XYZ[/email] --> <a href="mailto:ABC">XYZ</a>
*
* hide@address.com -->
* <a href="mailto:hide@address.com">hide@address.com</a> (automatic conversion)
*
* [url]XYZ[/url] --> <a href="XYZ">XYZ</a>
*
* [url=ABC]XYZ[/url] --> <a href="ABC">XYZ</a>
*
* http://url.domain.com/page -->
* <a href="http://url.domain.com/page">http://url.domain.com/page</a> (automatic conversion)
* </code>
*
* @access public
* @static
* @final
* @var string $OP_URLS
* @since 2.0
*/
var $OP_URLS = "HL";
/**
* Operator: Perform miscelaneous operations
*
* This includes:
* <code>
* [offtopic]text[/offtopic] --> <small>Offtopic:<br>text</small></code> (used for small unimportant notes)<code>
* [off topic]text[/off topic] --> <small>Off topic:<br>text</small></code> (used for small unimportant notes)<code>
* [edit]text[/edit] --> Edit:<br><i>text</i></code> (used to mark a note that was added later)<code>
* </code>
* @access public
* @static
* @final
* @var string $OP_MISC
* @since 2.0
*/
var $OP_MISC = "MC";
/**
* Operator: Replace newlines with html-breaks
*
* @access public
* @static
* @final
* @var string $OP_NL2BR
* @link http://www.php.net/nl2br
* @since 2.0
*/
var $OP_NL2BR = "NB";
/**
* Operator: Replace spaces and tabs with &amp;nbsp;
*
* @access public
* @static
* @final
* @var string $OP_NBSP
* @since 2.14
*/
var $OP_NBSP = "SC";
/**
* Operator: Process [me=XYZ] and [you] tags
*
* This includes:
*
* <code>[you] --> <span class="you">(you)</span></code> ((you) represents the string specified to the constructor)
* <code>[me=XYZ]text[/me] --> <span style='display: block' class='me'>» XYZ text</span></code>
*
* @access public
* @static
* @final
* @var string $OP_PERSONAL
* @see YBBtags()
* @since 2.0
*/
var $OP_PERSONAL = "PI";
/**
* Operator: Process [img] and [img2] tags
*
* This includes:
* <code>
* [img]XYZ[/img] --> <img src="XYZ" alt="picture: XYZ">
* [img2]XYZ[/img2] --> <a href="XYZ" target="_blank"><img src="icon.gif" alt="picture: XYZ"></a></code> (see also code in <code>_encapsulate()</code>)<code>
* </code>
* @access public
* @static
* @final
* @var string $OP_IMAGES
* @see _encapsulate()
* @since 2.0
*/
var $OP_IMAGES = "IM";
/**
* Operator: Process [rev]
*
* This includes:
* <code>
* [rev]a sample text[/rev] --> txet elpmas a
* </code>
* @access public
* @static
* @final
* @var string $OP_REVERSE
* @since 2.14
*/
var $OP_REVERSE = "BW";
/**
* Operator: Perform all available operations in a pre-defined sequence
*
* This operator is ignored when used in conjunction with other operations.
* See the code of <code>_processNormal()</code> for exact sequence.
*
* @access public
* @static
* @final
* @var string $OP_ALL
* @see _processNormal()
* @since 2.0
*/
var $OP_ALL = "AL";
/**
* This array contains language specific information.
*
* You should modify the contents of this array, which is hard coded in the constructor,
* when you want to translate certain output generated by class objects.
*
* @access private
* @static
* @var array $lang
* @see YBBtags()
* @since 2.0
*/
var $lang = array();
/**
* Constructor, used to construct new class objects ('instances').
*
* The passed text is automatically split into segments by <code>_split()</code>.
*
* @access public
* @param string $text Text to represent
* @param array $smilies An array of smiles.
*
* The proper format of this array is:
* <code>array(array("" => "blank.gif"), array(":)" => "smile.gif"), array(":(" => "sad.gif"))</code>
*
* Note that only items with non-empty keys ("") are processed.
* @param string $picURL Directory (or URI) where to locate the required images (icon.gif and pixel.gif).
*
* icon.gif is used to represent images that are inserted into the text using the [img2] tag
* pixel.gif is used to provide better layout support for browsers
* @param string $reader The name or description of the reader/viewer of the represented text (if appropriate)
* (used by [you] - $OP_PERSONAL)
* @return object YBBtags A new instance of this class
* @see $OP_PERSONAL, _split()
* @since 1.0
*/
function YBBtags($text, $smilies, $picURL = "", $reader = "you")
{
if (function_exists("set_time_limit") && !get_cfg_var('safe_mode')) // Static initializer (to disable time limit)
set_time_limit(0);
// Conduct preliminary tests
if (!is_array($smilies) || count($this->arraykeys($smilies)) == 0 || count($this->arrayvalues($smilies)) == 0)
{
$smilies = array();
echo '<pre>Warning: Wrong format for $smilies array!</pre>';
}
if (substr($picURL, -1, 1) != "/")
$picURL = "$picURL/";
$this->lang['quote'] = "quote"; // If you plan on translating this array,
$this->lang['code'] = "code"; // DO NOT ALTER THE KEYS!
$this->lang['image'] = "picture"; // Only modify the values!
$this->lang['edit'] = "Edit";
$this->lang['guest'] = "Visitor";
// Assign attributes
$this->_smilies = $smilies;
$this->_imgURL = $picURL;
$this->_reader = $reader;
$this->_isPHP3 = floor(phpversion()) < 4;
$this->_split($text); // Automatically begin dividing the text into sections
} // end constructor
/**
* Splits the text into segments (recursively), called by the constructor
*
* You should not call this function directly. Since it's not a static, it *COULD*
* mess things up.
*
* @access private
* @param string $text Text to further split up
* @see YBBtags()
* @since 2.0
*/
function _split($text)
{
$expression = "!(.*)\[(quote|code|php)\](.+)\[/\\2\](.*?)!Uis"; // technical note: quote should appear before code and php (so that it may contain one of the others)
if (preg_match($expression, $text, $matches))
{
if ($matches[1] != "") // if we have something...
{
$this->_segments[] = $matches[1]; // ... stockpile it
$this->_types[] = $this->_TYPE_NORMAL; // ... and mark it as a normal segment
}
$this->_segments[] = $matches[3]; // stockpile the found segment...
switch (strtolower($matches[2])) // ... and mark it correctly
{
case "php":
$this->_types[] = $this->_TYPE_PHP;
break;
case "code":
$this->_types[] = $this->_TYPE_CODE;
break;
case "quote":
$this->_types[] = $this->_TYPE_QUOTE;
break;
default: // error (should not even be happening!)
die("Parse error: unknown type (" . $matches[2] . ")");
break;
}
$this->_split($matches[4]); // split the rest (recursive call)
}
else // no new segment found (ie: the rest has no code or PHP or quote)
{
$this->_segments[] = $text; // add that text
$this->_types[] = $this->_TYPE_NORMAL; // and mark it as normal
}
} // end func _split
/**
* Process all found segments and parse each one.
*
* This function actually sets the parse process into motion. Afterwards the
* <code>getText</code> method can be called to retrieve the parsed text.
*
* @access public
* @param string $operations Operations to perform on the represented text
* @see _processTypes()
* @since 1.0
*/
function parse($operations)
{
$operations = strtoupper($operations);
$count = count($this->_segments);
for ($i = 0; !$this->_hasparsed && $i < $count; $i++) // step through each segment
$this->_segments[$i] = $this->_processTypes($this->_segments[$i], $operations, $this->_types[$i]);
unset($count);
unset($i);
$this->_hasparsed = true;
} // end func parse
/**
* Auxillary parse function, called from <code>parse()</code>, calls <code>_processNormal()</code>
*
* You should not call this function directly. But since it's a static, it could not
* possibly do any harm. :)
*
* @access private
* @static
* @param string $text The text to process
* @param string $operations The operations to perform
* @param integer $type Type of the text
* @return string The processed text
* @see _processNormal(), parse()
* @since 2.3
*/
function _processTypes($text, $operations, $type)
{
switch ($type) // determine current segment's type
{
case $this->_TYPE_QUOTE: // is a quote (treat it as an entirely new piece of text)
{
$recursiveYBB = new YBBtags($text, $this->_smilies, $this->_imgURL, $this->_reader);
$text = $recursiveYBB->pgetText($operations); // recursively parse it
unset($recursiveYBB);
if ($this->_has_operator($operations, $this->OP_NL2BR)) // encapsulate the result into a quote (if enabled)
$text = $this->_encapsulate('quote', $text);
break;
}
case $this->_TYPE_PHP: // is PHP code segment
{
if ($this->_has_operator($operations, $this->OP_PHP)) // is PHP code parsing enabled?
{
if (!$this->_isPHP3) // PHP3 has no highlight built in
{
$text = ("<" . "?\n$text\n?" . ">");
ob_start();
highlight_string($text);
$text = ob_get_contents();
ob_end_clean();
$text = $this->_encapsulate('code', $text);
}
else
$text = $this->_encapsulate('code', trim($this->highlightstring("<" . "?$text?" . ">")));
break;
}
else
; // see? no break; so continue to next
}
case $this->_TYPE_CODE: // is regular code segment
{
if ($this->_has_operator($operations, $this->OP_CODE)) // is code parsing enabled?
{
$text = $this->_encapsulate('code', nl2br(str_replace(' ', ' ', str_replace("\t", ' ', htmlentities("$text\n")))));
break;
}
// else, treat as normal segment
// see? no break; so continue to next
}
case $this->_TYPE_NORMAL: // is normal (non-code) segment
{
$text = $this->_processNormal($text, $operations);
break;
}
default: // ERROR! (should not even be happening)
{
die("parse error ($i: ." . $text . ". - $operations)!");
break;
}
}
return $text;
} // end func _processTypes
/**
* Process the 'normal' segments (that are neither code, PHP or quote).
*
* You should not call this function directly. But since it's a static, it could not
* possibly do any harm. :)
*
* @access private
* @static
* @param string $text The text to process
* @param string $operations The operations to perform
* @return string The processed text
* @see _processTypes()
* @todo Fix the nested simple markup bug for PHP3
* Fix the ' and \ in img2 urls (not really necessary though)
* @since 2.3
*/
function _processNormal($text, $operations)
{
$op = array();
$len = strlen($operations);
for ($j = 0; $j < $len; $j += 2)
{
switch (substr($operations, $j, 2))
{
case $this->OP_SMILIES: // enable smilies in this segment
$op[$this->OP_SMILIES] = TRUE;
break;
case $this->OP_LIST: // enable lists in this segment
$op[$this->OP_LIST] = TRUE;
break;
case $this->OP_REVERSE:
$op[$this->OP_REVERSE] = TRUE;
break;
case $this->OP_SIMPLE: // process simple markups in this segment
$op[$this->OP_SIMPLE] = TRUE;
break;
case $this->OP_APPEARANCE:
$op[$this->OP_APPEARANCE] = TRUE;
break;
case $this->OP_URLS: // process urls in this segment
$op[$this->OP_URLS] = TRUE;
break;
case $this->OP_MISC: // miscelaneous markups in this segment
$op[$this->OP_MISC] = TRUE;
break;
case $this->OP_PERSONAL: // convert [me=XYZ] and [you] in this segment
$op[$this->OP_PERSONAL] = TRUE;
break;
case $this->OP_IMAGES: // enable images in this segment
$op[$this->OP_IMAGES] = TRUE;
break;
case $this->OP_ALL: // process all operations
$op[$this->OP_NOHTML] = TRUE;
$op[$this->OP_SMILIES] = TRUE;
$op[$this->OP_PERSONAL] = TRUE;
$op[$this->OP_SIMPLE] = TRUE;
$op[$this->OP_APPEARANCE] = TRUE;
$op[$this->OP_REVERSE] = TRUE;
$op[$this->OP_CODE] = TRUE;
$op[$this->OP_PHP] = ($this->_isPHP3 ? FALSE : TRUE);
$op[$this->OP_QUOTE] = TRUE;
$op[$this->OP_URLS] = TRUE;
$op[$this->OP_LIST] = TRUE;
$op[$this->OP_IMAGES] = TRUE;
$op[$this->OP_MISC] = TRUE;
$op[$this->OP_NBSP] = TRUE;
$op[$this->OP_NL2BR] = TRUE;
$j = $len;
break;
case $this->OP_NOHTML: // disable all HTML
$op[$this->OP_NOHTML] = TRUE;
break;
case $this->OP_SAFEHTML: // disable only dangerous HTML
$op[$this->OP_SAFEHTML] = TRUE;
break;
case $this->OP_NL2BR: // convert newlines to <br>s in this segment
$op[$this->OP_NL2BR] = TRUE;
break;
case $this->OP_NBSP: // convert spaces and tabs to in this segment
$op[$this->OP_NBSP] = TRUE;
break;
case $this->OP_QUOTE: // There is no actual 'processing' of quotes,
$op[$this->OP_QUOTE] = TRUE;
break;
case $this->OP_PHP: // code and php code, as these
$op[$this->OP_PHP] = TRUE;
break;
case $this->OP_CODE: // segments require special treatment
$op[$this->OP_CODE] = TRUE;
break;
default: // ERROR!
die("Parse error ($j: " . substr($operations, $j, 2) . ") - $operations!");
break;
}
}
if ($op[$this->OP_NOHTML])
{
$text = htmlentities($text);
$expression = quotemeta("&") . "([A-Z]+|" . quotemeta("#") . "[0-9]+);";
$replacement = "&\\1;";
$text = eregi_replace($expression, $replacement, $text);
}
else if ($op[$this->OP_SAFEHTML])
{
$text = str_replace("<!--", "<!--", $text);
$text = str_replace("-->", "-->", $text);
$text = preg_replace("!<((/)?((td|tr|table|th|script|meta|xmp|html|body|head|textarea)( .*)?)|([A-Z]+.*style=.*))>!Ui", "<\\1>", $text);
}
if ($op[$this->OP_LIST]) // enable lists in this segment
{
$expression = "!" . quotemeta("[list]") . "[\n\r]*?((" . quotemeta("[*]") . ".+)+)[\n\r]*?" . quotemeta("[/list]") . "!Uis";
if (!$this->_isPHP3)
{
$expression .= "e";
$replacement = "\$this->_create_listitems('\\1')";
$text = preg_replace($expression, $replacement, $text);
}
else
{
if (preg_match_all($expression, $text, $tmp))
{
reset($tmp[1]);
while (list(, $var) = each($tmp[1]))
{
$exp = "!" . quotemeta("[list]") . "[\n\r]*?" . quotemeta($var) . "[\n\r]*?" . quotemeta("[/list]") . "!Uis";
$items = explode("[*]", $var);
$tmp2 = "";
for (reset($items); list(, $item) = each($items);)
if (trim($item) != "")
$tmp2 .= "<li>$item</li>";
$text = preg_replace($exp, "<ul>$tmp2</ul>", $text);
}
}
}
}
if ($op[$this->OP_SMILIES]) // enable smilies in this segment
for (reset($this->_smilies); list($key, $value) = each($this->_smilies);)
if ($key != "" && $value != "")
{
if ($op[$this->OP_NOHTML])
$s = htmlspecialchars($key);
else
$s = $key;
$text = str_replace($s, '<img src="' . $value . '" alt="' . $key . '">', $text);
}
if ($op[$this->OP_REVERSE])
if (!$this->_isPHP3)
{
$expression = "!" . quotemeta("[rev]") . "(.*)" . quotemeta("[/rev]") . "!Uise";
$replacement = "strrev(\"\\1\")";
$text = preg_replace($expression, $replacement, $text);
}
else
{
$expression = "!(.*)" . quotemeta("[rev]") . "(.*?)" . quotemeta("[/rev]") . "(.*)!is";
if (preg_match_all($expression, $text, $matches, PREG_SET_ORDER))
{
$count = count($matches);
for ($k = 0; $k < $count; $k++)
$text = $matches[$k][1] . strrev($matches[$k][2]) . $matches[$k][3];
}
}
if ($op[$this->OP_SIMPLE]) // process simple markups in this segment
{
// VERY simple ;)
$vars = array("b", "u", "i", "tt", "sub", "sup");
$vars = implode("|", $vars);
$oldText = $text . " ";
while ($oldText != $text)
{
$oldText = $text;
$text = preg_replace("!\[($vars)\](.+)\[/\\1\]!Uis", "<\\1>\\2</\\1>", $text);
}
// strike through
$expression = "!" . quotemeta("[s]") . "(.+)" . quotemeta("[/s]") . "!Uis";
$replacement = "<strike>\\1</strike>";
$text = preg_replace($expression, $replacement, $text);
// rulers
$text = eregi_replace("\[hr\]", "<hr width='90%' align='left'>", $text);
}
if ($op[$this->OP_APPEARANCE])
{
// color
$expression = "!" . quotemeta("[color=") . "(.+)" . quotemeta("]") . "(.+)" . quotemeta("[/color]") . "!Uis";
$replacement = "<font color='\\1'>\\2</font>";
$text = preg_replace($expression, $replacement, $text);
// size
$expression = "!" . quotemeta("[size=") . "(\d+)" . quotemeta("]") . "(.+)" . quotemeta("[/size]") . "!Uis";
$replacement = "<font size='\\1'>\\2</font>";
$text = preg_replace($expression, $replacement, $text);
}
if ($op[$this->OP_URLS]) // process urls in this segment
{
$expression = "!\\[email\\](.+)\\[/email\\]!Uis";
$replacement = "<a href=\"mailto:\\1\">\\1</a>";
$text = preg_replace($expression, $replacement, $text);
$expression = "!\\[email=(.+)\\](.+)\\[/email\\]!Uis";
$replacement = "<a href=\"mailto:\\1\">\\2</a>";
$text = preg_replace($expression, $replacement, $text);
//supplied by hide@address.com
$text = preg_replace("!(\[url\])(.+)(\[/url\])!Uis", "<a href='\\2' target='_blank'>\\2</a>", $text); //for all links
$text = preg_replace("!(\[url=)(http|https|ftp)(://\S+?)(\])(.+?)(\[/url\])!i", "<a href='\\2\\3' target='_blank'>\\5</a>", $text);//for http/https/ftp links
$text = preg_replace("!(\[url=)(\S+?)(\])(.+?)(\[/url\])!i", "<a href='\\2' target='_blank'>\\4</a>", $text);//for other links
//source: Mitchell Rietdijk / www.phpfreakz.com (customized by Arno van der Kolk)
$text = eregi_replace("(^|[ \n\r\t])((http(s?)://)(www\.)?([a-z0-9_-]+(\.[a-z0-9_-]+)+)(/[^/ \n\r]*)*)", "\\1<a href=\"\\2\" target=\"_blank\">\\2</a>", $text); //Hier worden alle http:// texten aanklikbare links.
//$text = eregi_replace("(^|[ \n\r\t])((ftp://)(www\.)?([a-z0-9_-]+(\.[a-z0-9_-]+)+)(/[^/ \n\r]*)*)", "\\1<a href=\"\\2\" target=\"_blank\">\\2</a>", $text); //Hier worden alle ftp:// texten aanklikbare links.
$text = preg_replace("!(^|[ \n\r\t])((ftp://)(([a-z0-9_-]+)(:([a-z0-9_-]+([a-z0-9_-]+\@)?))?\@)?(www\.)?([a-z0-9_-]+(\.[a-z0-9_-]+)+)(/[^/ \n\r]*)*)!i", "\\1<a href='\\2'>\\2</a>", $text);
$text = eregi_replace("(^|[ \n\r\t])([a-z_-][a-z0-9\._-]*@[a-z0-9_-]+(\.[a-z0-9_-]+)+)", "\\1<a href='mailto:\\2'>\\2</a>", $text); //Hier worden e-mail adressen aanklikbaar
$text = eregi_replace("(^|[ \n\r\t])(www\.([a-z0-9_-]+(\.[a-z0-9_-]+)+)(/[^/ \n\r]*)*)", "\\1<a href='http://\\2' target='_blank'>\\2</a>", $text); //Als iemand de http:// vergeet en met www. begint wordt automatisch http:// toegevoegd en aanklikbaar gemaakt.
$text = eregi_replace("(^|[ \n\r\t])(ftp\.([a-z0-9_-]+(\.[a-z0-9_-]+)+)(/[^/ \n\r]*)*)", "\\1<a href='ftp://\\2' target='_blank'>\\2</a>", $text); //Als iemand de ftp:// vergeet en met ftp. begint wordt automatisch ftp:// toegevoegd en aanklikbaar gemaakt.
}
if ($op[$this->OP_MISC]) // miscelaneous markups in this segment
{
$expression = "!\\[(off( )?topic)\\][\n\r]*?(.*)[\n\r]*?\\[/\\1\\]!Uis";
$replacement = "<small>\\1:<br>\\3<br></small>";
$text = preg_replace($expression, $replacement, $text);
$expression = "!\\[edit\\][\n\r]*?(.*)[\n\r]*?\\[/edit\\]!Uis";
$replacement = $this->lang['edit'] . ":<br><i>\\1</i>";
$text = preg_replace($expression, $replacement, $text);
}
if ($op[$this->OP_PERSONAL]) // convert [me=XYZ] and [you] in this segment
{
$you = ( ! empty( $this->_reader ) ) ? $this->_reader : $this->lang['guest'] ;
$expression = "!\[me=(.*)\]((.|\n|\r)*)\[/me\]!Ui"; // do not use 's' modifier because \\1 must NOT be multiline
$replacement = "<span style='display: block' class='me'>» \\1 \\2</span>";
$text = preg_replace($expression, $replacement, $text);
$expression = "!" . quotemeta("[you]") . "!i";
$replacement = "<span class='you'>$you</span>";
$text = preg_replace($expression, $replacement, $text);
}
if ($op[$this->OP_IMAGES]) // enable images in this segment
{
//not recommended: (automagically insert pictures wherever their URLs appear)
// $text = eregi_replace("(^|[ \n\r\t])((http(s?)://)(www\.)?([a-z0-9_-]+(\.[a-z0-9_-]+)+)(/[^/ \n\r]*)*(\.jpg|\.gif))","\\1<img src=\"\\2\">",$text); //Hier worden alle http:// texten aanklikbare links.
//supplied by hide@address.com
$text = preg_replace(
"!\[img\](.+?)\[/img\]!is",
"<img alt='" . $this->lang['image'] . ": \\1' src='\\1' border='0'>",
$text
); //for [img]
$expression = "!\[img2\](.+?)\[/img2\]!i";
// This is a bit buggy when \ and ' are in the URL, but normally that does not happen anyway:
$replacement = $this->_encapsulate('image', "<center><a href='\\1' target='viewPicture'><img border='0' src='" . $this->_imgURL . "icon.gif' alt='" . $this->lang['image'] . ": \\1'></a></center>");
$text = preg_replace($expression, $replacement, $text);
}
if ($op[$this->OP_NL2BR]) // now convert newlines
$text = nl2br($text);
if ($op[$this->OP_NBSP]) // now convert spaces and tabs
{
$text = str_replace("\t", " ", $text); // tabs are 4 spaces; you might just as well make it 8 :)
$text = str_replace(" ", " ", $text); // do not convert to " " for the sake of word wrapping
}
unset($op);
return $text;
} // end func _processNormal
/**
* Searches for a specific operator in a sequence of operations. (Called by <code>_processNormal()</code>)
*
* You should not call this function directly. But since it's a static, it could not
* possibly do any harm. :)
*
* @access private
* @static
* @param string $sequence Sequence of operations to be searched
* @param string $operator Operator to search for
* @return boolean TRUE represents found, FALSE represents not found
* @see _processNormal()
* @since 2.14
*/
function _has_operator($sequence, $operator)
{
$pos = strpos($sequence, $operator);
if ($pos % 2 == 0)
{
if ($pos > 0 || substr($sequence, 0, 2) == $operator)
return true;
}
return false;
} // end func _has_operator
/**
* Create the listitems for a list (called from <code>_processNormal()</code>).
*
* You should not call this function directly. But since it's a static, it could not
* possibly do any harm. :)
*
* @access private
* @static
* @param string $items string represents the list of list-items
* @return string A comlete HTML list
* @see _processNormal(), $OP_LIST
* @since 2.0
*/
function _create_listitems($items)
{
$items = explode("[*]", $items);
$count = count($items);
for ($i = 0; $i < $count; $i++)
{
$items[$i] = trim($items[$i]);
if ($items[$i] != "")
$items[$i] = "<li>" . $items[$i] . "</li>";
}
return str_replace("\'", "'", "<ul>" . implode("", $items) . "</ul>");
} // end func _create_listitems
/**
* Re-assembles all the segments and returns the resulting text
*
* This function is normally called after the <code>parse</code> method has been called.
* Otherwise the original text will just be returned, unmodified.
*
* @access public
* @return string The text (either parsed or not) represented by this instance
* @brother pgetText()
* @since 1.0
*/
function getText()
{
return implode("", $this->_segments);
} // end func getText
/**
* Parses and returns the text
*
* This function transitively calls the <code>parse</code> method and afterwards
* <code>getText</code> to return the result.
*
* @access public
* @param string $operations Operations to perform on the represented text
* @return string The parsed text represented by this instance
* @brother getText()
* @see parse()
* @since 2.0
*/
function pgetText($operations)
{
$this->parse($operations);
return $this->getText();
} // end func pgetText
/**
* Puts the specified text in a HTML box along with a caption
*
* Please see the source of this function to see what the exact result will be. If
* necessesary, you can also edit that html source to alter the results produced by
* this function.
*
* @access private
* @static
* @param string $caption Caption of the new html box (will be retrieved from the language data, using <code>$caption</code> as key)
* @param string $text Text to put into the html box
* @return string Text encapsulated in a html box
* @see _processTypes()
* @since 2.0
*/
function _encapsulate($caption, $text)
{
// create an appropriate seperator:
$sep = ( $this->_imgURL ?
"<td height='1'><img width='1' height='1' src='" . $this->_imgURL . "pixel.gif' alt=''>" : // use either an image (1x1) (more compatible)
"<td height='1'>" ) // or some advanced TD attribute
. "</td>"; // close cell off
// create the actual HTML box:
$tmp = "<blockquote>" .
"<table width='80%' cellpadding='0' cellspacing='0'>" .
"<tr>" .
"<td><small>" . $this->lang[$caption] . ":</small></td>" .
"</tr>" .
"<tr bgcolor='#000000' height='1'>" .
$sep .
"</tr>" .
"<tr class='$caption'>" .
"<td" . ($caption == 'code' ? " nowrap style='white-space: nowrap'" : "") . ">" .
str_replace("\'", "'", $text) .
"</td>" .
"</tr>" .
"<tr bgcolor='#000000' height='1'>" .
$sep .
"</tr>" .
"</table>" .
"</blockquote>";
unset($sep);
return $tmp;
} // end func _encapsulate
/**
* Auxilary function for the PHP4 impaired
*
* This is a re-implementation of <code>highlight_string</code>.
*
*
* Original information:
* (Source: http://www.phpbuilder.com/tips/item.php?id=216)
*
* Program name : Colorizator v1.0
* Author : Alexander Yanuar Koentjara
* hide@address.com
* Purpose : To make php code become a colorful HTML page !!
*
* @access private
* @static
* @param string $text String to highlight
* @return string The highlighted string
* @see _highlight_parse() Auxilary function
* @link http://www.php.net/highlight_string PHP4 function highlight_string on www.php.net
* @link http://www.phpbuilder.com/tips/item.php?id=216 Original location of source
* @since 2.9
* @todo Fix the bug which causes the last / of /x x/ blocks (where 'x' is a '*') to appear in normal font
*/
function highlightstring($text)
{
$result = "";
$CODE_BEGIN = "<" . "?"; // sorry ... so it will not caught by Colorizator
$CODE_END = "?" . ">"; // sorry ... so it will not caught by Colorizator
$arr_RESERVED_WORD = array("if", "while", "for", "return", "else");
$arr_DECLARATION_WORD = array("class", "var", "function", "global", "GLOBAL");
$color_RESERVED_WORD = "RED";
$color_DECLARATION_WORD = "BLUE";
$color_COMMENT = "#707090";
$color_DEFAULT = "#3333aa";
$color_STRING = "#800000";
$color_VARIABLE = "GREEN";
$color_HTML = "BLACK";
// The following 2 have to be 'random' strings, that cannot not occur in the text
$splitter = "|X*-(LexZ)-*X|" . time();
$splitter2 = "|X*-(Kick)-*X|" . time();
$RESERVED_WORD = implode("|", $arr_RESERVED_WORD);
$DECLARATION_WORD = implode("|", $arr_DECLARATION_WORD);
$result .=
"<PRE>
<!--
This php code is converted into HTML using :
Colorizator v1.0 (c) 2001 by Alexander Yanuar Koentjara (hide@address.com)
-->\n";
$result .= "<FONT FACE='Courier New' color='$color_DEFAULT'>";
$delimiter = array(
0 => 0,
"//" => array(2, "[\r\n]", $color_COMMENT),
"\"" => array(1, "\"", $color_STRING),
"'" => array(1, "'", $color_STRING),
"/*" => array(2, "\*/", $color_COMMENT),
"#" => array(1, "[\r\n]", $color_COMMENT)
);
$pos1 = 0;
$pos2 = 0;
while(1)
{
$posx = strpos(" $text", $CODE_BEGIN);
if (!$posx && strlen($text) > 0)
$posx = strlen($text) + 1;
if ($posx)
{
$posx--;
$result .= "<FONT COLOR='$color_HTML'>" . htmlspecialchars(substr($text, 0, $posx)) . "</FONT>";
}
if (!strpos(" $text", $CODE_BEGIN))
break;
$pos1 = strpos("$text", "$CODE_BEGIN") + 2;
$pos2 = strpos($text, "$CODE_END") - 1;
if ($pos2 < 1)
$pos2 = strlen($text) - 1;
$result .= "<?";
$str = substr($text, $pos1, $pos2 - $pos1 + 1);
// $result .= $this->_highlight_parse($str);
$result .= $this->_highlight_parse($str, $delimiter, $splitter, $splitter2, $color_VARIABLE, $RESERVED_WORD, $DECLARATION_WORD, $color_RESERVED_WORD, $color_DECLARATION_WORD);
$result .= "?>";
$text = substr($text, $pos2 + 3);
}
$result .= "</FONT></PRE>";
return $result;
} // end func highlightstring
/**
* Auxilary function for the PHP4 impaired
*
* This function is for continued program flow from <code>highlightstring()</code>.
* It actually highlights strings
*
*
* Original information:
* (Source: http://www.phpbuilder.com/tips/item.php?id=216)
*
* Program name : Colorizator v1.0
* Author : Alexander Yanuar Koentjara
* hide@address.com
* Purpose : To make php code become a colorful HTML page !!
*
* @access private
* @static
* @param string $str String to parse
* @param array $delimiter Array of delimiters
* @param string $splitter Line break delimiter
* @param string $splitter2 Line break delimiter
* @param string $color_VARIABLE Part of a regexp
* @param string $RESERVED_WORD Part of a regexp
* @param string $DECLARATION_WORD Part of a regexp
* @param string $color_RESERVED_WORD Part of a regexp
* @param string $color_DECLARATION_WORD Part of a regexp
* @return string The parsed string
* @see highlightstring() Calling function
* @since 2.9
* @todo Speed the darned thing up :)
*/
function _highlight_parse($str, $delimiter, $splitter, $splitter2, $color_VARIABLE, $RESERVED_WORD, $DECLARATION_WORD, $color_RESERVED_WORD, $color_DECLARATION_WORD)
{
//if (floor(phpversion()) < 4)
// return htmlspecialchars($str);
$flag = 0;
$pos2 = -1;
$all = "";
$strlen = strlen($str);
while ($pos2 < $strlen - 1)
{
$pos2++;
if ($flag)
{
$flag2 = 1;
if (substr($str, $pos2 - 1, 1) == "\\") $flag2 = 0;
if (substr($str, $pos2 - 2, 2) == "\\\\") $flag2 = 1;
if (ereg($delimiter[$flag][1], substr($str, $pos2, $delimiter[$flag][0])) && $flag2)
{
$all .= htmlspecialchars(substr($str, $pos2, 1)) . "$splitter2</FONT>";
$flag = 0;
}
else
$all .= htmlspecialchars(substr($str, $pos2, 1));
}
else
{
reset($delimiter);
while (list($key, $val) = each($delimiter))
{
if ($key)
{
if (substr($str, $pos2, $val[0]) == $key)
{
$all .= "<FONT COLOR='$val[2]'>$splitter" . htmlspecialchars(substr($str, $pos2, $val[0]));
$pos2 += ($val[0] - 1);
$flag = $key;
break;
}
}
}
if (!$flag)
$all .= htmlspecialchars(substr($str, $pos2, 1));
}
}
$all = eregi_replace(
"(\\\$[a-z0-9_]+)",
"<FONT COLOR='$color_VARIABLE'>\\1</FONT>",
$all
);
$all = ereg_replace(
// "([\r\n \t{};])($RESERVED_WORD)([\r\n \t{};])",
"([\r\n \t{};(),])($RESERVED_WORD)([\r\n \t{};(),])",
"\\1<FONT COLOR='$color_RESERVED_WORD'>\\2</FONT>\\3",
$all
);
$all = ereg_replace(
// "([\r\n \t{};])($DECLARATION_WORD)([\r\n \t{};])",
"([\r\n \t{};(),])($DECLARATION_WORD)([\r\n \t{};(),])",
"\\1<I><FONT COLOR='$color_DECLARATION_WORD'>\\2</FONT></I>\\3",
$all
);
$text = explode($splitter, $all);
$all = "";
$count = count($text);
if ($count > 1)
for ($i = 0; $i < $count; $i++)
{
$text2 = explode($splitter2, $text[$i]);
if (count($text2) > 1)
{
$text2[0] = eregi_replace(
"(<[/]{0,1}FONT[^>]*>|<[/]{0,1}B>|<[/]{0,1}I>)",
"",
$text2[0]
);
$all .= $text2[0] . $text2[1];
}
else
$all .= $text[$i];
}
else
$all = join("", $text);
return $all;
} // end func _highlight_parse
/**
* Auxilary function for the PHP4 impaired
*
* Emulated PHP4's <code>array_keys</code> function
*
* @access private
* @static
* @param array $arr Contains elements to be searched
* @param string $term Contains search term
* @return array All found items
* @link http://www.php.net/array_keys array_keys on www.php.net
* @since 2.10
*/
function arraykeys($arr, $term = "")
{
if (!function_exists("array_keys"))
{
$t = array();
while (list($k,$v) = each($arr)) {
if ($term && $v != $term)
continue;
$t[] = $k;
}
return $t;
}
else if ($term != "")
return array_keys($arr, $term);
else
return array_keys($arr);
} // end func arraykeys
/**
* Auxilary function for the PHP4 impaired
*
* Emulated PHP4's <code>array_values</code> function
*
* @access private
* @static
* @param array $arr Contains elements to be searched
* @return array All found items
* @link http://www.php.net/array_values array_values on www.php.net
* @since 2.10
*/
function arrayvalues($arr)
{
if (!function_exists("array_values"))
{
$t = array();
while (list($k, $v) = each ($arr))
$t[] = $v;
return $t;
}
else
return array_values($arr);
} // end func arrayvalues
}
?>