From: nohn Date: Wed, 13 Jul 2005 15:02:58 +0000 (+0000) Subject: updating bundled libs. X-Git-Tag: 0.9~314 X-Git-Url: http://git.mjollnir.org/gw?a=commitdiff_plain;h=c5827caf0f609d0d446fb6f4516e42c00dff5c84;p=s9y.git updating bundled libs. --- diff --git a/bundled-libs/.current_version b/bundled-libs/.current_version index a32af84..7879f99 100644 --- a/bundled-libs/.current_version +++ b/bundled-libs/.current_version @@ -1 +1,8 @@ -PEAR::XML_RPC 1.3.2 \ No newline at end of file +Cache_Lite 1.5.1 +HTTP_Request 1.2.4 +Net_CheckIP 1.1 +Net_Socket 1.0.6 +Net_URL 1.0.14 +PEAR 1.3.5 +Text_Wiki 1.0.0 +XML_RPC 1.3.2 \ No newline at end of file diff --git a/bundled-libs/Cache/Lite.php b/bundled-libs/Cache/Lite.php index 9b39342..34e5bcd 100644 --- a/bundled-libs/Cache/Lite.php +++ b/bundled-libs/Cache/Lite.php @@ -10,19 +10,16 @@ * There are some examples in the 'docs/examples' file * Technical choices are described in the 'docs/technical' file * -* A tutorial is available in english at this url : -* http://www.pearfr.org/index.php/en/article/cache_lite -* (big thanks to Pierre-Alain Joye for the translation) -* -* The same tutorial is also available in french at this url : -* http://www.pearfr.org/index.php/fr/article/cache_lite -* * Memory Caching is from an original idea of * Mike BENOIT * +* Nota : A chinese documentation (thanks to RainX ) is +* available at : +* http://rainx.phpmore.com/manual/cache_lite.html +* * @package Cache_Lite * @category Caching -* @version $Id: Lite.php,v 1.1 2004/12/02 14:23:52 nohn Exp $ +* @version $Id: Lite.php,v 1.30 2005/06/13 20:50:48 fab Exp $ * @author Fabien MARTY */ @@ -80,6 +77,13 @@ class Cache_Lite * @var string $_file */ var $_file; + + /** + * File name (without path) + * + * @var string $_fileName + */ + var $_fileName; /** * Enable / disable write control (the cache is read just after writing to detect corrupt entries) @@ -197,6 +201,39 @@ class Cache_Lite */ var $_automaticSerialization = false; + /** + * Disable / Tune the automatic cleaning process + * + * The automatic cleaning process destroy too old (for the given life time) + * cache files when a new cache file is written. + * 0 => no automatic cache cleaning + * 1 => systematic cache cleaning + * x (integer) > 1 => automatic cleaning randomly 1 times on x cache write + * + * @var int $_automaticCleaning + */ + var $_automaticCleaningFactor = 0; + + /** + * Nested directory level + * + * Set the hashed directory structure level. 0 means "no hashed directory + * structure", 1 means "one level of directory", 2 means "two levels"... + * This option can speed up Cache_Lite only when you have many thousands of + * cache file. Only specific benchs can help you to choose the perfect value + * for you. Maybe, 1 or 2 is a good start. + * + * @var int $_hashedDirectoryLevel + */ + var $_hashedDirectoryLevel = 0; + + /** + * Umask for hashed directory structure + * + * @var int $_hashedDirectoryUmask + */ + var $_hashedDirectoryUmask = 0700; + // --- Public methods --- /** @@ -217,6 +254,9 @@ class Cache_Lite * 'memoryCachingLimit' => max nbr of records to store into memory caching (int), * 'fileNameProtection' => enable / disable automatic file name protection (boolean), * 'automaticSerialization' => enable / disable automatic serialization (boolean) + * 'automaticCleaningFactor' => distable / tune automatic cleaning process (int) + * 'hashedDirectoryLevel' => level of the hashed directory system (int) + * 'hashedDirectoryUmask' => umask for hashed directory structure (int) * ); * * @param array $options options @@ -224,7 +264,7 @@ class Cache_Lite */ function Cache_Lite($options = array(NULL)) { - $availableOptions = array('automaticSerialization', 'fileNameProtection', 'memoryCaching', 'onlyMemoryCaching', 'memoryCachingLimit', 'cacheDir', 'caching', 'lifeTime', 'fileLocking', 'writeControl', 'readControl', 'readControlType', 'pearErrorMode'); + $availableOptions = array('hashedDirectoryUmask', 'hashedDirectoryLevel', 'automaticCleaningFactor', 'automaticSerialization', 'fileNameProtection', 'memoryCaching', 'onlyMemoryCaching', 'memoryCachingLimit', 'cacheDir', 'caching', 'lifeTime', 'fileLocking', 'writeControl', 'readControl', 'readControlType', 'pearErrorMode'); foreach($options as $key => $value) { if(in_array($key, $availableOptions)) { $property = '_'.$key; @@ -307,6 +347,12 @@ class Cache_Lite return true; } } + if ($this->_automaticCleaningFactor>0) { + $rand = rand(1, $this->_automaticCleaningFactor); + if ($rand==1) { + $this->clean(false, 'old'); + } + } if ($this->_writeControl) { if (!$this->_writeAndControl($data)) { @touch($this->_file, time() - 2*abs($this->_lifeTime)); @@ -315,8 +361,8 @@ class Cache_Lite return true; } } else { - return $this->_write($data); - } + return $this->_write($data); + } } return false; } @@ -341,11 +387,7 @@ class Cache_Lite return true; } } - if (!@unlink($this->_file)) { - $this->raiseError('Cache_Lite : Unable to remove cache !', -3); - return false; - } - return true; + return $this->_unlink($this->_file); } /** @@ -355,47 +397,16 @@ class Cache_Lite * else only cache files of the specified group will be destroyed * * @param string $group name of the cache group + * @param string $mode flush cache mode : 'old', 'ingroup', 'notingroup', + * 'callback_myFunction' * @return boolean true if no problem * @access public */ - function clean($group = false) + function clean($group = false, $mode = 'ingroup') { - if ($this->_fileNameProtection) { - $motif = ($group) ? 'cache_'.md5($group).'_' : 'cache_'; - } else { - $motif = ($group) ? 'cache_'.$group.'_' : 'cache_'; - } - if ($this->_memoryCaching) { - while (list($key, $value) = each($this->_memoryCachingArray)) { - if (strpos($key, $motif, 0)) { - unset($this->_memoryCachingArray[$key]); - $this->_memoryCachingCounter = $this->_memoryCachingCounter - 1; - } - } - if ($this->_onlyMemoryCaching) { - return true; - } - } - if (!($dh = opendir($this->_cacheDir))) { - $this->raiseError('Cache_Lite : Unable to open cache directory !', -4); - return false; - } - while ($file = readdir($dh)) { - if (($file != '.') && ($file != '..')) { - $file = $this->_cacheDir . $file; - if (is_file($file)) { - if (strpos($file, $motif, 0)) { - if (!@unlink($file)) { - $this->raiseError('Cache_Lite : Unable to remove cache !', -3); - return false; - } - } - } - } - } - return true; + return $this->_cleanDir($this->_cacheDir, $group, $mode); } - + /** * Set to debug mode * @@ -422,7 +433,10 @@ class Cache_Lite } /** + * Save the state of the caching memory array into a cache file cache * + * @param string $id cache id + * @param string $group name of the cache group * @access public */ function saveMemoryCachingState($id, $group = 'default') @@ -438,7 +452,11 @@ class Cache_Lite } /** + * Load the state of the caching memory array from a given cache file cache * + * @param string $id cache id + * @param string $group name of the cache group + * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested * @access public */ function getMemoryCachingState($id, $group = 'default', $doNotTestCacheValidity = false) @@ -460,7 +478,7 @@ class Cache_Lite * @return int last modification time */ function lastModified() { - return filemtime($this->_file); + return @filemtime($this->_file); } /** @@ -479,11 +497,104 @@ class Cache_Lite include_once('PEAR.php'); PEAR::raiseError($msg, $code, $this->_pearErrorMode); } - + // --- Private methods --- /** + * Remove a file + * + * @param string $file complete file path and name + * @return boolean true if no problem + * @access private + */ + function _unlink($file) + { + if (!@unlink($file)) { + $this->raiseError('Cache_Lite : Unable to remove cache !', -3); + return false; + } else { + return true; + } + } + + /** + * Recursive function for cleaning cache file in the given directory + * + * @param string $dir directory complete path (with a trailing slash) + * @param string $group name of the cache group + * @param string $mode flush cache mode : 'old', 'ingroup', 'notingroup', + 'callback_myFunction' + * @return boolean true if no problem + * @access private + */ + function _cleanDir($dir, $group = false, $mode = 'ingroup') + { + if ($this->_fileNameProtection) { + $motif = ($group) ? 'cache_'.md5($group).'_' : 'cache_'; + } else { + $motif = ($group) ? 'cache_'.$group.'_' : 'cache_'; + } + if ($this->_memoryCaching) { + while (list($key, $value) = each($this->_memoryCachingArray)) { + if (strpos($key, $motif, 0)) { + unset($this->_memoryCachingArray[$key]); + $this->_memoryCachingCounter = $this->_memoryCachingCounter - 1; + } + } + if ($this->_onlyMemoryCaching) { + return true; + } + } + if (!($dh = opendir($dir))) { + $this->raiseError('Cache_Lite : Unable to open cache directory !', -4); + return false; + } + $result = true; + while ($file = readdir($dh)) { + if (($file != '.') && ($file != '..')) { + if (substr($file, 0, 6)=='cache_') { + $file2 = $dir . $file; + if (is_file($file2)) { + switch (substr($mode, 0, 9)) { + case 'old': + // files older than lifeTime get deleted from cache + if ((mktime() - filemtime($file2)) > $this->_lifeTime) { + $result = ($result and ($this->_unlink($file2))); + } + break; + case 'notingrou': + if (!strpos($file2, $motif, 0)) { + $result = ($result and ($this->_unlink($file2))); + } + break; + case 'callback_': + $func = substr($mode, 9, strlen($mode) - 9); + if ($func($file2, $group)) { + $result = ($result and ($this->_unlink($file2))); + } + break; + case 'ingroup': + default: + if (strpos($file2, $motif, 0)) { + $result = ($result and ($this->_unlink($file2))); + } + break; + } + } + if ((is_dir($file2)) and ($this->_hashedDirectoryLevel>0)) { + $result = ($result and ($this->_cleanDir($file2 . '/', $group, $mode))); + } + } + } + } + return $result; + } + + /** + * Add some date in the memory caching array * + * @param string $id cache id + * @param string $data data to cache * @access private */ function _memoryCacheAdd($id, $data) @@ -506,11 +617,21 @@ class Cache_Lite */ function _setFileName($id, $group) { + if ($this->_fileNameProtection) { - $this->_file = ($this->_cacheDir.'cache_'.md5($group).'_'.md5($id)); + $suffix = 'cache_'.md5($group).'_'.md5($id); } else { - $this->_file = $this->_cacheDir.'cache_'.$group.'_'.$id; + $suffix = 'cache_'.$group.'_'.$id; + } + $root = $this->_cacheDir; + if ($this->_hashedDirectoryLevel>0) { + $hash = md5($suffix); + for ($i=0 ; $i<$this->_hashedDirectoryLevel ; $i++) { + $root = $root . 'cache_' . substr($hash, 0, $i + 1) . '/'; + } } + $this->_fileName = $suffix; + $this->_file = $root.$suffix; } /** @@ -532,7 +653,11 @@ class Cache_Lite $hashControl = @fread($fp, 32); $length = $length - 32; } - $data = @fread($fp, $length); + if ($length) { + $data = @fread($fp, $length); + } else { + $data = ''; + } set_magic_quotes_runtime($mqr); if ($this->_fileLocking) @flock($fp, LOCK_UN); @fclose($fp); @@ -558,19 +683,34 @@ class Cache_Lite */ function _write($data) { - $fp = @fopen($this->_file, "wb"); - if ($fp) { - if ($this->_fileLocking) @flock($fp, LOCK_EX); - if ($this->_readControl) { - @fwrite($fp, $this->_hash($data, $this->_readControlType), 32); + $try = 1; + while ($try<=2) { + $fp = @fopen($this->_file, "wb"); + if ($fp) { + if ($this->_fileLocking) @flock($fp, LOCK_EX); + if ($this->_readControl) { + @fwrite($fp, $this->_hash($data, $this->_readControlType), 32); + } + $len = strlen($data); + @fwrite($fp, $data, $len); + if ($this->_fileLocking) @flock($fp, LOCK_UN); + @fclose($fp); + return true; + } else { + if (($try==1) and ($this->_hashedDirectoryLevel>0)) { + $hash = md5($this->_fileName); + $root = $this->_cacheDir; + for ($i=0 ; $i<$this->_hashedDirectoryLevel ; $i++) { + $root = $root . 'cache_' . substr($hash, 0, $i + 1) . '/'; + @mkdir($root, $this->_hashedDirectoryUmask); + } + $try = 2; + } else { + $try = 999; + } } - $len = strlen($data); - @fwrite($fp, $data, $len); - if ($this->_fileLocking) @flock($fp, LOCK_UN); - @fclose($fp); - return true; } - $this->raiseError('Cache_Lite : Unable to write cache !', -1); + $this->raiseError('Cache_Lite : Unable to write cache file : '.$this->_file, -1); return false; } diff --git a/bundled-libs/Cache/Lite/Function.php b/bundled-libs/Cache/Lite/Function.php index a72023f..0d69e22 100644 --- a/bundled-libs/Cache/Lite/Function.php +++ b/bundled-libs/Cache/Lite/Function.php @@ -11,7 +11,7 @@ * Technical choices are described in the 'docs/technical' file * * @package Cache_Lite -* @version $Id: Function.php,v 1.1 2004/12/02 14:23:52 nohn Exp $ +* @version $Id: Function.php,v 1.6 2004/02/03 17:07:13 fab Exp $ * @author Sebastian BERGMANN * @author Fabien MARTY */ diff --git a/bundled-libs/Cache/Lite/Output.php b/bundled-libs/Cache/Lite/Output.php index d6d2460..1446641 100644 --- a/bundled-libs/Cache/Lite/Output.php +++ b/bundled-libs/Cache/Lite/Output.php @@ -7,7 +7,7 @@ * Technical choices are described in the 'docs/technical' file * * @package Cache_Lite -* @version $Id: Output.php,v 1.1 2004/12/02 14:23:52 nohn Exp $ +* @version $Id: Output.php,v 1.3 2005/04/17 21:40:18 fab Exp $ * @author Fabien MARTY */ @@ -37,12 +37,13 @@ class Cache_Lite_Output extends Cache_Lite * * @param string $id cache id * @param string $group name of the cache group + * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested * @return boolean true if the cache is hit (false else) * @access public */ - function start($id, $group = 'default') + function start($id, $group = 'default', $doNotTestCacheValidity = false) { - $data = $this->get($id, $group); + $data = $this->get($id, $group, $doNotTestCacheValidity); if ($data !== false) { echo($data); return true; diff --git a/bundled-libs/HTTP/Request.php b/bundled-libs/HTTP/Request.php index ce918fb..581dbc6 100644 --- a/bundled-libs/HTTP/Request.php +++ b/bundled-libs/HTTP/Request.php @@ -32,7 +32,7 @@ // | Author: Richard Heyes | // +-----------------------------------------------------------------------+ // -// $Id: Request.php,v 1.1 2004/12/06 09:18:15 nohn Exp $ +// $Id: Request.php,v 1.41 2004/12/10 14:42:57 avb Exp $ // // HTTP_Request Class // @@ -62,7 +62,7 @@ class HTTP_Request { /** * Instance of Net_URL - * @var object + * @var object Net_URL */ var $_url; @@ -98,7 +98,7 @@ class HTTP_Request { /** * Socket object - * @var object + * @var object Net_Socket */ var $_sock; @@ -140,13 +140,13 @@ class HTTP_Request { /** * Connection timeout. - * @var integer + * @var float */ var $_timeout; /** * HTTP_Response object - * @var object + * @var object HTTP_Response */ var $_response; @@ -202,21 +202,25 @@ class HTTP_Request { * Constructor * * Sets up the object - * @param $url The url to fetch/access - * @param $params Associative array of parameters which can be: - * method - Method to use, GET, POST etc - * http - HTTP Version to use, 1.0 or 1.1 - * user - Basic Auth username - * pass - Basic Auth password - * proxy_host - Proxy server host - * proxy_port - Proxy server port - * proxy_user - Proxy auth username - * proxy_pass - Proxy auth password - * timeout - Connection timeout in seconds. - * allowRedirects - Whether to follow redirects or not - * maxRedirects - Max number of redirects to follow - * useBrackets - Whether to append [] to array variable names - * saveBody - Whether to save response body in response object property + * @param string The url to fetch/access + * @param array Associative array of parameters which can have the following keys: + *
    + *
  • method - Method to use, GET, POST etc (string)
  • + *
  • http - HTTP Version to use, 1.0 or 1.1 (string)
  • + *
  • user - Basic Auth username (string)
  • + *
  • pass - Basic Auth password (string)
  • + *
  • proxy_host - Proxy server host (string)
  • + *
  • proxy_port - Proxy server port (integer)
  • + *
  • proxy_user - Proxy auth username (string)
  • + *
  • proxy_pass - Proxy auth password (string)
  • + *
  • timeout - Connection timeout in seconds (float)
  • + *
  • allowRedirects - Whether to follow redirects or not (bool)
  • + *
  • maxRedirects - Max number of redirects to follow (integer)
  • + *
  • useBrackets - Whether to append [] to array variable names (bool)
  • + *
  • saveBody - Whether to save response body in response object property (bool)
  • + *
  • readTimeout - Timeout for reading / writing data over the socket (array (seconds, microseconds))
  • + *
  • socketOptions - Options to pass to Net_Socket object (array)
  • + *
