Assembla home | Assembla project page
 

root/trunk/Phergie/Plugin/Acronym.php

Revision 259, 5.6 kB (checked in by tobias382, 3 months ago)

Fixes #41 - Acronym plugin was modified to update the host and web scraping logic (thanks caseyw)

Line 
1 <?php
2
3 /**
4  * Searches received messages for consecutive sequences of two or more capital
5  * letters followed by a question mark, performs an acronym lookup for each
6  * sequence, and either returns a limited number of possible meanings for the
7  * acronym or performs a random action should no results be returned.
8  *
9  * The limit configuration setting should be set to the maximum number of
10  * potential meanings to return for any single given acronym.
11  *
12  * @todo Add a cache to avoid exceeding the acronymfinder.com daily lookup
13  *       limit. Cache should be flushed daily.
14  */
15 class Phergie_Plugin_Acronym extends Phergie_Plugin_Abstract_Base
16 {
17     /**
18      * Maximum number of meanings to return for a single acronym
19      *
20      * @var int
21      */
22     protected $limit;
23
24     /**
25      * List of acronyms for which responses should not be sent
26      *
27      * @var array
28      */
29     protected $filter;
30
31     /**
32      * Caches the returned acronyms
33      *
34      * @var array
35      */
36     protected $cache;
37     protected $flushed;
38
39     /**
40      * Possible reactions to return when no result is returned
41      *
42      * @var array
43      */
44     protected $reactions = array(
45         'shrugs',
46         'blinks',
47         'giggles',
48         'sighs',
49         'yawns',
50         'hides behind %randomuser%'
51     );
52
53     /**
54      * Initializes the limit of meanings to return per acronym.
55      *
56      * @return void
57      */
58     public function onInit()
59     {
60         $limit = $this->getPluginIni('limit');
61         if ($limit < 0 || $limit === null) {
62             $this->limit = 5;
63         } else {
64             $this->limit = (int)$limit;
65         }
66
67         $this->filter = array_filter(preg_split('/[ ,]/', $this->getPluginIni('filter')), 'strlen');
68     }
69
70     /**
71      * Returns a random action, meant for cases where an acronym lookup
72      * returns no results.
73      *
74      * @param string $target Channel name or user nick to receive the action
75      * @return void
76      */
77     protected function randomAction($target)
78     {
79         do {
80             $reaction = $this->reactions[mt_rand(0, count($this->reactions) - 1)];
81             $randomUser = (strpos($reaction, '%randomuser%') !== false);
82         } while ($target[0] != '#' && $randomUser);
83         if ($randomUser) {
84             if ($this->pluginLoaded('ServerInfo')) {
85                 $nick = $this->getIni('nick');
86                 do {
87                     $user = Phergie_Plugin_ServerInfo::getRandomUser($target);
88                 } while ($user == $nick);
89             } else {
90                 $user = $this->event->getNick();
91             }
92             $reaction = str_replace('%randomuser%', $user, $reaction);
93         }
94         $this->doAction($target, $reaction . '.');
95     }
96
97     /**
98      * Processes acronym lookups and returns results when available, or
99      * returns a random action when a lookup returns no results.
100      *
101      * @return void
102      */
103     public function onPrivmsg()
104     {
105         $source = $this->event->getSource();
106         $message = $this->event->getArgument(1);
107         $target = $this->event->getNick();
108         $today = date('md');
109
110         // Matches an optional "Nick: " followed by an acronym formatted as A.B.C. or ABC
111         if (!preg_match('/^(?:[A-Za-z0-9\[\]`|{}_-]+: )?((?:[A-Z]\.?){2,})\?$/', $message, $acronym)) {
112             return;
113         }
114
115         $acronym = str_replace('.', '', $acronym[1]);
116
117         if (in_array($acronym, $this->filter)) {
118             return;
119         }
120
121         if (in_array($acronym, array('WHO', 'WHAT', 'WHERE', 'WHEN', 'WHY', 'HOW'))) {
122             $this->doAction($source, 'shrugs.');
123             return;
124         }
125
126         if ($this->flushed != $today) {
127             unset($this->cache);
128             $this->flushed = $today;
129             $this->cache = array();
130         }
131
132         if (!isset($this->cache[$acronym])) {
133             $opts = array(
134                 'http' => array(
135                     'timeout' => 10,
136                     'method' => 'GET',
137                     'header' => "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\r\n".
138                                 "Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5\r\n".
139                                 "Accept-Language: en-us,en;q=0.8\r\n".
140                                 "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n".
141                                 "Referer: http://acronyms.thefreedictionary.com/\r\n",
142                 )
143             );
144             $context = stream_context_create($opts);
145             $url = 'http://acronyms.thefreedictionary.com/' . urlencode($acronym);
146             $contents = @file_get_contents($url, false, $context);
147
148             if (empty ($contents) ||
149                 strpos($contents, 'Word not found') !== false) {
150                 $this->randomAction($source);
151                 return;
152             } else {
153                 $matches = array();
154                 $offset = 0;
155
156                 do {
157                     $count = preg_match('/<td>([^<]+)</i', $contents, $match, PREG_OFFSET_CAPTURE, $offset);
158                     if ($count == 1) {
159                         $matches[] = html_entity_decode($match[1][0]);
160                         $offset = $match[1][1];
161                     }
162                 } while (($this->limit == 0 || count($matches) < $this->limit) && $count == 1);
163             }
164         }
165
166         if (isset($this->cache[$acronym])) {
167             $matches = $this->cache[$acronym];
168         }
169
170         if (count($matches) > 0) {
171             $this->cache[$acronym] = $matches;
172
173             $text = 'Possible matches for ' . $acronym . ': ' . implode('; ', $matches);
174             $this->doPrivmsg($source, $target . ': ' . $text);
175         }
176     }
177 }
178
Note: See TracBrowser for help on using the browser.