Updated phergie library

This commit is contained in:
Luke Fitzgerald 2010-06-30 09:33:29 -07:00
parent 0b2bbd20aa
commit bf6ecfbffc
35 changed files with 2765 additions and 651 deletions

View File

@ -1,6 +1,6 @@
<?php <?php
/** /**
* Phergie * Phergie
* *
* PHP version 5 * PHP version 5
* *
@ -11,7 +11,7 @@
* It is also available through the world-wide-web at this URL: * It is also available through the world-wide-web at this URL:
* http://phergie.org/license * http://phergie.org/license
* *
* @category Phergie * @category Phergie
* @package Phergie * @package Phergie
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org) * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
@ -22,7 +22,7 @@
/** /**
* Autoloader for Phergie classes. * Autoloader for Phergie classes.
* *
* @category Phergie * @category Phergie
* @package Phergie * @package Phergie
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License * @license http://phergie.org/license New BSD License
@ -37,9 +37,9 @@ class Phergie_Autoload
*/ */
public function __construct() public function __construct()
{ {
$path = dirname(__FILE__); $path = realpath(dirname(__FILE__) . '/..');
$includePath = get_include_path(); $includePath = get_include_path();
$includePathList = explode(PATH_SEPARATOR, $includePath); $includePathList = explode(PATH_SEPARATOR, $includePath);
if (!in_array($path, $includePathList)) { if (!in_array($path, $includePathList)) {
self::addPath($path); self::addPath($path);
} }
@ -54,9 +54,6 @@ class Phergie_Autoload
*/ */
public function load($class) public function load($class)
{ {
if (substr($class, 0, 8) == 'Phergie_') {
$class = substr($class, 8);
}
include str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php'; include str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';
} }

View File

@ -1,6 +1,6 @@
<?php <?php
/** /**
* Phergie * Phergie
* *
* PHP version 5 * PHP version 5
* *
@ -11,7 +11,7 @@
* It is also available through the world-wide-web at this URL: * It is also available through the world-wide-web at this URL:
* http://phergie.org/license * http://phergie.org/license
* *
* @category Phergie * @category Phergie
* @package Phergie * @package Phergie
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org) * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
@ -22,7 +22,7 @@
/** /**
* Composite class for other components to represent the bot. * Composite class for other components to represent the bot.
* *
* @category Phergie * @category Phergie
* @package Phergie * @package Phergie
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License * @license http://phergie.org/license New BSD License
@ -50,9 +50,9 @@ class Phergie_Bot
protected $config; protected $config;
/** /**
* Current connection handler instance * Current connection handler instance
* *
* @var Phergie_Connection_Handler * @var Phergie_Connection_Handler
*/ */
protected $connections; protected $connections;
@ -85,7 +85,7 @@ class Phergie_Bot
protected $processor; protected $processor;
/** /**
* Returns a driver instance, creating one of the default class if * Returns a driver instance, creating one of the default class if
* none has been set. * none has been set.
* *
* @return Phergie_Driver_Abstract * @return Phergie_Driver_Abstract
@ -135,14 +135,14 @@ class Phergie_Bot
} }
/** /**
* Returns the entire configuration in use or the value of a specific * Returns the entire configuration in use or the value of a specific
* configuration setting. * configuration setting.
* *
* @param string $index Optional index of a specific configuration * @param string $index Optional index of a specific configuration
* setting for which the corresponding value should be returned * setting for which the corresponding value should be returned
* @param mixed $default Value to return if no match is found for $index * @param mixed $default Value to return if no match is found for $index
* *
* @return mixed Value corresponding to $index or the entire * @return mixed Value corresponding to $index or the entire
* configuration if $index is not specified * configuration if $index is not specified
*/ */
public function getConfig($index = null, $default = null) public function getConfig($index = null, $default = null)
@ -219,7 +219,7 @@ class Phergie_Bot
} }
/** /**
* Returns a connection handler instance, creating it if it does not * Returns a connection handler instance, creating it if it does not
* already exist and using a default class if none has been set. * already exist and using a default class if none has been set.
* *
* @return Phergie_Connection_Handler * @return Phergie_Connection_Handler
@ -246,7 +246,7 @@ class Phergie_Bot
} }
/** /**
* Returns an end-user interface instance, creating it if it does not * Returns an end-user interface instance, creating it if it does not
* already exist and using a default class if none has been set. * already exist and using a default class if none has been set.
* *
* @return Phergie_Ui_Abstract * @return Phergie_Ui_Abstract
@ -273,7 +273,7 @@ class Phergie_Bot
} }
/** /**
* Returns a processer instance, creating one if none exists. * Returns a processer instance, creating one if none exists.
* *
* @return Phergie_Process_Abstract * @return Phergie_Process_Abstract
*/ */
@ -281,14 +281,14 @@ class Phergie_Bot
{ {
if (empty($this->processor)) { if (empty($this->processor)) {
$class = 'Phergie_Process_Standard'; $class = 'Phergie_Process_Standard';
$type = $this->getConfig('processor'); $type = $this->getConfig('processor');
if (!empty($type)) { if (!empty($type)) {
$class = 'Phergie_Process_' . ucfirst($type); $class = 'Phergie_Process_' . ucfirst($type);
} }
$this->processor = new $class( $this->processor = new $class(
$this, $this,
$this->getConfig('processor.options', array()) $this->getConfig('processor.options', array())
); );
} }
@ -318,7 +318,7 @@ class Phergie_Bot
$config = $this->getConfig(); $config = $this->getConfig();
$plugins = $this->getPluginHandler(); $plugins = $this->getPluginHandler();
$ui = $this->getUi(); $ui = $this->getUi();
$plugins->setAutoload($config['plugins.autoload']); $plugins->setAutoload($config['plugins.autoload']);
foreach ($config['plugins'] as $name) { foreach ($config['plugins'] as $name) {
try { try {
@ -358,15 +358,15 @@ class Phergie_Bot
} }
/** /**
* Establishes server connections and initiates an execution loop to * Establishes server connections and initiates an execution loop to
* continuously receive and process events. * continuously receive and process events.
* *
* @return Phergie_Bot Provides a fluent interface * @return Phergie_Bot Provides a fluent interface
*/ */
public function run() public function run()
{ {
set_time_limit(0); set_time_limit(0);
$timezone = $this->getConfig('timezone', 'UTC'); $timezone = $this->getConfig('timezone', 'UTC');
date_default_timezone_set($timezone); date_default_timezone_set($timezone);

View File

@ -1,6 +1,6 @@
<?php <?php
/** /**
* Phergie * Phergie
* *
* PHP version 5 * PHP version 5
* *
@ -11,7 +11,7 @@
* It is also available through the world-wide-web at this URL: * It is also available through the world-wide-web at this URL:
* http://phergie.org/license * http://phergie.org/license
* *
* @category Phergie * @category Phergie
* @package Phergie * @package Phergie
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org) * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
@ -22,7 +22,7 @@
/** /**
* Data structure for connection metadata. * Data structure for connection metadata.
* *
* @category Phergie * @category Phergie
* @package Phergie * @package Phergie
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License * @license http://phergie.org/license New BSD License
@ -38,7 +38,7 @@ class Phergie_Connection
protected $host; protected $host;
/** /**
* Port on which the client will connect, defaults to the standard IRC * Port on which the client will connect, defaults to the standard IRC
* port * port
* *
* @var int * @var int
@ -46,13 +46,21 @@ class Phergie_Connection
protected $port; protected $port;
/** /**
* Transport for the connection, defaults to tcp but can be set to ssl * Transport for the connection, defaults to tcp but can be set to ssl
* or variations thereof to connect over SSL * or variations thereof to connect over SSL
* *
* @var string * @var string
*/ */
protected $transport; protected $transport;
/**
* Encoding method for the connection, defaults to ISO-8859-1 but can
* be set to UTF8 if necessary
*
* @var strng
*/
protected $encoding;
/** /**
* Nick that the client will use * Nick that the client will use
* *
@ -91,7 +99,7 @@ class Phergie_Connection
/** /**
* Constructor to initialize instance properties. * Constructor to initialize instance properties.
* *
* @param array $options Optional associative array of property values * @param array $options Optional associative array of property values
* to initialize * to initialize
* *
* @return void * @return void
@ -99,6 +107,9 @@ class Phergie_Connection
public function __construct(array $options = array()) public function __construct(array $options = array())
{ {
$this->transport = 'tcp'; $this->transport = 'tcp';
$this->encoding = 'ISO-8859-1';
// @note this may need changed to something different, for broader support.
// @note also may need to make use of http://us.php.net/manual/en/function.stream-encoding.php
$this->setOptions($options); $this->setOptions($options);
} }
@ -120,7 +131,7 @@ class Phergie_Connection
); );
} }
} }
/** /**
* Returns a hostmask that uniquely identifies the connection. * Returns a hostmask that uniquely identifies the connection.
* *
@ -136,7 +147,7 @@ class Phergie_Connection
); );
} }
return $this->hostmask; return $this->hostmask;
} }
/** /**
@ -144,7 +155,7 @@ class Phergie_Connection
* *
* @param string $host Hostname * @param string $host Hostname
* *
* @return Phergie_Connection Provides a fluent interface * @return Phergie_Connection Provides a fluent interface
*/ */
public function setHost($host) public function setHost($host)
{ {
@ -154,9 +165,9 @@ class Phergie_Connection
return $this; return $this;
} }
/** /**
* Returns the host to which the client will connect if it is set or * Returns the host to which the client will connect if it is set or
* emits an error if it is not set. * emits an error if it is not set.
* *
* @return string * @return string
@ -173,7 +184,7 @@ class Phergie_Connection
* *
* @param int $port Port * @param int $port Port
* *
* @return Phergie_Connection Provides a fluent interface * @return Phergie_Connection Provides a fluent interface
*/ */
public function setPort($port) public function setPort($port)
{ {
@ -199,9 +210,9 @@ class Phergie_Connection
} }
/** /**
* Sets the transport for the connection to use. * Sets the transport for the connection to use.
* *
* @param string $transport Transport (ex: tcp, ssl, etc.) * @param string $transport Transport (ex: tcp, ssl, etc.)
* *
* @return Phergie_Connection Provides a fluent interface * @return Phergie_Connection Provides a fluent interface
*/ */
@ -220,21 +231,52 @@ class Phergie_Connection
} }
/** /**
* Returns the transport in use by the connection. * Returns the transport in use by the connection.
* *
* @return string Transport (ex: tcp, ssl, etc.) * @return string Transport (ex: tcp, ssl, etc.)
*/ */
public function getTransport() public function getTransport()
{ {
return $this->transport; return $this->transport;
} }
/**
* Sets the encoding for the connection to use.
*
* @param string $encoding Encoding to use (ex: ASCII, ISO-8859-1, UTF8, etc.)
*
* @return Phergie_Connection Provides a fluent interface
*/
public function setEncoding($encoding)
{
$this->encoding = (string) $encoding;
if (!in_array($this->encoding, mb_list_encodings())) {
throw new Phergie_Connection_Exception(
'Encoding ' . $this->encoding . ' is not supported',
Phergie_Connection_Exception::ENCODING_NOT_SUPPORTED
);
}
return $this;
}
/**
* Returns the encoding in use by the connection.
*
* @return string Encoding (ex: ASCII, ISO-8859-1, UTF8, etc.)
*/
public function getEncoding()
{
return $this->encoding;
}
/** /**
* Sets the nick that the client will use. * Sets the nick that the client will use.
* *
* @param string $nick Nickname * @param string $nick Nickname
* *
* @return Phergie_Connection Provides a fluent interface * @return Phergie_Connection Provides a fluent interface
*/ */
public function setNick($nick) public function setNick($nick)
{ {
@ -262,7 +304,7 @@ class Phergie_Connection
* *
* @param string $username Username * @param string $username Username
* *
* @return Phergie_Connection Provides a fluent interface * @return Phergie_Connection Provides a fluent interface
*/ */
public function setUsername($username) public function setUsername($username)
{ {
@ -290,7 +332,7 @@ class Phergie_Connection
* *
* @param string $realname Real name * @param string $realname Real name
* *
* @return Phergie_Connection Provides a fluent interface * @return Phergie_Connection Provides a fluent interface
*/ */
public function setRealname($realname) public function setRealname($realname)
{ {
@ -318,7 +360,7 @@ class Phergie_Connection
* *
* @param string $password Password * @param string $password Password
* *
* @return Phergie_Connection Provides a fluent interface * @return Phergie_Connection Provides a fluent interface
*/ */
public function setPassword($password) public function setPassword($password)
{ {
@ -342,10 +384,10 @@ class Phergie_Connection
/** /**
* Sets multiple connection settings using an array. * Sets multiple connection settings using an array.
* *
* @param array $options Associative array of setting names mapped to * @param array $options Associative array of setting names mapped to
* corresponding values * corresponding values
* *
* @return Phergie_Connection Provides a fluent interface * @return Phergie_Connection Provides a fluent interface
*/ */
public function setOptions(array $options) public function setOptions(array $options)
{ {

View File

@ -0,0 +1,39 @@
<?php
/**
* Phergie
*
* PHP version 5
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.
* It is also available through the world-wide-web at this URL:
* http://phergie.org/license
*
* @category Phergie
* @package Phergie
* @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org)
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie
*/
/**
* Exceptions related to handling databases for plugins.
*
* @category Phergie
* @package Phergie
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie
*/
class Phergie_Db_Exception extends Phergie_Exception
{
/**
* Error indicating that a directory needed to support database
* functionality was unable to be created.
*/
const ERR_UNABLE_TO_CREATE_DIRECTORY = 1;
}

View File

@ -0,0 +1,49 @@
<?php
/**
* Phergie
*
* PHP version 5
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.
* It is also available through the world-wide-web at this URL:
* http://phergie.org/license
*
* @category Phergie
* @package Phergie
* @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org)
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Command
*/
/**
* Database management class. Provides a base API for managing databases
* within
*
* @category Phergie
* @package Phergie
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Db_Manager
*/
abstract class Phergie_Db_Manager
{
/**
* Returns a connection to the database.
*
* @return object
*/
public abstract function getDb();
/**
* Checks if a table/collection exists within the database.
*
* @param string $table Table/collection name to check for
*
* @return boolean
*/
public abstract function hasTable($table);
}

View File

@ -0,0 +1,117 @@
<?php
/**
* Phergie
*
* PHP version 5
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.
* It is also available through the world-wide-web at this URL:
* http://phergie.org/license
*
* @category Phergie
* @package Phergie
* @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org)
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie
*/
/**
* Provides basic management for SQLite databases
*
* @category Phergie
* @package Phergie
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie
*/
class Phergie_Db_Sqlite extends Phergie_Db_Manager
{
/**
* Database connection
*
* @var PDO
*/
protected $db;
/**
* Database file path
*
* @var string
*/
protected $dbFile;
/**
* Allows setting of the database file path when creating the class.
*
* @param string $dbFile database file path (optional)
*
* @return void
*/
public function __construct($dbFile = null)
{
if ($dbFile != null) {
$this->setDbFile($dbFile);
}
}
/**
* Sets the database file path.
*
* @param string $dbFile SQLite database file path
*
* @return null
*/
public function setDbFile($dbFile)
{
if (is_string($dbFile) && !empty($dbFile)) {
$this->dbFile = $dbFile;
}
}
/**
* Returns a configured database connection.
*
* @return PDO
*/
public function getDb()
{
if (!empty($this->db)) {
return $this->db;
}
$dir = dirname($this->dbFile);
if (!is_dir($dir) && !mkdir($dir, 0755, true)) {
throw new Phergie_Db_Exception(
'Unable to create directory',
Phergie_Db_Exception::ERR_UNABLE_TO_CREATE_DIRECTORY
);
}
$this->db = new PDO('sqlite:' . $this->dbFile);
return $this->db;
}
/**
* Returns whether a given table exists in the database.
*
* @param string $table Name of the table to check for
*
* @return boolean TRUE if the table exists, FALSE otherwise
*/
public function hasTable($table)
{
$db = $this->getDb();
return (bool) $db->query(
'SELECT COUNT(*) FROM sqlite_master WHERE name = '
. $db->quote($table)
)->fetchColumn();
}
}

View File

@ -46,4 +46,9 @@ class Phergie_Driver_Exception extends Phergie_Exception
* Error indicating that an attempt to initiate a connection failed * Error indicating that an attempt to initiate a connection failed
*/ */
const ERR_CONNECTION_ATTEMPT_FAILED = 3; const ERR_CONNECTION_ATTEMPT_FAILED = 3;
/**
* Error indicating that an attempt to send data via a connection failed
*/
const ERR_CONNECTION_WRITE_FAILED = 4;
} }

View File

@ -1,6 +1,6 @@
<?php <?php
/** /**
* Phergie * Phergie
* *
* PHP version 5 * PHP version 5
* *
@ -11,7 +11,7 @@
* It is also available through the world-wide-web at this URL: * It is also available through the world-wide-web at this URL:
* http://phergie.org/license * http://phergie.org/license
* *
* @category Phergie * @category Phergie
* @package Phergie * @package Phergie
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org) * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
@ -20,11 +20,11 @@
*/ */
/** /**
* Driver that uses the sockets wrapper of the streams extension for * Driver that uses the sockets wrapper of the streams extension for
* communicating with the server and handles formatting and parsing of * communicating with the server and handles formatting and parsing of
* events using PHP. * events using PHP.
* *
* @category Phergie * @category Phergie
* @package Phergie * @package Phergie
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License * @license http://phergie.org/license New BSD License
@ -47,26 +47,29 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
protected $socket; protected $socket;
/** /**
* Amount of time in seconds to wait to receive an event each time the * Amount of time in seconds to wait to receive an event each time the
* socket is polled * socket is polled
* *
* @var float * @var float
*/ */
protected $timeout = 0.1; protected $timeout = 0.1;
/** /**
* Handles construction of command strings and their transmission to the * Handles construction of command strings and their transmission to the
* server. * server.
* *
* @param string $command Command to send * @param string $command Command to send
* @param string|array $args Optional string or array of sequential * @param string|array $args Optional string or array of sequential
* arguments * arguments
* *
* @return string Command string that was sent * @return string Command string that was sent
* @throws Phergie_Driver_Exception * @throws Phergie_Driver_Exception
*/ */
protected function send($command, $args = '') protected function send($command, $args = '')
{ {
$connection = $this->getConnection();
$encoding = $connection->getEncoding();
// Require an open socket connection to continue // Require an open socket connection to continue
if (empty($this->socket)) { if (empty($this->socket)) {
throw new Phergie_Driver_Exception( throw new Phergie_Driver_Exception(
@ -86,20 +89,40 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
$end = count($args) - 1; $end = count($args) - 1;
$args[$end] = ':' . $args[$end]; $args[$end] = ':' . $args[$end];
$args = implode(' ', $args); $args = implode(' ', $args);
} else {
$args = ':' . $args;
} }
$buffer .= ' ' . $args; $buffer .= ' ' . $args;
} }
// Transmit the command over the socket connection // Transmit the command over the socket connection
fwrite($this->socket, $buffer . "\r\n"); $attempts = $written = 0;
$temp = $buffer . "\r\n";
$is_multibyte = !substr($encoding, 0, 8) === 'ISO-8859' && $encoding !== 'ASCII' && $encoding !== 'CP1252';
$length = ($is_multibyte) ? mb_strlen($buffer, '8bit') : strlen($buffer);
while (true) {
$written += (int) fwrite($this->socket, $temp);
if ($written < $length) {
$temp = substr($temp, $written);
$attempts++;
if ($attempts == 3) {
throw new Phergie_Driver_Exception(
'Unable to write to socket',
Phergie_Driver_Exception::ERR_CONNECTION_WRITE_FAILED
);
}
} else {
break;
}
}
// Return the command string that was transmitted // Return the command string that was transmitted
return $buffer; return $buffer;
} }
/** /**
* Overrides the parent class to set the currently active socket handler * Overrides the parent class to set the currently active socket handler
* when the active connection is changed. * when the active connection is changed.
* *
* @param Phergie_Connection $connection Active connection * @param Phergie_Connection $connection Active connection
@ -120,11 +143,11 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
/** /**
* Returns a list of hostmasks corresponding to sockets with data to read. * Returns a list of hostmasks corresponding to sockets with data to read.
* *
* @param int $sec Length of time to wait for new data (seconds) * @param int $sec Length of time to wait for new data (seconds)
* @param int $usec Length of time to wait for new data (microseconds) * @param int $usec Length of time to wait for new data (microseconds)
* *
* @return array List of hostmasks or an empty array if none were found * @return array List of hostmasks or an empty array if none were found
* to have data to read * to have data to read
*/ */
public function getActiveReadSockets($sec = 0, $usec = 200000) public function getActiveReadSockets($sec = 0, $usec = 200000)
@ -147,7 +170,7 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
} }
/** /**
* Sets the amount of time to wait for a new event each time the socket * Sets the amount of time to wait for a new event each time the socket
* is polled. * is polled.
* *
* @param float $timeout Amount of time in seconds * @param float $timeout Amount of time in seconds
@ -164,7 +187,7 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
} }
/** /**
* Returns the amount of time to wait for a new event each time the * Returns the amount of time to wait for a new event each time the
* socket is polled. * socket is polled.
* *
* @return float Amount of time in seconds * @return float Amount of time in seconds
@ -175,7 +198,7 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
} }
/** /**
* Supporting method to parse event argument strings where the last * Supporting method to parse event argument strings where the last
* argument may contain a colon. * argument may contain a colon.
* *
* @param string $args Argument string to parse * @param string $args Argument string to parse
@ -191,7 +214,7 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
/** /**
* Listens for an event on the current connection. * Listens for an event on the current connection.
* *
* @return Phergie_Event_Interface|null Event instance if an event was * @return Phergie_Event_Interface|null Event instance if an event was
* received, NULL otherwise * received, NULL otherwise
*/ */
public function getEvent() public function getEvent()
@ -217,7 +240,7 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
// If the event could be from the server or a user... // If the event could be from the server or a user...
// Parse the server hostname or user hostmask, command, and arguments // Parse the server hostname or user hostmask, command, and arguments
list($prefix, $cmd, $args) list($prefix, $cmd, $args)
= array_pad(explode(' ', ltrim($buffer, ':'), 3), 3, null); = array_pad(explode(' ', ltrim($buffer, ':'), 3), 3, null);
if (strpos($prefix, '@') !== false) { if (strpos($prefix, '@') !== false) {
$hostmask = Phergie_Hostmask::fromString($prefix); $hostmask = Phergie_Hostmask::fromString($prefix);
@ -279,17 +302,17 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
case 'oper': case 'oper':
case 'topic': case 'topic':
case 'mode': case 'mode':
$args = $this->parseArguments($args); $args = $this->parseArguments($args);
break; break;
case 'part': case 'part':
case 'kill': case 'kill':
case 'invite': case 'invite':
$args = $this->parseArguments($args, 2); $args = $this->parseArguments($args, 2);
break; break;
case 'kick': case 'kick':
$args = $this->parseArguments($args, 3); $args = $this->parseArguments($args, 3);
break; break;
// Remove the target from responses // Remove the target from responses
@ -360,14 +383,14 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
$this->send( $this->send(
'USER', 'USER',
array( array(
$username, $username,
$hostname, $hostname,
$hostname, $hostname,
$realname $realname
) )
); );
$this->send('NICK', $nick); $this->send('NICK', $nick);
// Add the socket handler to the internal array for socket handlers // Add the socket handler to the internal array for socket handlers
$this->sockets[(string) $connection->getHostmask()] = $this->socket; $this->sockets[(string) $connection->getHostmask()] = $this->socket;
@ -395,7 +418,7 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
/** /**
* Joins a channel. * Joins a channel.
* *
* @param string $channels Comma-delimited list of channels to join * @param string $channels Comma-delimited list of channels to join
* @param string $keys Optional comma-delimited list of channel keys * @param string $keys Optional comma-delimited list of channel keys
* *
* @return void * @return void
@ -414,7 +437,7 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
/** /**
* Leaves a channel. * Leaves a channel.
* *
* @param string $channels Comma-delimited list of channels to leave * @param string $channels Comma-delimited list of channels to leave
* *
* @return void * @return void
*/ */
@ -600,9 +623,9 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
/** /**
* Sends a CTCP response to a user. * Sends a CTCP response to a user.
* *
* @param string $nick User nick * @param string $nick User nick
* @param string $command Command to send * @param string $command Command to send
* @param string|array $args String or array of sequential arguments * @param string|array $args String or array of sequential arguments
* (optional) * (optional)
* *
* @return void * @return void
@ -615,7 +638,7 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
$buffer = rtrim(strtoupper($command) . ' ' . $args); $buffer = rtrim(strtoupper($command) . ' ' . $args);
$this->doNotice($nick, chr(1) . $buffer . chr(1)); $this->doNotice($nick, chr(1) . $buffer . chr(1));
} }
/** /**
@ -652,7 +675,7 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
* Sends a CTCP TIME request to a user. * Sends a CTCP TIME request to a user.
* *
* @param string $nick User nick * @param string $nick User nick
* @param string $time Time string to send for a response * @param string $time Time string to send for a response
* *
* @return void * @return void
*/ */

View File

@ -1,6 +1,6 @@
<?php <?php
/** /**
* Phergie * Phergie
* *
* PHP version 5 * PHP version 5
* *
@ -11,7 +11,7 @@
* It is also available through the world-wide-web at this URL: * It is also available through the world-wide-web at this URL:
* http://phergie.org/license * http://phergie.org/license
* *
* @category Phergie * @category Phergie
* @package Phergie * @package Phergie
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org) * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
@ -20,9 +20,9 @@
*/ */
/** /**
* Handles events initiated by plugins. * Handles events initiated by plugins.
* *
* @category Phergie * @category Phergie
* @package Phergie * @package Phergie
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License * @license http://phergie.org/license New BSD License
@ -51,13 +51,13 @@ class Phergie_Event_Handler implements IteratorAggregate, Countable
* Adds an event to the queue. * Adds an event to the queue.
* *
* @param Phergie_Plugin_Abstract $plugin Plugin originating the event * @param Phergie_Plugin_Abstract $plugin Plugin originating the event
* @param string $type Event type, corresponding to a * @param string $type Event type, corresponding to a
* Phergie_Event_Command::TYPE_* constant * Phergie_Event_Command::TYPE_* constant
* @param array $args Optional event arguments * @param array $args Optional event arguments
* *
* @return Phergie_Event_Handler Provides a fluent interface * @return Phergie_Event_Handler Provides a fluent interface
*/ */
public function addEvent(Phergie_Plugin_Abstract $plugin, $type, public function addEvent(Phergie_Plugin_Abstract $plugin, $type,
array $args = array() array $args = array()
) { ) {
if (!defined('Phergie_Event_Command::TYPE_' . strtoupper($type))) { if (!defined('Phergie_Event_Command::TYPE_' . strtoupper($type))) {
@ -102,7 +102,7 @@ class Phergie_Event_Handler implements IteratorAggregate, Countable
/** /**
* Replaces the current event queue with a given queue of events. * Replaces the current event queue with a given queue of events.
* *
* @param array $events Ordered list of objects of the class * @param array $events Ordered list of objects of the class
* Phergie_Event_Command * Phergie_Event_Command
* *
* @return Phergie_Event_Handler Provides a fluent interface * @return Phergie_Event_Handler Provides a fluent interface
@ -116,10 +116,10 @@ class Phergie_Event_Handler implements IteratorAggregate, Countable
/** /**
* Returns whether an event of the given type exists in the queue. * Returns whether an event of the given type exists in the queue.
* *
* @param string $type Event type from Phergie_Event_Request::TYPE_* * @param string $type Event type from Phergie_Event_Request::TYPE_*
* constants * constants
* *
* @return bool TRUE if an event of the specified type exists in the * @return bool TRUE if an event of the specified type exists in the
* queue, FALSE otherwise * queue, FALSE otherwise
*/ */
public function hasEventOfType($type) public function hasEventOfType($type)
@ -135,10 +135,10 @@ class Phergie_Event_Handler implements IteratorAggregate, Countable
/** /**
* Returns a list of events of a specified type. * Returns a list of events of a specified type.
* *
* @param string $type Event type from Phergie_Event_Request::TYPE_* * @param string $type Event type from Phergie_Event_Request::TYPE_*
* constants * constants
* *
* @return array Array containing event instances of the specified type * @return array Array containing event instances of the specified type
* or an empty array if no such events were found * or an empty array if no such events were found
*/ */
public function getEventsOfType($type) public function getEventsOfType($type)
@ -152,6 +152,22 @@ class Phergie_Event_Handler implements IteratorAggregate, Countable
return $events; return $events;
} }
/**
* Removes a single event from the event queue.
*
* @param Phergie_Event_Command $event Event to remove
*
* @return Phergie_Event_Handler Provides a fluent interface
*/
public function removeEvent(Phergie_Event_Command $event)
{
$key = array_search($event, $this->events);
if ($key !== false) {
unset($this->events[$key]);
}
return $this;
}
/** /**
* Returns an iterator for the current event queue. * Returns an iterator for the current event queue.
* *

View File

@ -1,6 +1,6 @@
<?php <?php
/** /**
* Phergie * Phergie
* *
* PHP version 5 * PHP version 5
* *
@ -11,7 +11,7 @@
* It is also available through the world-wide-web at this URL: * It is also available through the world-wide-web at this URL:
* http://phergie.org/license * http://phergie.org/license
* *
* @category Phergie * @category Phergie
* @package Phergie * @package Phergie
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org) * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
@ -22,15 +22,15 @@
/** /**
* Autonomous event originating from a user or the server. * Autonomous event originating from a user or the server.
* *
* @category Phergie * @category Phergie
* @package Phergie * @package Phergie
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License * @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie * @link http://pear.phergie.org/package/Phergie
* @link http://www.irchelp.org/irchelp/rfc/chapter4.html * @link http://www.irchelp.org/irchelp/rfc/chapter4.html
*/ */
class Phergie_Event_Request class Phergie_Event_Request
extends Phergie_Event_Abstract extends Phergie_Event_Abstract
implements ArrayAccess implements ArrayAccess
{ {
/** /**
@ -240,6 +240,24 @@ class Phergie_Event_Request
return $this; return $this;
} }
/**
* Sets the value of a single argument for the request.
*
* @param mixed $argument Integer position (starting from 0) or the
* equivalent string name of the argument from self::$map
* @param string $value Value to assign to the argument
*
* @return Phergie_Event_Request Provides a fluent interface
*/
public function setArgument($argument, $value)
{
$argument = $this->resolveArgument($argument);
if ($argument !== null) {
$this->arguments[$argument] = (string) $value;
}
return $this;
}
/** /**
* Returns the arguments for the request. * Returns the arguments for the request.
* *
@ -256,13 +274,13 @@ class Phergie_Event_Request
* @param mixed $argument Integer position (starting from 0) or the * @param mixed $argument Integer position (starting from 0) or the
* equivalent string name of the argument from self::$map * equivalent string name of the argument from self::$map
* *
* @return int|null Integer position of the argument or NULL if no * @return int|null Integer position of the argument or NULL if no
* corresponding argument was found * corresponding argument was found
*/ */
protected function resolveArgument($argument) protected function resolveArgument($argument)
{ {
if (isset($this->arguments[$argument])) { if (isset($this->arguments[$argument])) {
return $argument; return $argument;
} else { } else {
$argument = strtolower($argument); $argument = strtolower($argument);
if (isset(self::$map[$this->type][$argument]) if (isset(self::$map[$this->type][$argument])
@ -285,7 +303,7 @@ class Phergie_Event_Request
public function getArgument($argument) public function getArgument($argument)
{ {
$argument = $this->resolveArgument($argument); $argument = $this->resolveArgument($argument);
if ($argument !== null) { if ($argument !== null) {
return $this->arguments[$argument]; return $this->arguments[$argument];
} }
return null; return null;
@ -325,9 +343,9 @@ class Phergie_Event_Request
} }
/** /**
* Returns the channel name if the event occurred in a channel or the * Returns the channel name if the event occurred in a channel or the
* user nick if the event was a private message directed at the bot by a * user nick if the event was a private message directed at the bot by a
* user. * user.
* *
* @return string * @return string
*/ */
@ -395,7 +413,7 @@ class Phergie_Event_Request
* *
* @param string|int $offset Argument name or position beginning from 0 * @param string|int $offset Argument name or position beginning from 0
* *
* @return bool TRUE if the argument has a value, FALSE otherwise * @return bool TRUE if the argument has a value, FALSE otherwise
* @see ArrayAccess::offsetExists() * @see ArrayAccess::offsetExists()
*/ */
public function offsetExists($offset) public function offsetExists($offset)
@ -428,7 +446,7 @@ class Phergie_Event_Request
public function offsetSet($offset, $value) public function offsetSet($offset, $value)
{ {
$offset = $this->resolveArgument($offset); $offset = $this->resolveArgument($offset);
if ($offset !== null) { if ($offset !== null) {
$this->arguments[$offset] = $value; $this->arguments[$offset] = $value;
} }
} }

View File

@ -1,6 +1,6 @@
<?php <?php
/** /**
* Phergie * Phergie
* *
* PHP version 5 * PHP version 5
* *
@ -11,7 +11,7 @@
* It is also available through the world-wide-web at this URL: * It is also available through the world-wide-web at this URL:
* http://phergie.org/license * http://phergie.org/license
* *
* @category Phergie * @category Phergie
* @package Phergie * @package Phergie
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org) * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
@ -23,7 +23,7 @@
* Base class for plugins to provide event handler stubs and commonly needed * Base class for plugins to provide event handler stubs and commonly needed
* functionality. * functionality.
* *
* @category Phergie * @category Phergie
* @package Phergie * @package Phergie
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License * @license http://phergie.org/license New BSD License
@ -66,6 +66,13 @@ abstract class Phergie_Plugin_Abstract
*/ */
protected $event; protected $event;
/**
* Plugin short name
*
* @var string
*/
protected $name;
/** /**
* Returns the short name for the plugin based on its class name. * Returns the short name for the plugin based on its class name.
* *
@ -73,14 +80,30 @@ abstract class Phergie_Plugin_Abstract
*/ */
public function getName() public function getName()
{ {
return substr(strrchr(get_class($this), '_'), 1); if (empty($this->name)) {
$this->name = substr(strrchr(get_class($this), '_'), 1);
}
return $this->name;
} }
/** /**
* Indicates that the plugin failed to load due to an unsatisfied * Sets the short name for the plugin.
*
* @param string $name Plugin short name
*
* @return Phergie_Plugin_Abstract Provides a fluent interface
*/
public function setName($name)
{
$this->name = (string) $name;
return $this;
}
/**
* Indicates that the plugin failed to load due to an unsatisfied
* runtime requirement, such as a missing dependency. * runtime requirement, such as a missing dependency.
* *
* @param string $message Error message to provide more information * @param string $message Error message to provide more information
* about the reason for the failure * about the reason for the failure
* *
* @return Phergie_Plugin_Abstract Provides a fluent interface * @return Phergie_Plugin_Abstract Provides a fluent interface
@ -108,17 +131,17 @@ abstract class Phergie_Plugin_Abstract
} }
/** /**
* Returns the current configuration handler or the value of a single * Returns the current configuration handler or the value of a single
* setting from it. * setting from it.
* *
* @param string $name Optional name of a setting for which the value * @param string $name Optional name of a setting for which the value
* should be returned instead of the entire configuration handler * should be returned instead of the entire configuration handler
* @param mixed $default Optional default value to return if no value * @param mixed $default Optional default value to return if no value
* is set for the setting indicated by $name * is set for the setting indicated by $name
* *
* @return Phergie_Config|mixed Configuration handler or value of the * @return Phergie_Config|mixed Configuration handler or value of the
* setting specified by $name * setting specified by $name
* @throws Phergie_Plugin_Exception No configuration handler has been set * @throws Phergie_Plugin_Exception No configuration handler has been set
*/ */
public function getConfig($name = null, $default = null) public function getConfig($name = null, $default = null)
{ {
@ -154,7 +177,7 @@ abstract class Phergie_Plugin_Abstract
* Returns the current plugin handler. * Returns the current plugin handler.
* *
* @return Phergie_Plugin_Handler * @return Phergie_Plugin_Handler
* @throws Phergie_Plugin_Exception No plugin handler has been set * @throws Phergie_Plugin_Exception No plugin handler has been set
*/ */
public function getPluginHandler() public function getPluginHandler()
{ {
@ -184,7 +207,7 @@ abstract class Phergie_Plugin_Abstract
* Returns the current event handler. * Returns the current event handler.
* *
* @return Phergie_Event_Handler * @return Phergie_Event_Handler
* @throws Phergie_Plugin_Exception No event handler has been set * @throws Phergie_Plugin_Exception No event handler has been set
*/ */
public function getEventHandler() public function getEventHandler()
{ {
@ -214,7 +237,7 @@ abstract class Phergie_Plugin_Abstract
* Returns the current event connection. * Returns the current event connection.
* *
* @return Phergie_Connection * @return Phergie_Connection
* @throws Phergie_Plugin_Exception No connection has been set * @throws Phergie_Plugin_Exception No connection has been set
*/ */
public function getConnection() public function getConnection()
{ {
@ -281,8 +304,8 @@ abstract class Phergie_Plugin_Abstract
} }
/** /**
* Handler for when the plugin is initially loaded - useful for checking * Handler for when the plugin is initially loaded - useful for checking
* runtime dependencies or performing any setup necessary for the plugin * runtime dependencies or performing any setup necessary for the plugin
* to function properly such as initializing a database. * to function properly such as initializing a database.
* *
* @return void * @return void
@ -301,8 +324,8 @@ abstract class Phergie_Plugin_Abstract
} }
/** /**
* Handler for each tick, a single iteration of the continuous loop * Handler for each tick, a single iteration of the continuous loop
* executed by the bot to receive, handle, and send events - useful for * executed by the bot to receive, handle, and send events - useful for
* repeated execution of tasks on a time interval. * repeated execution of tasks on a time interval.
* *
* @return void * @return void
@ -312,10 +335,10 @@ abstract class Phergie_Plugin_Abstract
} }
/** /**
* Handler for when any event is received but has not yet been dispatched * Handler for when any event is received but has not yet been dispatched
* to the plugin handler method specific to its event type. * to the plugin handler method specific to its event type.
* *
* @return bool|null|void FALSE to short-circuit further event * @return bool|null|void FALSE to short-circuit further event
* processing, TRUE or NULL otherwise * processing, TRUE or NULL otherwise
*/ */
public function preEvent() public function preEvent()
@ -323,8 +346,8 @@ abstract class Phergie_Plugin_Abstract
} }
/** /**
* Handler for after plugin processing of an event has concluded but * Handler for after plugin processing of an event has concluded but
* before any events triggered in response by plugins are sent to the * before any events triggered in response by plugins are sent to the
* server - useful for modifying outgoing events before they are sent. * server - useful for modifying outgoing events before they are sent.
* *
* @return void * @return void
@ -334,8 +357,8 @@ abstract class Phergie_Plugin_Abstract
} }
/** /**
* Handler for after any events triggered by plugins in response to a * Handler for after any events triggered by plugins in response to a
* received event are sent to the server. * received event are sent to the server.
* *
* @return void * @return void
*/ */
@ -454,12 +477,12 @@ abstract class Phergie_Plugin_Abstract
} }
/** /**
* Handler for when the bot receives a ping event from a server, at * Handler for when the bot receives a ping event from a server, at
* which point it is expected to respond with a pong request within * which point it is expected to respond with a pong request within
* a short period else the server may terminate its connection. * a short period else the server may terminate its connection.
* *
* @return void * @return void
* @link http://irchelp.org/irchelp/rfc/chapter4.html#c4_6_2 * @link http://irchelp.org/irchelp/rfc/chapter4.html#c4_6_2
*/ */
public function onPing() public function onPing()
{ {
@ -496,7 +519,7 @@ abstract class Phergie_Plugin_Abstract
} }
/** /**
* Handler for when the bot receives a CTCP request of an unknown type. * Handler for when the bot receives a CTCP request of an unknown type.
* *
* @return void * @return void
* @link http://www.invlogic.com/irc/ctcp.html * @link http://www.invlogic.com/irc/ctcp.html
@ -506,7 +529,7 @@ abstract class Phergie_Plugin_Abstract
} }
/** /**
* Handler for when a reply is received for a CTCP PING request sent by * Handler for when a reply is received for a CTCP PING request sent by
* the bot. * the bot.
* *
* @return void * @return void
@ -517,7 +540,7 @@ abstract class Phergie_Plugin_Abstract
} }
/** /**
* Handler for when a reply is received for a CTCP TIME request sent by * Handler for when a reply is received for a CTCP TIME request sent by
* the bot. * the bot.
* *
* @return void * @return void
@ -528,7 +551,7 @@ abstract class Phergie_Plugin_Abstract
} }
/** /**
* Handler for when a reply is received for a CTCP VERSION request sent * Handler for when a reply is received for a CTCP VERSION request sent
* by the bot. * by the bot.
* *
* @return void * @return void
@ -539,7 +562,7 @@ abstract class Phergie_Plugin_Abstract
} }
/** /**
* Handler for when a reply received for a CTCP request of an unknown * Handler for when a reply received for a CTCP request of an unknown
* type. * type.
* *
* @return void * @return void
@ -560,7 +583,7 @@ abstract class Phergie_Plugin_Abstract
} }
/** /**
* Handler for when the bot receives an invitation to join a channel. * Handler for when the bot receives an invitation to join a channel.
* *
* @return void * @return void
* @link http://irchelp.org/irchelp/rfc/chapter4.html#c4_2_7 * @link http://irchelp.org/irchelp/rfc/chapter4.html#c4_2_7
@ -570,7 +593,7 @@ abstract class Phergie_Plugin_Abstract
} }
/** /**
* Handler for when a server response is received to a command issued by * Handler for when a server response is received to a command issued by
* the bot. * the bot.
* *
* @return void * @return void

View File

@ -0,0 +1,108 @@
<?php
/**
* Phergie
*
* PHP version 5
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.
* It is also available through the world-wide-web at this URL:
* http://phergie.org/license
*
* @category Phergie
* @package Phergie_Plugin_Censor
* @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org)
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Censor
*/
/**
* Facilitates censoring of event content or discardment of events
* containing potentially offensive phrases depending on the value of the
* configuration setting censor.mode ('off', 'censor', 'discard'). Also
* provides access to a web service for detecting censored words so that
* other plugins may optionally integrate and adjust behavior accordingly to
* prevent discardment of events.
*
* @category Phergie
* @package Phergie_Plugin_Censor
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Censor
* @uses extension soap
*/
class Phergie_Plugin_Censor extends Phergie_Plugin_Abstract
{
/**
* SOAP client to interact with the CDYNE Profanity Filter API
*
* @var SoapClient
*/
protected $soap;
/**
* Checks for dependencies.
*
* @return void
*/
public function onLoad()
{
if (!extension_loaded('soap')) {
$this->fail('The PHP soap extension is required');
}
if (!in_array($this->config['censor.mode'], array('censor', 'discard'))) {
$this->plugins->removePlugin($this);
}
}
/**
* Returns a "clean" version of a given string.
*
* @param string $string String to clean
*
* @return string Cleaned string
*/
public function cleanString($string)
{
if (empty($this->soap)) {
$this->soap = new SoapClient('http://ws.cdyne.com/ProfanityWS/Profanity.asmx?wsdl');
}
$params = array('Text' => $string);
$response = $this->soap->SimpleProfanityFilter($params);
return $response->SimpleProfanityFilterResult->CleanText;
}
/**
* Processes events before they are dispatched and either censors their
* content or discards them if they contain potentially offensive
* content.
*
* @return void
*/
public function preDispatch()
{
$events = $this->events->getEvents();
foreach ($events as $event) {
switch ($event->getType()) {
case Phergie_Event_Request::TYPE_PRIVMSG:
case Phergie_Event_Request::TYPE_ACTION:
case Phergie_Event_Request::TYPE_NOTICE:
$text = $event->getArgument(1);
$clean = $this->cleanString($text);
if ($text != $clean) {
if ($this->config['censor.mode'] == 'censor') {
$event->setArgument(1, $clean);
} else {
$this->events->removeEvent($event);
}
}
break;
}
}
}
}

View File

@ -0,0 +1,147 @@
<?php
/**
* Phergie
*
* PHP version 5
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.
* It is also available through the world-wide-web at this URL:
* http://phergie.org/license
*
* @category Phergie
* @package Phergie_Plugin_Cron
* @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org)
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Cron
*/
/**
* Allows callbacks to be registered for asynchronous execution.
*
* @category Phergie
* @package Phergie_Plugin_Cron
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Cron
*/
class Phergie_Plugin_Cron extends Phergie_Plugin_Abstract
{
/**
* Array of all registered callbacks with delays and arguments
*
* @var array
*/
protected $callbacks;
/**
* Returns a human-readable representation of a callback for debugging
* purposes.
*
* @param callback $callback Callback to analyze
*
* @return string|boolean String representation of the callback or FALSE
* if the specified value is not a valid callback
*/
protected function getCallbackString($callback)
{
if (!is_callable($callback)) {
return false;
}
if (is_array($callback)) {
$class = is_string($callback[0]) ?
$callback[0] : get_class($callback[0]);
$method = $class . '::' . $callback[1];
return $method;
}
return $callback;
}
/**
* Registers a callback for execution sometime after a given delay
* relative to now.
*
* @param callback $callback Callback to be registered
* @param int $delay Delay in seconds from now when the callback
* will be executed
* @param array $arguments Arguments to pass to the callback when
* it's executed
* @param bool $repeat TRUE to automatically re-register the
* callback for the same delay after it's executed, FALSE
* otherwise
*
* @return void
*/
public function registerCallback($callback, $delay,
array $arguments = array(), $repeat = false)
{
$callbackString = $this->getCallbackString($callback);
if ($callbackString === false) {
echo 'DEBUG(Cron): Invalid callback specified - ',
var_export($callback, true), PHP_EOL;
return;
}
$registered = time();
$scheduled = $registered + $delay;
$this->callbacks[] = array(
'callback' => $callback,
'delay' => $delay,
'arguments' => $arguments,
'registered' => $registered,
'scheduled' => $scheduled,
'repeat' => $repeat,
);
echo 'DEBUG(Cron): Callback ', $callbackString,
' scheduled for ', date('H:i:s', $scheduled), PHP_EOL;
}
/**
* Handles callback execution.
*
* @return void
*/
public function onTick()
{
$now = time();
foreach ($this->callbacks as $key => &$callback) {
$callbackString = $this->getCallbackString($callback);
$scheduled = $callback['scheduled'];
if ($time < $scheduled) {
continue;
}
if (empty($callback['arguments'])) {
call_user_func($callback['callback']);
} else {
call_user_func_array(
$callback['callback'],
$callback['arguments']
);
}
echo 'DEBUG(Cron): Callback ', $callbackString,
' scheduled for ', date('H:i:s', $scheduled), ',',
' executed at ', date('H:i:s', $now), PHP_EOL;
if ($callback['repeat']) {
$callback['scheduled'] = $time + $callback['delay'];
echo 'DEBUG(Cron): Callback ', $callbackString,
' scheduled for ', date('H:i:s', $callback['scheduled']),
PHP_EOL;
} else {
echo 'DEBUG(Cron): Callback ', $callbackString,
' removed from callback list', PHP_EOL;
unset($this->callbacks[$key]);
}
}
}
}

View File

@ -1,6 +1,6 @@
<?php <?php
/** /**
* Phergie * Phergie
* *
* PHP version 5 * PHP version 5
* *
@ -11,7 +11,7 @@
* It is also available through the world-wide-web at this URL: * It is also available through the world-wide-web at this URL:
* http://phergie.org/license * http://phergie.org/license
* *
* @category Phergie * @category Phergie
* @package Phergie * @package Phergie
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org) * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
@ -22,7 +22,7 @@
/** /**
* Exception related to plugin handling. * Exception related to plugin handling.
* *
* @category Phergie * @category Phergie
* @package Phergie * @package Phergie
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License * @license http://phergie.org/license New BSD License
@ -31,82 +31,82 @@
class Phergie_Plugin_Exception extends Phergie_Exception class Phergie_Plugin_Exception extends Phergie_Exception
{ {
/** /**
* Error indicating that a path containing plugins was specified, but * Error indicating that a path containing plugins was specified, but
* did not reference a readable directory * did not reference a readable directory
*/ */
const ERR_DIRECTORY_NOT_READABLE = 1; const ERR_DIRECTORY_NOT_READABLE = 1;
/** /**
* Error indicating that an attempt was made to locate the class for a * Error indicating that an attempt was made to locate the class for a
* specified plugin, but the class could not be found * specified plugin, but the class could not be found
*/ */
const ERR_CLASS_NOT_FOUND = 2; const ERR_CLASS_NOT_FOUND = 2;
/** /**
* Error indicating that an attempt was made to locate the class for a * Error indicating that an attempt was made to locate the class for a
* specified plugin, but that the found class did not extend the base * specified plugin, but that the found class did not extend the base
* plugin class * plugin class
*/ */
const ERR_INCORRECT_BASE_CLASS = 3; const ERR_INCORRECT_BASE_CLASS = 3;
/** /**
* Error indicating that an attempt was made to locate the class for a * Error indicating that an attempt was made to locate the class for a
* specified plugin, but that the found class cannot be instantiated * specified plugin, but that the found class cannot be instantiated
*/ */
const ERR_CLASS_NOT_INSTANTIABLE = 4; const ERR_CLASS_NOT_INSTANTIABLE = 4;
/** /**
* Error indicating that an attempt was made to access a plugin that had * Error indicating that an attempt was made to access a plugin that had
* not been loaded and autoloading was not enabled to load it * not been loaded and autoloading was not enabled to load it
*/ */
const ERR_PLUGIN_NOT_LOADED = 5; const ERR_PLUGIN_NOT_LOADED = 5;
/** /**
* Error indicating that an attempt was made to access the configuration * Error indicating that an attempt was made to access the configuration
* handler before one had been set * handler before one had been set
*/ */
const ERR_NO_CONFIG_HANDLER = 6; const ERR_NO_CONFIG_HANDLER = 6;
/** /**
* Error indicating that an attempt was made to access the plugin * Error indicating that an attempt was made to access the plugin
* handler before one had been set * handler before one had been set
*/ */
const ERR_NO_PLUGIN_HANDLER = 7; const ERR_NO_PLUGIN_HANDLER = 7;
/** /**
* Error indicating that an attempt was made to access the event * Error indicating that an attempt was made to access the event
* handler before one had been set * handler before one had been set
*/ */
const ERR_NO_EVENT_HANDLER = 8; const ERR_NO_EVENT_HANDLER = 8;
/** /**
* Error indicating that an attempt was made to access the connection * Error indicating that an attempt was made to access the connection
* before one had been set * before one had been set
*/ */
const ERR_NO_CONNECTION = 9; const ERR_NO_CONNECTION = 9;
/** /**
* Error indicating that an attempt was made to access the current * Error indicating that an attempt was made to access the current
* incoming event before one had been set * incoming event before one had been set
*/ */
const ERR_NO_EVENT = 10; const ERR_NO_EVENT = 10;
/** /**
* Error indicating that a dependency of the plugin was unavailable at * Error indicating that a dependency of the plugin was unavailable at
* the time that an attempt was made to load it * the time that an attempt was made to load it
*/ */
const ERR_REQUIREMENT_UNSATISFIED = 11; const ERR_REQUIREMENT_UNSATISFIED = 11;
/** /**
* Error indicating that a call was made to a nonexistent plugin method * Error indicating that a call was made to a nonexistent plugin method
* and that its __call() implementation did not process that call as an * and that its __call() implementation did not process that call as an
* attempt to trigger an event - this is intended to aid in debugging of * attempt to trigger an event - this is intended to aid in debugging of
* such situations * such situations
*/ */
const ERR_INVALID_CALL = 12; const ERR_INVALID_CALL = 12;
/** /**
* Error indicating that a fatal runtime issue was encountered within a * Error indicating that a fatal runtime issue was encountered within a
* plugin * plugin
*/ */
const ERR_FATAL_ERROR = 13; const ERR_FATAL_ERROR = 13;

View File

@ -222,7 +222,11 @@ class Phergie_Plugin_Google extends Phergie_Plugin_Abstract
* @pluginCmd [location] Get the location from Google Maps to the location specified * @pluginCmd [location] Get the location from Google Maps to the location specified
*/ */
public function onCommandGmap($location) public function onCommandGmap($location)
{ {
$event = $this->getEvent();
$source = $event->getSource();
$nick = $event->getNick();
$location = utf8_encode($location); $location = utf8_encode($location);
$url = 'http://maps.google.com/maps/geo'; $url = 'http://maps.google.com/maps/geo';
$params = array( $params = array(
@ -232,20 +236,17 @@ class Phergie_Plugin_Google extends Phergie_Plugin_Abstract
'sensor' => 'false', 'sensor' => 'false',
'oe' => 'utf8', 'oe' => 'utf8',
'mrt' => 'all', 'mrt' => 'all',
'key' => $this->_config['google.key'] 'key' => $this->getConfig('google.key')
); );
$response = $this->http->get($url, $params); $response = $this->http->get($url, $params);
$json = (array) $response->getContent(); $json = $response->getContent();
$event = $this->getEvent();
$source = $event->getSource();
$nick = $event->getNick();
if (!empty($json)) { if (!empty($json)) {
$qtd = count($json['Placemark']); $qtd = count($json->Placemark);
if ($qtd > 1) { if ($qtd > 1) {
if ($qtd <= 3) { if ($qtd <= 3) {
foreach ($json['Placemark'] as $places) { foreach ($json->Placemark as $places) {
$xy = $places['Point']['coordinates']; $xy = $places->Point->coordinates;
$address = utf8_decode($places['address']); $address = utf8_decode($places->address);
$url = 'http://maps.google.com/maps?sll=' . $xy[1] . ',' $url = 'http://maps.google.com/maps?sll=' . $xy[1] . ','
. $xy[0] . '&z=15'; . $xy[0] . '&z=15';
$msg = $nick . ' -> ' . $address . ' - ' . $url; $msg = $nick . ' -> ' . $address . ' - ' . $url;
@ -259,8 +260,8 @@ class Phergie_Plugin_Google extends Phergie_Plugin_Abstract
$this->doPrivmsg($source, $msg); $this->doPrivmsg($source, $msg);
} }
} elseif ($qtd == 1) { } elseif ($qtd == 1) {
$xy = $json['Placemark'][0]['Point']['coordinates']; $xy = $json->Placemark[0]->Point->coordinates;
$address = utf8_decode($json['Placemark'][0]['address']); $address = utf8_decode($json->Placemark[0]->address);
$url = 'http://maps.google.com/maps?sll=' . $xy[1] . ',' . $xy[0] $url = 'http://maps.google.com/maps?sll=' . $xy[1] . ',' . $xy[0]
. '&z=15'; . '&z=15';
$msg = $nick . ' -> ' . $address . ' - ' . $url; $msg = $nick . ' -> ' . $address . ' - ' . $url;
@ -322,54 +323,44 @@ class Phergie_Plugin_Google extends Phergie_Plugin_Abstract
/** /**
* Performs a Google search to convert a value from one unit to another. * Performs a Google search to convert a value from one unit to another.
* *
* @param string $unit Source metric * @param string $query Query of the form "[quantity] [unit] to [unit2]"
* @param string $to Value to be converted
* @param string $unit2 Destination metric
* *
* @return void * @return void
* *
* @pluginCmd [unit] [to] [unit2] Convert a value from one metric to another * @pluginCmd [quantity] [unit] to [unit2] Convert a value from one
* metric to another
*/ */
public function onCommandConvert($unit, $to, $unit2) public function onCommandConvert($query)
{ {
$url = 'http://www.google.com/search?q=' $url = 'http://www.google.com/search?q=' . urlencode($query);
. urlencode($unit . ' ' . $to . ' ' . $unit2);
$response = $this->http->get($url); $response = $this->http->get($url);
$contents = $response->getContent(); $contents = $response->getContent();
$event = $this->getEvent(); $event = $this->getEvent();
$source = $event->getSource(); $source = $event->getSource();
$nick = $event->getNick(); $nick = $event->getNick();
if (empty($contents)) { if ($response->isError()) {
$this->doPrivmsg( $code = $response->getCode();
$target, $message = $response->getMessage();
$nick . ', sorry, I can\'t give you an answer right now.' $this->doNotice($nick, 'ERROR: ' . $code . ' ' . $message);
);
return; return;
} }
$doc = new DomDocument; $start = strpos($contents, '<h3 class=r>');
$doc->loadHTML($contents); if ($start !== false) {
foreach ($doc->getElementsByTagName('h2') as $element) { $end = strpos($contents, '</b>', $start);
if ($element->getAttribute('class') == 'r') { $text = strip_tags(substr($contents, $start, $end - $start));
$children = $element->childNodes; $text = str_replace(
$text = str_replace( array(chr(195), chr(151), chr(160)),
array(chr(195), chr(151), chr(160)), array('x', '', ' '),
array('x', '', ' '), $text
$children->item(0)->nodeValue );
);
if ($children->length >= 3) {
$text
.= '^' . $children->item(1)->nodeValue
. $children->item(2)->nodeValue;
}
}
} }
if (isset($text)) { if (isset($text)) {
$this->doPrivmsg($source, $nick . ': ' . $text); $this->doPrivmsg($source, $nick . ': ' . $text);
} else { } else {
$this->doPrivmsg($target, $nick . ', sorry I can\'t do that.'); $this->doNotice($nick, 'Sorry I couldn\'t find an answer.');
} }
} }
} }

View File

@ -1,6 +1,6 @@
<?php <?php
/** /**
* Phergie * Phergie
* *
* PHP version 5 * PHP version 5
* *
@ -11,7 +11,7 @@
* It is also available through the world-wide-web at this URL: * It is also available through the world-wide-web at this URL:
* http://phergie.org/license * http://phergie.org/license
* *
* @category Phergie * @category Phergie
* @package Phergie * @package Phergie
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org) * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
@ -22,13 +22,13 @@
/** /**
* Handles on-demand loading of, iteration over, and access to plugins. * Handles on-demand loading of, iteration over, and access to plugins.
* *
* @category Phergie * @category Phergie
* @package Phergie * @package Phergie
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License * @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie * @link http://pear.phergie.org/package/Phergie
*/ */
class Phergie_Plugin_Handler implements IteratorAggregate class Phergie_Plugin_Handler implements IteratorAggregate, Countable
{ {
/** /**
* Current list of plugin instances * Current list of plugin instances
@ -45,7 +45,7 @@ class Phergie_Plugin_Handler implements IteratorAggregate
protected $paths; protected $paths;
/** /**
* Flag indicating whether plugin classes should be instantiated on * Flag indicating whether plugin classes should be instantiated on
* demand if they are requested but no instance currently exists * demand if they are requested but no instance currently exists
* *
* @var bool * @var bool
@ -69,13 +69,13 @@ class Phergie_Plugin_Handler implements IteratorAggregate
protected $events; protected $events;
/** /**
* Constructor to initialize class properties and add the path for core * Constructor to initialize class properties and add the path for core
* plugins. * plugins.
* *
* @param Phergie_Config $config configuration to pass to any * @param Phergie_Config $config configuration to pass to any
* instantiated plugin * instantiated plugin
* @param Phergie_Event_Handler $events event handler to pass to any * @param Phergie_Event_Handler $events event handler to pass to any
* instantiated plugin * instantiated plugin
* *
* @return void * @return void
*/ */
@ -99,7 +99,7 @@ class Phergie_Plugin_Handler implements IteratorAggregate
* the reverse order in which they are added. * the reverse order in which they are added.
* *
* @param string $path Filesystem directory path * @param string $path Filesystem directory path
* @param string $prefix Optional class name prefix corresponding to the * @param string $prefix Optional class name prefix corresponding to the
* path * path
* *
* @return Phergie_Plugin_Handler Provides a fluent interface * @return Phergie_Plugin_Handler Provides a fluent interface
@ -123,12 +123,43 @@ class Phergie_Plugin_Handler implements IteratorAggregate
} }
/** /**
* Adds a plugin instance to the handler. * Returns metadata corresponding to a specified plugin.
* *
* @param string|Phergie_Plugin_Abstract $plugin Short name of the * @param string $plugin Short name of the plugin class
* @throws Phergie_Plugin_Exception Class file can't be found
*
* @return array|boolean Associative array containing the path to the
* class file and its containing directory as well as the full
* class name
*/
public function getPluginInfo($plugin)
{
foreach (array_reverse($this->paths) as $path) {
$file = $path['path'] . $plugin . '.php';
if (file_exists($file)) {
$path = array(
'dir' => $path['path'],
'file' => $file,
'class' => $path['prefix'] . $plugin,
);
return $path;
}
}
// If the class can't be found, display an error
throw new Phergie_Plugin_Exception(
'Class file for plugin "' . $plugin . '" cannot be found',
Phergie_Plugin_Exception::ERR_CLASS_NOT_FOUND
);
}
/**
* Adds a plugin instance to the handler.
*
* @param string|Phergie_Plugin_Abstract $plugin Short name of the
* plugin class or a plugin object * plugin class or a plugin object
* @param array $args Optional array of * @param array $args Optional array of
* arguments to pass to the plugin constructor if a short name is * arguments to pass to the plugin constructor if a short name is
* passed for $plugin * passed for $plugin
* *
* @return Phergie_Plugin_Abstract New plugin instance * @return Phergie_Plugin_Abstract New plugin instance
@ -143,30 +174,21 @@ class Phergie_Plugin_Handler implements IteratorAggregate
} }
// Attempt to locate and load the class // Attempt to locate and load the class
foreach (array_reverse($this->paths) as $path) { $info = $this->getPluginInfo($plugin);
$file = $path['path'] . $plugin . '.php'; $file = $info['file'];
if (file_exists($file)) { $class = $info['class'];
include_once $file; include_once $file;
$class = $path['prefix'] . $plugin; if (!class_exists($class, false)) {
if (class_exists($class)) {
break;
}
unset($class);
}
}
// If the class can't be found, display an error
if (!isset($class)) {
throw new Phergie_Plugin_Exception( throw new Phergie_Plugin_Exception(
'Class file for plugin "' . $plugin . '" cannot be found', 'File "' . $file . '" does not contain class "' . $class . '"',
Phergie_Plugin_Exception::ERR_CLASS_NOT_FOUND Phergie_Plugin_Exception::ERR_CLASS_NOT_FOUND
); );
} }
// Check to ensure the class is a plugin class // Check to ensure the class is a plugin class
if (!is_subclass_of($class, 'Phergie_Plugin_Abstract')) { if (!is_subclass_of($class, 'Phergie_Plugin_Abstract')) {
$msg $msg
= 'Class for plugin "' . $plugin . = 'Class for plugin "' . $plugin .
'" does not extend Phergie_Plugin_Abstract'; '" does not extend Phergie_Plugin_Abstract';
throw new Phergie_Plugin_Exception( throw new Phergie_Plugin_Exception(
$msg, $msg,
@ -190,11 +212,7 @@ class Phergie_Plugin_Handler implements IteratorAggregate
$instance = new $class; $instance = new $class;
} }
// Configure and add the instance // Store the instance
$instance->setPluginHandler($this);
$instance->setConfig($this->config);
$instance->setEventHandler($this->events);
$instance->onLoad();
$this->plugins[$index] = $instance; $this->plugins[$index] = $instance;
$plugin = $instance; $plugin = $instance;
@ -205,14 +223,20 @@ class Phergie_Plugin_Handler implements IteratorAggregate
$this->plugins[strtolower($plugin->getName())] = $plugin; $this->plugins[strtolower($plugin->getName())] = $plugin;
} }
// Configure and initialize the instance
$plugin->setPluginHandler($this);
$plugin->setConfig($this->config);
$plugin->setEventHandler($this->events);
$plugin->onLoad();
return $plugin; return $plugin;
} }
/** /**
* Adds multiple plugin instances to the handler. * Adds multiple plugin instances to the handler.
* *
* @param array $plugins List of elements where each is of the form * @param array $plugins List of elements where each is of the form
* 'ShortPluginName' or array('ShortPluginName', array($arg1, * 'ShortPluginName' or array('ShortPluginName', array($arg1,
* ..., $argN)) * ..., $argN))
* *
* @return Phergie_Plugin_Handler Provides a fluent interface * @return Phergie_Plugin_Handler Provides a fluent interface
@ -233,7 +257,7 @@ class Phergie_Plugin_Handler implements IteratorAggregate
/** /**
* Removes a plugin instance from the handler. * Removes a plugin instance from the handler.
* *
* @param string|Phergie_Plugin_Abstract $plugin Short name of the * @param string|Phergie_Plugin_Abstract $plugin Short name of the
* plugin class or a plugin object * plugin class or a plugin object
* *
* @return Phergie_Plugin_Handler Provides a fluent interface * @return Phergie_Plugin_Handler Provides a fluent interface
@ -251,7 +275,7 @@ class Phergie_Plugin_Handler implements IteratorAggregate
} }
/** /**
* Returns the corresponding instance for a specified plugin, loading it * Returns the corresponding instance for a specified plugin, loading it
* if it is not already loaded and autoloading is enabled. * if it is not already loaded and autoloading is enabled.
* *
* @param string $name Short name of the plugin class * @param string $name Short name of the plugin class
@ -268,8 +292,8 @@ class Phergie_Plugin_Handler implements IteratorAggregate
// If autoloading is disabled, display an error // If autoloading is disabled, display an error
if (!$this->autoload) { if (!$this->autoload) {
$msg $msg
= 'Plugin "' . $name . '" has been requested, ' . = 'Plugin "' . $name . '" has been requested, ' .
'is not loaded, and autoload is disabled'; 'is not loaded, and autoload is disabled';
throw new Phergie_Plugin_Exception( throw new Phergie_Plugin_Exception(
$msg, $msg,
@ -285,17 +309,23 @@ class Phergie_Plugin_Handler implements IteratorAggregate
} }
/** /**
* Returns the corresponding instances for multiple specified plugins, * Returns the corresponding instances for multiple specified plugins,
* loading them if they are not already loaded and autoloading is * loading them if they are not already loaded and autoloading is
* enabled. * enabled.
* *
* @param array $names List of short names of the plugin classes * @param array $names Optional list of short names of the plugin
* classes to which the returned plugin list will be limited,
* defaults to all presently loaded plugins
* *
* @return array Associative array mapping plugin class short names to * @return array Associative array mapping lowercased plugin class short
* corresponding plugin instances * names to corresponding plugin instances
*/ */
public function getPlugins(array $names) public function getPlugins(array $names = array())
{ {
if (empty($names)) {
return $this->plugins;
}
$plugins = array(); $plugins = array();
foreach ($names as $name) { foreach ($names as $name) {
$plugins[$name] = $this->getPlugin($name); $plugins[$name] = $this->getPlugin($name);
@ -304,7 +334,7 @@ class Phergie_Plugin_Handler implements IteratorAggregate
} }
/** /**
* Returns whether or not at least one instance of a specified plugin * Returns whether or not at least one instance of a specified plugin
* class is loaded. * class is loaded.
* *
* @param string $name Short name of the plugin class * @param string $name Short name of the plugin class
@ -317,10 +347,10 @@ class Phergie_Plugin_Handler implements IteratorAggregate
} }
/** /**
* Sets a flag used to determine whether plugins should be loaded * Sets a flag used to determine whether plugins should be loaded
* automatically if they have not been explicitly loaded. * automatically if they have not been explicitly loaded.
* *
* @param bool $flag TRUE to have plugins autoload (default), FALSE * @param bool $flag TRUE to have plugins autoload (default), FALSE
* otherwise * otherwise
* *
* @return Phergie_Plugin_Handler Provides a fluent interface. * @return Phergie_Plugin_Handler Provides a fluent interface.
@ -333,7 +363,7 @@ class Phergie_Plugin_Handler implements IteratorAggregate
} }
/** /**
* Returns the value of a flag used to determine whether plugins should * Returns the value of a flag used to determine whether plugins should
* be loaded automatically if they have not been explicitly loaded. * be loaded automatically if they have not been explicitly loaded.
* *
* @return bool TRUE if autoloading is enabled, FALSE otherwise * @return bool TRUE if autoloading is enabled, FALSE otherwise
@ -344,7 +374,7 @@ class Phergie_Plugin_Handler implements IteratorAggregate
} }
/** /**
* Allows plugin instances to be accessed as properties of the handler. * Allows plugin instances to be accessed as properties of the handler.
* *
* @param string $name Short name of the plugin * @param string $name Short name of the plugin
* *
@ -352,7 +382,7 @@ class Phergie_Plugin_Handler implements IteratorAggregate
*/ */
public function __get($name) public function __get($name)
{ {
return $this->getPlugin($name); return $this->getPlugin($name);
} }
/** /**
@ -390,14 +420,14 @@ class Phergie_Plugin_Handler implements IteratorAggregate
} }
/** /**
* Proxies method calls to all plugins containing the called method. An * Proxies method calls to all plugins containing the called method. An
* individual plugin may short-circuit this process by explicitly * individual plugin may short-circuit this process by explicitly
* returning FALSE. * returning FALSE.
* *
* @param string $name Name of the method called * @param string $name Name of the method called
* @param array $args Arguments passed in the method call * @param array $args Arguments passed in the method call
* *
* @return bool FALSE if a plugin short-circuits processing by returning * @return bool FALSE if a plugin short-circuits processing by returning
* FALSE, TRUE otherwise * FALSE, TRUE otherwise
*/ */
public function __call($name, array $args) public function __call($name, array $args)
@ -409,4 +439,14 @@ class Phergie_Plugin_Handler implements IteratorAggregate
} }
return true; return true;
} }
/**
* Returns the number of plugins contained within the handler.
*
* @return int Plugin count
*/
public function count()
{
return count($this->plugins);
}
} }

View File

@ -1,6 +1,6 @@
<?php <?php
/** /**
* Phergie * Phergie
* *
* PHP version 5 * PHP version 5
* *
@ -11,7 +11,7 @@
* It is also available through the world-wide-web at this URL: * It is also available through the world-wide-web at this URL:
* http://phergie.org/license * http://phergie.org/license
* *
* @category Phergie * @category Phergie
* @package Phergie_Plugin_Help * @package Phergie_Plugin_Help
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org) * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
@ -22,7 +22,7 @@
/** /**
* Provides access to descriptions of plugins and the commands they provide. * Provides access to descriptions of plugins and the commands they provide.
* *
* @category Phergie * @category Phergie
* @package Phergie_Plugin_Help * @package Phergie_Plugin_Help
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License * @license http://phergie.org/license New BSD License
@ -60,11 +60,11 @@ class Phergie_Plugin_Help extends Phergie_Plugin_Abstract
} }
/** /**
* Displays a list of plugins with help information available or * Displays a list of plugins with help information available or
* commands available for a specific plugin. * commands available for a specific plugin.
* *
* @param string $plugin Short name of the plugin for which commands * @param string $plugin Short name of the plugin for which commands
* should be returned, else a list of plugins with help * should be returned, else a list of plugins with help
* information available is returned * information available is returned
* *
* @return void * @return void
@ -94,13 +94,13 @@ class Phergie_Plugin_Help extends Phergie_Plugin_Abstract
&& isset($this->registry[strtolower($plugin)]['cmd']) && isset($this->registry[strtolower($plugin)]['cmd'])
) { ) {
$msg $msg
= 'The ' . = 'The ' .
$plugin . $plugin .
' plugin exposes the commands shown below.'; ' plugin exposes the commands shown below.';
$this->doPrivMsg($nick, $msg); $this->doPrivMsg($nick, $msg);
if ($this->getConfig('command.prefix')) { if ($this->getConfig('command.prefix')) {
$msg $msg
= 'Note that these commands must be prefixed with "' . = 'Note that these commands must be prefixed with "' .
$this->getConfig('command.prefix') . $this->getConfig('command.prefix') .
'" (without quotes) when issued in a public channel.'; '" (without quotes) when issued in a public channel.';
$this->doPrivMsg($nick, $msg); $this->doPrivMsg($nick, $msg);
@ -122,10 +122,10 @@ class Phergie_Plugin_Help extends Phergie_Plugin_Abstract
/** /**
* Sets the description for the plugin instance * Sets the description for the plugin instance
* *
* @param Phergie_Plugin_Abstract $plugin plugin instance * @param Phergie_Plugin_Abstract $plugin plugin instance
* @param string $description plugin description * @param string $description plugin description
* *
* @return void * @return void
*/ */
public function setPluginDescription( public function setPluginDescription(
@ -138,7 +138,7 @@ class Phergie_Plugin_Help extends Phergie_Plugin_Abstract
/** /**
* Sets the description for the command on the plugin instance * Sets the description for the command on the plugin instance
* *
* @param Phergie_Plugin_Abstract $plugin plugin instance * @param Phergie_Plugin_Abstract $plugin plugin instance
* @param string $command from onCommand method * @param string $command from onCommand method
* @param string $description command description * @param string $description command description
@ -158,7 +158,7 @@ class Phergie_Plugin_Help extends Phergie_Plugin_Abstract
* registers the plugin with the help plugin. this will parse the docblocks * registers the plugin with the help plugin. this will parse the docblocks
* for specific annotations that this plugin will respond with when * for specific annotations that this plugin will respond with when
* queried. * queried.
* *
* @param Phergie_Plugin_Abstract $plugin plugin instance * @param Phergie_Plugin_Abstract $plugin plugin instance
* *
* @return void * @return void
@ -191,7 +191,8 @@ class Phergie_Plugin_Help extends Phergie_Plugin_Abstract
} }
/** /**
* Taken from PHPUnit/Util/Test.php:436 * Taken from PHPUnit/Util/Test.php:243 and modified to fix an issue
* with tag content spanning multiple lines.
* *
* PHPUnit * PHPUnit
* *
@ -235,13 +236,16 @@ class Phergie_Plugin_Help extends Phergie_Plugin_Abstract
{ {
$annotations = array(); $annotations = array();
$regex = '/@(?P<name>[A-Za-z_-]+)(?:[ \t]+(?P<value>.*?))?[ \t]*\r?$/m'; $regex = '/@(?P<name>[A-Za-z_-]+)(?:[ \t]+(?P<value>.*?))?(?:\*\/|\* @)/ms';
if (preg_match_all($regex, $docblock, $matches)) { if (preg_match_all($regex, $docblock, $matches)) {
$numMatches = count($matches[0]); $numMatches = count($matches[0]);
for ($i = 0; $i < $numMatches; ++$i) { for ($i = 0; $i < $numMatches; ++$i) {
$annotations[$matches['name'][$i]][] = $matches['value'][$i]; $annotation = $matches['value'][$i];
$annotation = preg_replace('/\s*\v+\s*\*\s*/', ' ', $annotation);
$annotation = rtrim($annotation);
$annotations[$matches['name'][$i]][] = $annotation;
} }
} }

View File

@ -37,6 +37,43 @@ class Phergie_Plugin_Http_Response
*/ */
protected $code; protected $code;
/**
* HTTP response strings
*
* @var array
*/
protected $codeStrings = array(
0 => 'No Response',
100 => 'Continue',
200 => 'OK',
201 => 'Created',
204 => 'No Content',
206 => 'Partial Content',
300 => 'Multiple Choices',
301 => 'Moved Permanently',
302 => 'Found',
303 => 'See Other',
304 => 'Not Modified',
307 => 'Temporary Redirect',
400 => 'Bad Request',
401 => 'Unauthorized',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
406 => 'Not Acceptable',
408 => 'Request Timeout',
410 => 'Gone',
413 => 'Request Entity Too Large',
414 => 'Request URI Too Long',
415 => 'Unsupported Media Type',
416 => 'Requested Range Not Satisfiable',
417 => 'Expectation Failed',
500 => 'Internal Server Error',
501 => 'Method Not Implemented',
503 => 'Service Unavailable',
506 => 'Variant Also Negotiates'
);
/** /**
* Description of the HTTP response code or the error message if no HTTP * Description of the HTTP response code or the error message if no HTTP
* response was received * response was received
@ -89,6 +126,22 @@ class Phergie_Plugin_Http_Response
return $this->code; return $this->code;
} }
/**
* Returns the HTTP response code text.
*
* @return string Response code text
*/
public function getCodeAsString()
{
$code = $this->code;
if (!isset($this->codeStrings[$code])) {
return 'Unkown HTTP Status';
}
return $this->codeStrings[$code];
}
/** /**
* Returns whether the response indicates a client- or server-side error. * Returns whether the response indicates a client- or server-side error.
* *

View File

@ -62,7 +62,6 @@ class Phergie_Plugin_Php extends Phergie_Plugin_Abstract
*/ */
public function onConnect() public function onConnect()
{ {
// Construct a new data source
$this->source = new Phergie_Plugin_Php_Source_Local; $this->source = new Phergie_Plugin_Php_Source_Local;
} }
@ -75,14 +74,13 @@ class Phergie_Plugin_Php extends Phergie_Plugin_Abstract
*/ */
public function onCommandPhp($functionName) public function onCommandPhp($functionName)
{ {
// Search for the function $nick = $this->event->getNick();
if ($function = $this->source->findFunction($functionName)) { if ($function = $this->source->findFunction($functionName)) {
$msg = 'PHP ' . $function['name'] . ': ' . $function['description']; $msg = $nick . ': ' . $function['description'];
$this->doPrivmsg($this->event->getSource(), $msg);
} else { } else {
$msg = 'Search for function ' . $functionName . ' returned no results.'; $msg = 'Search for function ' . $functionName . ' returned no results.';
$this->doNotice($nick, $msg);
} }
// Return the result to the source
$this->doPrivmsg($this->getEvent()->getSource(), $msg);
} }
} }

View File

@ -65,7 +65,8 @@ class Phergie_Plugin_Php_Source_Local implements Phergie_Plugin_Php_Source
// @todo Modify this to be rethrown as an appropriate // @todo Modify this to be rethrown as an appropriate
// Phergie_Plugin_Exception and handled in Phergie_Plugin_Php // Phergie_Plugin_Exception and handled in Phergie_Plugin_Php
} catch (PDOException $e) { } catch (PDOException $e) {
} echo 'PDO failure: '.$e->getMessage();
}
} }
/** /**
@ -114,12 +115,16 @@ class Phergie_Plugin_Php_Source_Local implements Phergie_Plugin_Php_Source
protected function buildDatabase($rebuild = false) protected function buildDatabase($rebuild = false)
{ {
// Check to see if the functions table exists // Check to see if the functions table exists
$table = $this->database->exec("SELECT COUNT(*) FROM `sqlite_master` WHERE `name` = 'functions'"); $checkstmt = $this->database->query("SELECT COUNT(*) FROM `sqlite_master` WHERE `name` = 'functions'");
$checkstmt->execute();
$result = $checkstmt->fetch(PDO::FETCH_ASSOC);
unset( $checkstmt );
$table = $result['COUNT(*)'];
unset( $result );
// If the table doesn't exist, create it // If the table doesn't exist, create it
if (!$table) { if (!$table) {
$this->database->exec('CREATE TABLE `functions` (`name` VARCHAR(255), `description` TEXT)'); $this->database->exec('CREATE TABLE `functions` (`name` VARCHAR(255), `description` TEXT)');
$this->database->exec('CREATE UNIQUE INDEX `functions_name` ON `functions` (`name`)'); $this->database->exec('CREATE UNIQUE INDEX `functions_name` ON `functions` (`name`)');
} }
// If we created a new table, fill it with data // If we created a new table, fill it with data
@ -160,7 +165,7 @@ class Phergie_Plugin_Php_Source_Local implements Phergie_Plugin_Php_Source
// ... it's the last part of the complete function description // ... it's the last part of the complete function description
$completeLine = $firstPart . ' ' . $line; $completeLine = $firstPart . ' ' . $line;
$firstPart = ''; $firstPart = '';
if (preg_match('{^([^\s]*)[\s]?([^)]*)\(([^\)]*)\)[\sU]+([\sa-zA-Z0-9\.\-_]*)$}', $completeLine, $matches)) { if (preg_match('{^([^\s]*)[\s]?([^)]*)\(([^\)]*)\)[\sU]+([\sa-zA-Z0-9\.,\-_()]*)$}', $completeLine, $matches)) {
$valid[] = $matches; $valid[] = $matches;
} }
} }

View File

@ -0,0 +1,96 @@
<?php
/**
* Phergie
*
* PHP version 5
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.
* It is also available through the world-wide-web at this URL:
* http://phergie.org/license
*
* @category Phergie
* @package Phergie_Plugin_Reload
* @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org)
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Reload
*/
/**
* Facilitates reloading of individual plugins for development purposes.
* Note that, because existing class definitions cannot be removed from
* memory, increased memory usage is an expected result of using this plugin.
*
* @category Phergie
* @package Phergie_Plugin_Reload
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Reload
* @uses Phergie_Plugin_Command pear.phergie.org
*/
class Phergie_Plugin_Reload extends Phergie_Plugin_Abstract
{
/**
* Checks for dependencies.
*
* @return void
*/
public function onLoad()
{
$this->getPluginHandler()->getPlugin('Command');
}
/**
* Reloads a specified plugin.
*
* @param string $plugin Short name of the plugin to reload
*
* @return void
*/
public function onCommandReload($plugin)
{
$plugin = ucfirst($plugin);
if (!$this->plugins->hasPlugin($plugin)) {
echo 'DEBUG(Reload): ' . ucfirst($plugin) . ' is not loaded yet, loading', PHP_EOL;
$this->plugins->getPlugin($plugin);
return;
}
try {
$info = $this->plugins->getPluginInfo($plugin);
} catch (Phergie_Plugin_Exception $e) {
$source = $this->event->getSource();
$nick = $this->event->getNick();
$this->doNotice($source, $nick . ': ' . $e->getMessage());
return;
}
$class = $info['class'];
$contents = file_get_contents($info['file']);
$newClass = $class . '_' . sha1($contents);
if (class_exists($newClass, false)) {
echo 'DEBUG(Reload): Class ', $class, ' has not changed since last reload', PHP_EOL;
return;
}
$contents = preg_replace(
array('/<\?(?:php)?/', '/class\s+' . $class . '/i'),
array('', 'class ' . $newClass),
$contents
);
eval($contents);
$instance = new $newClass;
$instance->setName($plugin);
$this->plugins
->removePlugin($plugin)
->addPlugin($instance);
echo 'DEBUG(Reload): Reloaded ', $class, ' to ', $newClass, PHP_EOL;
}
}

View File

@ -27,16 +27,16 @@
* @package Phergie_Plugin_Remind * @package Phergie_Plugin_Remind
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License * @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Drink * @link http://pear.phergie.org/package/Phergie_Plugin_Remind
* @uses Phergie_Plugin_Command pear.phergie.org * @uses Phergie_Plugin_Command pear.phergie.org
* @uses Phergie_Plugin_Helper_Time pear.phergie.org * @uses Phergie_Plugin_Time pear.phergie.org
*/ */
class Phergie_Plugin_Remind extends Phergie_Plugin_Abstract class Phergie_Plugin_Remind extends Phergie_Plugin_Abstract
{ {
/** /**
* Number of reminders to show in public. * Number of reminders to show in public.
*/ */
const PUBLIC_REMINDERS = 3; protected $publicReminders = 3;
/** /**
* PDO resource for a SQLite database containing the reminders. * PDO resource for a SQLite database containing the reminders.
@ -64,11 +64,31 @@ class Phergie_Plugin_Remind extends Phergie_Plugin_Abstract
*/ */
public function onLoad() public function onLoad()
{ {
$this->getPluginHandler()->getPlugin('Command'); $plugins = $this->getPluginHandler();
$path = dirname(__FILE__) . '/reminder.db'; $plugins->getPlugin('Command');
$plugins->getPlugin('Time');
}
/**
* Creates the database if it does not already exist.
*
* @return void
*/
public function onConnect()
{
$dir = dirname(__FILE__) . '/' . $this->getName();
$path = $dir . '/reminder.db';
if (!file_exists($dir)) {
mkdir($dir);
}
if (isset($this->config['remind.use_memory'])) { if (isset($this->config['remind.use_memory'])) {
$this->keepListInMemory = (bool)$this->config['remind.use_memory']; $this->keepListInMemory = (bool) $this->config['remind.use_memory'];
}
if (isset($this->config['remind.public_reminders'])) {
$this->publicReminders = (int) $this->config['remind.public_reminders'];
$this->publicReminders = max($this->publicReminders, 0);
} }
try { try {
@ -222,19 +242,19 @@ class Phergie_Plugin_Remind extends Phergie_Plugin_Abstract
// fetch and deliver messages // fetch and deliver messages
$reminders = $this->fetchMessages($channel, $nick); $reminders = $this->fetchMessages($channel, $nick);
if (count($reminders) > self::PUBLIC_REMINDERS) { if (count($reminders) > $this->publicReminders) {
$msgs = array_slice($reminders, 0, self::PUBLIC_REMINDERS); $msgs = array_slice($reminders, 0, $this->publicReminders);
$privmsgs = array_slice($reminders, self::PUBLIC_REMINDERS); $privmsgs = array_slice($reminders, $this->publicReminders);
} else { } else {
$msgs = $reminders; $msgs = $reminders;
$privmsgs = false; $privmsgs = false;
} }
foreach ($msgs as $msg) { foreach ($msgs as $msg) {
$ts = new Phergie_Plugin_Helper_Time($msg['time']); $ts = $this->plugins->time->getCountdown($msg['time']);
$formatted = sprintf( $formatted = sprintf(
'%s: (from %s, %s ago) %s', '%s: (from %s, %s ago) %s',
$nick, $msg['sender'], $ts->getCountdown(), $msg['message'] $nick, $msg['sender'], $ts, $msg['message']
); );
$this->doPrivmsg($channel, $formatted); $this->doPrivmsg($channel, $formatted);
$this->deleteMessage($msg['rowid'], $channel, $nick); $this->deleteMessage($msg['rowid'], $channel, $nick);
@ -242,10 +262,10 @@ class Phergie_Plugin_Remind extends Phergie_Plugin_Abstract
if ($privmsgs) { if ($privmsgs) {
foreach ($privmsgs as $msg) { foreach ($privmsgs as $msg) {
$ts = new Phergie_Plugin_Helper_Time($msg['time']); $ts = $this->plugins->time->getCountdown($msg['time']);
$formatted = sprintf( $formatted = sprintf(
'from %s, %s ago: %s', 'from %s, %s ago: %s',
$msg['sender'], $ts->getCountdown(), $msg['message'] $msg['sender'], $ts, $msg['message']
); );
$this->doPrivmsg($nick, $formatted); $this->doPrivmsg($nick, $formatted);
$this->deleteMessage($msg['rowid'], $channel, $nick); $this->deleteMessage($msg['rowid'], $channel, $nick);

View File

@ -0,0 +1,120 @@
<?php
/**
* Phergie
*
* PHP version 5
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.
* It is also available through the world-wide-web at this URL:
* http://phergie.org/license
*
* @category Phergie
* @package Phergie_Plugin_TerryChay
* @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org)
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_TerryChay
*/
/**
* Handles requests for checking spelling of specified words and returning
* either confirmation of correctly spelled words or potential correct
* spellings for misspelled words.
*
* @category Phergie
* @package Phergie_Plugin_SpellCheck
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_TerryChay
* @uses Phergie_Plugin_Command pear.phergie.org
* @uses extension pspell
*/
class Phergie_Plugin_SpellCheck extends Phergie_Plugin_Abstract
{
/**
* Spell check dictionary handler
*
* @var resource
*/
protected $pspell;
/**
* Limit on the number of potential correct spellings returned
*
* @var int
*/
protected $limit;
/**
* Check for dependencies.
*
* @return void
*/
public function onLoad()
{
if (!extension_loaded('pspell')) {
$this->fail('pspell php extension is required');
}
if (!$this->getConfig('spellcheck.lang')) {
$this->fail('Setting spellcheck.lang must be filled-in');
}
$this->plugins->getPlugin('Command');
set_error_handler(array($this, 'loadDictionaryError'));
$this->pspell = pspell_new($this->getConfig('spellcheck.lang'));
restore_error_handler();
$this->limit = $this->getConfig('spellcheck.limit', 5);
}
/**
* Intercepts and handles requests for spell checks.
*
* @param string $word the string to perform checks against
*
* @return void
*/
public function onCommandSpell($word)
{
$source = $this->event->getSource();
$target = $this->event->getNick();
$message = $target . ': The word "' . $word;
$message .= '" seems to be spelt correctly.';
if (!pspell_check($this->pspell, $word)) {
$suggestions = pspell_suggest($this->pspell, $word);
$message = $target;
$message .= ': I could not find any suggestions for "' . $word . '".';
if (!empty($suggestions)) {
$suggestions = array_splice($suggestions, 0, $this->limit);
$message = $target . ': Suggestions for "';
$message .= $word . '": ' . implode(', ', $suggestions) . '.';
}
}
$this->doPrivmsg($source, $message);
}
/**
* Handle any errors from loading dictionary
*
* @param integer $errno Error code
* @param string $errstr Error message
* @param string $errfile File that errored
* @param integer $errline Line where the error happened
*
* @return void
*/
protected function loadDictionaryError($errno, $errstr, $errfile, $errline)
{
$this->fail($errstr);
}
}

View File

@ -0,0 +1,261 @@
<?php
/**
* Phergie
*
* PHP version 5
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.
* It is also available through the world-wide-web at this URL:
* http://phergie.org/license
*
* @category Phergie
* @package Phergie_Plugin_Url
* @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org)
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Url
*/
/**
* Responds to a request for a TLD (formatted as .tld where tld is the TLD to
* be looked up) with its corresponding description.
*
* @category Phergie
* @package Phergie_Plugin_Tld
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Tld
* @uses Phergie_Plugin_Http pear.phergie.org
*
* @pluginDesc Provides information for a top level domain.
*/
class Phergie_Plugin_Tld extends Phergie_Plugin_Abstract
{
/**
* connection to the database
* @var PDO
*/
protected $db;
/**
* Some fixed TLD values, keys must be lowercase
* @var array
*/
protected static $fixedTlds;
/**
* Prepared statement for selecting a single tld
* @var PDOStatement
*/
protected $select;
/**
* Prepared statement for selecting all tlds
* @var PDOStatement
*/
protected $selectAll;
/**
* Checks for dependencies, sets up database and hard coded values
*
* @return void
*/
public function onLoad()
{
$help = $this->getPluginHandler()->getPlugin('Help');
$help->register($this);
if (!is_array(self::$fixedTlds)) {
self::$fixedTlds = array(
'phergie' => 'You can find Phergie at http://www.phergie.org',
'spoon' => 'Don\'t you know? There is no spoon!',
'poo' => 'Do you really think that\'s funny?',
'root' => 'Diagnostic marker to indicate '
. 'a root zone load was not truncated.'
);
}
try {
$dbFile = dirname(__FILE__) . '/Tld/tld.db';
$dbManager = new Phergie_Db_Sqlite($dbFile);
$this->db = $dbManager->getDb();
if (!$dbManager->hasTable('tld')) {
$query = 'CREATE TABLE tld ('
. 'tld VARCHAR(20), '
. 'type VARCHAR(20), '
. 'description VARCHAR(255))';
$this->db->exec($query);
// prepare a statement to populate the table with
// tld information
$insert = $this->db->prepare(
'INSERT INTO tld
(tld, type, description)
VALUES (:tld, :type, :description)'
);
// grab tld data from iana.org...
$contents = file_get_contents(
'http://www.iana.org/domains/root/db/'
);
// ...and then parse it out
$regex = '{<tr class="iana-group[^>]*><td><a[^>]*>\s*\.?([^<]+)\s*'
. '(?:<br/><span[^>]*>[^<]*</span>)?</a></td><td>\s*'
. '([^<]+)\s*</td><td>\s*([^<]+)\s*}i';
preg_match_all($regex, $contents, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
list(, $tld, $type, $description) = array_pad($match, 4, null);
$type = trim(strtolower($type));
if ($type != 'test') {
$tld = trim(strtolower($tld));
$description = trim($description);
switch ($tld) {
case 'com':
$description = 'Commercial';
break;
case 'info':
$description = 'Information';
break;
case 'net':
$description = 'Network';
break;
case 'org':
$description = 'Organization';
break;
case 'edu':
$description = 'Educational';
break;
case 'name':
$description = 'Individuals, by name';
break;
}
if (empty($tld) || empty($description)) {
continue;
}
$regex = '{(^(?:Reserved|Restricted)\s*(?:exclusively\s*)?'
. '(?:for|to)\s*(?:members of\s*)?(?:the|support)?'
. '\s*|\s*as advised.*$)}i';
$description = preg_replace($regex, '', $description);
$description = ucfirst(trim($description));
$data = array_map(
'html_entity_decode', array(
'tld' => $tld,
'type' => $type,
'description' => $description
)
);
$insert->execute($data);
}
}
unset(
$insert,
$matches,
$match,
$contents,
$tld,
$type,
$description,
$data,
$regex
);
}
// Create a prepared statements for retrieving TLDs
$this->select = $this->db->prepare(
'SELECT type, description '
. 'FROM tld WHERE LOWER(tld) = LOWER(:tld)'
);
$this->selectAll = $this->db->prepare(
'SELECT tld, type, description FROM tld'
);
} catch (PDOException $e) {
}
}
/**
* takes a tld in the format '.tld' and returns its related data
*
* @param string $tld tld to process
*
* @return null
*
* @pluginCmd .[tld] request details about the tld
*/
public function onCommandTld($tld)
{
$tld = ltrim($tld, '.');
$description = $this->getTld($tld);
$this->doPrivmsg(
$this->event->getSource(),
"{$this->getEvent()->getNick()}: .{$tld} -> "
. ($description ? $description : 'Unknown TLD')
);
}
/**
* Retrieves the definition for a given TLD if it exists
*
* @param string $tld TLD to search for
*
* @return string Definition of the given TLD
*/
public function getTld($tld)
{
$tld = trim(strtolower($tld));
if (isset(self::$fixedTlds[$tld])) {
return self::$fixedTlds[$tld];
} else {
if ($this->select->execute(array('tld' => $tld))) {
$tlds = $this->select->fetch();
if (is_array($tlds)) {
return '(' . $tlds['type'] . ') ' . $tlds['description'];
}
}
}
return false;
}
/**
* Retrieves a list of all the TLDs and their definitions
*
* @return array Array of all the TLDs and their definitions
*/
public function getTlds()
{
if ($this->selectAll->execute()) {
$tlds = $this->selectAll->fetchAll();
if (is_array($tlds)) {
$tldinfo = array();
foreach ($tlds as $key => $tld) {
if (!empty($tld['tld'])) {
$tldinfo[$tld['tld']] = "({$tld['type']}) "
. $tld['description'];
}
}
unset($tlds);
return $tldinfo;
}
}
return false;
}
}

View File

@ -1,6 +1,6 @@
<?php <?php
/** /**
* Phergie * Phergie
* *
* PHP version 5 * PHP version 5
* *
@ -11,7 +11,7 @@
* It is also available through the world-wide-web at this URL: * It is also available through the world-wide-web at this URL:
* http://phergie.org/license * http://phergie.org/license
* *
* @category Phergie * @category Phergie
* @package Phergie_Plugin_Url * @package Phergie_Plugin_Url
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org) * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
@ -23,30 +23,31 @@
* Monitors incoming messages for instances of URLs and responds with messages * Monitors incoming messages for instances of URLs and responds with messages
* containing relevant information about detected URLs. * containing relevant information about detected URLs.
* *
* Has an utility method accessible via * Has an utility method accessible via
* $this->getPlugin('Url')->getTitle('http://foo..'). * $this->getPlugin('Url')->getTitle('http://foo..').
* *
* @category Phergie * @category Phergie
* @package Phergie_Plugin_Url * @package Phergie_Plugin_Url
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License * @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Url * @link http://pear.phergie.org/package/Phergie_Plugin_Url
* @uses Phergie_Plugin_Http pear.phergie.org
*/ */
class Phergie_Plugin_Url extends Phergie_Plugin_Abstract class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
{ {
/** /**
* Links output format * Links output format
* *
* Can use the variables %nick%, %title% and %link% in it to display * Can use the variables %nick%, %title% and %link% in it to display
* page titles and links * page titles and links
* *
* @var string * @var string
*/ */
protected $baseFormat = '%nick%: %message%'; protected $baseFormat = '%message%';
protected $messageFormat = '[ %link% ] %title%'; protected $messageFormat = '[ %link% ] %title%';
/** /**
* Flag indicating whether a single response should be sent for a single * Flag indicating whether a single response should be sent for a single
* message containing multiple links * message containing multiple links
* *
* @var bool * @var bool
@ -61,7 +62,7 @@ class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
protected $titleLength = 40; protected $titleLength = 40;
/** /**
* Url cache to prevent spamming, especially with multiple bots on the * Url cache to prevent spamming, especially with multiple bots on the
* same channel * same channel
* *
* @var array * @var array
@ -88,16 +89,16 @@ class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
protected $limit = 10; protected $limit = 10;
/** /**
* Flag that determines if the plugin will fall back to using an HTTP * Flag that determines if the plugin will fall back to using an HTTP
* stream when a URL using SSL is detected and OpenSSL support isn't * stream when a URL using SSL is detected and OpenSSL support isn't
* available in the PHP installation in use * available in the PHP installation in use
* *
* @var bool * @var bool
*/ */
protected $sslFallback = true; protected $sslFallback = true;
/** /**
* Flag that is set to true by the custom error handler if an HTTP error * Flag that is set to true by the custom error handler if an HTTP error
* code has been received * code has been received
* *
* @var boolean * @var boolean
@ -106,7 +107,7 @@ class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
protected $errorMessage = null; protected $errorMessage = null;
/** /**
* Flag indicating whether or not to display error messages as the title * Flag indicating whether or not to display error messages as the title
* if a link posted encounters an error * if a link posted encounters an error
* *
* @var boolean * @var boolean
@ -121,7 +122,7 @@ class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
protected $detectSchemeless = false; protected $detectSchemeless = false;
/** /**
* List of error messages to return when the requested URL returns an * List of error messages to return when the requested URL returns an
* HTTP error * HTTP error
* *
* @var array * @var array
@ -184,7 +185,7 @@ class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
// make the shortener configurable // make the shortener configurable
$shortener = $this->getConfig('url.shortener', 'Trim'); $shortener = $this->getConfig('url.shortener', 'Trim');
$shortener = "Phergie_Plugin_Url_Shorten_{$shortener}"; $shortener = "Phergie_Plugin_Url_Shorten_{$shortener}";
$this->shortener = new $shortener; $this->shortener = new $shortener($this->plugins->getPlugin('Http'));
if (!$this->shortener instanceof Phergie_Plugin_Url_Shorten_Abstract) { if (!$this->shortener instanceof Phergie_Plugin_Url_Shorten_Abstract) {
$this->fail("Declared shortener class {$shortener} is not of proper ancestry"); $this->fail("Declared shortener class {$shortener} is not of proper ancestry");
@ -192,17 +193,9 @@ class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
// Get a list of valid TLDs // Get a list of valid TLDs
if (!is_array($this->tldList) || count($this->tldList) <= 6) { if (!is_array($this->tldList) || count($this->tldList) <= 6) {
/* Omitted for port $tldPath = dirname(__FILE__) . '/Url/url.tld.txt';
if ($this->pluginLoaded('Tld')) { $this->tldList = explode("\n", file_get_contents($tldPath));
$this->tldList = Phergie_Plugin_Tld::getTlds(); $this->debug('Loaded ' . count($this->tldList) . ' tlds');
if (is_array($this->tldList)) {
$this->tldList = array_keys($this->tldList);
}
}
*/
if (!is_array($this->tldList) || count($this->tldList) <= 0) {
$this->tldList = array('ac', 'ad', 'ae', 'aero', 'af', 'ag', 'ai', 'al', 'am', 'an', 'ao', 'aq', 'ar', 'arpa', 'as', 'asia', 'at', 'au', 'aw', 'ax', 'az', 'ba', 'bb', 'bd', 'be', 'bf', 'bg', 'bh', 'bi', 'biz', 'bj', 'bl', 'bm', 'bn', 'bo', 'br', 'bs', 'bt', 'bv', 'bw', 'by', 'bz', 'ca', 'cat', 'cc', 'cd', 'cf', 'cg', 'ch', 'ci', 'ck', 'cl', 'cm', 'cn', 'co', 'com', 'coop', 'cr', 'cu', 'cv', 'cx', 'cy', 'cz', 'de', 'dj', 'dk', 'dm', 'do', 'dz', 'ec', 'edu', 'ee', 'eg', 'eh', 'er', 'es', 'et', 'eu', 'fi', 'fj', 'fk', 'fm', 'fo', 'fr', 'ga', 'gb', 'gd', 'ge', 'gf', 'gg', 'gh', 'gi', 'gl', 'gm', 'gn', 'gov', 'gp', 'gq', 'gr', 'gs', 'gt', 'gu', 'gw', 'gy', 'hk', 'hm', 'hn', 'hr', 'ht', 'hu', 'id', 'ie', 'il', 'im', 'in', 'info', 'int', 'io', 'iq', 'ir', 'is', 'it', 'je', 'jm', 'jo', 'jobs', 'jp', 'ke', 'kg', 'kh', 'ki', 'km', 'kn', 'kp', 'kr', 'kw', 'ky', 'kz', 'la', 'lb', 'lc', 'li', 'lk', 'lr', 'ls', 'lt', 'lu', 'lv', 'ly', 'ma', 'mc', 'md', 'me', 'mf', 'mg', 'mh', 'mil', 'mk', 'ml', 'mm', 'mn', 'mo', 'mobi', 'mp', 'mq', 'mr', 'ms', 'mt', 'mu', 'museum', 'mv', 'mw', 'mx', 'my', 'mz', 'na', 'name', 'nc', 'ne', 'net', 'nf', 'ng', 'ni', 'nl', 'no', 'np', 'nr', 'nu', 'nz', 'om', 'org', 'pa', 'pe', 'pf', 'pg', 'ph', 'pk', 'pl', 'pm', 'pn', 'pr', 'pro', 'ps', 'pt', 'pw', 'py', 'qa', 're', 'ro', 'rs', 'ru', 'rw', 'sa', 'sb', 'sc', 'sd', 'se', 'sg', 'sh', 'si', 'sj', 'sk', 'sl', 'sm', 'sn', 'so', 'sr', 'st', 'su', 'sv', 'sy', 'sz', 'tc', 'td', 'tel', 'tf', 'tg', 'th', 'tj', 'tk', 'tl', 'tm', 'tn', 'to', 'tp', 'tr', 'travel', 'tt', 'tv', 'tw', 'tz', 'ua', 'ug', 'uk', 'um', 'us', 'uy', 'uz', 'va', 'vc', 've', 'vg', 'vi', 'vn', 'vu', 'wf', 'ws', 'ye', 'yt', 'yu', 'za', 'zm', 'zw');
}
rsort($this->tldList); rsort($this->tldList);
} }
@ -215,6 +208,7 @@ class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
'merge_links' => 'mergeLinks', 'merge_links' => 'mergeLinks',
'title_length' => 'titleLength', 'title_length' => 'titleLength',
'show_errors' => 'showErrors', 'show_errors' => 'showErrors',
'expire' => 'expire',
) as $config => $local) { ) as $config => $local) {
if (isset($this->config["url.{$config}"])) { if (isset($this->config["url.{$config}"])) {
$this->$local = $this->config["uri.{$config}"]; $this->$local = $this->config["uri.{$config}"];
@ -227,7 +221,7 @@ class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
* found, responds with its title if it is an HTML document and the * found, responds with its title if it is an HTML document and the
* shortened equivalent of its original URL if it meets length requirements. * shortened equivalent of its original URL if it meets length requirements.
* *
* @todo Update this to pull configuration settings from $this->config * @todo Update this to pull configuration settings from $this->config
* rather than caching them as class properties * rather than caching them as class properties
* @return void * @return void
*/ */
@ -306,6 +300,10 @@ class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
// Convert url // Convert url
$shortenedUrl = $this->shortener->shorten($url); $shortenedUrl = $this->shortener->shorten($url);
if (!$shortenedUrl) {
$this->debug('Invalid Url: Unable to shorten. (' . $url . ')');
continue;
}
// Prevent spamfest // Prevent spamfest
if ($this->checkUrlCache($url, $shortenedUrl)) { if ($this->checkUrlCache($url, $shortenedUrl)) {
@ -624,73 +622,29 @@ class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
*/ */
public function getTitle($url) public function getTitle($url)
{ {
$opts = array( $http = $this->plugins->getPlugin('Http');
'http' => array( $options = array(
'timeout' => 3.5, 'timeout' => 3.5,
'method' => 'GET', 'user_agent' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.12) Gecko/20080201 Firefox/2.0.0.12'
'user_agent' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.12) Gecko/20080201 Firefox/2.0.0.12'
)
); );
$context = stream_context_create($opts);
if ($page = fopen($url, 'r', false, $context)) { $response = $http->get($url, array(), $options);
stream_set_timeout($page, 3.5);
$data = stream_get_meta_data($page);
foreach ($data['wrapper_data'] as $header) {
if (preg_match('/^Content-Type: ([^;]+)/', $header, $match)
&& !preg_match('#^(text/x?html|application/xhtml+xml)$#', $match[1])
) {
$title = $match[1];
}
}
if (!isset($title)) {
$content = '';
$tstamp = time() + 5;
while ($chunk = fread($page, 64)) { $header = $response->getHeaders('Content-Type');
$data = stream_get_meta_data($page); if (!preg_match('#^(text/x?html|application/xhtml+xml)(?:;.*)?$#', $header)) {
if ($data['timed_out']) { $title = $header;
$this->debug('Url Timed Out: ' . $url); }
$this->errorStatus = true;
break; $content = $response->getContent();
} if (empty($title)) {
$content .= $chunk; if (preg_match('#<title[^>]*>(.*?)</title>#is', $content, $match)) {
// Check for timeout $title = html_entity_decode(trim($match[1]));
if (time() > $tstamp) break;
// Try to read title
if (preg_match('#<title[^>]*>(.*)#is', $content, $m)) {
// Start another loop to grab some more data in order to be sure we have the complete title
$content = $m[1];
$loop = 2;
while (($chunk = fread($page, 64)) && $loop-- && !strstr($content, '<')) {
$content .= $chunk;
// Check for timeout
if (time() > $tstamp) break;
}
preg_match('#^([^<]*)#is', $content, $m);
$title = preg_replace('#\s+#', ' ', $m[1]);
$title = trim($this->decode($title, $this->titleLength));
break;
}
// Title won't appear beyond that point so stop parsing
if (preg_match('#</head>|<body#i', $content)) {
break;
}
}
} }
fclose($page);
} else if (!$this->errorStatus) {
$this->debug('Couldn\t Open Url: ' . $url);
} }
if (empty($title)) { if (empty($title)) {
if ($this->errorStatus) { if ($response->isError()) {
if (!$this->showErrors || empty($this->errorMessage)) { $title = $response->getCodeAsString();
return;
}
$title = $this->errorMessage;
$this->errorStatus = false;
$this->errorMessage = null;
} else { } else {
$title = 'No Title'; $title = 'No Title';
} }

View File

@ -27,15 +27,79 @@
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License * @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Url * @link http://pear.phergie.org/package/Phergie_Plugin_Url
* @uses Phergie_Plugin_Http pear.phergie.org
*/ */
abstract class Phergie_Plugin_Url_Shorten_Abstract abstract class Phergie_Plugin_Url_Shorten_Abstract
{ {
protected $http;
/** /**
* Takes a long url and returns a shortened link * Constructor
*
* @param Phergie_Plugin_Http $http instance of the http plugin
*/
public function __construct(Phergie_Plugin_Http $http)
{
$this->http = $http;
}
/**
* Returns an array of request parameters given a url to shorten. The
* following keys are valid request parameters:
*
* * 'uri': the URI for the request (required)
* * 'query': an array of key-value pairs sent in a GET request
* * 'post': an array of key-value pairs sent in a POST request
* * 'callback': to be called after the request is finished. Should accept
* a Phergie_Plugin_Http_Response object and return either the shortened
* url or false if an error has occured.
*
* If the 'post' key is present a POST request shall be made; otherwise
* a GET request will be made. The 'post' key can be an empty array and
* a post request will still be made.
*
* If no callback is provided the contents of the response will be returned.
* *
* @param string $url the url to shorten * @param string $url the url to shorten
* *
* @return string string the shortened url * @return array the request parameters
*/ */
public abstract function shorten($url); protected abstract function getRequestParams($url);
/**
* Shortens a given url.
*
* @param string $url the url to shorten
*
* @return string the shortened url or false on a failure
*/
public function shorten($url)
{
$defaults = array('get' => array(), 'post' => array(), 'callback' => null);
$options = array('timeout' => 2);
$params = $this->getRequestParams($url) + $defaults;
// Should some kind of notice be thrown? Maybe just if getRequestParams does not return an array?
if (!is_array($params) || empty($params['uri'])) {
return $url;
}
if (!empty($params['post'])) {
$response = $this->http->post($params['uri'], $params['get'], $params['post'], $options);
} else {
$response = $this->http->get($params['uri'], $params['get'], $options);
}
if (is_callable($params['callback'])) {
return call_user_func($params['callback'], $response);
}
$code = $response->getCode();
$content = trim($response->getContent);
if ($code < 200 || $code >= 300 || empty($content)) {
return false;
}
return $response->getContent();
}
} }

View File

@ -31,14 +31,34 @@
class Phergie_Plugin_Url_Shorten_Trim extends Phergie_Plugin_Url_Shorten_Abstract class Phergie_Plugin_Url_Shorten_Trim extends Phergie_Plugin_Url_Shorten_Abstract
{ {
/** /**
* Short a URL through the tr.im api * Returns an array of request parameters given a url to shorten. The
* following keys are valid request parameters:
* *
* @param string $url the url to shorten * @param string $url the url to shorten
* *
* @return string string the shortened url * @return array the request parameters
*/ */
public function shorten($url) protected function getRequestParams($url)
{ {
return file_get_contents('http://api.tr.im/v1/trim_simple?url=' . rawurlencode($url)); return array(
'uri' => 'http://api.tr.im/v1/trim_simple?url=' . rawurlencode($url),
'callback' => array($this, 'onComplete')
);
}
/**
* Callback for when the URL has been shortened. Checks for error messages.
*
* @param Phergie_Plugin_Http_Response $response the response object
*
* @return string|bool the shortened url or false on failure
*/
protected function onComplete($response)
{
if (strpos($response->getContent(), 'Error: ') === 0) {
return false;
}
return $response->getContent();
} }
} }

View File

@ -0,0 +1,273 @@
ac
ad
ae
aero
af
ag
ai
al
am
an
ao
aq
ar
arpa
as
asia
at
au
aw
ax
az
ba
bb
bd
be
bf
bg
bh
bi
biz
bj
bl
bm
bn
bo
br
bs
bt
bv
bw
by
bz
ca
cat
cc
cd
cf
cg
ch
ci
ck
cl
cm
cn
co
com
coop
cr
cu
cv
cx
cy
cz
de
dj
dk
dm
do
dz
ec
edu
ee
eg
eh
er
es
et
eu
fi
fj
fk
fm
fo
fr
ga
gb
gd
ge
gf
gg
gh
gi
gl
gm
gn
gov
gp
gq
gr
gs
gt
gu
gw
gy
hk
hm
hn
hr
ht
hu
id
ie
il
im
in
info
int
io
iq
ir
is
it
je
jm
jo
jobs
jp
ke
kg
kh
ki
km
kn
kp
kr
kw
ky
kz
la
lb
lc
li
lk
lr
ls
lt
lu
lv
ly
ma
mc
md
me
mf
mg
mh
mil
mk
ml
mm
mn
mo
mobi
mp
mq
mr
ms
mt
mu
museum
mv
mw
mx
my
mz
na
name
nc
ne
net
nf
ng
ni
nl
no
np
nr
nu
nz
om
org
pa
pe
pf
pg
ph
pk
pl
pm
pn
pr
pro
ps
pt
pw
py
qa
re
ro
rs
ru
rw
sa
sb
sc
sd
se
sg
sh
si
sj
sk
sl
sm
sn
so
sr
st
su
sv
sy
sz
tc
td
tel
tf
tg
th
tj
tk
tl
tm
tn
to
tp
tr
travel
tt
tv
tw
tz
ua
ug
uk
um
us
uy
uz
va
vc
ve
vg
vi
vn
vu
wf
ws
ye
yt
yu
za
zm
zw

View File

@ -0,0 +1,132 @@
<?php
/**
* Phergie
*
* PHP version 5
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.
* It is also available through the world-wide-web at this URL:
* http://phergie.org/license
*
* @category Phergie
* @package Phergie_Plugin_Weather
* @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org)
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Weather
*/
/**
* Detects and responds to requests for current weather conditions in a
* particular location using data from a web service. Requires registering
* with weather.com to obtain authentication credentials, which must be
* stored in the configuration settings weather.partner_id and
* weather.license_key for the plugin to function.
*
* @category Phergie
* @package Phergie_Plugin_Weather
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Weather
* @link http://www.weather.com/services/xmloap.html
* @uses Phergie_Plugin_Command pear.phergie.org
* @uses Phergie_Plugin_Http pear.phergie.org
* @uses extension SimpleXML
*/
class Phergie_Plugin_Weather extends Phergie_Plugin_Abstract
{
/**
* Checks for dependencies.
*
* @return void
*/
public function onLoad()
{
$plugins = $this->getPluginHandler();
$plugins->getPlugin('Command');
$plugins->getPlugin('Http');
if (empty($this->config['weather.partner_id'])
|| empty($this->config['weather.license_key'])) {
$this->fail('weather.partner_id and weather.license_key must be specified');
}
}
/**
* Returns a weather report for a specified location.
*
* @param string $location Zip code or city/state/country specification
*
* @return void
*/
public function onCommandWeather($location)
{
$response = $this->plugins->http->get(
'http://xoap.weather.com/search/search',
array('where' => $location)
);
if ($response->isError()) {
$this->doNotice(
$this->event->getNick(),
'ERROR: ' . $response->getCode() . ' ' . $response->getMessage()
);
return;
}
$nick = $this->event->getNick();
$xml = $response->getContent();
if (count($xml->loc) == 0) {
$this->doNotice($nick, 'No results for that location.');
return;
}
$where = (string) $xml->loc[0]['id'];
$response = $this->plugins->http->get(
'http://xoap.weather.com/weather/local/' . $where,
array(
'cc' => '*',
'link' => 'xoap',
'prod' => 'xoap',
'par' => $this->config['weather.partner_id'],
'key' => $this->config['weather.license_key'],
)
);
if ($response->isError()) {
$this->doNotice(
$this->event->getNick(),
'ERROR: ' . $response->getCode() . ' ' . $response->getMessage()
);
return;
}
$xml = $response->getContent();
$weather = 'Weather for ' . (string) $xml->loc->dnam . ' - ';
$weather .= 'Current temperature ' .
(string) $xml->cc->tmp .
(string) $xml->head->ut . ' / ';
if ((string) $xml->head->ut == 'F') {
$weather .= round(((((int) $xml->cc->tmp - 32) * 5) / 9)) . 'C';
} else {
$weather .= round(((((int) $xml->cc->tmp * 9) / 5) + 32)) . 'F';
}
$weather .=
', Relative humidity ' . (string) $xml->cc->hmid . '%' .
', Current conditions ' . (string) $xml->cc->t .
', Last update ' . (string) $xml->cc->lsup .
' [ http://weather.com/weather/today/' .
str_replace(
array('(', ')', ',', ' '),
array('', '', '', '+'),
(string) $xml->loc->dnam
) .
' ]';
$this->doPrivmsg($this->event->getSource(), $nick . ': ' . $weather);
}
}

View File

@ -12,61 +12,62 @@ return array(
'realname' => 'Matthew Turland', 'realname' => 'Matthew Turland',
'nick' => 'Phergie2', 'nick' => 'Phergie2',
// 'password' => 'password goes here if needed', // 'password' => 'password goes here if needed',
// 'transport' => 'ssl' // uncomment to connect using SSL // 'transport' => 'ssl', // uncomment to connect using SSL
// 'encoding' => 'UTF8', // uncomment if using UTF8
) )
), ),
'processor' => 'async', 'processor' => 'async',
'processor.options' => array('usec' => 200000), 'processor.options' => array('usec' => 200000),
// Time zone. See: http://www.php.net/manual/en/timezones.php // Time zone. See: http://www.php.net/manual/en/timezones.php
'timezone' => 'UTC', 'timezone' => 'UTC',
// Whitelist of plugins to load // Whitelist of plugins to load
'plugins' => array( 'plugins' => array(
// To enable a plugin, simply add a string to this array containing // To enable a plugin, simply add a string to this array containing
// the short name of the plugin as shown below. // the short name of the plugin as shown below.
// 'ShortPluginName', // 'ShortPluginName',
// Below is an example of enabling the AutoJoin plugin, for which // Below is an example of enabling the AutoJoin plugin, for which
// the corresponding PEAR package is Phergie_Plugin_AutoJoin. This // the corresponding PEAR package is Phergie_Plugin_AutoJoin. This
// plugin allows you to set a list of channels in this configuration // plugin allows you to set a list of channels in this configuration
// file that the bot will automatically join when it connects to a // file that the bot will automatically join when it connects to a
// server. If you'd like to enable this plugin, simply install it, // server. If you'd like to enable this plugin, simply install it,
// uncomment the line below, and set a value for the setting // uncomment the line below, and set a value for the setting
// autojoin.channels (examples for which are located further down in // autojoin.channels (examples for which are located further down in
// this file). // this file).
// 'AutoJoin', // 'AutoJoin',
// A few other recommended plugins: // A few other recommended plugins:
// Servers randomly send PING events to clients to ensure that // Servers randomly send PING events to clients to ensure that
// they're still connected and will eventually terminate the // they're still connected and will eventually terminate the
// connection if a PONG response is not received. The Pong plugin // connection if a PONG response is not received. The Pong plugin
// handles sending these responses. // handles sending these responses.
// 'Pong', // 'Pong',
// It's sometimes difficult to distinguish between a lack of // It's sometimes difficult to distinguish between a lack of
// activity on a server and the client not receiving data even // activity on a server and the client not receiving data even
// though a connection remains open. The Ping plugin performs a self // though a connection remains open. The Ping plugin performs a self
// CTCP PING sporadically to ensure that its connection is still // CTCP PING sporadically to ensure that its connection is still
// functioning and, if not, terminates the bot. // functioning and, if not, terminates the bot.
// 'Ping', // 'Ping',
// Sometimes it's desirable to have the bot disconnect gracefully // Sometimes it's desirable to have the bot disconnect gracefully
// when issued a command to do so via a PRIVMSG event. The Quit // when issued a command to do so via a PRIVMSG event. The Quit
// plugin implements this using the Command plugin to intercept the // plugin implements this using the Command plugin to intercept the
// command. // command.
// 'Quit', // 'Quit',
), ),
// If set to true, this allows any plugin dependencies for plugins // If set to true, this allows any plugin dependencies for plugins
// listed in the 'plugins' option to be loaded even if they are not // listed in the 'plugins' option to be loaded even if they are not
// explicitly included in that list // explicitly included in that list
'plugins.autoload' => true, 'plugins.autoload' => true,
@ -83,13 +84,13 @@ return array(
// Examples of setting values for Ping plugin settings // Examples of setting values for Ping plugin settings
// This is the amount of time in seconds that the Ping plugin will wait // This is the amount of time in seconds that the Ping plugin will wait
// to receive an event from the server before it initiates a self-ping // to receive an event from the server before it initiates a self-ping
// 'ping.event' => 300, // 5 minutes // 'ping.event' => 300, // 5 minutes
// This is the amount of time in seconds that the Ping plugin will wait // This is the amount of time in seconds that the Ping plugin will wait
// following a self-ping attempt before it assumes that a response will // following a self-ping attempt before it assumes that a response will
// never be received and terminates the connection // never be received and terminates the connection
// 'ping.ping' => 10, // 10 seconds // 'ping.ping' => 10, // 10 seconds

View File

@ -37,6 +37,41 @@ class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
*/ */
protected $handler; protected $handler;
/**
* Mock Phergie_Config instance passed to the plugin handler constructor
*
* @var Phergie_Config
*/
protected $config;
/**
* Mock Phergie_Event_Handler instance passed to the plugin handler
* constructor
*
* @var Phergie_Event_Handler
*/
protected $events;
/**
* Returns a mock plugin instance.
*
* @param string $name Optional short name for the mock plugin, defaults
* to 'TestPlugin'
* @param array $methods Optional list of methods to override
*
* @return Phergie_Plugin_Abstract
*/
protected function getMockPlugin($name = 'TestPlugin', array $methods = array())
{
$methods[] = 'getName';
$plugin = $this->getMock('Phergie_Plugin_Abstract', $methods);
$plugin
->expects($this->any())
->method('getName')
->will($this->returnValue($name));
return $plugin;
}
/** /**
* Sets up a new handler instance before each test. * Sets up a new handler instance before each test.
* *
@ -44,69 +79,191 @@ class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
*/ */
public function setUp() public function setUp()
{ {
$this->config = $this->getMock('Phergie_Config');
$this->events = $this->getMock('Phergie_Event_Handler');
$this->handler = new Phergie_Plugin_Handler( $this->handler = new Phergie_Plugin_Handler(
new Phergie_Config(), $this->config,
new Phergie_Event_Handler() $this->events
); );
} }
/** /**
* Destroys the handler instance after each test * Tests iterability of the plugin handler.
* *
* @return void * @return void
*/ */
public function tearDown() public function testImplementsIteratorAggregate()
{
unset($this->handler);
}
/**
* Ensures that we can iterate over the handler
*
* @return void
*/
public function testImplementsIterator()
{ {
$reflection = new ReflectionObject($this->handler); $reflection = new ReflectionObject($this->handler);
$this->assertTrue( $this->assertTrue(
$reflection->implementsInterface('IteratorAggregate') $reflection->implementsInterface('IteratorAggregate'),
'Handler does not implement IteratorAggregate'
); );
$this->assertType( $this->assertType(
'Iterator', $this->handler->getIterator(), 'Iterator',
'getIterator() must actually return an Iterator' $this->handler->getIterator(),
'getIterator() must return an iterator'
); );
} }
/** /**
* Ensures a newly instantiated handler does not have plugins associated * Tests countability of the plugin handler.
* with it
* *
* @depends testImplementsIterator * @return void
*/
public function testImplementsCountable()
{
$reflection = new ReflectionObject($this->handler);
$this->assertTrue(
$reflection->implementsInterface('Countable'),
'Handler does not implement Countable'
);
$this->assertType(
'int',
count($this->handler),
'count() must return an integer'
);
}
/**
* Tests the plugin handler exposing added plugins as instance
* properties of the handler via isset().
*
* @return void
*/
public function testImplementsIsset()
{
$pluginName = 'TestPlugin';
$this->assertFalse(isset($this->handler->{$pluginName}));
$plugin = $this->getMockPlugin($pluginName);
$this->handler->addPlugin($plugin);
$this->assertTrue(isset($this->handler->{$pluginName}));
}
/**
* Tests the plugin handler exposing added plugins as instance
* properties of the handler.
*
* @depends testImplementsIsset
* @return void
*/
public function testImplementsGet()
{
$plugin = $this->getMockPlugin();
$this->handler->addPlugin($plugin);
$name = $plugin->getName();
$getPlugin = $this->handler->getPlugin($name);
$this->assertTrue(isset($this->handler->$name));
$get = $this->handler->$name;
$this->assertSame($getPlugin, $get);
}
/**
* Tests the plugin handler allowing for plugin removal via unset().
*
* @depends testImplementsGet
* @return void
*/
public function testImplementsUnset()
{
$plugin = $this->getMockPlugin();
$this->handler->addPlugin($plugin);
unset($this->handler->{$plugin->getName()});
$this->assertFalse($this->handler->hasPlugin($plugin->getName()));
}
/**
* Tests the plugin handler executing a callback on all contained
* plugins where one plugin short-circuits the process.
*
* @return void
*/
public function testImplementsCallWithShortCircuit()
{
$plugin1 = $this->getMockPlugin('TestPlugin1', array('callback'));
$plugin1
->expects($this->once())
->method('callback')
->will($this->returnValue(false));
$this->handler->addPlugin($plugin1);
$plugin2 = $this->getMockPlugin('TestPlugin2', array('callback'));
$plugin2
->expects($this->exactly(0))
->method('callback');
$this->handler->addPlugin($plugin2);
$this->assertFalse($this->handler->callback());
}
/**
* Tests the plugin handler executing a callback on all contained
* plugins where no plugins short-circuit the process.
*
* @return void
*/
public function testImplementsCallWithoutShortCircuit()
{
foreach (range(1, 2) as $index) {
$plugin = $this->getMockPlugin('TestPlugin' . $index, array('callback'));
$plugin
->expects($this->once())
->method('callback');
$this->handler->addPlugin($plugin);
}
$this->assertTrue($this->handler->callback());
}
/**
* Tests a newly instantiated handler not having plugins associated with
* it.
*
* @depends testImplementsCountable
* @return void * @return void
*/ */
public function testEmptyHandlerHasNoPlugins() public function testEmptyHandlerHasNoPlugins()
{ {
$count = 0; $this->assertEquals(0, count($this->handler));
foreach ($this->handler as $plugin) {
$count++;
}
$this->assertEquals(0, $count);
} }
/** /**
* Ensures a newly instantiated handler does not default to autoload * Tests a newly instantiated handler not having autoloading enabled by
* default.
* *
* @return void * @return void
*/ */
public function testDefaultsToNotAutoload() public function testGetAutoloadDefaultsToNotAutoload()
{ {
$this->assertFalse($this->handler->getAutoload()); $this->assertFalse($this->handler->getAutoload());
} }
/** /**
* addPath provides a fluent interface * Tests setAutoload().
*
* @depends testGetAutoloadDefaultsToNotAutoload
* @return void
*/
public function testSetAutoload()
{
$this->assertSame(
$this->handler->setAutoload(true),
$this->handler,
'setAutoload() does not provide a fluent interface'
);
$this->assertTrue(
$this->handler->getAutoload(),
'setAutoload() had no effect on getAutoload()'
);
}
/**
* Tests addPath() providing a fluent interface.
* *
* @return void * @return void
*/ */
@ -117,7 +274,8 @@ class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
} }
/** /**
* addPath throws an exception when it cannot read the directory * Tests addPath() throwing an exception when it cannot read the
* directory.
* *
* @return void * @return void
*/ */
@ -133,122 +291,113 @@ class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
return; return;
} }
$this->fail('An expected exception has not been raised.'); $this->fail('An expected exception has not been raised');
} }
/** /**
* adds a path into the plugin handler and then ensures that files * Tests adding a path to the plugin handler.
* in that location can be found
* *
* @return void * @return void
*/ */
public function testAddPath() public function testAddPath()
{ {
$plugin_name = 'Mock'; $pluginName = 'Mock';
try { try {
$this->handler->addPlugin($plugin_name); $this->handler->addPlugin($pluginName);
} catch(Phergie_Plugin_Exception $e) { } catch(Phergie_Plugin_Exception $e) {
$this->assertEquals( $this->assertEquals(
Phergie_Plugin_Exception::ERR_CLASS_NOT_FOUND, Phergie_Plugin_Exception::ERR_CLASS_NOT_FOUND,
$e->getCode() $e->getCode()
); );
$this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
try {
$this->handler->addPlugin($plugin_name);
} catch(Phergie_Plugin_Exception $e) {
$this->fail(
'After adding the directory, the plugin was still '
. 'not found.'
);
}
return;
} }
$this->fail( if (!isset($e)) {
'Before adding the directory, an expected exception ' $this->fail('Plugin loaded, path was already present');
. 'was not raised' }
);
}
/**
* addPlugin returns the plugin instance that was added
*
* @return void
*/
public function testAddPluginByInstanceReturnsPluginInstance() {
$plugin = $this->getMock('Phergie_Plugin_Abstract');
$plugin
->expects($this->any())
->method('getName')
->will($this->returnValue('TestPlugin'));
$returned_plugin = $this->handler->addPlugin($plugin);
$this->assertSame(
$returned_plugin,
$plugin,
'addPlugin returns the same instance that is passed to it'
);
}
/**
* Can add a plugin to the handler by shortname
*
* @return void
*/
public function testAddPluginToHandlerByShortname()
{
$plugin_name = 'Mock';
$this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_'); $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
$returned_plugin = $this->handler->addPlugin($plugin_name); try {
$this->assertTrue($this->handler->hasPlugin($plugin_name)); $this->handler->addPlugin($pluginName);
} catch(Phergie_Plugin_Exception $e) {
$this->fail('Added path, plugin still not found');
}
}
/**
* Tests addPlugin() returning an added plugin instance.
*
* @return void
*/
public function testAddPluginByInstanceReturnsPluginInstance()
{
$plugin = $this->getMockPlugin();
$returnedPlugin = $this->handler->addPlugin($plugin);
$this->assertSame(
$returnedPlugin,
$plugin,
'addPlugin() does not return the instance passed to it'
);
}
/**
* Tests adding a plugin to the handler using the plugin's short name.
*
* @return void
*/
public function testAddPluginByShortName()
{
$pluginName = 'Mock';
$this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
$returnedPlugin = $this->handler->addPlugin($pluginName);
$this->assertTrue($this->handler->hasPlugin($pluginName));
$this->assertType( $this->assertType(
'Phergie_Plugin_Mock', 'Phergie_Plugin_Mock',
$this->handler->getPlugin($plugin_name) $this->handler->getPlugin($pluginName)
); );
$this->assertSame( $this->assertSame(
$this->handler->getPlugin($plugin_name), $this->handler->getPlugin($pluginName),
$returned_plugin, $returnedPlugin,
'Handler contains plugin when added by shortname.' 'Handler does not contain added plugin'
); );
} }
/** /**
* Can add a plugin to the handler by instance * Tests adding a plugin instance to the handler.
* *
* @return void * @return void
*/ */
public function testAddPluginToHandlerByInstance() public function testAddPluginByInstance()
{ {
$plugin = $this->getMock('Phergie_Plugin_Abstract'); $plugin = $this->getMockPlugin();
$plugin $returnedPlugin = $this->handler->addPlugin($plugin);
->expects($this->any())
->method('getName')
->will($this->returnValue('TestPlugin'));
$returned_plugin = $this->handler->addPlugin($plugin);
$this->assertTrue($this->handler->hasPlugin('TestPlugin')); $this->assertTrue($this->handler->hasPlugin('TestPlugin'));
$this->assertSame( $this->assertSame(
$plugin, $returned_plugin, $plugin,
'addPlugin returns the same plugin' $returnedPlugin,
'addPlugin() does not return added plugin instance'
); );
$this->assertSame( $this->assertSame(
$plugin, $this->handler->getPlugin('TestPlugin'), $plugin,
'getPlugin returns the same plugin' $this->handler->getPlugin('TestPlugin'),
'getPlugin() does not return added plugin instance'
); );
} }
/** /**
* addPlugin throws an exception when it can't find the plugin * Tests addPlugin() throwing an exception when the plugin class file
* can't be found.
* *
* @return void * @return void
*/ */
public function testAddPluginThrowsExceptionIfCannotFindPlugin() public function testAddPluginThrowsExceptionWhenPluginFileNotFound()
{ {
try { try {
$this->handler->addPlugin('TestPlugin'); $this->handler->addPlugin('TestPlugin');
@ -260,12 +409,68 @@ class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
return; return;
} }
$this->fail('An expected exception has not been raised.'); $this->fail('An expected exception has not been raised');
} }
/** /**
* addPlugin throws an exception when trying to instantiate a * Recursively removes all files and subdirectories in a directory.
* class that doesn't extend from Phergie_Plugin_Abstract *
* @param string $path Directory path
* @return void
*/
private function removeDirectory($path)
{
if (file_exists($path)) {
$it = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($path),
RecursiveIteratorIterator::CHILD_FIRST
);
foreach ($it as $entry) {
if ($it->isDot()) {
continue;
}
if ($entry->isDir()) {
rmdir($entry->getPathname());
} else {
unlink($entry->getPathname());
}
}
}
}
/**
* Tests addPlugin() throwing an exception when the plugin class file is
* found, but does not contain the plugin class as expected.
*
* @return void
*/
public function testAddPluginThrowsExceptionWhenPluginClassNotFound()
{
$path = sys_get_temp_dir() . '/Phergie/Plugin';
$this->removeDirectory(dirname($path));
mkdir($path, 0777, true);
touch($path . '/TestPlugin.php');
$this->handler->addPath($path, 'Phergie_Plugin_');
try {
$this->handler->addPlugin('TestPlugin');
} catch(Phergie_Plugin_Exception $e) { }
if (isset($e)) {
$this->assertEquals(
Phergie_Plugin_Exception::ERR_CLASS_NOT_FOUND,
$e->getCode()
);
} else {
$this->fail('An expected exception has not been raised');
}
$this->removeDirectory(dirname($path));
}
/**
* Tests addPlugin() throwing an exception when trying to instantiate a
* class that doesn't extend Phergie_Plugin_Abstract.
* *
* @return void * @return void
*/ */
@ -281,11 +486,11 @@ class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
return; return;
} }
$this->fail('An expected exception has not been raised.'); $this->fail('An expected exception has not been raised');
} }
/** /**
* addPlugin throws an exception when trying to instantiate a * Tests addPlugin() throwing an exception when trying to instantiate a
* class that can't be instantiated. * class that can't be instantiated.
* *
* @return void * @return void
@ -303,143 +508,88 @@ class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
return; return;
} }
$this->fail('An expected exception has not been raised.'); $this->fail('An expected exception has not been raised');
} }
/** /**
* addPlugin with shortname and arguments passes args to constructor * Tests adding a plugin by its short name with arguments passed to the
* * plugin constructor.
* @return null
*/
public function testAddPluginShortnamePassesArgsToConstructor()
{
$plugin_name = 'Mock';
$this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
$arguments = array('a', 'b', 'c');
$plugin = $this->handler->addPlugin($plugin_name, $arguments);
$this->assertAttributeSame(
$arguments,
'args',
$plugin,
'Arguments passed in to addPlugin match the arguments '
. 'the Mock plugin constructor received'
);
}
/**
* addPlugin passes Phergie_Config to instantiated plugin
*
* @return null
*/
public function testAddPluginPassesPhergieConfigToInstantiatedPlugin()
{
$my_config = new Phergie_Config();
$my_config['my_option'] = 'my_value';
// create a new handler with this config
unset($this->handler);
$this->handler = new Phergie_Plugin_Handler(
$my_config,
new Phergie_Event_Handler()
);
$plugin_name = 'Mock';
$this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
$plugin = $this->handler->addPlugin($plugin_name);
$this->assertSame(
$my_config,
$plugin->getConfig(),
'addPlugin passes Phergie_Config to instantiated plugin'
);
}
/**
* addPlugin passes Phergie_Event_Handler to instantiated plugin
*
* @return null
*/
public function testAddPluginPassesPhergieEventHandlerToInstantiatedPlugin()
{
$plugin = $this->getMock('Phergie_Plugin_Abstract');
$plugin
->expects($this->any())
->method('getName')
->will($this->returnValue('TestPlugin'));
$my_event_handler = new Phergie_Event_Handler();
$my_event_handler->addEvent($plugin, 'ping');
// create a new plugin handler with this event handler
unset($this->handler);
$this->handler = new Phergie_Plugin_Handler(
new Phergie_Config(),
$my_event_handler
);
$plugin_name = 'Mock';
$this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
$plugin = $this->handler->addPlugin($plugin_name);
$this->assertSame(
$my_event_handler,
$plugin->getEventHandler(),
'addPlugin passes Phergie_Event_Handler to instantiated plugin'
);
}
/**
* @todo addPlugin calls onLoad() to instantiated plugin
*/
/**
* implements __isset
* *
* @return void * @return void
*/ */
public function testPluginHandlerImplementsIsset() public function testAddPluginShortNamePassesArgsToConstructor()
{ {
$plugin_name = 'TestPlugin'; $pluginName = 'Mock';
$this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
$this->assertFalse(isset($this->handler->{$plugin_name})); $arguments = array('a', 'b', 'c');
$plugin = $this->handler->addPlugin($pluginName, $arguments);
$plugin = $this->getMock('Phergie_Plugin_Abstract');
$plugin
->expects($this->any())
->method('getName')
->will($this->returnValue($plugin_name));
$this->handler->addPlugin($plugin);
$this->assertTrue(isset($this->handler->{$plugin_name}));
$this->assertAttributeSame(
$arguments,
'arguments',
$plugin,
'Arguments do not match'
);
} }
/** /**
* addPlugin() returns the same plugin when requested twice * Tests addPlugin() passing Phergie_Config to an instantiated plugin.
*
* @return void
*/
public function testAddPluginPassesConstructorArguments()
{
$pluginName = 'Mock';
$this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
$plugin = $this->handler->addPlugin($pluginName);
$this->assertSame(
$this->config,
$plugin->getConfig(),
'Phergie_Config instances do not match'
);
$this->assertSame(
$this->events,
$plugin->getEventHandler(),
'Phergie_Event_Handler instances do not match'
);
}
/**
* Tests addPlugin() calling onLoad() on an instantiated plugin.
*
* @return void
*/
public function testAddPluginCallsOnLoadOnInstantiatedPlugin()
{
$plugin = $this->getMockPlugin(null, array('onLoad'));
$plugin
->expects($this->once())
->method('onLoad');
$this->handler->addPlugin($plugin);
}
/**
* Tests addPlugin() returning the same plugin when called twice.
* *
* @return void * @return void
*/ */
public function testAddPluginReturnsSamePluginWhenAskedTwice() public function testAddPluginReturnsSamePluginWhenAskedTwice()
{ {
$plugin_name = 'Mock'; $pluginName = 'Mock';
$this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_'); $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
$plugin1 = $this->handler->addPlugin($pluginName);
$plugin1 = $this->handler->addPlugin($plugin_name); $plugin2 = $this->handler->addPlugin($pluginName);
$plugin2 = $this->handler->addPlugin($plugin_name);
$this->assertSame($plugin1, $plugin2); $this->assertSame($plugin1, $plugin2);
} }
/** /**
* Tests an exception is thrown when trying to get a plugin * Tests getPlugin() throwing an exception when trying to get an
* that is not already loaded and autoload is off * unloaded plugin with autoload disabled.
* *
* @depends testDefaultsToNotAutoload * @depends testGetAutoloadDefaultsToNotAutoload
* @return void * @return void
*/ */
public function testExceptionThrownWhenLoadingPluginWithoutAutoload() public function testExceptionThrownWhenLoadingPluginWithoutAutoload()
@ -456,6 +606,134 @@ class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
return; return;
} }
$this->fail('An expected exception has not been raised.'); $this->fail('An expected exception has not been raised');
}
/**
* Tests addPlugins() with a plugin short name and no plugin constructor
* arguments.
*
* @depends testAddPluginByShortName
* @depends testAddPluginByInstance
* @return void
*/
public function testAddPluginsWithoutArguments()
{
$prefix = 'Phergie_Plugin_';
$this->handler->addPath(dirname(__FILE__), $prefix);
$plugin = 'Mock';
$this->handler->addPlugins(array($plugin));
$returnedPlugin = $this->handler->getPlugin($plugin);
$this->assertContains(
get_class($returnedPlugin),
$prefix . $plugin,
'Short name plugin not of expected class'
);
}
/**
* Tests addPlugins() with a plugin short name and plugin constructor
* arguments.
*
* @depends testAddPluginByShortName
* @depends testAddPluginByInstance
* @return void
*/
public function testAddPluginsWithArguments()
{
$prefix = 'Phergie_Plugin_';
$this->handler->addPath(dirname(__FILE__), $prefix);
$arguments = array(1, 2, 3);
$plugin = array('Mock', $arguments);
$this->handler->addPlugins(array($plugin));
$returnedPlugin = $this->handler->getPlugin('Mock');
$this->assertEquals(
$arguments,
$returnedPlugin->getArguments(),
'Constructor arguments for instance plugin do not match'
);
}
/**
* Tests removePlugin() with a plugin instance.
*
* @depends testAddPluginByInstance
* @return void
*/
public function testRemovePluginByInstance()
{
$plugin = $this->getMockPlugin();
$this->handler->addPlugin($plugin);
$this->handler->removePlugin($plugin);
$this->assertFalse(
$this->handler->hasPlugin($plugin->getName()),
'Plugin was not removed'
);
}
/**
* Tests removePlugin() with a plugin short name.
*
* @depends testAddPluginByShortName
* @return void
*/
public function testRemovePluginByShortName()
{
$plugin = 'Mock';
$this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
$this->handler->addPlugin($plugin);
$this->handler->removePlugin($plugin);
$this->assertFalse(
$this->handler->hasPlugin($plugin),
'Plugin was not removed'
);
}
/**
* Tests getPlugin() when the plugin is not already loaded and
* autoloading is disabled.
*
* @depends testSetAutoload
* @return void
*/
public function testGetPluginWithAutoloadEnabled()
{
$this->handler->setAutoload(true);
$this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
$plugin = $this->handler->getPlugin('Mock');
$this->assertType(
'Phergie_Plugin_Mock',
$plugin,
'Retrieved plugin not of expected class'
);
}
/**
* Tests getPlugins().
*
* @depends testGetPluginWithAutoloadEnabled
* @return void
*/
public function testGetPlugins()
{
$plugin1 = $this->getMockPlugin('TestPlugin1');
$this->handler->addPlugin($plugin1);
$plugin2 = $this->getMockPlugin('TestPlugin2');
$this->handler->addPlugin($plugin2);
$expected = array(
'testplugin1' => $plugin1,
'testplugin2' => $plugin2,
);
$actual = $this->handler->getPlugins();
$this->assertEquals($expected, $actual);
$actual = $this->handler->getPlugins(array('testplugin1', 'testplugin2'));
$this->assertEquals($expected, $actual);
} }
} }

View File

@ -21,7 +21,7 @@
/** /**
* Creates a plugin on the filesystem that can be used by * Creates a plugin on the filesystem that can be used by
* Phergie_Plugin_Handler's addPath utility to be located and loaded. * Phergie_Plugin_Handler::addPath() to be located and loaded.
* *
* @category Phergie * @category Phergie
* @package Phergie_Tests * @package Phergie_Tests
@ -32,18 +32,30 @@
class Phergie_Plugin_Mock extends Phergie_Plugin_Abstract class Phergie_Plugin_Mock extends Phergie_Plugin_Abstract
{ {
/** /**
* holds the arguments that were passed in to the constructor * Arguments passed to the constructor
*
* @var array * @var array
*/ */
protected $args; protected $arguments;
/** /**
* processes a variable number of arguments into the args property * Stores all arguments for later use.
* *
* @return null * @return void
*/ */
public function __construct() public function __construct()
{ {
$this->args = func_get_args(); $this->arguments = func_get_args();
}
/**
* Returns all constructor arguments.
*
* @return array Enumerated array containing the arguments passed to the
* constructor in order
*/
public function getArguments()
{
return $this->arguments;
} }
} }

View File

@ -0,0 +1,205 @@
<?php
/**
* Phergie
*
* PHP version 5
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.
* It is also available through the world-wide-web at this URL:
* http://phergie.org/license
*
* @category Phergie
* @package Phergie
* @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org)
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie
*/
require_once dirname(__FILE__) . '/TestCase.php';
/**
* Unit test suite for Pherge_Plugin_SpellCheck.
*
* @category Phergie
* @package Phergie_Tests
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie
*/
class Phergie_Plugin_SpellCheckTest extends Phergie_Plugin_TestCase
{
/**
* Current SpellCheck plugin instance
*
* @var Phergie_Plugin_SpellCheck
*/
protected $spell;
/**
* Sets up the fixture, for example, opens a network connection.
* This method is called before a test is executed.
*
* @return void
*/
protected function setUp()
{
$this->config = array('spellcheck.lang' => 'en');
$this->spell = new Phergie_Plugin_SpellCheck();
$this->setPlugin(new Phergie_Plugin_Command());
$config = $this->plugin->getConfig();
$handler = new Phergie_Plugin_Handler($config, $this->handler);
$this->plugin->setPluginHandler($handler);
$handler->addPlugin($this->plugin);
$handler->addPlugin($this->spell);
$this->spell->setEventHandler($this->handler);
$this->spell->setConnection($this->connection);
}
/**
* @event Phergie_Event_Request::privmsg
* @eventArg #zftalk
* @eventArg spell
*/
public function testSpell()
{
$this->spell->onLoad();
$this->copyEvent();
$this->plugin->onPrivMsg();
$this->assertDoesNotHaveEvent(Phergie_Event_Command::TYPE_PRIVMSG);
}
/**
* @event Phergie_Event_Request::privmsg
* @eventArg #phergie
* @eventArg spell test
*/
public function testSpellTest()
{
$this->spell->onLoad();
$this->copyEvent();
$this->plugin->onPrivMsg();
$events = $this->getResponseEvents(Phergie_Event_Command::TYPE_PRIVMSG);
$this->assertEquals(1, count($events));
foreach ($events as $event) {
$args = $event->getArguments();
$this->assertEquals('#phergie', $args[0]);
$this->assertContains('CheckSpellUser:', $args[1]);
$this->assertContains('test', $args[1]);
$this->assertContains('correct', $args[1]);
}
}
/**
* @event Phergie_Event_Request::privmsg
* @eventArg #phergie
* @eventArg spell testz
*/
public function testSpellTestz()
{
$this->spell->onLoad();
$this->copyEvent();
$this->plugin->onPrivMsg();
$events = $this->getResponseEvents(Phergie_Event_Command::TYPE_PRIVMSG);
$this->assertEquals(1, count($events));
foreach ($events as $event) {
$args = $event->getArguments();
$this->assertEquals('#phergie', $args[0]);
$this->assertContains('CheckSpellUser:', $args[1]);
$this->assertRegExp('/([a-z]+, ){4}/', $args[1]);
$this->assertContains('testz', $args[1]);
$this->assertContains('test,', $args[1]);
}
}
/**
* @event Phergie_Event_Request::privmsg
* @eventArg #phergie
* @eventArg spell testz
*/
public function testSpellMoreSuggestions()
{
$config = $this->spell->getConfig();
$this->copyEvent();
$config['spellcheck.limit'] = 6;
$this->spell->onLoad();
$this->plugin->onPrivMsg();
$events = $this->getResponseEvents(Phergie_Event_Command::TYPE_PRIVMSG);
$this->assertEquals(1, count($events));
foreach ($events as $event) {
$args = $event->getArguments();
$this->assertEquals('#phergie', $args[0]);
$this->assertContains('CheckSpellUser:', $args[1]);
$this->assertRegExp('/([a-z]+, ){5}/', $args[1]);
$this->assertContains('testz', $args[1]);
$this->assertContains('test,', $args[1]);
}
}
/**
* @event Phergie_Event_Request::privmsg
* @eventArg #phergie
* @eventArg spell qwertyuiopasdfghjklzxcvbnm
*/
public function testSpellNoSuggestions()
{
$this->spell->onLoad();
$this->copyEvent();
$this->plugin->onPrivMsg();
$events = $this->getResponseEvents(Phergie_Event_Command::TYPE_PRIVMSG);
$this->assertEquals(1, count($events));
foreach ($events as $event) {
$args = $event->getArguments();
$this->assertEquals('#phergie', $args[0]);
$this->assertContains('CheckSpellUser:', $args[1]);
$this->assertContains('find any suggestions', $args[1]);
}
}
/**
* Copy event from command to spell plugin
*
* @return void
*/
protected function copyEvent()
{
$hostmask = Phergie_Hostmask::fromString('CheckSpellUser!test@testing.org');
$event = $this->plugin->getEvent();
$event->setHostmask($hostmask);
$this->spell->setEvent($event);
}
}

View File

@ -12,7 +12,7 @@
* http://phergie.org/license * http://phergie.org/license
* *
* @category Phergie * @category Phergie
* @package Phergie_Tests * @package Phergie_Tests
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org) * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
* @license http://phergie.org/license New BSD License * @license http://phergie.org/license New BSD License

View File

@ -45,6 +45,9 @@
<include name="Phergie/Connection/Exception.php" /> <include name="Phergie/Connection/Exception.php" />
<include name="Phergie/Connection/Handler.php" /> <include name="Phergie/Connection/Handler.php" />
<include name="Phergie/Connection.php" /> <include name="Phergie/Connection.php" />
<include name="Phergie/Db/Exception.php" />
<include name="Phergie/Db/Manager.php" />
<include name="Phergie/Db/Sqlite.php" />
<include name="Phergie/Driver/Abstract.php" /> <include name="Phergie/Driver/Abstract.php" />
<include name="Phergie/Driver/Exception.php" /> <include name="Phergie/Driver/Exception.php" />
<include name="Phergie/Driver/Streams.php" /> <include name="Phergie/Driver/Streams.php" />