root/trunk/Phergie/Plugin/Quit.php

Revision 272, 8.8 KB (checked in by Seldaek, 5 years ago)

fixes #56

Line 
1<?php
2
3/**
4 * Handles requests from administrators for the bot to disconnect from the
5 * server.
6 */
7class 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}
Note: See TracBrowser for help on using the browser.