Assembla home | Assembla project page
 

root/trunk/Phergie/Plugin/Quit.php

Revision 272, 8.8 kB (checked in by Seldaek, 1 month ago)

fixes #56

Line 
1 <?php
2
3 /**
4  * Handles requests from administrators for the bot to disconnect from the
5  * server.
6  */
7 class Phergie_Plugin_Quit extends Phergie_Plugin_Abstract_Command
8 {
9     /**
10      * Flag indicating whether or not the plugin is an admin plugin or not
11      *
12      * @var bool
13      */
14     public $needsAdmin = true;
15
16     /**
17      * Random reconnect messages used if a quit message isn't given
18      *
19      * @var array
20      */
21     protected $messages = array(
22         'I\'ll be back.',
23         'I shall return.',
24         'Look to my coming at first light on the fifth day. At dawn look to the East.',
25         'kthx, brb.',
26         'Beam me up, Scotty!',
27     );
28
29     /**
30      * Path to the PHP executable file
31      *
32      * @var string
33      */
34     protected $phpPath;
35
36     /**
37      * Attempts to auto-detect the path to the PHP executable if the path isn't
38      * set in the setting file
39      *
40      * @return void
41      */
42     public function onInit()
43     {
44         $phpPath = trim($this->getPluginIni('php_path'));
45         if (empty($phpPath) || !is_file($phpPath) ||
46             strtolower($phpPath) == 'autodetect' || strtolower($phpPath) == 'auto-detect') {
47             /**
48              * Array of file names to check for when auto-detecting the path to PHP
49              */
50             $files = array(
51                 'php',
52                 'php.exe',
53                 'php-win.exe'
54             );
55
56             /**
57              * Array of file paths to check for the PHP executable
58              */
59             $paths = array();
60             $paths = array_merge($paths, explode(PATH_SEPARATOR, ini_get('include_path')));
61             $paths = array_merge($paths, explode(PATH_SEPARATOR, ini_get('extension_dir')));
62
63             if (!empty($phpPath) &&
64                 strtolower($phpPath) != 'autodetect' && strtolower($phpPath) != 'auto-detect') {
65                 $files[] = $phpPath;
66                 $paths[] = $phpPath;
67             }
68
69             /**
70              * Attempt to auto-detect the path to the PHP executable from the list of file names and paths
71              */
72             $phpPath = null;
73             foreach($paths as $path) {
74                 if (empty($path)) {
75                     continue;
76                 }
77                 $path = trim($path) . (!in_array(substr($path, -1), array(DIRECTORY_SEPARATOR, '/', '\\')) ? DIRECTORY_SEPARATOR : '');
78                 foreach($files as $file) {
79                     if (empty($file)) {
80                         continue;
81                     }
82                     $file = trim($file);
83                     if (@is_file($path . $file)) {
84                         $phpPath = $path . $file;
85                         break 2;
86                     } else if (@is_file(dirname($path) . DIRECTORY_SEPARATOR . $file)) {
87                         $phpPath = dirname($path) . DIRECTORY_SEPARATOR . $file;
88                         break 2;
89                     }
90                 }
91             }
92
93             /**
94              * Try 'which php' if using a non-windows OS to get the path to the
95              * PHP executable
96              */
97             if (strtolower(substr(PHP_OS, 0, 3)) !== 'win' && function_exists('exec')) {
98                 $func = new ReflectionFunction('exec');
99                 // skip this if exec is disabled by safe_mode or whatever
100                 if (!$func->isDisabled()) {
101                     $exec = trim(exec('which php'));
102                     if (!empty($exec) && is_file($exec)) {
103                         $phpPath = $exec;
104                     }
105                 }
106                 unset($func);
107             }
108             unset($files, $file, $paths, $path, $exec);
109         }
110         $this->phpPath = $phpPath;
111         if (!defined('PHERGIE_PHP_PATH')) {
112             define('PHERGIE_PHP_PATH', $phpPath);
113         }
114     }
115
116     /**
117      * Processes requests for the bot to disconnect from the server.
118      *
119      * Note: The Freenode IRC daemon will display "Client Quit" in place of
120      * any provided reason for quitting if the bot has not been connected for
121      * at least 5 minutes prior to disconnecting. This is meant to prevent
122      * spamming via quit messages. It is possible that IRC daemons for other
123      * networks have similar behavior.
124      *
125      * @return void
126      */
127     public function handleQuit($message = '', $reconnect = false)
128     {
129         $user = $this->event->getNick();
130         $message = trim(!empty($message) || $reconnect ? $message : $this->getPluginIni('reason'));
131         if (substr($message, 0, 1) === '(' && substr($message, -1) === ')') {
132             $message = substr($message, 1, -1);
133         }
134         if (!$reconnect && empty($message)) {
135             $message = 'by request of %nick%';
136         }
137         if (empty($message)) {
138             $message = $this->messages[array_rand($this->messages, 1) ];
139         }
140         $message = str_replace('%nick%', $user, trim($message));
141         $this->doQuit($message, $reconnect);
142     }
143
144     /**
145      * Creates a new instance of Phergie and closes the original one
146      *
147      * @return void
148      */
149     public function handleReboot($message = '')
150     {
151         $user = $this->event->getNick();
152         if (empty($this->phpPath) or !is_file($this->phpPath)) {
153             trigger_error('Could not restart Phergie, make sure the setting "quit.php_path" is correct', E_USER_WARNING);
154             $this->doNotice($user, 'Error: Couldn\'t restart Phergie.');
155             return;
156         }
157
158         $exec = shell_exec(PHERGIE_PHP_PATH . ' -l ' . PHERGIE_DIR . 'Bot.php ' . PHERGIE_INI_PATH);
159         if (stripos($exec, 'No syntax errors') === false) {
160             trigger_error('Encountered an error while trying to restart.', E_USER_WARNING);
161             $this->debug('Restart Error: ' . trim($exec));
162             $this->doNotice($user, 'Error: Couldn\'t restart Phergie.');
163             return;
164         }
165
166         if (strtolower(substr(PHP_OS, 0, 3)) === 'win') {
167             $handle = popen('cmd /c start "' . $this->getIni('nick') . '" "' . PHERGIE_PHP_PATH . '" "' . PHERGIE_DIR . 'Bot.php" "' . PHERGIE_INI_PATH . '"', 'r');
168         } else {
169             exec(PHERGIE_PHP_PATH . ' -f ' . PHERGIE_DIR . 'Bot.php ' . PHERGIE_INI_PATH . '> /dev/null  &');
170             $handle = true;
171         }
172
173         if ($handle) {
174             if (is_resource($handle)) {
175                 pclose($handle);
176             }
177             $this->doNotice($user, 'Restarting ' . $this->getIni('nick') . '.');
178             $this->handleQuit($message);
179         } else {
180             trigger_error('Could not create another instance of Phergie.', E_USER_WARNING);
181             $this->doNotice($user, 'Error: Couldn\'t restart Phergie.');
182         }
183     }
184
185     /**
186      * Processes requests for the bot to disconnect from the server.
187      *
188      * @return void
189      */
190     public function onDoQuit($message = '')
191     {
192         $user = $this->event->getNick();
193         if ($this->fromAdmin(true)) {
194             $this->handleQuit($message);
195         } else {
196             $this->doNotice($user, 'You do not have permission to use quit.');
197         }
198     }
199
200     /**
201      * Processes requests for the bot to disconnect from the server.
202      *
203      * @return void
204      */
205     public function onDoDie($message = '')
206     {
207         $user = $this->event->getNick();
208         if ($this->fromAdmin(true)) {
209             $this->handleQuit($message);
210         } else {
211             $this->doNotice($user, 'You do not have permission to use die.');
212         }
213     }
214
215     /**
216      * Processes requests for the bot to disconnect from the server.
217      *
218      * @return void
219      */
220     public function onDoExit($message = '')
221     {
222         $user = $this->event->getNick();
223         if ($this->fromAdmin(true)) {
224             $this->handleQuit($message);
225         } else {
226             $this->doNotice($user, 'You do not have permission to use exit.');
227         }
228     }
229
230     /**
231      * Reconnects to the server and rehashes the ini data
232      *
233      * @return void
234      */
235     public function onDoReconnect($message = '')
236     {
237         $user = $this->event->getNick();
238         if ($this->fromAdmin(true)) {
239             $this->handleQuit($message, true);
240         } else {
241             $this->doNotice($user, 'You do not have permission to use reconnect.');
242         }
243     }
244
245     /**
246      * Creates a new instance of Phergie and closes the original one
247      *
248      * @return void
249      */
250     public function onDoRestart($message = '')
251     {
252         $user = $this->event->getNick();
253         if ($this->fromAdmin(true)) {
254             $this->handleReboot($message);
255         } else {
256             $this->doNotice($user, 'You do not have permission to use restart.');
257         }
258     }
259
260     /**
261      * Creates a new instance of Phergie and closes the original one
262      *
263      * @return void
264      */
265     public function onDoReboot($message = '')
266     {
267         $user = $this->event->getNick();
268         if ($this->fromAdmin(true)) {
269             $this->handleReboot($message);
270         } else {
271             $this->doNotice($user, 'You do not have permission to use reboot.');
272         }
273     }
274 }
275
Note: See TracBrowser for help on using the browser.