<?php
/**
- * Phergie
+ * Phergie
*
* PHP version 5
*
* It is also available through the world-wide-web at this URL:
* http://phergie.org/license
*
- * @category Phergie
+ * @category Phergie
* @package Phergie
* @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org)
/**
* Exception related to driver operations.
*
- * @category Phergie
+ * @category Phergie
* @package Phergie
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
class Phergie_Driver_Exception extends Phergie_Exception
{
/**
- * Error indicating that an operation was requested requiring an active
+ * Error indicating that an operation was requested requiring an active
* connection before one had been set
*/
const ERR_NO_ACTIVE_CONNECTION = 1;
/**
- * Error indicating that an operation was requested requiring an active
+ * Error indicating that an operation was requested requiring an active
* connection where one had been set but not initiated
*/
const ERR_NO_INITIATED_CONNECTION = 2;
* Error indicating that an attempt to send data via a connection failed
*/
const ERR_CONNECTION_WRITE_FAILED = 4;
+
+ /**
+ * Error indicating that an attempt to read data via a connection failed
+ */
+ const ERR_CONNECTION_READ_FAILED = 5;
}
{
// Check for a new event on the current connection
$buffer = fgets($this->socket, 512);
+ if ($buffer === false) {
+ throw new Phergie_Driver_Exception(
+ 'Unable to read from socket',
+ Phergie_Driver_Exception::ERR_CONNECTION_READ_FAILED
+ );
+ }
// If no new event was found, return NULL
if (empty($buffer)) {
case 'privmsg':
case 'notice':
- $ctcp = substr(strstr($args, ':'), 1);
- if (substr($ctcp, 0, 1) === "\x01" && substr($ctcp, -1) === "\x01") {
+ $args = $this->parseArguments($args, 2);
+ list($source, $ctcp) = $args;
+ if (substr($ctcp, 0, 1) === "\001" && substr($ctcp, -1) === "\001") {
$ctcp = substr($ctcp, 1, -1);
$reply = ($cmd == 'notice');
list($cmd, $args) = array_pad(explode(' ', $ctcp, 2), 2, null);
}
break;
case 'action':
- $args = array($this->getConnection()->getNick(), $args);
+ $args = array($source, $args);
break;
default:
if ($reply) {
$cmd .= 'Response';
}
- $args = array($this->getConnection()->getNick(), $ctcp);
+ $args = array($source, $args);
break;
}
- } else {
- $args = $this->parseArguments($args, 2);
}
break;
--- /dev/null
+<?php
+
+if (!defined('__DIR__')) {
+ define('__DIR__', dirname(__FILE__));
+}
+
+// Create database schema
+echo 'Creating database', PHP_EOL;
+$file = __DIR__ . '/beer.db';
+if (file_exists($file)) {
+ unlink($file);
+}
+$db = new PDO('sqlite:' . $file);
+$db->exec('CREATE TABLE beer (name VARCHAR(255), link VARCHAR(255))');
+$db->exec('CREATE UNIQUE INDEX beer_name ON beer (name)');
+$insert = $db->prepare('INSERT INTO beer (name, link) VALUES (:name, :link)');
+
+// Get raw beerme.com data set
+echo 'Downloading beerme.com data set', PHP_EOL;
+$file = __DIR__ . '/beerlist.txt';
+if (!file_exists($file)) {
+ copy('http://beerme.com/beerlist.php', $file);
+}
+$contents = file_get_contents($file);
+
+// Extract data from data set
+echo 'Processing beerme.com data', PHP_EOL;
+$contents = tidy_repair_string($contents);
+libxml_use_internal_errors(true);
+$doc = new DOMDocument;
+$doc->loadHTML($contents);
+libxml_clear_errors();
+$xpath = new DOMXPath($doc);
+$beers = $xpath->query('//table[@class="beerlist"]/tr/td[1]');
+$db->beginTransaction();
+foreach ($beers as $beer) {
+ $name = $beer->textContent;
+ $link = 'http://beerme.com' . $beer->childNodes->item(1)->getAttribute('href');
+ $insert->execute(array($name, $link));
+}
+$db->commit();
+
+// Clean up
+echo 'Cleaning up', PHP_EOL;
+unlink($file);
+
+// Get and decompress openbeerdb.com data set
+$archive = __DIR__ . '/beers.zip';
+if (!file_exists($archive)) {
+ echo 'Downloading openbeerdb.com data set', PHP_EOL;
+ copy('http://openbeerdb.googlecode.com/files/beers.zip', $archive);
+}
+
+echo 'Decompressing openbeerdb.com data set', PHP_EOL;
+$zip = new ZipArchive;
+$zip->open($archive);
+$zip->extractTo(__DIR__, 'beers/beers.csv');
+$zip->close();
+$file = __DIR__ . '/beers/beers.csv';
+
+// Extract data from data set
+echo 'Processing openbeerdb.com data', PHP_EOL;
+$fp = fopen($file, 'r');
+$columns = fgetcsv($fp, 0, '|');
+$db->beginTransaction();
+while ($line = fgetcsv($fp, 0, '|')) {
+ $line = array_combine($columns, $line);
+ $name = $line['name'];
+ $link = null;
+ $insert->execute(array($name, $link));
+}
+$db->commit();
+fclose($fp);
+
+// Clean up
+echo 'Cleaning up', PHP_EOL;
+unlink($file);
+unlink($archive);
+rmdir(__DIR__ . '/beers');
--- /dev/null
+<?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_Encoding
+ * @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_Encoding
+ */
+
+/**
+ * Handles decoding markup entities and converting text between character
+ * encodings.
+ *
+ * @category Phergie
+ * @package Phergie_Plugin_Encoding
+ * @author Phergie Development Team <team@phergie.org>
+ * @license http://phergie.org/license New BSD License
+ * @link http://pear.phergie.org/package/Phergie_Plugin_Encoding
+ */
+class Phergie_Plugin_Encoding extends Phergie_Plugin_Abstract
+{
+ /**
+ * Lookup table for entity conversions not supported by
+ * html_entity_decode()
+ *
+ * @var array
+ * @link http://us.php.net/manual/en/function.get-html-translation-table.php#73409
+ * @link http://us.php.net/manual/en/function.get-html-translation-table.php#73410
+ */
+ protected static $entities = array(
+ 'α' => 913,
+ ''' => 39,
+ 'β' => 914,
+ '•' => 149,
+ 'χ' => 935,
+ 'ˆ' => 94,
+ 'δ' => 916,
+ 'ε' => 917,
+ 'η' => 919,
+ 'ƒ' => 402,
+ 'γ' => 915,
+ 'ι' => 921,
+ 'κ' => 922,
+ 'λ' => 923,
+ '“' => 147,
+ '‹' => 139,
+ '‘' => 145,
+ '—' => 151,
+ '−' => 45,
+ 'μ' => 924,
+ '–' => 150,
+ 'ν' => 925,
+ 'œ' => 140,
+ 'ω' => 937,
+ 'ο' => 927,
+ 'φ' => 934,
+ 'π' => 928,
+ 'ϖ' => 982,
+ 'ψ' => 936,
+ '”' => 148,
+ 'ρ' => 929,
+ '›' => 155,
+ '’' => 146,
+ 'š' => 138,
+ 'σ' => 931,
+ 'ς' => 962,
+ 'τ' => 932,
+ 'θ' => 920,
+ 'ϑ' => 977,
+ '˜' => 126,
+ '™' => 153,
+ 'ϒ' => 978,
+ 'υ' => 933,
+ 'ξ' => 926,
+ 'ÿ' => 159,
+ 'ζ' => 918,
+ );
+
+ /**
+ * Decodes markup entities in a given string.
+ *
+ * @param string $string String containing markup entities
+ * @param string $charset Optional character set name to use in decoding
+ * entities, defaults to UTF-8
+ *
+ * @return string String with markup entities decoded
+ */
+ public function decodeEntities($string, $charset = 'UTF-8')
+ {
+ $string = str_ireplace(
+ array_keys(self::$entities),
+ array_map('chr', self::$entities),
+ $string
+ );
+ $string = html_entity_decode($string, ENT_QUOTES, $charset);
+ $string = preg_replace(
+ array('/�*([0-9]+);/me', '/�*([a-f0-9]+);/mei'),
+ array('$this->codeToUtf(\\1)', '$this->codeToUtf(hexdec(\\1))'),
+ $string
+ );
+ return $string;
+ }
+
+ /**
+ * Converts a given unicode to its UTF-8 equivalent.
+ *
+ * @param int $code Code to convert
+ * @return string Character corresponding to code
+ */
+ public function codeToUtf8($code)
+ {
+ $code = (int) $code;
+ switch ($code) {
+ // 1 byte, 7 bits
+ case 0:
+ return chr(0);
+ case ($code & 0x7F):
+ return chr($code);
+
+ // 2 bytes, 11 bits
+ case ($code & 0x7FF):
+ return chr(0xC0 | (($code >> 6) & 0x1F)) .
+ chr(0x80 | ($code & 0x3F));
+
+ // 3 bytes, 16 bits
+ case ($code & 0xFFFF):
+ return chr(0xE0 | (($code >> 12) & 0x0F)) .
+ chr(0x80 | (($code >> 6) & 0x3F)) .
+ chr(0x80 | ($code & 0x3F));
+
+ // 4 bytes, 21 bits
+ case ($code & 0x1FFFFF):
+ return chr(0xF0 | ($code >> 18)) .
+ chr(0x80 | (($code >> 12) & 0x3F)) .
+ chr(0x80 | (($code >> 6) & 0x3F)) .
+ chr(0x80 | ($code & 0x3F));
+ }
+ }
+
+ /**
+ * Transliterates characters in a given string where possible.
+ *
+ * @param string $string String containing characters to
+ * transliterate
+ * @param string $charsetFrom Optional character set of the string,
+ * defaults to UTF-8
+ * @param string $charsetTo Optional character set to which the string
+ * should be converted, defaults to ISO-8859-1
+ *
+ * @return string String with characters transliterated or the original
+ * string if transliteration was not possible
+ */
+ public function transliterate($string, $charsetFrom = 'UTF-8', $charsetTo = 'ISO-8859-1')
+ {
+ // @link http://pecl.php.net/package/translit
+ if (function_exists('transliterate')) {
+ $string = transliterate($string, array('han_transliterate', 'diacritical_remove'), $charsetFrom, $charsetTo);
+ } elseif (function_exists('iconv')) {
+ $string = iconv($charsetFrom, $charsetTo . '//TRANSLIT', $string);
+ } else {
+ // @link http://stackoverflow.com/questions/1284535/php-transliteration/1285491#1285491
+ $string = preg_replace(
+ '~&([a-z]{1,2})(acute|cedil|circ|grave|lig|orn|ring|slash|th|tilde|uml);~i',
+ '$1',
+ htmlentities($string, ENT_COMPAT, $charsetFrom)
+ );
+ }
+ return $string;
+ }
+}
<?php
/**
- * Phergie
+ * Phergie
*
* PHP version 5
*
* It is also available through the world-wide-web at this URL:
* http://phergie.org/license
*
- * @category Phergie
+ * @category Phergie
* @package Phergie_Plugin_Google
* @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org)
*/
/**
- * Provides commands used to access several services offered by Google
- * including search, translation, weather, maps, and currency and general
+ * Provides commands used to access several services offered by Google
+ * including search, translation, weather, maps, and currency and general
* value unit conversion.
*
- * @category Phergie
+ * @category Phergie
* @package Phergie_Plugin_Google
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Google
* @uses Phergie_Plugin_Command pear.phergie.org
* @uses Phergie_Plugin_Http pear.phergie.org
+ * @uses Phergie_Plugin_Temperature pear.phergie.org
*
* @pluginDesc Provide access to some Google services
*/
*/
protected $http;
+ /**
+ * Language for Google Services
+ */
+ protected $lang;
+
/**
* Checks for dependencies.
*
$plugins->getPlugin('Command');
$this->http = $plugins->getPlugin('Http');
$plugins->getPlugin('Help')->register($this);
+ $plugins->getPlugin('Weather');
+
+ $this->lang = $this->getConfig('google.lang', 'en');
}
/**
$nick = $event->getNick();
if ($count) {
$msg
- = $nick . ': ' .
- number_format($count, 0) .
+ = $nick . ': ' .
+ number_format($count, 0) .
' estimated results for ' . $query;
$this->doPrivmsg($source, $msg);
} else {
* Performs a Google Translate search for the given term.
*
* @param string $from Language of the search term
- * @param string $to Language to which the search term should be
+ * @param string $to Language to which the search term should be
* translated
* @param string $query Term to translate
*
$this->doPrivmsg($source, $nick . ': ' . $json->responseDetails);
} else {
$this->doPrivmsg(
- $source,
+ $source,
$nick . ': ' . $json->responseData->translatedText
);
}
/**
* Performs a Google Weather search for the given term.
- *
+ *
* @param string $location Location to search for
+ * @param int $offset Optional day offset from the current date
+ * between 0 and 3 to get the forecast
*
* @return void
*
* @pluginCmd [location] Show the weather for the specified location
*/
- public function onCommandGw($location)
+ public function onCommandGw($location, $offset = null)
{
$url = 'http://www.google.com/ig/api';
$params = array(
'weather' => $location,
- 'hl' => 'pt-br',
+ 'hl' => $this->lang,
'oe' => 'UTF-8'
);
$response = $this->http->get($url, $params);
$xml = $response->getContent()->weather;
- $source = $this->getEvent()->getSource();
- if (!isset($xml->problem_cause)) {
- $city = $xml->forecast_information->city->attributes()->data[0];
- $time = $xml->forecast_information->current_date_time->attributes()
- ->data[0];
- $condition = $xml->current_conditions->condition->attributes()->data[0];
- $temp = $xml->current_conditions->temp_c->attributes()->data[0]
- . '� C';
- $humidity = $xml->current_conditions->humidity->attributes()->data[0];
- $wind = $xml->current_conditions->wind_condition->attributes()->data[0];
- $msg = implode(' - ', array($city, $temp, $condition, $humidity, $wind));
+
+ $event = $this->getEvent();
+ $source = $event->getSource();
+ $msg = '';
+ if ($event->isInChannel()) {
+ $msg .= $event->getNick() . ': ';
+ }
+
+ if (isset($xml->problem_cause)) {
+ $msg .= $xml->problem_cause->attributes()->data[0];
$this->doPrivmsg($source, $msg);
+ return;
+ }
- foreach ($xml->forecast_conditions as $key => $linha) {
- $day = ucfirst($linha->day_of_week->attributes()->data[0]);
- $min = $linha->low->attributes()->data[0];
- $max = $linha->high->attributes()->data[0];
- $condition = $linha->condition->attributes()->data[0];
- $msg
- = 'Forecast: ' . $day .
- ' - Min: ' . $min . '� C' .
- ' - Max: ' . $max . '� C' .
- ' - ' . $condition;
- $this->doPrivmsg($source, $msg);
+ $temperature = $this->plugins->getPlugin('Temperature');
+
+ $forecast = $xml->forecast_information;
+ $city = $forecast->city->attributes()->data[0];
+ $zip = $forecast->postal_code->attributes()->data[0];
+
+ if ($offset !== null) {
+ $offset = (int) $offset;
+ if ($offset < 0) {
+ $this->doNotice($source, 'Past weather data is not available');
+ return;
+ } elseif ($offset > 3) {
+ $this->doNotice($source, 'Future weather data is limited to 3 days from today');
+ return;
+ }
+
+ $linha = $xml->forecast_conditions[$offset];
+ $low = $linha->low->attributes()->data[0];
+ $high = $linha->high->attributes()->data[0];
+ $units = $forecast->unit_system->attributes()->data[0];
+ $condition = $linha->condition->attributes()->data[0];
+ $day = $linha->day_of_week->attributes()->data[0];
+
+ $date = ($offset == 0) ? time() : strtotime('next ' . $day);
+ $day = ucfirst($day) . ' ' . date('n/j/y', $date);
+
+ if ($units == 'US') {
+ $lowF = $low;
+ $lowC = $temperature->convertFahrenheitToCelsius($low);
+ $highF = $high;
+ $highC = $temperature->convertFahrenheitToCelsius($high);
+ } else {
+ $lowC = $low;
+ $lowF = $temperature->convertCelsiusToFahrenheit($lowC);
+ $highC = $high;
+ $highF = $temperature->convertCelsiusToFahrenheit($high);
}
+
+ $msg .= 'Forecast for ' . $city . ' (' . $zip . ')'
+ . ' on ' . $day . ' ::'
+ . ' Low: ' . $lowF . 'F/' . $lowC . 'C,'
+ . ' High: ' . $highF . 'F/' . $highC . 'C,'
+ . ' Conditions: ' . $condition;
} else {
- $this->doPrivmsg($source, $xml->problem_cause->attributes()->data[0]);
+ $conditions = $xml->current_conditions;
+ $condition = $conditions->condition->attributes()->data[0];
+ $tempF = $conditions->temp_f->attributes()->data[0];
+ $tempC = $conditions->temp_c->attributes()->data[0];
+ $humidity = $conditions->humidity->attributes()->data[0];
+ $wind = $conditions->wind_condition->attributes()->data[0];
+ $time = $forecast->current_date_time->attributes()->data[0];
+ $time = date('n/j/y g:i A', strtotime($time)) . ' +0000';
+
+ $hiF = $temperature->getHeatIndex($tempF, $humidity);
+ $hiC = $temperature->convertFahrenheitToCelsius($hiF);
+
+ $msg .= 'Weather for ' . $city . ' (' . $zip . ') -'
+ . ' Temperature: ' . $tempF . 'F/' . $tempC . 'C,'
+ . ' ' . $humidity . ','
+ . ' Heat Index: ' . $hiF . 'F/' . $hiC . 'C,'
+ . ' Conditions: ' . $condition . ','
+ . ' Updated: ' . $time;
}
+
+ $this->doPrivmsg($source, $msg);
}
/**
* @pluginCmd [location] Get the location from Google Maps to the location specified
*/
public function onCommandGmap($location)
- {
+ {
$event = $this->getEvent();
$source = $event->getSource();
$nick = $event->getNick();
-
+
$location = utf8_encode($location);
$url = 'http://maps.google.com/maps/geo';
$params = array(
'q' => $location,
'output' => 'json',
- 'gl' => 'br',
+ 'gl' => $this->lang,
'sensor' => 'false',
'oe' => 'utf8',
'mrt' => 'all',
'key' => $this->getConfig('google.key')
);
- $response = $this->http->get($url, $params);
+ $response = $this->http->get($url, $params);
$json = $response->getContent();
if (!empty($json)) {
$qtd = count($json->Placemark);
foreach ($json->Placemark as $places) {
$xy = $places->Point->coordinates;
$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';
$msg = $nick . ' -> ' . $address . ' - ' . $url;
$this->doPrivmsg($source, $msg);
}
} else {
$msg
- = $nick .
- ', there are a lot of places with that query.' .
+ = $nick .
+ ', there are a lot of places with that query.' .
' Try to be more specific!';
$this->doPrivmsg($source, $msg);
}
} elseif ($qtd == 1) {
$xy = $json->Placemark[0]->Point->coordinates;
$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';
$msg = $nick . ' -> ' . $address . ' - ' . $url;
$this->doPrivmsg($source, $msg);
}
/**
- * Perform a Google Convert query to convert a value from one metric to
+ * Perform a Google Convert query to convert a value from one metric to
* another.
*
* @param string $value Value to convert
} else {
$str = str_replace('<span class=bld>', '', $matches[0]);
$str = str_replace($to . '</span>', '', $str);
- $text
- = number_format($value, 2, ',', '.') . ' ' . $from .
+ $text
+ = number_format($value, 2, ',', '.') . ' ' . $from .
' => ' . number_format($str, 2, ',', '.') . ' ' . $to;
$this->doPrivmsg($source, $text);
}
*
* @return void
*
- * @pluginCmd [quantity] [unit] to [unit2] Convert a value from one
+ * @pluginCmd [quantity] [unit] to [unit2] Convert a value from one
* metric to another
*/
public function onCommandConvert($query)
$this->doNotice($nick, 'Sorry I couldn\'t find an answer.');
}
}
+
+
+ /**
+ * Returns the first definition of a Google Dictionary search.
+ *
+ * @param string $query Word to get the definition
+ *
+ * @return void
+ * @todo Implement use of URL shortening here
+ *
+ * @pluginCmd [query] do a search of a definition on Google Dictionary
+ */
+ public function onCommandDefine($query)
+ {
+ $query = urlencode($query);
+ $url = 'http://www.google.com/dictionary/json?callback=result'.
+ '&q='.$query.'&sl='.$this->lang.'&tl='.$this->lang.
+ '&restrict=pr,de';
+ $json = file_get_contents($url);
+
+ //Remove some garbage from the json
+ $json = str_replace(array("result(", ",200,null)"), "", $json);
+
+ //Awesome workaround to remove a lot of slashes from json
+ $json = str_replace('"', '¿?¿', $json);
+ $json = strip_tags(stripcslashes($json));
+ $json = str_replace('"', "'", $json);
+ $json = str_replace('¿?¿', '"', $json);
+
+ $json = json_decode($json);
+
+ $event = $this->getEvent();
+ $source = $event->getSource();
+ $nick = $event->getNick();
+ if (!empty($json->webDefinitions)){
+ $results = count($json->webDefinitions[0]->entries);
+ $more = $results > 1 ? ($results-1).' ' : NULL;
+ $lang_code = substr($this->lang, 0, 2);
+ $msg =
+ $nick . ': ' .
+ $json->webDefinitions[0]->entries[0]->terms[0]->text .
+ ' - You can find more '.$more.'results at '.
+ 'http://www.google.com/dictionary?aq=f&langpair='.
+ $lang_code.'%7C'.$lang_code.'&q='.$query.'&hl='.$lang_code;
+ $this->doPrivmsg($source, $msg);
+ }else{
+ if ($this->lang != 'en'){
+ $temp = $this->lang;
+ $this->lang = 'en';
+ $this->onCommandDefine($query);
+ $this->lang = $temp;
+ }else{
+ $msg = $nick . ': No results for this query.';
+ $this->doPrivmsg($source, $msg);
+ }
+ }
+ }
}
<?php
/**
- * Phergie
+ * Phergie
*
* PHP version 5
*
* It is also available through the world-wide-web at this URL:
* http://phergie.org/license
*
- * @category Phergie
+ * @category Phergie
* @package Phergie_Plugin_Http
* @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org)
*/
/**
- * Provides an HTTP client for plugins to use in contacting web services or
+ * Provides an HTTP client for plugins to use in contacting web services or
* retrieving feeds or web pages.
*
- * @category Phergie
+ * @category Phergie
* @package Phergie_Plugin_Http
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @var array
*/
protected $handlers;
-
+
/**
* Initializes the handler lookup table.
*
public function onLoad()
{
$this->handlers = array(
- '(?:application|text)/xml(?:;.*)?' => 'simplexml_load_string',
- '(?:(?:application|text)/(?:x-)?json)|text/javascript.*' => 'json_decode',
+ '(?:application|text)/xml(?:;.*)?'
+ => 'simplexml_load_string',
+ '(?:(?:application|text)/(?:x-)?json)|text/javascript.*'
+ => 'json_decode',
);
if (is_array($this->config['http.handlers'])) {
}
/**
- * Sets a handler callback for a content type, which is called when a
- * response of that content type is received to perform any needed
- * transformations on the response body content before storing it in the
- * response object. Note that the calling plugin is responsible for
+ * Sets a handler callback for a content type, which is called when a
+ * response of that content type is received to perform any needed
+ * transformations on the response body content before storing it in the
+ * response object. Note that the calling plugin is responsible for
* indicating any dependencies related to specified handler callbacks.
*
* @param string $type PCRE regular expression (without delimiters) that
}
/**
- * Supporting method that parses the status line of an HTTP response
+ * Supporting method that parses the status line of an HTTP response
* message.
*
* @param string $status Status line
*
- * @return array Associative array containing the HTTP version, response
+ * @return array Associative array containing the HTTP version, response
* code, and response description
*/
protected function parseStatusLine($status)
}
/**
- * Supporting method that acts as an error handler to intercept HTTP
+ * Supporting method that acts as an error handler to intercept HTTP
* responses resulting in PHP-level errors.
*
* @param int $errno Level of the error raised
* @param string $errfile Name of the file in which the error was raised
* @param string $errline Line number on which the error was raised
*
- * @return bool Always returns TRUE to allow normal execution to
+ * @return bool Always returns TRUE to allow normal execution to
* continue once this method terminates
*/
- protected function handleError($errno, $errstr, $errfile, $errline)
+ public function handleError($errno, $errstr, $errfile, $errline)
{
if ($httperr = strstr($errstr, 'HTTP/')) {
- $parts = $this->parseStatusLine($httperr);
+ $parts = $this->parseStatusLine($httperr);
$this->response
->setCode($parts['code'])
->setMessage($parts['message']);
* Supporting method that executes a request and handles the response.
*
* @param string $url URL to request
- * @param array $context Associative array of stream context parameters
+ * @param array $context Associative array of stream context parameters
*
- * @return Phergie_Plugin_Http_Response Object representing the response
+ * @return Phergie_Plugin_Http_Response Object representing the response
* resulting from the request
*/
public function request($url, array $context)
$message = $status['message'];
$headers = array();
foreach (array_slice($meta['wrapper_data'], 1) as $header) {
+ if (!strpos($header, ':')) {
+ continue;
+ }
list($name, $value) = explode(': ', $header, 2);
$headers[$name] = $value;
}
->setMessage($message)
->setHeaders($headers)
->setMeta($meta);
-
+
$body = stream_get_contents($stream);
$type = $this->response->getHeaders('content-type');
foreach ($this->handlers as $expr => $handler) {
* @param string $url URL for the request
* @param array $query Optional associative array of parameters
* constituting the URL query string if $url has none
- * @param array $context Optional associative array of additional stream
+ * @param array $context Optional associative array of additional stream
* context parameters
*
* @return Phergie_Plugin_Http_Response Received response data
* Performs a POST request.
*
* @param string $url URL for the request
- * @param array $query Optional associative array of parameters
+ * @param array $query Optional associative array of parameters
* constituting the URL query string if $url has none
- * @param array $post Optional associative array of parameters
- * constituting the POST request body if it is using the
+ * @param array $post Optional associative array of parameters
+ * constituting the POST request body if it is using the
* traditional URL-encoded format
- * @param array $context Optional associative array of additional stream
+ * @param array $context Optional associative array of additional stream
* context parameters
*
* @return Phergie_Plugin_Http_Response Received response data
*/
- public function post($url, array $query = array(), array $post = array(), array $context = array())
- {
+ public function post($url, array $query = array(),
+ array $post = array(), array $context = array()
+ ) {
if (!empty($params)) {
$url .= '?' . http_build_query($query);
}
$context['method'] = 'POST';
- if (!empty($post)
+ if (!empty($post)
&& (!empty($context['header'])
xor stripos($context['header'], 'Content-Type'))
) {
} else {
$context['header'] = '';
}
- $context['header'] .=
+ $context['header'] .=
'Content-Type: application/x-www-form-urlencoded';
$context['content'] = http_build_query($post);
}
<?php
/**
- * Phergie
+ * Phergie
*
* PHP version 5
*
* It is also available through the world-wide-web at this URL:
* http://phergie.org/license
*
- * @category Phergie
+ * @category Phergie
* @package Phergie_Plugin_Http
* @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org)
*/
/**
- * Data structure for HTTP response information.
+ * Data structure for HTTP response information.
*
- * @category Phergie
+ * @category Phergie
* @package Phergie_Plugin_Http
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
/**
* HTTP response code or 0 if no HTTP response was received
*
- * @var string
+ * @var string
*/
protected $code;
*
* @var array
*/
- protected $codeStrings = array(
+ protected static $codeStrings = array(
0 => 'No Response',
100 => 'Continue',
200 => 'OK',
);
/**
- * 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
*
* @var string
{
$code = $this->code;
- if (!isset($this->codeStrings[$code])) {
+ if (!isset(self::$codeStrings[$code])) {
return 'Unkown HTTP Status';
}
- return $this->codeStrings[$code];
+ return self::$codeStrings[$code];
}
/**
/**
* Returns the content of the response body.
*
- * @return mixed Response body content, decoded for supported content
+ * @return mixed Response body content, decoded for supported content
* types
*/
public function getContent()
/**
* Sets the response headers.
*
- * @param array $headers Associative array of response headers indexed
+ * @param array $headers Associative array of response headers indexed
* by header name
*
* @return Phergie_Plugin_Http_Response Provides a fluent interface
}
/**
- * Returns all response headers or the value of a single specified
+ * Returns all response headers or the value of a single specified
* response header.
*
- * @param string $name Optional name of a single header for which the
+ * @param string $name Optional name of a single header for which the
* associated value should be returned
*
- * @return array|string Associative array of all header values, a string
- * containing the value of the header indicated by $name if one
+ * @return array|string Associative array of all header values, a string
+ * containing the value of the header indicated by $name if one
* is set, or null if one is not
*/
public function getHeaders($name = null)
/**
* Returns all metadata or the value of a single specified metadatum.
*
- * @param string $name Optional name of a single metadatum for which the
+ * @param string $name Optional name of a single metadatum for which the
* associated value should be returned
- *
- * @return array|string|null Associative array of all metadata values, a
- * string containing the value of the metadatum indicated by
+ *
+ * @return array|string|null Associative array of all metadata values, a
+ * string containing the value of the metadatum indicated by
* $name if one is set, or null if one is not
*/
public function getMeta($name = null)
--- /dev/null
+<?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_Lart
+ * @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_Lart
+ */
+
+/**
+ * Accepts terms and corresponding definitions for storage to a local data
+ * source and performs and returns the result of lookups for term definitions
+ * as they are requested.
+ *
+ * @category Phergie
+ * @package Phergie_Plugin_Lart
+ * @author Phergie Development Team <team@phergie.org>
+ * @license http://phergie.org/license New BSD License
+ * @link http://pear.phergie.org/package/Phergie_Plugin_Lart
+ * @uses Phergie_Plugin_Command pear.phergie.org
+ * @uses extension PDO
+ * @uses extension pdo_sqlite
+ */
+class Phergie_Plugin_Lart extends Phergie_Plugin_Abstract
+{
+ /**
+ * PDO instance for the database
+ *
+ * @var PDO
+ */
+ protected $db;
+
+ /**
+ * Prepared statement for inserting a new definition
+ *
+ * @var PDOStatement
+ */
+ protected $save;
+
+ /**
+ * Prepared statement for deleting the definition for a given term
+ *
+ * @var PDOStatement
+ */
+ protected $delete;
+
+ /**
+ * Prepared statement for searching for a definition for which the term
+ * matches as a regular expression against a given search string
+ *
+ * @var PDOStatement
+ */
+ protected $process;
+
+ /**
+ * Prepared statement for searching for a definition by its exact term
+ *
+ * @var PDOStatement
+ */
+ protected $select;
+
+ /**
+ * Checks for dependencies and initializes the database.
+ *
+ * @return void
+ */
+ public function onLoad()
+ {
+ if (!extension_loaded('PDO') || !extension_loaded('pdo_sqlite')) {
+ $this->fail('PDO and pdo_sqlite extensions must be installed');
+ }
+
+ $this->plugins->getPlugin('Command');
+
+ $dir = dirname(__FILE__) . '/' . $this->getName();
+ $path = $dir . '/lart.db';
+ $exists = file_exists($path);
+ if (!$exists) {
+ mkdir($dir);
+ }
+
+ try {
+ $this->db = new PDO('sqlite:' . $path);
+ } catch (PDO_Exception $e) {
+ throw new Phergie_Plugin_Exception($e->getMessage());
+ }
+
+ $this->db->sqliteCreateFunction('preg_match', 'preg_match');
+
+ if (!$exists) {
+ $this->db->exec('
+ CREATE TABLE lart (
+ name VARCHAR(255),
+ definition TEXT,
+ hostmask VARCHAR(50),
+ tstamp VARCHAR(19)
+ )
+ ');
+ $this->db->exec('
+ CREATE UNIQUE INDEX lart_name ON lart (name)
+ ');
+ }
+
+ $this->save = $this->db->prepare('
+ REPLACE INTO lart (name, definition, hostmask, tstamp)
+ VALUES (:name, :definition, :hostmask, :tstamp)
+ ');
+
+ $this->process = $this->db->prepare('
+ SELECT *
+ FROM lart
+ WHERE preg_match(name, :name)
+ ');
+
+ $this->select = $this->db->prepare('
+ SELECT *
+ FROM lart
+ WHERE name = :name
+ ');
+
+ $this->delete = $this->db->prepare('
+ DELETE FROM lart
+ WHERE name = :name
+ ');
+ }
+
+ /**
+ * Retrieves the definition for a given term if it exists.
+ *
+ * @param string $term Term to search for
+ *
+ * @return mixed String containing the definition or FALSE if no definition
+ * exists
+ */
+ protected function getLart($term)
+ {
+ $this->process->execute(array(':name' => $term));
+ $row = $this->process->fetchObject();
+ if ($row === false) {
+ return false;
+ }
+ preg_match($row->name, $term, $match);
+ $definition = preg_replace(
+ "/(?:\\\\|\\$)([0-9]+)/e",
+ '$match[\1]',
+ $row->definition
+ );
+ $event = $this->getEvent();
+ $definition = str_replace(
+ array('$source', '$nick'),
+ array($event->getSource(), $event->getNick()),
+ $definition
+ );
+ return $definition;
+ }
+
+ /**
+ * Deletes a given definition.
+ *
+ * @param string $term Term for which the definition should be deleted
+ *
+ * @return boolean TRUE if the definition was found and deleted, FALSE
+ * otherwise
+ */
+ protected function deleteLart($term)
+ {
+ $this->delete->execute(array(':name' => $term));
+ return ($this->delete->rowCount() > 0);
+ }
+
+ /**
+ * Saves a given definition.
+ *
+ * @param string $term Term to trigger a response containing the
+ * corresponding definition, may be a regular expression
+ * @param string $definition Definition corresponding to the term
+ *
+ * @return boolean TRUE if the definition was saved successfully, FALSE
+ * otherwise
+ */
+ protected function saveLart($term, $definition)
+ {
+ $data = array(
+ ':name' => $term,
+ ':definition' => $definition,
+ ':hostmask' => (string) $this->getEvent()->getHostmask(),
+ ':tstamp' => time()
+ );
+ $this->save->execute($data);
+ return ($this->save->rowCount() > 0);
+ }
+
+ /**
+ * Returns information about a definition.
+ *
+ * @param string $term Term about which to return information
+ *
+ * @return void
+ */
+ public function onCommandLartinfo($term)
+ {
+ $this->select->execute(array(':name' => $term));
+ $row = $this->select->fetchObject();
+ $msg = $this->getEvent()->getNick() . ': ';
+ if (!$row) {
+ $msg .= 'Lart not found';
+ } else {
+ $msg .= 'Term: ' . $row->name
+ . ', Definition: ' . $row->definition
+ . ', User: ' . $row->hostmask
+ . ', Added: ' . date('n/j/y g:i A', $row->tstamp);
+ }
+ $this->doNotice($this->getEvent()->getSource(), $msg);
+ }
+
+ /**
+ * Creates a new definition.
+ *
+ * @param string $term Term to add
+ * @param string $definition Definition to add
+ *
+ * @return void
+ */
+ public function onCommandAddlart($term, $definition)
+ {
+ $result = $this->saveLart($term, $definition);
+ if ($result) {
+ $msg = 'Lart saved successfully';
+ } else {
+ $msg = 'Lart could not be saved';
+ }
+ $this->doNotice($this->getEvent()->getSource(), $msg);
+ }
+
+ /**
+ * Removes an existing definition.
+ *
+ * @param string $term Term for which the definition should be removed
+ *
+ * @return void
+ */
+ public function onCommandDeletelart($term)
+ {
+ $source = $this->getEvent()->getSource();
+ if ($this->deleteLart($term)) {
+ $msg = 'Lart deleted successfully';
+ } else {
+ $msg = 'Lart not found';
+ }
+ $this->doNotice($source, $msg);
+ }
+
+ /**
+ * Processes definition triggers in the text of the current event.
+ *
+ * @return void
+ */
+ protected function processLart()
+ {
+ $lart = $this->getLart($this->getEvent()->getText());
+ if ($lart) {
+ if (strpos($lart, '/me') === 0) {
+ $lart = substr($lart, 4);
+ $method = 'doAction';
+ } else {
+ $method = 'doPrivmsg';
+ }
+ $this->$method($this->getEvent()->getSource(), $lart);
+ }
+ }
+
+ /**
+ * Processes definition triggers in messages.
+ *
+ * @return void
+ */
+ public function onPrivmsg()
+ {
+ $this->processLart();
+ }
+
+ /**
+ * Processes definition triggers in CTCP actions.
+ *
+ * @return void
+ */
+ public function onAction()
+ {
+ $this->processLart();
+ }
+}
$this->getPluginHandler()->getPlugin('Command');\r
\r
// Get the name of the NickServ bot, defaults to NickServ\r
- $this->botNick = $this->config['nickserv.botnick'];\r
- if (!$this->botNick) {\r
- $this->botNick = 'NickServ';\r
- }\r
+ $this->botNick = $this->getConfig('nickserv.botnick', 'NickServ');\r
\r
// Get the identify message\r
- $this->identifyMessage = $this->config['nickserv.identify_message'];\r
- if (!$this->identifyMessage) {\r
- $this->identifyMessage = '/This nickname is registered./';\r
- }\r
+ $this->identifyMessage = $this->getConfig(\r
+ 'nickserv.identify_message',\r
+ '/This nickname is registered./'\r
+ );\r
}\r
\r
/**\r
* @link http://pear.phergie.org/package/Phergie_Plugin_Remind
* @uses Phergie_Plugin_Command pear.phergie.org
* @uses Phergie_Plugin_Time pear.phergie.org
+ * @uses extension PDO
+ * @uses extension pdo_sqlite
*/
class Phergie_Plugin_Remind extends Phergie_Plugin_Abstract
{
$plugins = $this->getPluginHandler();
$plugins->getPlugin('Command');
$plugins->getPlugin('Time');
- }
- /**
- * Creates the database if it does not already exist.
- *
- * @return void
- */
- public function onConnect()
- {
+ if (!extension_loaded('PDO') || !extension_loaded('pdo_sqlite')) {
+ $this->fail('PDO and pdo_sqlite extensions must be installed');
+ }
+
$dir = dirname(__FILE__) . '/' . $this->getName();
$path = $dir . '/reminder.db';
if (!file_exists($dir)) {
--- /dev/null
+<?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_Temperature
+ * @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_Temperature
+ */
+
+/**
+ * Performs temperature calculations for other plugins.
+ *
+ * @category Phergie
+ * @package Phergie_Plugin_Temperature
+ * @author Phergie Development Team <team@phergie.org>
+ * @license http://phergie.org/license New BSD License
+ * @link http://pear.phergie.org/package/Phergie_Plugin_Temperature
+ */
+class Phergie_Plugin_Temperature extends Phergie_Plugin_Abstract
+{
+ /**
+ * Converts a temperature in Celsius to Fahrenheit.
+ *
+ * @param int $temp Temperature in Celsius
+ *
+ * @return int Temperature converted to Fahrenheit
+ */
+ public function convertCelsiusToFahrenheit($temp)
+ {
+ return round(((((int) $temp * 9) / 5) + 32));
+ }
+
+ /**
+ * Converts a temperature in Fahrenheit to Celsius.
+ *
+ * @param int $temp Temperature in Fahrenheit
+ *
+ * @return int Temperature converted to Celsius
+ */
+ public function convertFahrenheitToCelsius($temp)
+ {
+ return round(((((int) $temp - 32) * 5) / 9));
+ }
+
+ /**
+ * Calculates the heat index (i.e. "feels like" temperature) based on
+ * temperature and relative humidity.
+ *
+ * @param int $temperature Temperature in degrees Fahrenheit
+ * @param int $humidity Relative humidity (ex: 68)
+ * @return int Heat index in degrees Fahrenheit
+ */
+ public function getHeatIndex($temperature, $humidity)
+ {
+ $temperature2 = $temperature * $temperature;
+ $humidity2 = $humidity * $humidity;
+ return round(
+ -42.379 +
+ (2.04901523 * $temperature) +
+ (10.14333127 * $humidity) -
+ (0.22475541 * $temperature * $humidity) -
+ (0.00683783 * $temperature2) -
+ (0.05481717 * $humidity2) +
+ (0.00122874 * $temperature2 * $humidity) +
+ (0.00085282 * $temperature * $humidity2) -
+ (0.00000199 * $temperature2 * $humidity2)
+ );
+ }
+}
* @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
* @uses extension PDO
* @uses extension pdo_sqlite
*
* @var PDO
*/
protected $db;
- /**
- * Some fixed TLD values, keys must be lowercase
- * @var array
- */
- protected static $fixedTlds;
/**
* Prepared statement for selecting a single tld
*/
public function onLoad()
{
+ if (!extension_loaded('PDO') || !extension_loaded('pdo_sqlite')) {
+ $this->fail('PDO and pdo_sqlite extensions must be installed');
+ }
+
$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.'
- );
- }
-
$dbFile = dirname(__FILE__) . '/Tld/tld.db';
try {
$this->db = new PDO('sqlite:' . $dbFile);
*
* @param string $tld TLD to search for
*
- * @return string Definition of the given TLD
+ * @return mixed Definition of the given TLD as a string or false if unknown
*/
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'];
- }
+ 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
+ * @return mixed Array of all the TLDs and their definitions or FALSE on
+ * failure
*/
public function getTlds()
{
. $tld['description'];
}
}
- unset($tlds);
return $tldinfo;
}
}
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Url
+ * @uses Phergie_Plugin_Encoding pear.phergie.org
* @uses Phergie_Plugin_Http pear.phergie.org
+ * @uses Phergie_Plugin_Tld pear.phergie.org
*/
class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
{
*/
protected $detectSchemeless = false;
- /**
- * List of error messages to return when the requested URL returns an
- * HTTP error
- *
- * @var array
- */
- protected $httpErrors = array(
- 100 => '100 Continue',
- 200 => '200 OK',
- 201 => '201 Created',
- 204 => '204 No Content',
- 206 => '206 Partial Content',
- 300 => '300 Multiple Choices',
- 301 => '301 Moved Permanently',
- 302 => '302 Found',
- 303 => '303 See Other',
- 304 => '304 Not Modified',
- 307 => '307 Temporary Redirect',
- 400 => '400 Bad Request',
- 401 => '401 Unauthorized',
- 403 => '403 Forbidden',
- 404 => '404 Not Found',
- 405 => '405 Method Not Allowed',
- 406 => '406 Not Acceptable',
- 408 => '408 Request Timeout',
- 410 => '410 Gone',
- 413 => '413 Request Entity Too Large',
- 414 => '414 Request URI Too Long',
- 415 => '415 Unsupported Media Type',
- 416 => '416 Requested Range Not Satisfiable',
- 417 => '417 Expectation Failed',
- 500 => '500 Internal Server Error',
- 501 => '501 Method Not Implemented',
- 503 => '503 Service Unavailable',
- 506 => '506 Variant Also Negotiates'
- );
-
- /**
- * An array containing a list of TLDs used for non-scheme matches
- *
- * @var array
- */
- protected $tldList = array();
-
/**
* Shortener object
*/
protected $renderers = array();
/**
- * Initializes settings, checks dependencies.
+ * Checks for dependencies.
*
* @return void
*/
- public function onConnect()
+ public function onLoad()
{
+ $plugins = $this->plugins;
+ $plugins->getPlugin('Encoding');
+ $plugins->getPlugin('Http');
+ $plugins->getPlugin('Tld');
+
// make the shortener configurable
$shortener = $this->getConfig('url.shortener', 'Trim');
$shortener = "Phergie_Plugin_Url_Shorten_{$shortener}";
$this->fail("Declared shortener class {$shortener} is not of proper ancestry");
}
- // Get a list of valid TLDs
- if (!is_array($this->tldList) || count($this->tldList) <= 6) {
- $tldPath = dirname(__FILE__) . '/Url/url.tld.txt';
- $this->tldList = explode("\n", file_get_contents($tldPath));
- $this->debug('Loaded ' . count($this->tldList) . ' tlds');
- rsort($this->tldList);
- }
-
// load config (a bit ugly, but focusing on porting):
foreach (
array(
* @return void
*/
public function onPrivmsg()
+ {
+ $this->handleMsg();
+ }
+
+ /**
+ * Checks an incoming message for the presence of a URL and, if one is
+ * found, responds with its title if it is an HTML document and the
+ * shortened equivalent of its original URL if it meets length requirements.
+ *
+ * @todo Update this to pull configuration settings from $this->config
+ * rather than caching them as class properties
+ * @return void
+ */
+ public function onAction()
+ {
+ $this->handleMsg();
+ }
+
+ /**
+ * Handles message events and responds with url titles.
+ *
+ * @return void
+ */
+ protected function handleMsg()
{
$source = $this->getEvent()->getSource();
$user = $this->getEvent()->getNick();
+ $responses = array();
+ $urls = $this->findUrls($this->getEvent()->getArgument(1));
+
+ foreach ($urls as $parsed) {
+ $url = $parsed['glued'];
+
+ // allow out-of-class renderers to handle this URL
+ foreach ($this->renderers as $renderer) {
+ if ($renderer->renderUrl($parsed) === true) {
+ // renderers should return true if they've fully
+ // rendered the passed URL (they're responsible
+ // for their own output)
+ $this->debug('Handled by renderer: ' . get_class($renderer));
+ continue 2;
+ }
+ }
+
+ // Convert url
+ $shortenedUrl = $this->shortener->shorten($url);
+ if (!$shortenedUrl) {
+ $this->debug('Invalid Url: Unable to shorten. (' . $url . ')');
+ $shortenedUrl = $url;
+ }
+
+ // Prevent spamfest
+ if ($this->checkUrlCache($url, $shortenedUrl)) {
+ $this->debug('Invalid Url: URL is in the cache. (' . $url . ')');
+ continue;
+ }
+
+ $title = $this->getTitle($url);
+ if (!empty($title)) {
+ $responses[] = str_replace(
+ array(
+ '%title%',
+ '%link%',
+ '%nick%'
+ ), array(
+ $title,
+ $shortenedUrl,
+ $user
+ ), $this->messageFormat
+ );
+ }
+
+ // Update cache
+ $this->updateUrlCache($url, $shortenedUrl);
+ unset($title, $shortenedUrl, $title);
+ }
+
+ // Check to see if there were any URL responses, format them and handle if they
+ // get merged into one message or not
+ if (count($responses) > 0) {
+ if ($this->mergeLinks) {
+ $message = str_replace(
+ array(
+ '%message%',
+ '%nick%'
+ ), array(
+ implode('; ', $responses),
+ $user
+ ), $this->baseFormat
+ );
+ $this->doPrivmsg($source, $message);
+ } else {
+ foreach ($responses as $response) {
+ $message = str_replace(
+ array(
+ '%message%',
+ '%nick%'
+ ), array(
+ implode('; ', $responses),
+ $user
+ ), $this->baseFormat
+ );
+ $this->doPrivmsg($source, $message);
+ }
+ }
+ }
+ }
+
+ /**
+ * Detect URLs in a given string.
+ *
+ * @param string $message the string to detect urls in
+ *
+ * @return array the array of urls found
+ */
+ public function findUrls($message)
+ {
$pattern = '#'.($this->detectSchemeless ? '' : 'https?://').'(?:([0-9]{1,3}(?:\.[0-9]{1,3}){3})(?![^/]) | ('
.($this->detectSchemeless ? '(?<!http:/|https:/)[@/\\\]' : '').')?(?:(?:[a-z0-9_-]+\.?)+\.[a-z0-9]{1,6}))[^\s]*#xis';
+ $urls = array();
// URL Match
- if (preg_match_all($pattern, $this->getEvent()->getArgument(1), $matches, PREG_SET_ORDER)) {
- $responses = array();
+ if (preg_match_all($pattern, $message, $matches, PREG_SET_ORDER)) {
foreach ($matches as $m) {
$url = trim(rtrim($m[0], ', ].?!;'));
continue;
}
- // allow out-of-class renderers to handle this URL
- foreach ($this->renderers as $renderer) {
- if ($renderer->renderUrl($parsed) === true) {
- // renderers should return true if they've fully
- // rendered the passed URL (they're responsible
- // for their own output)
- $this->debug('Handled by renderer: ' . get_class($renderer));
- continue 2;
- }
- }
-
// Check to see if the given IP/Host is valid
if (!empty($m[1]) and !$this->checkValidIP($m[1])) {
$this->debug('Invalid Url: ' . $m[1] . ' is not a valid IP address. (' . $url . ')');
$parsed['tld'] = ($pos !== false ? substr($parsed['host'], ($pos+1)) : '');
// Check to see if the URL has a valid TLD
- if (is_array($this->tldList) && !in_array(strtolower($parsed['tld']), $this->tldList)) {
+ if ($this->plugins->tld->getTld($parsed['tld']) === false) {
$this->debug('Invalid Url: ' . $parsed['tld'] . ' is not a supported TLD. (' . $url . ')');
continue;
}
$this->debug('Invalid Url: ' . $parsed['scheme'] . ' is not a supported scheme. (' . $url . ')');
continue;
}
- $url = $this->glueURL($parsed);
- unset($parsed);
-
- // Convert url
- $shortenedUrl = $this->shortener->shorten($url);
- if (!$shortenedUrl) {
- $this->debug('Invalid Url: Unable to shorten. (' . $url . ')');
- continue;
- }
-
- // Prevent spamfest
- if ($this->checkUrlCache($url, $shortenedUrl)) {
- $this->debug('Invalid Url: URL is in the cache. (' . $url . ')');
- continue;
- }
- $title = self::getTitle($url);
- if (!empty($title)) {
- $responses[] = str_replace(
- array(
- '%title%',
- '%link%',
- '%nick%'
- ), array(
- $title,
- $shortenedUrl,
- $user
- ), $this->messageFormat
- );
- }
-
- // Update cache
- $this->updateUrlCache($url, $shortenedUrl);
- unset($title, $shortenedUrl, $title);
- }
- /**
- * Check to see if there were any URL responses, format them and handle if they
- * get merged into one message or not
- */
- if (count($responses) > 0) {
- if ($this->mergeLinks) {
- $message = str_replace(
- array(
- '%message%',
- '%nick%'
- ), array(
- implode('; ', $responses),
- $user
- ), $this->baseFormat
- );
- $this->doPrivmsg($source, $message);
- } else {
- foreach ($responses as $response) {
- $message = str_replace(
- array(
- '%message%',
- '%nick%'
- ), array(
- implode('; ', $responses),
- $user
- ), $this->baseFormat
- );
- $this->doPrivmsg($source, $message);
- }
- }
+ $urls[] = $parsed + array('glued' => $this->glueURL($parsed));
}
}
+
+ return $urls;
}
/**
*/
protected function decode($str, $trim = null)
{
- $out = $this->decodeTranslit($str);
+ $out = $this->plugins->encoding->transliterate($str);
if ($trim > 0) {
$out = substr($out, 0, $trim) . (strlen($out) > $trim ? '...' : '');
}
return $out;
}
- /**
- * Custom error handler meant to handle 404 errors and such
- *
- * @param int $errno the error code
- * @param string $errstr the error string
- * @param string $errfile file the error occured in
- * @param int $errline line the error occured on
- *
- * @return bool
- */
- public function onPhpError($errno, $errstr, $errfile, $errline)
- {
- if ($errno === E_WARNING) {
- // Check to see if there was HTTP warning while connecting to the site
- if (preg_match('{HTTP/1\.[01] ([0-9]{3})}i', $errstr, $m)) {
- $this->errorStatus = $m[1];
- $this->errorMessage = (isset($this->httpErrors[$m[1]]) ? $this->httpErrors[$m[1]] : $m[1]);
- $this->debug('PHP Warning: ' . $errstr . 'in ' . $errfile . ' on line ' . $errline);
- return true;
- }
-
- // Safely ignore these SSL warnings so they don't appear in the log
- if (stripos($errstr, 'SSL: fatal protocol error in') !== false
- || stripos($errstr, 'failed to open stream') !== false
- || stripos($errstr, 'HTTP request failed') !== false
- || stripos($errstr, 'SSL: An existing connection was forcibly closed by the remote host') !== false
- || stripos($errstr, 'Failed to enable crypto in') !== false
- || stripos($errstr, 'SSL: An established connection was aborted by the software in your host machine') !== false
- || stripos($errstr, 'SSL operation failed with code') !== false
- || stripos($errstr, 'unable to connect to') !== false
- ) {
- $this->errorStatus = true;
- $this->debug('PHP Warning: ' . $errstr . 'in ' . $errfile . ' on line ' . $errline);
- return true;
- }
- }
- return false;
- }
-
/**
* Takes a url, parses and cleans the URL without of all the junk
* and then return the hex checksum of the url.
protected function getUrlChecksum($url)
{
$checksum = strtolower(urldecode($this->glueUrl($url, true)));
- $checksum = preg_replace('#\s#', '', $this->decodeTranslit($checksum));
+ $checksum = preg_replace('#\s#', '', $this->plugins->encoding->transliterate($checksum));
return dechex(crc32($checksum));
}
'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'
);
- $response = $http->get($url, array(), $options);
-
+ $response = $http->head($url, array(), $options);
$header = $response->getHeaders('Content-Type');
+
if (!preg_match('#^(text/x?html|application/xhtml+xml)(?:;.*)?$#', $header)) {
$title = $header;
- }
-
- $content = $response->getContent();
- if (empty($title)) {
+ } else {
+ $response = $http->get($url, array(), $options);
+ $content = $response->getContent();
if (preg_match('#<title[^>]*>(.*?)</title>#is', $content, $match)) {
- $title = html_entity_decode(trim($match[1]));
+ $title = preg_replace('/[\s\v]+/', ' ', trim($match[1]));
}
}
+ $encoding = $this->plugins->getPlugin('Encoding');
+ $title = $encoding->decodeEntities($title);
if (empty($title)) {
if ($response->isError()) {
echo "(DEBUG:Url) $msg\n";
}
- /**
- * Placeholder/porting helper. Has no function.
- *
- * @param string $str a string to return
- *
- * @return string
- */
- protected function decodeTranslit($str)
- {
- // placeholder/porting helper
- return $str;
- }
-
/**
* Add a renderer to the stack
*
*/
public function registerRenderer($obj)
{
- $this->renderers[] = $obj;
- array_unique($this->renderers);
+ $this->renderers[spl_object_hash($obj)] = $obj;
}
}
+++ /dev/null
-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
* @link http://www.weather.com/services/xmloap.html
* @uses Phergie_Plugin_Command pear.phergie.org
* @uses Phergie_Plugin_Http pear.phergie.org
+ * @uses Phergie_Plugin_Temperature pear.phergie.org
* @uses extension SimpleXML
*/
class Phergie_Plugin_Weather extends Phergie_Plugin_Abstract
$plugins = $this->getPluginHandler();
$plugins->getPlugin('Command');
$plugins->getPlugin('Http');
+ $plugins->getPlugin('Temperature');
if (empty($this->config['weather.partner_id'])
|| empty($this->config['weather.license_key'])) {
}
}
- /**
- * Converts a temperature in Celsius to Fahrenheit.
- *
- * @param int $temp Temperature in Celsius
- *
- * @return int Temperature converted to Fahrenheit
- */
- public function convertCelsiusToFahrenheit($temp)
- {
- return round(((((int) $temp * 9) / 5) + 32));
- }
-
- /**
- * Converts a temperature in Fahrenheit to Celsius.
- *
- * @param int $temp Temperature in Fahrenheit
- *
- * @return int Temperature converted to Celsius
- */
- public function convertFahrenheitToCelsius($temp)
- {
- return round(((((int) $temp - 32) * 5) / 9));
- }
-
/**
* Returns a weather report for a specified location.
*
return;
}
+ $temperature = $this->plugins->getPlugin('Temperature');
$xml = $response->getContent();
$weather = 'Weather for ' . (string) $xml->loc->dnam . ' - ';
switch ($xml->head->ut) {
case 'F':
$tempF = $xml->cc->tmp;
- $tempC = $this->convertFahrenheitToCelsius($tempF);
+ $tempC = $temperature->convertFahrenheitToCelsius($tempF);
break;
case 'C':
$tempC = $xml->cc->tmp;
- $tempF = $this->convertCelsiusToFahrenheit($tempC);
+ $tempF = $temperature->convertCelsiusToFahrenheit($tempC);
break;
default:
$this->doNotice(
break;
}
$r = $xml->cc->hmid;
- $tempF2 = $tempF * $tempF;
- $r2 = $r * $r;
- $hiF = round(
- -42.379 +
- (2.04901523 * $tempF) +
- (10.14333127 * $r) -
- (.22475541 * $tempF * $r) -
- (6.83783 * pow(10,-3) * $tempF2) -
- (5.481717 * pow(10,-2) * $r2) +
- (1.22874 * pow(10,-3) * $tempF2 * $r) +
- (8.5282 * pow(10,-4) * $tempF * $r2) -
- (1.99 * pow(10,-6) * $tempF2 * $r2)
- );
- $hiC = $this->convertFahrenheitToCelsius($hiF);
+ $hiF = $temperature->getHeatIndex($tempF, $r);
+ $hiC = $temperature->convertFahrenheitToCelsius($hiF);
$weather .= 'Temperature: ' . $tempF . 'F/' . $tempC . 'C';
$weather .= ', Humidity: ' . (string) $xml->cc->hmid . '%';
if ($hiF > $tempF || $hiC > $tempC) {
--- /dev/null
+<?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_Youtube
+ * @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_Youtube
+ */
+
+/**
+ * Provides commands used to access several services offered by Google
+ * including search, translation, weather, maps, and currency and general
+ * value unit conversion.
+ *
+ * @category Phergie
+ * @package Phergie_Plugin_Youtube
+ * @author Phergie Development Team <team@phergie.org>
+ * @license http://phergie.org/license New BSD License
+ * @link http://pear.phergie.org/package/Phergie_Plugin_Youtube
+ * @uses Phergie_Plugin_Command pear.phergie.org
+ * @uses Phergie_Plugin_Http pear.phergie.org
+ */
+class Phergie_Plugin_Youtube extends Phergie_Plugin_Abstract
+{
+ /**
+ * Checks for dependencies.
+ *
+ * @return void
+ */
+ public function onLoad()
+ {
+ $plugins = $this->getPluginHandler();
+ $plugins->getPlugin('Command');
+ $plugins->getPlugin('Http');
+ if ($url = $plugins->getPlugin('Url')) {
+ $url->registerRenderer($this);
+ }
+ }
+
+ /**
+ * Queries the YouTube video search web service, processes the first
+ * result, and sends a message back to the current event source.
+ *
+ * @param string $query Search term
+ *
+ * @return object YouTube result object
+ */
+ protected function queryYoutube($query)
+ {
+ $url = 'http://gdata.youtube.com/feeds/api/videos';
+ $params = array(
+ 'max-results' => '1',
+ 'alt' => 'json',
+ 'q' => $query
+ );
+ $http = $this->plugins->getPlugin('Http');
+ $response = $http->get($url, $params);
+ $json = $response->getContent();
+
+ $entries = $json->feed->entry;
+ if (!$entries) {
+ $this->doNotice($this->event->getNick(), 'Query returned no results');
+ return;
+ }
+ $entry = reset($entries);
+
+ $nick = $this->event->getNick();
+ $link = $entry->link[0]->href;
+ $title = $entry->title->{'$t'};
+ $author = $entry->author[0]->name->{'$t'};
+ $seconds = $entry->{'media$group'}->{'yt$duration'}->seconds;
+ $published = $entry->published->{'$t'};
+ $views = $entry->{'yt$statistics'}->viewCount;
+ $rating = $entry->{'gd$rating'}->average;
+
+ $minutes = floor($seconds / 60);
+ $seconds = str_pad($seconds % 60, 2, '0', STR_PAD_LEFT);
+ $parsed_link = parse_url($link);
+ parse_str($parsed_link['query'], $parsed_query);
+ $link = 'http://youtu.be/' . $parsed_query['v'];
+ $published = date('n/j/y g:i A', strtotime($published));
+ $views = number_format($views, 0);
+ $rating = round($rating, 2);
+
+ $format = $this->getConfig('youtube.format');
+ if (!$format) {
+ $format = '%nick%:'
+ . ' [ %link% ]'
+ . ' "%title%" by %author%,'
+ . ' Length %minutes%:%seconds%,'
+ . ' Published %published%,'
+ . ' Views %views%,'
+ . ' Rating %rating%';
+ }
+
+ $replacements = array(
+ 'nick' => $nick,
+ 'link' => $link,
+ 'title' => $title,
+ 'author' => $author,
+ 'minutes' => $minutes,
+ 'seconds' => $seconds,
+ 'published' => $published,
+ 'views' => $views,
+ 'rating' => $rating
+ );
+
+ $msg = $format;
+ foreach ($replacements as $from => $to) {
+ $msg = str_replace('%' . $from . '%', $to, $msg);
+ }
+ $this->doPrivmsg($this->event->getSource(), $msg);
+ }
+
+ /**
+ * Returns the first result of a YouTube search.
+ *
+ * @param string $query Search query
+ *
+ * @return void
+ */
+ public function onCommandYoutube($query)
+ {
+ $this->queryYoutube($query);
+ }
+
+ /**
+ * Renders YouTube URLs.
+ *
+ * @param array $parsed parse_url() output for the URL to render
+ *
+ * @return boolean TRUE if the URL was rendered successfully, FALSE
+ * otherwise
+ */
+ public function renderUrl(array $parsed)
+ {
+ switch ($parsed['host']) {
+ case 'youtu.be':
+ $v = ltrim('/', $parsed['path']);
+ break;
+ case 'youtube.com':
+ case 'www.youtube.com':
+ parse_str($parsed['query'], $parsed_query);
+ if (!empty($parsed_query['v'])) {
+ $v = $parsed_query['v'];
+ break;
+ }
+ default:
+ return false;
+ }
+
+ $this->queryYoutube($v);
+
+ return true;
+ }
+}