-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
* 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 <ipso@snappymail.ca>
*
+* Nota : A chinese documentation (thanks to RainX <china_1982@163.com>) 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 <fab@php.net>
*/
* @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)
*/
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 ---
/**
* '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
*/
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;
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));
return true;
}
} else {
- return $this->_write($data);
- }
+ return $this->_write($data);
+ }
}
return false;
}
return true;
}
}
- if (!@unlink($this->_file)) {
- $this->raiseError('Cache_Lite : Unable to remove cache !', -3);
- return false;
- }
- return true;
+ return $this->_unlink($this->_file);
}
/**
* 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
*
}
/**
+ * 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')
}
/**
+ * 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)
* @return int last modification time
*/
function lastModified() {
- return filemtime($this->_file);
+ return @filemtime($this->_file);
}
/**
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)
*/
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;
}
/**
$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);
*/
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;
}
* 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 <sb@sebastian-bergmann.de>
* @author Fabien MARTY <fab@php.net>
*/
* 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 <fab@php.net>
*/
*
* @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;
// | Author: Richard Heyes <richard@phpguru.org> |
// +-----------------------------------------------------------------------+
//
-// $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
//
/**
* Instance of Net_URL
- * @var object
+ * @var object Net_URL
*/
var $_url;
/**
* Socket object
- * @var object
+ * @var object Net_Socket
*/
var $_sock;
/**
* Connection timeout.
- * @var integer
+ * @var float
*/
var $_timeout;
/**
* HTTP_Response object
- * @var object
+ * @var object HTTP_Response
*/
var $_response;
* 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:
+ * <ul>
+ * <li>method - Method to use, GET, POST etc (string)</li>
+ * <li>http - HTTP Version to use, 1.0 or 1.1 (string)</li>
+ * <li>user - Basic Auth username (string)</li>
+ * <li>pass - Basic Auth password (string)</li>
+ * <li>proxy_host - Proxy server host (string)</li>
+ * <li>proxy_port - Proxy server port (integer)</li>
+ * <li>proxy_user - Proxy auth username (string)</li>
+ * <li>proxy_pass - Proxy auth password (string)</li>
+ * <li>timeout - Connection timeout in seconds (float)</li>
+ * <li>allowRedirects - Whether to follow redirects or not (bool)</li>
+ * <li>maxRedirects - Max number of redirects to follow (integer)</li>
+ * <li>useBrackets - Whether to append [] to array variable names (bool)</li>
+ * <li>saveBody - Whether to save response body in response object property (bool)</li>
+ * <li>readTimeout - Timeout for reading / writing data over the socket (array (seconds, microseconds))</li>
+ * <li>socketOptions - Options to pass to Net_Socket object (array)</li>
+ * </ul>
* @access public
*/
function HTTP_Request($url = '', $params = array())
$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;
$this->_sock->readAll(); // make this an eof()
return '';
}
+ } elseif ($this->_sock->eof()) {
+ return '';
}
}
$data = $this->_sock->read($this->_chunkLength);
// | Author: Alexey Borzov <avb@php.net> |
// +-----------------------------------------------------------------------+
//
-// $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 $
//
/**
*
* @package HTTP_Request
* @author Alexey Borzov <avb@php.net>
- * @version $Revision: 1.1 $
+ * @version $Revision: 1.2 $
*/
class HTTP_Request_Listener
{
// | Guido Haeger <gh-lists@ecora.de> |
// +----------------------------------------------------------------------+
//
-// $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
// | Chuck Hagenbuch <chuck@horde.org> |
// +----------------------------------------------------------------------+
//
-// $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 <ssb@php.net>
* @author Chuck Hagenbuch <chuck@horde.org>
*/
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 = '';
$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);
return $this->setBlocking($this->blocking);
}
- // }}}
- // {{{ disconnect()
/**
* Disconnects from the peer, closes the socket.
*
*/
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:
*/
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
*
*/
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
{
return (is_resource($this->fp) && feof($this->fp));
}
- // }}}
- // {{{ readByte()
/**
* Reads a byte of data
*
*/
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
*
*/
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
*/
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
*
*/
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.
*/
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;
}
- // }}}
}
// | Author: Richard Heyes <richard at php net> |
// +-----------------------------------------------------------------------+
//
-// $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
<?php
//
-// +----------------------------------------------------------------------+
-// | PEAR, the PHP Extension and Application Repository |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2003 The PHP Group |
-// +----------------------------------------------------------------------+
-// | This source file is subject to version 2.0 of the PHP license, |
-// | that is bundled with this package in the file LICENSE, and is |
-// | available at through the world-wide-web at |
-// | http://www.php.net/license/2_02.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 <sterling@php.net> |
-// | Stig Bakken <ssb@fast.no> |
-// | Tomas V.V.Cox <cox@idecnet.com> |
-// +----------------------------------------------------------------------+
+// +--------------------------------------------------------------------+
+// | 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 <sterling@php.net> |
+// | Stig Bakken <ssb@php.net> |
+// | Tomas V.V.Cox <cox@idecnet.com> |
+// +--------------------------------------------------------------------+
//
-// $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);
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")));
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
* 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 <ssb@fast.no>
+ * @author Stig Bakken <ssb@php.net>
* @see http://pear.php.net/manual/
*/
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);
*/
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)));
}
}
/**
* 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
*
* @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;
}
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 {
}
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;
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);
// $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 {
* @see PEAR::setErrorHandling
* @since PHP 4.0.5
*/
- function &raiseError($message = null,
+ function raiseError($message = null,
$code = null,
$mode = null,
$options = null,
$code = $message->getCode();
$userinfo = $message->getUserInfo();
$error_class = $message->getType();
+ $message->error_message_prefix = '';
$message = $message->getMessage();
}
* @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);
}
// }}}
+ 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()
/**
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 {
}
$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);
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);
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') {
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) {
$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;
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);');
}
}
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);
}
}
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);
// }}}
}
-register_shutdown_function("_PEAR_call_destructors");
-
/*
* Local Variables:
* mode: php
<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4: */
-// +----------------------------------------------------------------------+
-// | PHP version 4 |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2003 The PHP Group |
-// +----------------------------------------------------------------------+
-// | This source file is subject to version 2.0 of the PHP license, |
-// | that is bundled with this package in the file LICENSE, and is |
-// | available through the world-wide-web at |
-// | http://www.php.net/license/2_02.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: Paul M. Jones <pmjones@ciaweb.net> |
-// +----------------------------------------------------------------------+
-//
-// $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 <pmjones@php.net>
+*
+* @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 <pmjones@ciaweb.net>
+* @category Text
+*
+* @package Text_Wiki
*
-* @version 0.15 alpha
+<<<<<<< Wiki.php
+* @version 0.25.0
+*
+* @license LGPL
+=======
+* @author Paul M. Jones <pmjones@php.net>
+*
+* @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:
+ *
+ * <code>
+ * $parseConf = array(
+ * 'Include' => array(
+ * 'base' => '/path/to/scripts/'
+ * )
+ * );
+ * </code>
+ *
+ * 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
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)
------------------------------------------------------------------------