* @access public */ function HTTP_Request($url = '', $params = array()) @@ -1068,7 +1072,12 @@ class HTTP_Response $cookie['value'] = trim(substr($elements[0], $pos + 1)); for ($i = 1; $i < count($elements); $i++) { - list ($elName, $elValue) = array_map('trim', explode('=', $elements[$i])); + if (false === strpos($elements[$i], '=')) { + $elName = trim($elements[$i]); + $elValue = null; + } else { + list ($elName, $elValue) = array_map('trim', explode('=', $elements[$i])); + } $elName = strtolower($elName); if ('secure' == $elName) { $cookie['secure'] = true; @@ -1103,6 +1112,8 @@ class HTTP_Response $this->_sock->readAll(); // make this an eof() return ''; } + } elseif ($this->_sock->eof()) { + return ''; } } $data = $this->_sock->read($this->_chunkLength); diff --git a/bundled-libs/HTTP/Request/Listener.php b/bundled-libs/HTTP/Request/Listener.php index 70d4731..38b115a 100644 --- a/bundled-libs/HTTP/Request/Listener.php +++ b/bundled-libs/HTTP/Request/Listener.php @@ -32,7 +32,7 @@ // | Author: Alexey Borzov | // +-----------------------------------------------------------------------+ // -// $Id: Listener.php,v 1.1 2004/12/06 09:18:23 nohn Exp $ +// $Id: Listener.php,v 1.2 2003/10/26 10:28:29 avb Exp $ // /** @@ -42,7 +42,7 @@ * * @package HTTP_Request * @author Alexey Borzov - * @version $Revision: 1.1 $ + * @version $Revision: 1.2 $ */ class HTTP_Request_Listener { diff --git a/bundled-libs/Net/CheckIP.php b/bundled-libs/Net/CheckIP.php index 2e3f15a..b0fbc73 100644 --- a/bundled-libs/Net/CheckIP.php +++ b/bundled-libs/Net/CheckIP.php @@ -17,7 +17,7 @@ // | Guido Haeger | // +----------------------------------------------------------------------+ // -// $Id: CheckIP.php,v 1.2 2004/11/19 11:05:24 garvinhicking Exp $ +// $Id: CheckIP.php,v 1.5 2002/08/17 09:41:24 mj Exp $ /** * Class to validate the syntax of IPv4 adresses diff --git a/bundled-libs/Net/Socket.php b/bundled-libs/Net/Socket.php index 9d73e06..7c4ff1d 100644 --- a/bundled-libs/Net/Socket.php +++ b/bundled-libs/Net/Socket.php @@ -17,90 +17,109 @@ // | Chuck Hagenbuch | // +----------------------------------------------------------------------+ // -// $Id: Socket.php,v 1.1 2004/12/06 09:18:23 nohn Exp $ -// +// $Id: Socket.php,v 1.24 2005/02/03 20:40:16 chagenbu Exp $ require_once 'PEAR.php'; +define('NET_SOCKET_READ', 1); +define('NET_SOCKET_WRITE', 2); +define('NET_SOCKET_ERROR', 3); + /** - * Generalized Socket class. More docs to be written. + * Generalized Socket class. * - * @version 1.0 + * @version 1.1 * @author Stig Bakken * @author Chuck Hagenbuch */ class Net_Socket extends PEAR { - // {{{ properties - /** Socket file pointer. */ + /** + * Socket file pointer. + * @var resource $fp + */ var $fp = null; - /** Whether the socket is blocking. */ + /** + * Whether the socket is blocking. Defaults to true. + * @var boolean $blocking + */ var $blocking = true; - /** Whether the socket is persistent. */ + /** + * Whether the socket is persistent. Defaults to false. + * @var boolean $persistent + */ var $persistent = false; - /** The IP address to connect to. */ + /** + * The IP address to connect to. + * @var string $addr + */ var $addr = ''; - /** The port number to connect to. */ + /** + * The port number to connect to. + * @var integer $port + */ var $port = 0; - /** Number of seconds to wait on socket connections before - assuming there's no more data. */ + /** + * Number of seconds to wait on socket connections before assuming + * there's no more data. Defaults to no timeout. + * @var integer $timeout + */ var $timeout = false; - /** Number of bytes to read at a time in readLine() and - readAll(). */ - var $lineLength = 2048; - // }}} - - // {{{ constructor /** - * Constructs a new Net_Socket object. - * - * @access public + * Number of bytes to read at a time in readLine() and + * readAll(). Defaults to 2048. + * @var integer $lineLength */ - function Net_Socket() - { - $this->PEAR(); - } - // }}} + var $lineLength = 2048; - // {{{ connect() /** * Connect to the specified port. If called when the socket is * already connected, it disconnects and connects again. * - * @param $addr string IP address or host name - * @param $port int TCP port number - * @param $persistent bool (optional) whether the connection is - * persistent (kept open between requests by the web server) - * @param $timeout int (optional) how long to wait for data - * @param $options array see options for stream_context_create + * @param string $addr IP address or host name. + * @param integer $port TCP port number. + * @param boolean $persistent (optional) Whether the connection is + * persistent (kept open between requests + * by the web server). + * @param integer $timeout (optional) How long to wait for data. + * @param array $options See options for stream_context_create. + * * @access public - * @return mixed true on success or error object + * + * @return boolean | PEAR_Error True on success or a PEAR_Error on failure. */ - function connect($addr, $port, $persistent = null, $timeout = null, $options = null) + function connect($addr, $port = 0, $persistent = null, $timeout = null, $options = null) { if (is_resource($this->fp)) { @fclose($this->fp); $this->fp = null; } - if (strspn($addr, '.0123456789') == strlen($addr)) { + if (!$addr) { + return $this->raiseError('$addr cannot be empty'); + } elseif (strspn($addr, '.0123456789') == strlen($addr) || + strstr($addr, '/') !== false) { $this->addr = $addr; } else { - $this->addr = gethostbyname($addr); + $this->addr = @gethostbyname($addr); } + $this->port = $port % 65536; + if ($persistent !== null) { $this->persistent = $persistent; } + if ($timeout !== null) { $this->timeout = $timeout; } + $openfunc = $this->persistent ? 'pfsockopen' : 'fsockopen'; $errno = 0; $errstr = ''; @@ -111,7 +130,7 @@ class Net_Socket extends PEAR { $timeout = 0; } $context = stream_context_create($options); - $fp = $openfunc($this->addr, $this->port, $errno, $errstr, $timeout, $context); + $fp = @$openfunc($this->addr, $this->port, $errno, $errstr, $timeout, $context); } else { if ($this->timeout) { $fp = @$openfunc($this->addr, $this->port, $errno, $errstr, $this->timeout); @@ -128,9 +147,7 @@ class Net_Socket extends PEAR { return $this->setBlocking($this->blocking); } - // }}} - // {{{ disconnect() /** * Disconnects from the peer, closes the socket. * @@ -139,71 +156,65 @@ class Net_Socket extends PEAR { */ function disconnect() { - if (is_resource($this->fp)) { - fclose($this->fp); - $this->fp = null; - return true; + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); } - return $this->raiseError("not connected"); + + @fclose($this->fp); + $this->fp = null; + return true; } - // }}} - // {{{ isBlocking() /** * Find out if the socket is in blocking mode. * * @access public - * @return bool the current blocking mode. + * @return boolean The current blocking mode. */ function isBlocking() { return $this->blocking; } - // }}} - // {{{ setBlocking() /** * Sets whether the socket connection should be blocking or * not. A read call to a non-blocking socket will return immediately * if there is no data available, whereas it will block until there * is data for blocking sockets. * - * @param $mode bool true for blocking sockets, false for nonblocking + * @param boolean $mode True for blocking sockets, false for nonblocking. * @access public * @return mixed true on success or an error object otherwise */ function setBlocking($mode) { - if (is_resource($this->fp)) { - $this->blocking = $mode; - socket_set_blocking($this->fp, $this->blocking); - return true; + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); } - return $this->raiseError("not connected"); + + $this->blocking = $mode; + socket_set_blocking($this->fp, $this->blocking); + return true; } - // }}} - // {{{ setTimeout() /** * Sets the timeout value on socket descriptor, * expressed in the sum of seconds and microseconds * - * @param $seconds int seconds - * @param $microseconds int microseconds + * @param integer $seconds Seconds. + * @param integer $microseconds Microseconds. * @access public * @return mixed true on success or an error object otherwise */ function setTimeout($seconds, $microseconds) { - if (is_resource($this->fp)) { - socket_set_timeout($this->fp, $seconds, $microseconds); - return true; + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); } - return $this->raiseError("not connected"); + + return socket_set_timeout($this->fp, $seconds, $microseconds); } - // }}} - // {{{ getStatus() /** * Returns information about an existing socket resource. * Currently returns four entries in the result array: @@ -220,14 +231,13 @@ class Net_Socket extends PEAR { */ function getStatus() { - if (is_resource($this->fp)) { - return socket_get_status($this->fp); + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); } - return $this->raiseError("not connected"); + + return socket_get_status($this->fp); } - // }}} - // {{{ gets() /** * Get a specified line of data * @@ -237,69 +247,87 @@ class Net_Socket extends PEAR { */ function gets($size) { - if (is_resource($this->fp)) { - return fgets($this->fp, $size); + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); } - return $this->raiseError("not connected"); + + return @fgets($this->fp, $size); } - // }}} - // {{{ read() /** * Read a specified amount of data. This is guaranteed to return, * and has the added benefit of getting everything in one fread() * chunk; if you know the size of the data you're getting * beforehand, this is definitely the way to go. * - * @param $size The number of bytes to read from the socket. + * @param integer $size The number of bytes to read from the socket. * @access public * @return $size bytes of data from the socket, or a PEAR_Error if * not connected. */ function read($size) { - if (is_resource($this->fp)) { - return fread($this->fp, $size); + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); } - return $this->raiseError("not connected"); + + return @fread($this->fp, $size); } - // }}} - // {{{ write() /** * Write a specified amount of data. * + * @param string $data Data to write. + * @param integer $blocksize Amount of data to write at once. + * NULL means all at once. + * * @access public * @return mixed true on success or an error object otherwise */ - function write($data) + function write($data, $blocksize = null) { - if (is_resource($this->fp)) { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + if (is_null($blocksize) && !OS_WINDOWS) { return fwrite($this->fp, $data); + } else { + if (is_null($blocksize)) { + $blocksize = 1024; + } + + $pos = 0; + $size = strlen($data); + while ($pos < $size) { + $written = @fwrite($this->fp, substr($data, $pos, $blocksize)); + if ($written === false) { + return false; + } + $pos += $written; + } + + return $pos; } - return $this->raiseError("not connected"); } - // }}} - // {{{ writeLine() /** * Write a line of data to the socket, followed by a trailing "\r\n". * * @access public * @return mixed fputs result, or an error */ - function writeLine ($data) + function writeLine($data) { - if (is_resource($this->fp)) { - return $this->write($data . "\r\n"); + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); } - return $this->raiseError("not connected"); + + return fwrite($this->fp, $data . "\r\n"); } - // }}} - // {{{ eof() /** - * Tests for end-of-file on a socket descriptor + * Tests for end-of-file on a socket descriptor. * * @access public * @return bool @@ -308,9 +336,7 @@ class Net_Socket extends PEAR { { return (is_resource($this->fp) && feof($this->fp)); } - // }}} - // {{{ readByte() /** * Reads a byte of data * @@ -320,14 +346,13 @@ class Net_Socket extends PEAR { */ function readByte() { - if (is_resource($this->fp)) { - return ord($this->read(1)); + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); } - return $this->raiseError("not connected"); + + return ord(@fread($this->fp, 1)); } - // }}} - // {{{ readWord() /** * Reads a word of data * @@ -337,36 +362,34 @@ class Net_Socket extends PEAR { */ function readWord() { - if (is_resource($this->fp)) { - $buf = $this->read(2); - return (ord($buf[0]) + (ord($buf[1]) << 8)); + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); } - return $this->raiseError("not connected"); + + $buf = @fread($this->fp, 2); + return (ord($buf[0]) + (ord($buf[1]) << 8)); } - // }}} - // {{{ readInt() /** * Reads an int of data * * @access public - * @return 1 int of data from the socket, or a PEAR_Error if - * not connected. + * @return integer 1 int of data from the socket, or a PEAR_Error if + * not connected. */ function readInt() { - if (is_resource($this->fp)) { - $buf = $this->read(4); - return (ord($buf[0]) + (ord($buf[1]) << 8) + - (ord($buf[2]) << 16) + (ord($buf[3]) << 24)); + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); } - return $this->raiseError("not connected"); + + $buf = @fread($this->fp, 4); + return (ord($buf[0]) + (ord($buf[1]) << 8) + + (ord($buf[2]) << 16) + (ord($buf[3]) << 24)); } - // }}} - // {{{ readString() /** - * Reads a zeroterminated string of data + * Reads a zero-terminated string of data * * @access public * @return string, or a PEAR_Error if @@ -374,18 +397,17 @@ class Net_Socket extends PEAR { */ function readString() { - if (is_resource($this->fp)) { - $string = ''; - while (($char = $this->read(1)) != "\x00") { - $string .= $char; - } - return $string; + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); } - return $this->raiseError("not connected"); + + $string = ''; + while (($char = @fread($this->fp, 1)) != "\x00") { + $string .= $char; + } + return $string; } - // }}} - // {{{ readIPAddress() /** * Reads an IP Address and returns it in a dot formated string * @@ -395,16 +417,15 @@ class Net_Socket extends PEAR { */ function readIPAddress() { - if (is_resource($this->fp)) { - $buf = $this->read(4); - return sprintf("%s.%s.%s.%s", ord($buf[0]), ord($buf[1]), - ord($buf[2]), ord($buf[3])); + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); } - return $this->raiseError("not connected"); + + $buf = @fread($this->fp, 4); + return sprintf("%s.%s.%s.%s", ord($buf[0]), ord($buf[1]), + ord($buf[2]), ord($buf[3])); } - // }}} - // {{{ readLine() /** * Read until either the end of the socket or a newline, whichever * comes first. Strips the trailing newline from the returned data. @@ -416,41 +437,92 @@ class Net_Socket extends PEAR { */ function readLine() { - if (is_resource($this->fp)) { - $line = ''; - $timeout = time() + $this->timeout; - while (!$this->eof() && (!$this->timeout || time() < $timeout)) { - $line .= $this->gets($this->lineLength); - if (substr($line, -2) == "\r\n" || - substr($line, -1) == "\n") { - return rtrim($line, "\r\n"); - } + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + $line = ''; + $timeout = time() + $this->timeout; + while (!feof($this->fp) && (!$this->timeout || time() < $timeout)) { + $line .= @fgets($this->fp, $this->lineLength); + if (substr($line, -1) == "\n") { + return rtrim($line, "\r\n"); } - return $line; } - return $this->raiseError("not connected"); + return $line; } - // }}} - // {{{ readAll() /** - * Read until the socket closes. THIS FUNCTION WILL NOT EXIT if the - * socket is in blocking mode until the socket closes. + * Read until the socket closes, or until there is no more data in + * the inner PHP buffer. If the inner buffer is empty, in blocking + * mode we wait for at least 1 byte of data. Therefore, in + * blocking mode, if there is no data at all to be read, this + * function will never exit (unless the socket is closed on the + * remote end). * * @access public - * @return All data until the socket closes, or a PEAR_Error if - * not connected. + * + * @return string All data until the socket closes, or a PEAR_Error if + * not connected. */ function readAll() { - if (is_resource($this->fp)) { - $data = ''; - while (!$this->eof()) - $data .= $this->read($this->lineLength); - return $data; + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + $data = ''; + while (!feof($this->fp)) { + $data .= @fread($this->fp, $this->lineLength); + } + return $data; + } + + /** + * Runs the equivalent of the select() system call on the socket + * with a timeout specified by tv_sec and tv_usec. + * + * @param integer $state Which of read/write/error to check for. + * @param integer $tv_sec Number of seconds for timeout. + * @param integer $tv_usec Number of microseconds for timeout. + * + * @access public + * @return False if select fails, integer describing which of read/write/error + * are ready, or PEAR_Error if not connected. + */ + function select($state, $tv_sec, $tv_usec = 0) + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + $read = null; + $write = null; + $except = null; + if ($state & NET_SOCKET_READ) { + $read[] = $this->fp; + } + if ($state & NET_SOCKET_WRITE) { + $write[] = $this->fp; + } + if ($state & NET_SOCKET_ERROR) { + $except[] = $this->fp; + } + if (false === ($sr = stream_select($read, $write, $except, $tv_sec, $tv_usec))) { + return false; + } + + $result = 0; + if (count($read)) { + $result |= NET_SOCKET_READ; + } + if (count($write)) { + $result |= NET_SOCKET_WRITE; + } + if (count($except)) { + $result |= NET_SOCKET_ERROR; } - return $this->raiseError("not connected"); + return $result; } - // }}} } diff --git a/bundled-libs/Net/URL.php b/bundled-libs/Net/URL.php index 349c59c..6331fc0 100644 --- a/bundled-libs/Net/URL.php +++ b/bundled-libs/Net/URL.php @@ -32,7 +32,7 @@ // | Author: Richard Heyes | // +-----------------------------------------------------------------------+ // -// $Id: URL.php,v 1.1 2004/12/06 09:18:23 nohn Exp $ +// $Id: URL.php,v 1.36 2004/06/19 18:58:50 richard Exp $ // // Net_URL Class diff --git a/bundled-libs/PEAR.php b/bundled-libs/PEAR.php index 5ed8eac..6f4d652 100644 --- a/bundled-libs/PEAR.php +++ b/bundled-libs/PEAR.php @@ -1,24 +1,24 @@ | -// | Stig Bakken | -// | Tomas V.V.Cox | -// +----------------------------------------------------------------------+ +// +--------------------------------------------------------------------+ +// | PEAR, the PHP Extension and Application Repository | +// +--------------------------------------------------------------------+ +// | Copyright (c) 1997-2004 The PHP Group | +// +--------------------------------------------------------------------+ +// | This source file is subject to version 3.0 of the PHP license, | +// | that is bundled with this package in the file LICENSE, and is | +// | available through the world-wide-web at the following url: | +// | http://www.php.net/license/3_0.txt. | +// | If you did not receive a copy of the PHP license and are unable to | +// | obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +--------------------------------------------------------------------+ +// | Authors: Sterling Hughes | +// | Stig Bakken | +// | Tomas V.V.Cox | +// +--------------------------------------------------------------------+ // -// $Id: PEAR.php,v 1.1.1.1 2003/03/28 20:05:27 sterling Exp $ +// $Id: PEAR.php,v 1.83 2005/03/28 16:38:58 cellog Exp $ // define('PEAR_ERROR_RETURN', 1); @@ -26,6 +26,10 @@ define('PEAR_ERROR_PRINT', 2); define('PEAR_ERROR_TRIGGER', 4); define('PEAR_ERROR_DIE', 8); define('PEAR_ERROR_CALLBACK', 16); +/** + * WARNING: obsolete + * @deprecated + */ define('PEAR_ERROR_EXCEPTION', 32); define('PEAR_ZE2', (function_exists('version_compare') && version_compare(zend_version(), "2-dev", "ge"))); @@ -40,13 +44,22 @@ if (substr(PHP_OS, 0, 3) == 'WIN') { define('PEAR_OS', 'Unix'); // blatant assumption } +// instant backwards compatibility +if (!defined('PATH_SEPARATOR')) { + if (OS_WINDOWS) { + define('PATH_SEPARATOR', ';'); + } else { + define('PATH_SEPARATOR', ':'); + } +} + $GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN; $GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE; $GLOBALS['_PEAR_destructor_object_list'] = array(); $GLOBALS['_PEAR_shutdown_funcs'] = array(); $GLOBALS['_PEAR_error_handler_stack'] = array(); -ini_set('track_errors', true); +@ini_set('track_errors', true); /** * Base class for other PEAR classes. Provides rudimentary @@ -63,10 +76,10 @@ ini_set('track_errors', true); * destructor, use error_log(), syslog() or something similar. * * IMPORTANT! To use the emulated destructors you need to create the - * objects by reference, ej: $obj =& new PEAR_child; + * objects by reference: $obj =& new PEAR_child; * * @since PHP 4.0.2 - * @author Stig Bakken + * @author Stig Bakken * @see http://pear.php.net/manual/ */ class PEAR @@ -139,18 +152,22 @@ class PEAR */ function PEAR($error_class = null) { - $classname = get_class($this); + $classname = strtolower(get_class($this)); if ($this->_debug) { print "PEAR constructor called, class=$classname\n"; } if ($error_class !== null) { $this->_error_class = $error_class; } - while ($classname) { + while ($classname && strcasecmp($classname, "pear")) { $destructor = "_$classname"; if (method_exists($this, $destructor)) { global $_PEAR_destructor_object_list; $_PEAR_destructor_object_list[] = &$this; + if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { + register_shutdown_function("_PEAR_call_destructors"); + $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; + } break; } else { $classname = get_parent_class($classname); @@ -174,7 +191,7 @@ class PEAR */ function _PEAR() { if ($this->_debug) { - printf("PEAR destructor called, class=%s\n", get_class($this)); + printf("PEAR destructor called, class=%s\n", strtolower(get_class($this))); } } @@ -184,7 +201,7 @@ class PEAR /** * If you have a class that's mostly/entirely static, and you need static * properties, you can use this method to simulate them. Eg. in your method(s) - * do this: $myVar = &PEAR::getStaticProperty('myVar'); + * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar'); * You MUST use a reference, or they will not persist! * * @access public @@ -224,15 +241,22 @@ class PEAR * * @param mixed $data the value to test * @param int $code if $data is an error object, return true - * only if $obj->getCode() == $code + * only if $code is a string and + * $obj->getMessage() == $code or + * $code is an integer and $obj->getCode() == $code * @access public * @return bool true if parameter is an error */ function isError($data, $code = null) { - if (is_object($data) && (get_class($data) == 'pear_error' || - is_subclass_of($data, 'pear_error'))) { - return $code === null ? true : $data->getCode() == $code; + if (is_a($data, 'PEAR_Error')) { + if (is_null($code)) { + return true; + } elseif (is_string($code)) { + return $data->getMessage() == $code; + } else { + return $data->getCode() == $code; + } } return false; } @@ -281,7 +305,7 @@ class PEAR function setErrorHandling($mode = null, $options = null) { - if (isset($this)) { + if (isset($this) && is_a($this, 'PEAR')) { $setmode = &$this->_default_error_mode; $setoptions = &$this->_default_error_options; } else { @@ -290,11 +314,11 @@ class PEAR } switch ($mode) { + case PEAR_ERROR_EXCEPTION: case PEAR_ERROR_RETURN: case PEAR_ERROR_PRINT: case PEAR_ERROR_TRIGGER: case PEAR_ERROR_DIE: - case PEAR_ERROR_EXCEPTION: case null: $setmode = $mode; $setoptions = $options; @@ -302,9 +326,8 @@ class PEAR case PEAR_ERROR_CALLBACK: $setmode = $mode; - if ((is_string($options) && function_exists($options)) || - (is_array($options) && method_exists(@$options[0], @$options[1]))) - { + // class/object method callback + if (is_callable($options)) { $setoptions = $options; } else { trigger_error("invalid error callback", E_USER_WARNING); @@ -408,7 +431,7 @@ class PEAR // $error_code is a non-empty array here; // we walk through it trying to unset all // values - foreach($error_code AS $key => $error) { + foreach($error_code as $key => $error) { if ($this->_checkDelExpect($error)) { $deleted = true; } else { @@ -469,7 +492,7 @@ class PEAR * @see PEAR::setErrorHandling * @since PHP 4.0.5 */ - function &raiseError($message = null, + function raiseError($message = null, $code = null, $mode = null, $options = null, @@ -482,6 +505,7 @@ class PEAR $code = $message->getCode(); $userinfo = $message->getUserInfo(); $error_class = $message->getType(); + $message->error_message_prefix = ''; $message = $message->getMessage(); } @@ -529,11 +553,11 @@ class PEAR * @param string $message * */ - function &throwError($message = null, + function throwError($message = null, $code = null, $userinfo = null) { - if (isset($this)) { + if (isset($this) && is_a($this, 'PEAR')) { return $this->raiseError($message, $code, null, null, $userinfo); } else { return PEAR::raiseError($message, $code, null, null, $userinfo); @@ -541,6 +565,77 @@ class PEAR } // }}} + function staticPushErrorHandling($mode, $options = null) + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + $def_mode = &$GLOBALS['_PEAR_default_error_mode']; + $def_options = &$GLOBALS['_PEAR_default_error_options']; + $stack[] = array($def_mode, $def_options); + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $def_mode = $mode; + $def_options = $options; + break; + + case PEAR_ERROR_CALLBACK: + $def_mode = $mode; + // class/object method callback + if (is_callable($options)) { + $def_options = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + $stack[] = array($mode, $options); + return true; + } + + function staticPopErrorHandling() + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + $setmode = &$GLOBALS['_PEAR_default_error_mode']; + $setoptions = &$GLOBALS['_PEAR_default_error_options']; + array_pop($stack); + list($mode, $options) = $stack[sizeof($stack) - 1]; + array_pop($stack); + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $setmode = $mode; + $setoptions = $options; + break; + + case PEAR_ERROR_CALLBACK: + $setmode = $mode; + // class/object method callback + if (is_callable($options)) { + $setoptions = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + return true; + } + // {{{ pushErrorHandling() /** @@ -558,7 +653,7 @@ class PEAR function pushErrorHandling($mode, $options = null) { $stack = &$GLOBALS['_PEAR_error_handler_stack']; - if (isset($this)) { + if (isset($this) && is_a($this, 'PEAR')) { $def_mode = &$this->_default_error_mode; $def_options = &$this->_default_error_options; } else { @@ -567,7 +662,7 @@ class PEAR } $stack[] = array($def_mode, $def_options); - if (isset($this)) { + if (isset($this) && is_a($this, 'PEAR')) { $this->setErrorHandling($mode, $options); } else { PEAR::setErrorHandling($mode, $options); @@ -592,7 +687,7 @@ class PEAR array_pop($stack); list($mode, $options) = $stack[sizeof($stack) - 1]; array_pop($stack); - if (isset($this)) { + if (isset($this) && is_a($this, 'PEAR')) { $this->setErrorHandling($mode, $options); } else { PEAR::setErrorHandling($mode, $options); @@ -613,6 +708,10 @@ class PEAR function loadExtension($ext) { if (!extension_loaded($ext)) { + // if either returns true dl() will produce a FATAL error, stop that + if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) { + return false; + } if (OS_WINDOWS) { $suffix = '.dll'; } elseif (PHP_OS == 'HP-UX') { @@ -641,6 +740,9 @@ function _PEAR_call_destructors() sizeof($_PEAR_destructor_object_list)) { reset($_PEAR_destructor_object_list); + if (@PEAR::getStaticProperty('PEAR', 'destructlifo')) { + $_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list); + } while (list($k, $objref) = each($_PEAR_destructor_object_list)) { $classname = get_class($objref); while ($classname) { @@ -714,7 +816,9 @@ class PEAR_Error $this->mode = $mode; $this->userinfo = $userinfo; if (function_exists("debug_backtrace")) { - $this->backtrace = debug_backtrace(); + if (@!PEAR::getStaticProperty('PEAR_Error', 'skiptrace')) { + $this->backtrace = debug_backtrace(); + } } if ($mode & PEAR_ERROR_CALLBACK) { $this->level = E_USER_NOTICE; @@ -750,18 +854,13 @@ class PEAR_Error die(sprintf($format, $msg)); } if ($this->mode & PEAR_ERROR_CALLBACK) { - if (is_string($this->callback) && strlen($this->callback)) { + if (is_callable($this->callback)) { call_user_func($this->callback, $this); - } elseif (is_array($this->callback) && - sizeof($this->callback) == 2 && - is_object($this->callback[0]) && - is_string($this->callback[1]) && - strlen($this->callback[1])) { - @call_user_func($this->callback, $this); } } - if (PEAR_ZE2 && $this->mode & PEAR_ERROR_EXCEPTION) { - eval('throw $this;'); + if ($this->mode & PEAR_ERROR_EXCEPTION) { + trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_ErrorStack for exceptions", E_USER_WARNING); + eval('$e = new Exception($this->message, $this->code);$e->PEAR_Error = $this;throw($e);'); } } @@ -910,14 +1009,16 @@ class PEAR_Error E_USER_ERROR => 'error'); if ($this->mode & PEAR_ERROR_CALLBACK) { if (is_array($this->callback)) { - $callback = get_class($this->callback[0]) . '::' . + $callback = (is_object($this->callback[0]) ? + strtolower(get_class($this->callback[0])) : + $this->callback[0]) . '::' . $this->callback[1]; } else { $callback = $this->callback; } return sprintf('[%s: message="%s" code=%d mode=callback '. 'callback=%s prefix="%s" info="%s"]', - get_class($this), $this->message, $this->code, + strtolower(get_class($this)), $this->message, $this->code, $callback, $this->error_message_prefix, $this->userinfo); } @@ -935,7 +1036,7 @@ class PEAR_Error } return sprintf('[%s: message="%s" code=%d mode=%s level=%s '. 'prefix="%s" info="%s"]', - get_class($this), $this->message, $this->code, + strtolower(get_class($this)), $this->message, $this->code, implode("|", $modes), $levels[$this->level], $this->error_message_prefix, $this->userinfo); @@ -944,8 +1045,6 @@ class PEAR_Error // }}} } -register_shutdown_function("_PEAR_call_destructors"); - /* * Local Variables: * mode: php diff --git a/bundled-libs/Text/Wiki.php b/bundled-libs/Text/Wiki.php index 72f805e..291650a 100644 --- a/bundled-libs/Text/Wiki.php +++ b/bundled-libs/Text/Wiki.php @@ -1,557 +1,1280 @@ | -// +----------------------------------------------------------------------+ -// -// $Id: Wiki.php,v 1.3 2004/12/02 10:54:30 nohn Exp $ -require_once 'Text/Wiki/Rule.php'; +/** +* +* Parse structured wiki text and render into arbitrary formats such as XHTML. +* +* @category Text +* +* @package Text_Wiki +* +* @author Paul M. Jones +* +* @license LGPL +* +* @version $Id: Wiki.php,v 1.29 2005/02/24 17:26:29 pmjones Exp $ +* +*/ + +/** +* The baseline abstract parser class. +*/ + +require_once 'Text/Wiki/Parse.php'; + +/** +* The baseline abstract render class. +*/ + +require_once 'Text/Wiki/Render.php'; /** * +* Parse structured wiki text and render into arbitrary formats such as XHTML. +* * This is the "master" class for handling the management and convenience * functions to transform Wiki-formatted text. * -* @author Paul M. Jones +* @category Text +* +* @package Text_Wiki * -* @version 0.15 alpha +<<<<<<< Wiki.php +* @version 0.25.0 +* +* @license LGPL +======= +* @author Paul M. Jones +* +* @version 1.0.0 +>>>>>>> 1.28 * */ class Text_Wiki { - - - /** - * - * The array of rules to apply to the source text, in order. - * - * @access public - * - * @var array - * - */ - - var $rules = array(); - + + /** + * + * The default list of rules, in order, to apply to the source text. + * + * @access public + * + * @var array + * + */ + + var $rules = array( + 'Prefilter', + 'Delimiter', + 'Code', + 'Function', + 'Html', + 'Raw', + 'Include', + 'Embed', + 'Anchor', + 'Heading', + 'Toc', + 'Horiz', + 'Break', + 'Blockquote', + 'List', + 'Deflist', + 'Table', + 'Image', + 'Phplookup', + 'Center', + 'Newline', + 'Paragraph', + 'Url', + 'Freelink', + 'Interwiki', + 'Wikilink', + 'Colortext', + 'Strong', + 'Bold', + 'Emphasis', + 'Italic', + 'Tt', + 'Superscript', + 'Subscript', + 'Revise', + 'Tighten' + ); + + + /** + * + * The list of rules to not-apply to the source text. + * + * @access public + * + * @var array + * + */ + + var $disable = array( + 'Html', + 'Include', + 'Embed' + ); + + + /** + * + * Custom configuration for rules at the parsing stage. + * + * In this array, the key is the parsing rule name, and the value is + * an array of key-value configuration pairs corresponding to the $conf + * property in the target parsing rule. + * + * For example: + * + * + * $parseConf = array( + * 'Include' => array( + * 'base' => '/path/to/scripts/' + * ) + * ); + * + * + * Note that most default rules do not need any parsing configuration. + * + * @access public + * + * @var array + * + */ + + var $parseConf = array(); + + + /** + * + * Custom configuration for rules at the rendering stage. + * + * Because rendering may be different for each target format, the + * first-level element in this array is always a format name (e.g., + * 'Xhtml'). + * + * Within that first level element, the subsequent elements match the + * $parseConf format. That is, the sub-key is the rendering rule name, + * and the sub-value is an array of key-value configuration pairs + * corresponding to the $conf property in the target rendering rule. + * + * @access public + * + * @var array + * + */ + + var $renderConf = array( + 'Docbook' => array(), + 'Latex' => array(), + 'Pdf' => array(), + 'Plain' => array(), + 'Rtf' => array(), + 'Xhtml' => array() + ); + + + /** + * + * Custom configuration for the output format itself. + * + * Even though Text_Wiki will render the tokens from parsed text, + * the format itself may require some configuration. For example, + * RTF needs to know font names and sizes, PDF requires page layout + * information, and DocBook needs a section hierarchy. This array + * matches the $conf property of the the format-level renderer + * (e.g., Text_Wiki_Render_Xhtml). + * + * In this array, the key is the rendering format name, and the value is + * an array of key-value configuration pairs corresponding to the $conf + * property in the rendering format rule. + * + * @access public + * + * @var array + * + */ + + var $formatConf = array( + 'Docbook' => array(), + 'Latex' => array(), + 'Pdf' => array(), + 'Plain' => array(), + 'Rtf' => array(), + 'Xhtml' => array() + ); + + + /** + * + * The delimiter for token numbers of parsed elements in source text. + * + * @access public + * + * @var string + * + */ + + var $delim = "\xFF"; + + + /** + * + * The tokens generated by rules as the source text is parsed. + * + * As Text_Wiki applies rule classes to the source text, it will + * replace portions of the text with a delimited token number. This + * is the array of those tokens, representing the replaced text and + * any options set by the parser for that replaced text. + * + * The tokens array is sequential; each element is itself a sequential + * array where element 0 is the name of the rule that generated the + * token, and element 1 is an associative array where the key is an + * option name and the value is an option value. + * + * @access private + * + * @var array + * + */ + + var $tokens = array(); + + + /** + * + * The source text to which rules will be applied. + * + * This text will be transformed in-place, which means that it will + * change as the rules are applied. + * + * @access private + * + * @var string + * + */ + + var $source = ''; + + + /** + * + * Array of rule parsers. + * + * Text_Wiki creates one instance of every rule that is applied to + * the source text; this array holds those instances. The array key + * is the rule name, and the array value is an instance of the rule + * class. + * + * @access private + * + * @var array + * + */ + + var $parseObj = array(); + + + /** + * + * Array of rule renderers. + * + * Text_Wiki creates one instance of every rule that is applied to + * the source text; this array holds those instances. The array key + * is the rule name, and the array value is an instance of the rule + * class. + * + * @access private + * + * @var array + * + */ + + var $renderObj = array(); + + + /** + * + * Array of format renderers. + * + * @access private + * + * @var array + * + */ + + var $formatObj = array(); + + + /** + * + * Array of paths to search, in order, for parsing and rendering rules. + * + * @access private + * + * @var array + * + */ + + var $path = array( + 'parse' => array(), + 'render' => array() + ); + + + + /** + * + * The directory separator character. + * + * @access private + * + * @var string + * + */ + + var $_dirSep = DIRECTORY_SEPARATOR; + + + /** + * + * Constructor. + * + * @access public + * + * @param array $rules The set of rules to load for this object. + * + */ + + function Text_Wiki($rules = null) + { + if (is_array($rules)) { + $this->rules = $rules; + } + + $this->addPath( + 'parse', + $this->fixPath(dirname(__FILE__)) . 'Wiki/Parse/Default/' + ); + + $this->addPath( + 'render', + $this->fixPath(dirname(__FILE__)) . 'Wiki/Render/' + ); + + } + + + /** + * + * Set parser configuration for a specific rule and key. + * + * @access public + * + * @param string $rule The parse rule to set config for. + * + * @param array|string $arg1 The full config array to use for the + * parse rule, or a conf key in that array. + * + * @param string $arg2 The config value for the key. + * + * @return void + * + */ + + function setParseConf($rule, $arg1, $arg2 = null) + { + $rule = ucwords(strtolower($rule)); + + if (! isset($this->parseConf[$rule])) { + $this->parseConf[$rule] = array(); + } + + // if first arg is an array, use it as the entire + // conf array for the rule. otherwise, treat arg1 + // as a key and arg2 as a value for the rule conf. + if (is_array($arg1)) { + $this->parseConf[$rule] = $arg1; + } else { + $this->parseConf[$rule][$arg1] = $arg2; + } + } + + + /** + * + * Get parser configuration for a specific rule and key. + * + * @access public + * + * @param string $rule The parse rule to get config for. + * + * @param string $key A key in the conf array; if null, + * returns the entire conf array. + * + * @return mixed The whole conf array if no key is specified, + * or the specific conf key value. + * + */ + + function getParseConf($rule, $key = null) + { + $rule = ucwords(strtolower($rule)); + + // the rule does not exist + if (! isset($this->parseConf[$rule])) { + return null; + } + + // no key requested, return the whole array + if (is_null($key)) { + return $this->parseConf[$rule]; + } + + // does the requested key exist? + if (isset($this->parseConf[$rule][$key])) { + // yes, return that value + return $this->parseConf[$rule][$key]; + } else { + // no + return null; + } + } + + + /** + * + * Set renderer configuration for a specific format, rule, and key. + * + * @access public + * + * @param string $format The render format to set config for. + * + * @param string $rule The render rule to set config for in the format. + * + * @param array|string $arg1 The config array, or the config key + * within the render rule. + * + * @param string $arg2 The config value for the key. + * + * @return void + * + */ + + function setRenderConf($format, $rule, $arg1, $arg2 = null) + { + $format = ucwords(strtolower($format)); + $rule = ucwords(strtolower($rule)); + + if (! isset($this->renderConf[$format])) { + $this->renderConf[$format] = array(); + } + + if (! isset($this->renderConf[$format][$rule])) { + $this->renderConf[$format][$rule] = array(); + } + + // if first arg is an array, use it as the entire + // conf array for the render rule. otherwise, treat arg1 + // as a key and arg2 as a value for the render rule conf. + if (is_array($arg1)) { + $this->renderConf[$format][$rule] = $arg1; + } else { + $this->renderConf[$format][$rule][$arg1] = $arg2; + } + } + + + /** + * + * Get renderer configuration for a specific format, rule, and key. + * + * @access public + * + * @param string $format The render format to get config for. + * + * @param string $rule The render format rule to get config for. + * + * @param string $key A key in the conf array; if null, + * returns the entire conf array. + * + * @return mixed The whole conf array if no key is specified, + * or the specific conf key value. + * + */ + + function getRenderConf($format, $rule, $key = null) + { + $format = ucwords(strtolower($format)); + $rule = ucwords(strtolower($rule)); + + if (! isset($this->renderConf[$format]) || + ! isset($this->renderConf[$format][$rule])) { + return null; + } + + // no key requested, return the whole array + if (is_null($key)) { + return $this->renderConf[$format][$rule]; + } + + // does the requested key exist? + if (isset($this->renderConf[$format][$rule][$key])) { + // yes, return that value + return $this->renderConf[$format][$rule][$key]; + } else { + // no + return null; + } + + } + + /** + * + * Set format configuration for a specific rule and key. + * + * @access public + * + * @param string $format The format to set config for. + * + * @param string $key The config key within the format. + * + * @param string $val The config value for the key. + * + * @return void + * + */ + + function setFormatConf($format, $arg1, $arg2 = null) + { + if (! is_array($this->formatConf[$format])) { + $this->formatConf[$format] = array(); + } + + // if first arg is an array, use it as the entire + // conf array for the format. otherwise, treat arg1 + // as a key and arg2 as a value for the format conf. + if (is_array($arg1)) { + $this->formatConf[$format] = $arg1; + } else { + $this->formatConf[$format][$arg1] = $arg2; + } + } + + + + /** + * + * Get configuration for a specific format and key. + * + * @access public + * + * @param string $format The format to get config for. + * + * @param mixed $key A key in the conf array; if null, + * returns the entire conf array. + * + * @return mixed The whole conf array if no key is specified, + * or the specific conf key value. + * + */ + + function getFormatConf($format, $key = null) + { + // the format does not exist + if (! isset($this->formatConf[$format])) { + return null; + } + + // no key requested, return the whole array + if (is_null($key)) { + return $this->formatConf[$format]; + } + + // does the requested key exist? + if (isset($this->formatConf[$format][$key])) { + // yes, return that value + return $this->formatConf[$format][$key]; + } else { + // no + return null; + } + } + + + /** + * + * Inserts a rule into to the rule set. + * + * @access public + * + * @param string $name The name of the rule. Should be different from + * all other keys in the rule set. + * + * @param string $tgt The rule after which to insert this new rule. By + * default (null) the rule is inserted at the end; if set to '', inserts + * at the beginning. + * + * @return void + * + */ + + function insertRule($name, $tgt = null) + { + $name = ucwords(strtolower($name)); + if (! is_null($tgt)) { + $tgt = ucwords(strtolower($tgt)); + } + + // does the rule name to be inserted already exist? + if (in_array($name, $this->rules)) { + // yes, return + return null; + } + + // the target name is not null, and not '', but does not exist + // in the list of rules. this means we're trying to insert after + // a target key, but the target key isn't there. + if (! is_null($tgt) && $tgt != '' && + ! in_array($tgt, $this->rules)) { + return false; + } + + // if $tgt is null, insert at the end. We know this is at the + // end (instead of resetting an existing rule) becuase we exited + // at the top of this method if the rule was already in place. + if (is_null($tgt)) { + $this->rules[] = $name; + return true; + } + + // save a copy of the current rules, then reset the rule set + // so we can insert in the proper place later. + // where to insert the rule? + if ($tgt == '') { + // insert at the beginning + array_unshift($this->rules, $name); + return true; + } + + // insert after the named rule + $tmp = $this->rules; + $this->rules = array(); + + foreach ($tmp as $val) { + $this->rules[] = $val; + if ($val == $tgt) { + $this->rules[] = $name; + } + } + + return true; + + } + + + /** + * + * Delete (remove or unset) a rule from the $rules property. + * + * @access public + * + * @param string $rule The name of the rule to remove. + * + * @return void + * + */ + + function deleteRule($name) + { + $name = ucwords(strtolower($name)); + $key = array_search($name, $this->rules); + if ($key !== false) { + unset($this->rules[$key]); + } + } + + + /** + * + * Change from one rule to another in-place. + * + * @access public + * + * @param string $old The name of the rule to change from. + * + * @param string $new The name of the rule to change to. + * + * @return void + * + */ + + function changeRule($old, $new) + { + $old = ucwords(strtolower($old)); + $new = ucwords(strtolower($new)); + $key = array_search($old, $this->rules); + if ($key !== false) { + $this->rules[$old] = $new; + } + } + + + /** + * + * Enables a rule so that it is applied when parsing. + * + * @access public + * + * @param string $rule The name of the rule to enable. + * + * @return void + * + */ + + function enableRule($name) + { + $name = ucwords(strtolower($name)); + $key = array_search($name, $this->disable); + if ($key !== false) { + unset($this->disable[$key]); + } + } + + + /** + * + * Disables a rule so that it is not applied when parsing. + * + * @access public + * + * @param string $rule The name of the rule to disable. + * + * @return void + * + */ + + function disableRule($name) + { + $name = ucwords(strtolower($name)); + $key = array_search($name, $this->disable); + if ($key === false) { + $this->disable[] = $name; + } + } + + + /** + * + * Parses and renders the text passed to it, and returns the results. + * + * First, the method parses the source text, applying rules to the + * text as it goes. These rules will modify the source text + * in-place, replacing some text with delimited tokens (and + * populating the $this->tokens array as it goes). + * + * Next, the method renders the in-place tokens into the requested + * output format. + * + * Finally, the method returns the transformed text. Note that the + * source text is transformed in place; once it is transformed, it is + * no longer the same as the original source text. + * + * @access public + * + * @param string $text The source text to which wiki rules should be + * applied, both for parsing and for rendering. + * + * @param string $format The target output format, typically 'xhtml'. + * If a rule does not support a given format, the output from that + * rule is rule-specific. + * + * @return string The transformed wiki text. + * + */ + + function transform($text, $format = 'Xhtml') + { + $this->parse($text); + return $this->render($format); + } + + + /** + * + * Sets the $_source text property, then parses it in place and + * retains tokens in the $_tokens array property. + * + * @access public + * + * @param string $text The source text to which wiki rules should be + * applied, both for parsing and for rendering. + * + * @return void + * + */ + + function parse($text) + { + // set the object property for the source text + $this->source = $text; + + // reset the tokens. + $this->tokens = array(); + + // apply the parse() method of each requested rule to the source + // text. + foreach ($this->rules as $name) { + // do not parse the rules listed in $disable + if (! in_array($name, $this->disable)) { + + // load the parsing object + $this->loadParseObj($name); + + // load may have failed; only parse if + // an object is in the array now + if (is_object($this->parseObj[$name])) { + $this->parseObj[$name]->parse(); + } + } + } + } + + + /** + * + * Renders tokens back into the source text, based on the requested format. + * + * @access public + * + * @param string $format The target output format, typically 'xhtml'. + * If a rule does not support a given format, the output from that + * rule is rule-specific. + * + * @return string The transformed wiki text. + * + */ + + function render($format = 'Xhtml') + { + // the rendering method we're going to use from each rule + $format = ucwords(strtolower($format)); + + // the eventual output text + $output = ''; + + // when passing through the parsed source text, keep track of when + // we are in a delimited section + $in_delim = false; + + // when in a delimited section, capture the token key number + $key = ''; + + // load the format object + $this->loadFormatObj($format); + + // pre-rendering activity + if (is_object($this->formatObj[$format])) { + $output .= $this->formatObj[$format]->pre(); + } + + // load the render objects + foreach (array_keys($this->parseObj) as $rule) { + $this->loadRenderObj($format, $rule); + } + + // pass through the parsed source text character by character + $k = strlen($this->source); + for ($i = 0; $i < $k; $i++) { + + // the current character + $char = $this->source{$i}; + + // are alredy in a delimited section? + if ($in_delim) { + + // yes; are we ending the section? + if ($char == $this->delim) { + + // yes, get the replacement text for the delimited + // token number and unset the flag. + $key = (int)$key; + $rule = $this->tokens[$key][0]; + $opts = $this->tokens[$key][1]; + $output .= $this->renderObj[$rule]->token($opts); + $in_delim = false; + + } else { + + // no, add to the dlimited token key number + $key .= $char; + + } + + } else { + + // not currently in a delimited section. + // are we starting into a delimited section? + if ($char == $this->delim) { + // yes, reset the previous key and + // set the flag. + $key = ''; + $in_delim = true; + } else { + // no, add to the output as-is + $output .= $char; + } + } + } + + // post-rendering activity + if (is_object($this->formatObj[$format])) { + $output .= $this->formatObj[$format]->post(); + } + + // return the rendered source text. + return $output; + } + + + /** + * + * Returns the parsed source text with delimited token placeholders. + * + * @access public + * + * @return string The parsed source text. + * + */ + + function getSource() + { + return $this->source; + } + + + /** + * + * Returns tokens that have been parsed out of the source text. + * + * @access public + * + * @param array $rules If an array of rule names is passed, only return + * tokens matching these rule names. If no array is passed, return all + * tokens. + * + * @return array An array of tokens. + * + */ + + function getTokens($rules = null) + { + if (is_null($rules)) { + return $this->tokens; + } else { + settype($rules, 'array'); + $result = array(); + foreach ($this->tokens as $key => $val) { + if (in_array($val[0], $rules)) { + $result[] = $val; + } + } + return $result; + } + } + + + /** + * + * Add a token to the Text_Wiki tokens array, and return a delimited + * token number. + * + * @access public + * + * @param array $options An associative array of options for the new + * token array element. The keys and values are specific to the + * rule, and may or may not be common to other rule options. Typical + * options keys are 'text' and 'type' but may include others. + * + * @param boolean $id_only If true, return only the token number, not + * a delimited token string. + * + * @return string|int By default, return the number of the + * newly-created token array element with a delimiter prefix and + * suffix; however, if $id_only is set to true, return only the token + * number (no delimiters). + * + */ + + function addToken($rule, $options = array(), $id_only = false) + { + // increment the token ID number. note that if you parse + // multiple times with the same Text_Wiki object, the ID number + // will not reset to zero. + static $id; + if (! isset($id)) { + $id = 0; + } else { + $id ++; + } + + // force the options to be an array + settype($options, 'array'); + + // add the token + $this->tokens[$id] = array( + 0 => $rule, + 1 => $options + ); + + // return a value + if ($id_only) { + // return the last token number + return $id; + } else { + // return the token number with delimiters + return $this->delim . $id . $this->delim; + } + } + + + /** + * + * Set or re-set a token with specific information, overwriting any + * previous rule name and rule options. + * + * @access public + * + * @param int $id The token number to reset. + * + * @param int $rule The rule name to use. + * + * @param array $options An associative array of options for the + * token array element. The keys and values are specific to the + * rule, and may or may not be common to other rule options. Typical + * options keys are 'text' and 'type' but may include others. + * + * @return void + * + */ + + function setToken($id, $rule, $options = array()) + { + // reset the token + $this->tokens[$id] = array( + 0 => $rule, + 1 => $options + ); + } + + + /** + * + * Load a rule parser class file. + * + * @access public + * + * @return bool True if loaded, false if not. + * + */ + + function loadParseObj($rule) + { + $rule = ucwords(strtolower($rule)); + $file = $rule . '.php'; + $class = "Text_Wiki_Parse_$rule"; + + if (! class_exists($class)) { + $loc = $this->findFile('parse', $file); + if ($loc) { + // found the class + include_once $loc; + } else { + // can't find the class + $this->parseObj[$rule] = null; + return false; + } + } + + $this->parseObj[$rule] =& new $class($this); - /** - * - * The delimiter that surrounds a token number embedded in the source - * wiki text. - * - * @access public - * - * @var string - * - */ - - var $delim = "\xFF"; - - - /** - * - * An array of tokens generated by rules as the source text is - * parsed. - * - * As Text_Wiki applies rule classes to the source text, it will - * replace portions of the text with a delimited token number. This - * is the array of those tokens, representing the replaced text and - * any options set by the parser for that replaced text. - * - * The tokens array is seqential; each element is itself a sequential - * array where element 0 is the name of the rule that generated the - * token, and element 1 is an associative array where the key is an - * option name and the value is an option value. - * - * @access private - * - * @var string - * - */ - - var $_tokens = array(); - - - /** - * - * The source text to which rules will be applied. This text will be - * transformed in-place, which means that it will change as the rules - * are applied. - * - * @access private - * - * @var string - * - */ - - var $_source = ''; - - - /** - * - * Text_Wiki creates one instance of every rule that is applied to - * the source text; this array holds those instances. The array key - * is the rule name, and the array value is an instance of the rule - * class. - * - * @access private - * - * @var string - * - */ - - var $_rule_obj = array(); - - - /** - * - * Constructor. Loads the rule objects. - * - * @access public - * - * @param array $rules The set of rules to load for this object. - * - */ - - function Text_Wiki($rules = null) - { - // set up the list of rules - if (is_array($rules)) { - $this->rules = $rules; - } - } - - - /** - * - * Inserts a rule into to the rule set. - * - * @access public - * - * @param string $key The key name for the rule. Should be different from - * all other keys in the rule set. - * - * @param string $val The rule values; should be an associative array with - * the keys 'file', 'name', 'flag', and 'conf'. - * - * @param string $tgt The rule after which to insert this new rule. By - * default (null) the rule is inserted at the end; if set to '', inserts - * at the beginning. - * - * @return void - * - */ - - function insertRule($key, $val, $tgt = null) - { - // does the rule key to be inserted already exist? - if (isset($this->rules[$key])) { - // yes, return - return false; - } - - // the target name is not null, not '', but does not exist. this - // means we're trying to insert after a target key, but the - // target key isn't there. - if (! is_null($tgt) && $tgt != '' && ! isset($this->rules[$tgt])) { - return false; - } - - // if $tgt is null, insert at the end. We know this is at the - // end (instead of resetting an existing rule) becuase we exited - // at the top of this method if the rule was already in place. - if (is_null($tgt)) { - $this->rules[$key] = $val; - return true; - } - - // save a copy of the current rules, then reset the rule set - // so we can insert in the proper place later. - $tmp = $this->rules; - $this->rules = array(); - - // where to insert the rule? - if ($tgt == '') { - // insert at the beginning - $this->rules[$key] = $val; - foreach ($tmp as $k => $v) { - $this->rules[$k] = $v; - } - return true; - } else { - // insert after the named rule - foreach ($tmp as $k => $v) { - $this->rules[$k] = $v; - if ($k == $tgt) { - $this->rules[$key] = $val; - } - } - } - return true; - } - - - /** - * - * Delete (remove or unset) a rule from the $rules property. - * - * @access public - * - * @param string $rule The name of the rule to remove. - * - * @return void - * - */ - - function deleteRule($key) - { - unset($this->rules[$key]); - } - - - /** - * - * Sets the value of a rule's configuration keys. - * - * @access public - * - * @param string $rule The name of the rule for which to set - * configuration keys. - * - * @param array|string $arg1 If an array, sets the entire 'conf' key - * for the rule; if a string, specifies which 'conf' subkey to set. - * - * @param mixed $arg2 If $arg1 is a string, the 'conf' subkey - * specified by $arg1 is set to this value. - * - * @return void - * - */ - - function setRuleConf($rule, $arg1, $arg2 = null) - { - if (! isset($this->rules[$rule])) { - return; - } - - if (! isset($this->rules[$rule]['conf'])) { - $this->rules[$rule]['conf'] = array(); - } - - if (is_array($arg1)) { - $this->rules[$rule]['conf'] = $arg1; - } else { - $this->rules[$rule]['conf'][$arg1] = $arg2; - } - } - - - /** - * - * Sets the value of a rule's configuration keys. - * - * @access public - * - * @param string $rule The name of the rule from which to get - * configuration keys. - * - * @param string $key Which 'conf' subkey to retrieve. If null, - * gets the entire 'conf' key for the rule. - * - * @return void - * - */ - - function getRuleConf($rule, $key = null) - { - if (! isset($this->rules[$rule])) { - return null; - } - - if (! isset($this->rules[$rule]['conf'])) { - $this->rules[$rule]['conf'] = array(); - } - - if (is_null($key)) { - return $this->rules[$rule]['conf']; - } - - if (! isset($this->rules[$rule]['conf'][$key])) { - return null; - } else { - return $this->rules[$rule]['conf'][$key]; - } - - } - - - /** - * - * Enables a rule so that it is applied when parsing. - * - * @access public - * - * @param string $rule The name of the rule to enable. - * - * @return void - * - */ - - function enableRule($rule) - { - if (isset($this->rules[$rule])) { - $this->rules[$rule]['flag'] = true; - } - } - - - /** - * - * Disables a rule so that it is not applied when parsing. - * - * @access public - * - * @param string $rule The name of the rule to disable. - * - * @return void - * - */ - - function disableRule($rule) - { - if (isset($this->rules[$rule])) { - $this->rules[$rule]['flag'] = false; - } - } - - - /** - * - * Parses and renders the text passed to it, and returns the results. - * - * First, the method parses the source text, applying rules to the - * text as it goes. These rules will modify the source text - * in-place, replacing some text with delimited tokens (and - * populating the $this->_tokens array as it goes). - * - * Next, the method renders the in-place tokens into the requested - * output format. - * - * Finally, the method returns the transformed text. Note that the - * source text is transformed in place; once it is transformed, it is - * no longer the same as the original source text. - * - * @access public - * - * @param string $text The source text to which wiki rules should be - * applied, both for parsing and for rendering. - * - * @param string $format The target output format, typically 'xhtml'. - * If a rule does not support a given format, the output from that - * rule is rule-specific. - * - * @return string The transformed wiki text. - * - */ - - function transform($text, $format = 'Xhtml') - { - $this->parse($text); - return $this->render($format); - } - - - /** - * - * Sets the $_source text property, then parses it in place and - * retains tokens in the $_tokens array property. - * - * @access public - * - * @param string $text The source text to which wiki rules should be - * applied, both for parsing and for rendering. - * - * @return void - * - */ - - function parse($text) - { - // set the object property for the source text - $this->_source = $text; - - // apply the parse() method of each requested rule to the source - // text. - foreach ($this->rules as $key => $val) { - // if flag is not set to 'true' (active), - // do not parse under this rule. assume - // that if a rule exists, but has no flag, - // that it wants to be parsed with. - if (! isset($val['flag']) || $val['flag'] == true) { - $this->_loadRuleObject($key); - $this->_rule_obj[$key]->parse(); - } - } - } - - - /** - * - * Renders tokens back into the source text, based on the requested format. - * - * @access public - * - * @param string $format The target output format, typically 'xhtml'. - * If a rule does not support a given format, the output from that - * rule is rule-specific. - * - * @return string The transformed wiki text. - * - */ - - function render($format = 'Xhtml') - { - // the rendering method we're going to use from each rule - $method = "render$format"; - - // the eventual output text - $output = ''; - - // when passing through the parsed source text, keep track of when - // we are in a delimited section - $in_delim = false; - - // when in a delimited section, capture the token key number - $key = ''; - - // pass through the parsed source text character by character - $k = strlen($this->_source); - for ($i = 0; $i < $k; $i++) { - - // the current character - $char = $this->_source{$i}; - - // are alredy in a delimited section? - if ($in_delim) { - - // yes; are we ending the section? - if ($char == $this->delim) { - - // yes, get the replacement text for the delimited - // token number and unset the flag. - $key = (int)$key; - $rule = $this->_tokens[$key][0]; - $opts = $this->_tokens[$key][1]; - $output .= $this->_rule_obj[$rule]->$method($opts); - $in_delim = false; - - } else { - - // no, add to the dlimited token key number - $key .= $char; - - } - - } else { - - // not currently in a delimited section. - // are we starting into a delimited section? - if ($char == $this->delim) { - // yes, reset the previous key and - // set the flag. - $key = ''; - $in_delim = true; - } else { - // no, add to the output as-is - $output .= $char; - } - } - } - - // return the rendered source text - return $output; - } - - - /** - * - * Returns the parsed source text with delimited token placeholders. - * - * @access public - * - * @return string The parsed source text. - * - */ - - function getSource() - { - return $this->_source; - } - - - /** - * - * Returns tokens that have been parsed out of the source text. - * - * @access public - * - * @param array $rules If an array of rule names is passed, only return - * tokens matching these rule names. If no array is passed, return all - * tokens. - * - * @return array An array of tokens. - * - */ - - function getTokens($rules = null) - { - if (is_null($rules)) { - return $this->_tokens; - } else { - settype($rules, 'array'); - $result = array(); - foreach ($this->_tokens as $key => $val) { - if (in_array($val[0], $rules)) { - $result[] = $val; - } - } - return $result; - } - } - - - /** - * - * Loads a rule class file and creates an instance of it. - * - * @access public - * - * @return void - * - */ - - function _loadRuleObject($key) - { - $name = $this->rules[$key]['name']; - if (! class_exists($name)) { - include_once $this->rules[$key]['file']; - } - $this->_rule_obj[$key] =& new $name($this, $key); - } + } + + + /** + * + * Load a rule-render class file. + * + * @access public + * + * @return bool True if loaded, false if not. + * + */ + + function loadRenderObj($format, $rule) + { + $format = ucwords(strtolower($format)); + $rule = ucwords(strtolower($rule)); + $file = "$format/$rule.php"; + $class = "Text_Wiki_Render_$format" . "_$rule"; + + if (! class_exists($class)) { + // load the class + $loc = $this->findFile('render', $file); + if ($loc) { + // found the class + include_once $loc; + } else { + // can't find the class + return false; + } + } + + $this->renderObj[$rule] =& new $class($this); + } + + + /** + * + * Load a format-render class file. + * + * @access public + * + * @return bool True if loaded, false if not. + * + */ + + function loadFormatObj($format) + { + $format = ucwords(strtolower($format)); + $file = $format . '.php'; + $class = "Text_Wiki_Render_$format"; + + if (! class_exists($class)) { + $loc = $this->findFile('render', $file); + if ($loc) { + // found the class + include_once $loc; + } else { + // can't find the class + return false; + } + } + + $this->formatObj[$format] =& new $class($this); + } + + + /** + * + * Add a path to a path array. + * + * @access public + * + * @param string $type The path-type to add (parse or render). + * + * @param string $dir The directory to add to the path-type. + * + * @return void + * + */ + + function addPath($type, $dir) + { + $dir = $this->fixPath($dir); + if (! isset($this->path[$type])) { + $this->path[$type] = array($dir); + } else { + array_unshift($this->path[$type], $dir); + } + } + + + /** + * + * Get the current path array for a path-type. + * + * @access public + * + * @param string $type The path-type to look up (plugin, filter, or + * template). If not set, returns all path types. + * + * @return array The array of paths for the requested type. + * + */ + + function getPath($type = null) + { + if (is_null($type)) { + return $this->path; + } elseif (! isset($this->path[$type])) { + return array(); + } else { + return $this->path[$type]; + } + } + + + /** + * + * Searches a series of paths for a given file. + * + * @param array $type The type of paths to search (template, plugin, + * or filter). + * + * @param string $file The file name to look for. + * + * @return string|bool The full path and file name for the target file, + * or boolean false if the file is not found in any of the paths. + * + */ + + function findFile($type, $file) + { + // get the set of paths + $set = $this->getPath($type); + + // start looping through them + foreach ($set as $path) { + $fullname = $path . $file; + if (file_exists($fullname) && is_readable($fullname)) { + return $fullname; + } + } + + // could not find the file in the set of paths + return false; + } + + + /** + * + * Append a trailing '/' to paths, unless the path is empty. + * + * @access private + * + * @param string $path The file path to fix + * + * @return string The fixed file path + * + */ + + function fixPath($path) + { + $len = strlen($this->_dirSep); + + if (! empty($path) && + substr($path, -1 * $len, $len) != $this->_dirSep) { + return $path . $this->_dirSep; + } else { + return $path; + } + } } -?> +?> \ No newline at end of file diff --git a/docs/NEWS b/docs/NEWS index b5330ca..9c525cb 100644 --- a/docs/NEWS +++ b/docs/NEWS @@ -149,15 +149,24 @@ Version 0.9 () Version 0.8.3 () ------------------------------------------------------------------------ + + * Upgraded bundled libs: + Cache_Lite to 1.5.1 + HTTP_Request to 1.2.4 + Net_CheckIP to 1.1 + Net_Socket to 1.0.6 + Net_URL to 1.0.14 + PEAR to 1.3.5 + Text_Wiki to 1.0.0 + XML_RPC to 1.3.2 + Fixing several bugs and vulnerabilities. (nohn) + + * Fix editing a draft article to be properly displayed as draft + in PostgreSQL setups. Thanks to Penny Leach! (garvinhicking) * Fixed possible XSS in comment input validation, thanks to Ilia Alshanetsky - * XML_RPC: Eliminate path disclosure vulnerabilities by suppressing - error messages when eval()'ing. Eliminate path disclosure - vulnerability by catching bogus parameters submitted - to XML_RPC_Value::serializeval(). (nohn) - Version 0.8.2 (June 29th, 2005) ------------------------------------------------------------------------