Assembla home | Assembla project page
 

root/trunk/Phergie/Plugin/Math.php

Revision 265, 6.4 kB (checked in by tobias382, 4 months ago)

Added constant checks and declarations in the Math and Karma plugins for versions of PHP prior to 5.2 (thanks kniolet)

Line 
1 <?php
2
3 /**
4  * Checks incoming requests for simple mathematical expressions, computes the
5  * result of such expressions, and responds with a message containing the
6  * result.
7  */
8 class Phergie_Plugin_Math extends Phergie_Plugin_Abstract_Command
9 {
10     /**
11      * Backwards compatibility for constants not defined in PHP 5.1.x
12      */
13     public function onInit()
14     {
15         if(!defined('M_EULER')) {
16             define('M_EULER', '0.57721566490153286061');
17         }
18         if(!defined('M_LNPI')) {
19             define('M_LNPI', '1.14472988584940017414');
20         }
21         if(!defined('M_SQRTPI')) {
22             define('M_SQRTPI', '1.77245385090551602729');
23         }
24     }
25
26     /**
27      * Holds the allowed function, characters, operators and constants
28      *
29      * @var array
30      */
31     protected $allowed = array(
32         '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
33         '+', '-', '/', '*', '.', ' ', '<<', '>>', '%', '&', '^', '|', '~',
34         'abs(', 'ceil(', 'floor(', 'exp(', 'log10(',
35         'cos(', 'sin(', 'sqrt(', 'tan(', 'rad2deg(',
36         'acosh(', 'asin(', 'atan(', 'atanh(', 'cosh(',
37         'sinh(', 'tanh(',
38         'M_PI', 'INF', 'M_E', 'M_LOG2E', 'M_LOG10E',
39         'M_LN2', 'M_LN10', 'M_PI_2', 'M_PI_4', 'M_1_PI',
40         'M_2_PI', 'M_SQRTPI', 'M_2_SQRTPI', 'M_SQRT2',
41         'M_SQRT2', 'M_SQRT1_2', 'M_LNPI', 'M_EULER'
42     );
43
44     /**
45      * Holds the functions that are allowed that are contained in the class
46      *
47      * @return void
48      */
49     protected $classFuncs = array(
50         'sind(', 'cosd(', 'tand(',
51         'atand(', 'asind(', 'acosd('
52     );
53
54     /**
55      * Holds the functions that can accept multiple arguments.
56      *
57      * @return void
58      */
59     protected $funcs = array(
60         'round(', 'log(', 'pow(',
61         'max(', 'min(', 'rand(',
62         'atan2(', 'mt_rand('
63     );
64     /**
65      * Custom functions as defined in $classFuncs to be used in math operations
66      * these automatically get prepended with $this-> before the calculations
67      * take place.
68      */
69     //return sine of <an angle in degrees>
70     protected function sind($degrees)
71     {
72         return sin(deg2rad($degrees));
73     }
74     //return cosd of <an angle in degrees>
75     protected function cosd($degrees)
76     {
77         return cos(deg2rad($degrees));
78     }
79     //return tand of <an angle in degrees>
80     protected function tand($degrees)
81     {
82         return tan(deg2rad($degrees));
83     }
84     //return atand of <an angle in degrees>
85     protected function atand($x)
86     {
87         return rad2deg(atan($x));
88     }
89     //return asind of <an angle in degrees>
90     protected function asind($x)
91     {
92         return rad2deg(asin($x));
93     }
94     //return acosd of <an angle in degrees>
95     protected function acosd($x)
96     {
97         return rad2deg(acos($x));
98     }
99
100     /**
101      * Processes a request to perform a calculations.
102      *
103      * @param string $expr Expression to evaluate
104      * @return void
105      */
106     protected function processRequest($expr, $quietMode = false)
107     {
108         $user = $this->event->getNick();
109
110         // Replace constants
111         $equation = str_ireplace(
112             array('pi', 'M_PI()', 'chucknorris', 'inf', ' e ', '\\'),
113             array('M_PI', 'M_PI', 1e10000, 'INF', ' M_E ', '/'),
114             $expr
115         );
116         $equationSrc = $equation;
117         $equation = preg_replace('/\s/', '', $equation);
118         $this->allowed = array_merge($this->allowed, $this->classFuncs);
119
120         // Parse equation
121         $out = '';
122         $ptr = 1;
123         $allowcomma = 0;
124         while (strlen($equation) > 0) {
125             $substr = substr($equation, 0, $ptr);
126             // Allowed string
127             if (array_search($substr, $this->allowed) !== false) {
128                 $out .= $substr;
129                 $equation = substr($equation, $ptr);
130                 $ptr = 0;
131             // Allowed func
132             } elseif (array_search($substr, $this->funcs) !== false) {
133                 $out .= $substr;
134                 $equation = substr($equation, $ptr);
135                 $ptr = 0;
136                 $allowcomma++;
137                 if ($allowcomma === 1) {
138                     $this->allowed[] = ',';
139                 }
140                 // Opening parenthesis
141             } elseif ($substr === '(') {
142                 if ($allowcomma > 0) {
143                     $allowcomma++;
144                 }
145                 $last = substr($out, -1);
146                 if (!empty($last) && !in_array($last, array('+', '-', '/', '*', '('))) {
147                     $out .= '*';
148                 }
149                 $out .= $substr;
150                 $equation = substr($equation, $ptr);
151                 $ptr = 0;
152             // Closing parenthesis
153             } elseif ($substr === ')') {
154                 if ($allowcomma > 0) {
155                     $allowcomma--;
156                     if ($allowcomma === 0) {
157                         array_pop($this->allowed);
158                     }
159                 }
160
161                 $out .= $substr;
162                 $next = substr($equation, 1, 1);
163                 if (!empty($next) && !in_array($next, array('+', '-', '/', '*', ')'))) {
164                     $out .= '*';
165                 }
166                 $equation = substr($equation, $ptr);
167                 $ptr = 0;
168             // Parse error if we've consumed the entire equation without finding anything valid
169             } elseif ($ptr >= strlen($equation)) {
170                 if (!$quietMode) {
171                     $this->doNotice($user, 'Syntax error at "' . $substr . '" in equation "' . $equationSrc . '"');
172                 }
173                 return;
174             } else {
175                 $ptr++;
176             }
177         }
178
179         foreach($this->classFuncs as $func) {
180             $out = str_replace($func, '$this->' . $func, $out);
181         }
182
183         $res = @eval('return ' . $out . ';');
184         $source = $this->event->getSource();
185         if ($res === false) {
186             if (!$quietMode) {
187                 $this->doNotice($user, 'Computation error, nothing was returned, perhaps division by zero?');
188             }
189         } else {
190             $this->doPrivmsg($source, $user . ': Result -> ' . $res);
191         }
192     }
193
194     /**
195      * Forwards math commands onto a central handler.
196      *
197      * @return void
198      */
199     public function onDoMath($expr)
200     {
201         $this->processRequest($expr, true);
202     }
203
204     /**
205      * Forwards calc commands onto a central handler.
206      *
207      * @return void
208      */
209     public function onDoCalc($expr)
210     {
211         $this->processRequest($expr);
212     }
213 }
214
Note: See TracBrowser for help on using the browser.