Assembla home | Assembla project page
 

root/trunk/Phergie/Bot.php

Revision 273, 7.3 kB (checked in by Seldaek, 4 months ago)

* Plugins that can't load now return error messages to say why
fixes #35

Line 
1 <?php
2
3 /**
4  * This file functions as a daemon process used to bootstrap and execute the
5  * client by loading its configuration file, instantiating it and event
6  * handlers for it, configuring it, and executing its event handling loop.
7  */
8
9 /**
10  * Check to see if the version of PHP meets the minimum requirement
11  */
12 if (version_compare('5.1.2', PHP_VERSION, '>')) {
13     trigger_error('Fatal error: PHP 5.1.2+ is required, current version: ' . PHP_VERSION, E_USER_ERROR);
14
15 /**
16  * Backwards compatibility check to see if the PHP version is lower than 5.2
17  */
18 } elseif (version_compare('5.2', PHP_VERSION, '>')) {
19     trigger_error('PHP 5.2+ is recommended, current version: ' . PHP_VERSION, E_USER_WARNING);
20 }
21
22 /**
23  * Code base version
24  *
25  * @const string
26  */
27 define('PHERGIE_VERSION', '1.0.3');
28
29 /**
30  * Path to the configuration file used by default when one is not specified or
31  * register_argc_argv is disabled in php.ini
32  *
33  * @const string
34  */
35 define('PHERGIE_DEFAULT_INI', 'phergie.ini');
36
37 /**
38  * Path to the directory containing the Phergie directory
39  *
40  * @const string
41  */
42 define('PHERGIE_BASE_DIR', realpath('..') . DIRECTORY_SEPARATOR);
43
44 /**
45  * Path to the directory containing the actual Phergie files
46  *
47  * @const string
48  */
49 define('PHERGIE_DIR', realpath('.') . DIRECTORY_SEPARATOR);
50
51 /**
52  * Path to the directory containing the plugins
53  *
54  * @const string
55  */
56 define('PHERGIE_PLUGIN_DIR', PHERGIE_DIR . 'Plugin' . DIRECTORY_SEPARATOR);
57
58 /**
59  * Add the Phergie directory to the include path
60  */
61 set_include_path(get_include_path() . PATH_SEPARATOR . PHERGIE_DIR . PATH_SEPARATOR. PHERGIE_BASE_DIR);
62
63 /**
64  * Check to make sure the CLI SAPI is being used
65  */
66 if (strtolower(PHP_SAPI) != 'cli') {
67     trigger_error('Phergie requires the CLI SAPI in order to run', E_USER_ERROR);
68 }
69
70 /**
71  * Check to see if date.timezone is empty in the PHP.ini, if so, set the
72  * default timezone to prevent strict errors.
73  */
74 if (!ini_get('date.timezone')) {
75     date_default_timezone_set(date_default_timezone_get());
76 }
77
78 /**
79  * Allow the bot to run indefinitely
80  */
81 set_time_limit(0);
82
83 /**
84  * Determine what configuration file should be used
85  */
86 if (!ini_get('register_argc_argv')) {
87     echo 'The register_argc_argv setting in php.ini is disabled, defaulting to ' . PHERGIE_DEFAULT_INI . PHP_EOL;
88     $ini = PHERGIE_DEFAULT_INI;
89 } else if ($argc == 1) {
90     echo 'No configuration file specified, defaulting to ' . PHERGIE_DEFAULT_INI . PHP_EOL;
91     $ini = PHERGIE_DEFAULT_INI;
92 } else if (!empty($argv[1]) && is_file($argv[1]) && is_readable($argv[1])) {
93     echo 'Using specified configuration file ' . $argv[1] . PHP_EOL;
94     $ini = $argv[1];
95 } else {
96     echo 'Invalid or no configuration file specified, defaulting to ' . PHERGIE_DEFAULT_INI . PHP_EOL;
97     $ini = PHERGIE_DEFAULT_INI;
98 }
99
100 /**
101  * Name of the configuration file currently in use
102  *
103  * @const string
104  */
105 define('PHERGIE_INI', basename($ini));
106
107 /**
108  * Path to the configuration file
109  *
110  * @const string
111  */
112 define('PHERGIE_INI_PATH', realpath($ini));
113
114 /**
115  * Loader to automate inclusion of classes based on directory structure and
116  * class naming conventions.
117  *
118  * @param string $class Class name to check and attempt to load
119  * @return void
120  */
121 function phergieAutoLoader($class)
122 {
123     $file = $class;
124     if (stripos($file, 'phergie_') === 0) {
125         $file = substr($file, 8);
126     }
127     if (is_file($file = str_replace('_', DIRECTORY_SEPARATOR, $file) . '.php')) {
128         require $file;
129     }
130 }
131
132 spl_autoload_register('phergieAutoLoader');
133
134 /**
135  * Start a runtime loop that will reload all settings from the configuration
136  * file if the bot disconnects and reconnects, allowing for flushing of the
137  * configuration without a full shutdown of the bot
138  */
139 while (true) {
140     /**
141      * Obtain and validate the contents of the configuration file
142      */
143     $required = array('server', 'username', 'realname', 'nick');
144     $config = parse_ini_file(PHERGIE_INI_PATH);
145
146     if (empty($config)) {
147         trigger_error('Configuration file inaccessible or empty: ' . $ini, E_USER_ERROR);
148     }
149
150     $missing = array();
151     foreach($required as $value) {
152         if (empty($config[$value])) {
153             $missing[] = $value;
154         }
155     }
156     if (!empty($missing)) {
157         trigger_error('Fatal error: Required configuration settings missing: ' . implode(', ', $missing), E_USER_ERROR);
158     }
159     unset($required, $missing, $value);
160
161     /**
162      * Set error reporting to display errors if debug mode is enabled
163      */
164     if ($config['debug']) {
165         error_reporting(E_ALL | E_STRICT);
166         ini_set('display_errors', true);
167         ini_set('ignore_repeated_errors', true);
168     }
169
170     /**
171      * Configure the client
172      */
173     if (isset($config['driver'])) {
174         $driver = ucfirst(strtolower($config['driver']));
175     }
176     if (!isset($driver) || !file_exists(PHERGIE_DIR . 'Driver' . DIRECTORY_SEPARATOR . $driver . '.php')) {
177         trigger_error('Driver not specified or not found, defaulting to Streams', E_USER_NOTICE);
178         $driver = 'Streams';
179     }
180     $class = 'Phergie_Driver_' . $driver;
181     $client = new $class();
182
183     foreach($config as $setting => $value) {
184         $client->setIni($setting, $value);
185     }
186     unset($setting, $value, $driver, $class);
187
188     /**
189      * Determine which plugins should be loaded
190      */
191     $all = true;
192     $include = array();
193     if (!empty($config['plugins']) &&
194         preg_match('/(all|none)(?:\s*except\s*(.+))?/ADi', $config['plugins'], $match)) {
195         $all = strtolower(trim($match[1])) != 'none';
196         if (!empty($match[2])) {
197             $include = array_map('strtolower', preg_split('/[, ]+/', trim($match[2])));
198         }
199     }
200     unset($config, $match);
201
202     /**
203      * Set up plugins
204      */
205     $iterator = new DirectoryIterator(PHERGIE_PLUGIN_DIR);
206     $plugins = array();
207     foreach($iterator as $entry) {
208         if ($iterator->isFile() && pathinfo($entry, PATHINFO_EXTENSION) == 'php') {
209             $name = basename($entry, '.php');
210             if ($all xor in_array(strtolower($name), $include)) {
211                 $plugins[] = $name;
212             }
213         }
214     }
215     ksort($plugins);
216
217     unset($iterator, $entry, $name, $all, $include);
218
219     foreach($plugins as $plugin) {
220         $class = 'Phergie_Plugin_' . $plugin;
221         /**
222          * @todo When PHP 5.3 is a stable release, change this to
223          *       $class::checkDependencies($client, $plugins);
224          */
225         $result = call_user_func(array($class, 'checkDependencies'), $client, $plugins);
226         if ($result === true) {
227             $instance = new $class($client);
228             $client->addPlugin($instance);
229             $client->debug('Loaded ' . $plugin);
230         } else {
231             // handle bc
232             if ($plugin === false) {
233                 $client->debug('Unable to load ' . $plugin);
234             } else {
235                 $client->debug('Unable to load ' . $plugin . ":\r\n  " . implode("\r\n  ", (array) $result));
236             }
237         }
238     }
239     unset($plugins, $plugin, $class, $instance);
240
241     /**
242      * Execute the event handling loop for the client
243      */
244     $state = $client->run();
245     unset($client);
246
247     switch ($state) {
248         case Phergie_Driver_Abstract::RETURN_RECONNECT:
249             sleep(1);
250         break;
251         case Phergie_Driver_Abstract::RETURN_KEEPALIVE:
252             sleep(15);
253         break;
254         case Phergie_Driver_Abstract::RETURN_END:
255         break 2;
256     }
257 }
258
Note: See TracBrowser for help on using the browser.