diff --git a/ajax.php b/ajax.php index 57b6274ccee12f4292f97aa7df5b4f9c9cd938ce..3374776c7a54ef4cbaa1c0bf7a8139d2179be2dc 100644 --- a/ajax.php +++ b/ajax.php @@ -39,5 +39,6 @@ $dispatcher = patterns('', url_get('^help-topic/(?P<id>\d+)$', 'getClientFormsForHelpTopic') )) ); +Signal::send('ajax.client', $dispatcher); print $dispatcher->resolve($ost->get_path_info()); ?> diff --git a/include/class.dispatcher.php b/include/class.dispatcher.php index 0448f5024eb3e9244f1bf1bbe1b8b462d171117a..d586fd0ba77e010549d72196bcaec0a5f94c44d2 100644 --- a/include/class.dispatcher.php +++ b/include/class.dispatcher.php @@ -153,7 +153,10 @@ class UrlMatcher { function apply_prefix() { if (is_array($this->func)) { list($class, $func) = $this->func; } else { $func = $this->func; $class = ""; } - $class = $this->prefix . $class; + if (is_object($class)) + return array(false, $this->func); + if ($this->prefix) + $class = $this->prefix . $class; if (strpos($class, ":")) { list($file, $class) = explode(":", $class, 2); diff --git a/include/class.plugin.php b/include/class.plugin.php index 107ff4f46d8b451c038ae4b850f4731a6ada8b7e..29dddf0f982c9549e5300e40a462e6906de83e08 100644 --- a/include/class.plugin.php +++ b/include/class.plugin.php @@ -114,25 +114,39 @@ class PluginManager { if (!($res = db_query($sql))) return static::$plugin_list; - $infos = static::allInfos(); while ($ht = db_fetch_array($res)) { // XXX: Only read active plugins here. allInfos() will // read all plugins - if (isset($infos[$ht['install_path']])) { - $info = $infos[$ht['install_path']]; - if ($ht['isactive']) { - list($path, $class) = explode(':', $info['plugin']); - if (!$class) - $class = $path; - else - require_once(INCLUDE_DIR . $ht['install_path'] - . '/' . $path); - static::$plugin_list[$ht['install_path']] - = new $class($ht['id']); - } - else { - static::$plugin_list[$ht['install_path']] = $ht; - } + $info = static::getInfoForPath( + INCLUDE_DIR . $ht['install_path'], $ht['isphar']); + list($path, $class) = explode(':', $info['plugin']); + if (!$class) + $class = $path; + elseif ($ht['isphar']) + require_once('phar://' . INCLUDE_DIR . $ht['install_path'] + . '/' . $path); + else + require_once(INCLUDE_DIR . $ht['install_path'] + . '/' . $path); + if ($ht['isactive']) { + static::$plugin_list[$ht['install_path']] + = new $class($ht['id']); + } + else { + // Get instance without calling the constructor. Thanks + // http://stackoverflow.com/a/2556089 + $a = unserialize( + sprintf( + 'O:%d:"%s":0:{}', + strlen($class), $class + ) + ); + // Simulate __construct() and load() + $a->id = $ht['id']; + $a->ht = $ht; + $a->info = $info; + static::$plugin_list[$ht['install_path']] = &$a; + unset($a); } } return static::$plugin_list; @@ -146,6 +160,10 @@ class PluginManager { return $plugins; } + function throwException($errno, $errstr) { + throw new RuntimeException($errstr); + } + /** * allInfos * @@ -158,34 +176,62 @@ class PluginManager { * queried to determine if the plugin is installed */ static function allInfos() { - static $defaults = array( - 'include' => 'include/', - 'stream' => false, - ); + foreach (glob(INCLUDE_DIR . 'plugins/*', + GLOB_NOSORT|GLOB_BRACE) as $p) { + $is_phar = false; + if (substr($p, strlen($p) - 5) == '.phar' + && Phar::isValidPharFilename($p)) { + try { + // When public key is invalid, openssl throws a + // 'supplied key param cannot be coerced into a public key' warning + // and phar ignores sig verification. + // We need to protect from that by catching the warning + // Thanks, https://github.com/koto/phar-util + set_error_handler(array('self', 'throwException')); + $ph = new Phar($p); + restore_error_handler(); + // Verify the signature + $ph->getSignature(); + $p = 'phar://' . $p; + $is_phar = true; + } catch (UnexpectedValueException $e) { + // Cannot find signature file + } catch (RuntimeException $e) { + // Invalid signature file + } - if (static::$plugin_info) - return static::$plugin_info; + } - foreach (glob(INCLUDE_DIR . 'plugins/*', GLOB_ONLYDIR) as $p) { if (!is_file($p . '/plugin.php')) // Invalid plugin -- must define "/plugin.php" continue; - // plugin.php is require to return an array of informaiton about - // the plugin. - $info = array_merge($defaults, (include $p . '/plugin.php')); - $info['install_path'] = str_replace(INCLUDE_DIR, '', $p); - // XXX: Ensure 'id' key isset - static::$plugin_info[$info['install_path']] = $info; + // Cache the info into static::$plugin_info + static::getInfoForPath($p, $is_phar); } return static::$plugin_info; } - static function getInfoForPath($path) { - $infos = static::allInfos(); - if (isset($infos[$path])) - return $infos[$path]; - return null; + static function getInfoForPath($path, $is_phar=false) { + static $defaults = array( + 'include' => 'include/', + 'stream' => false, + ); + + $install_path = str_replace(INCLUDE_DIR, '', $path); + $install_path = str_replace('phar://', '', $install_path); + if ($is_phar && substr($path, 0, 7) != 'phar://') + $path = 'phar://' . $path; + if (!isset(static::$plugin_info[$install_path])) { + // plugin.php is require to return an array of informaiton about + // the plugin. + $info = array_merge($defaults, (include $path . '/plugin.php')); + $info['install_path'] = $install_path; + + // XXX: Ensure 'id' key isset + static::$plugin_info[$install_path] = $info; + } + return static::$plugin_info[$install_path]; } function getInstance($path) { @@ -215,17 +261,22 @@ class PluginManager { * registered in the plugin registry -- the %plugin table. */ function install($path) { - if (!($info = $this->getInfoForPath($path))) + $is_phar = substr($path, strlen($path) - 5) == '.phar'; + if (!($info = $this->getInfoForPath(INCLUDE_DIR . $path, $is_phar))) return false; $sql='INSERT INTO '.PLUGIN_TABLE.' SET installed=NOW() ' .', install_path='.db_input($path) - .', name='.db_input($info['name']); + .', name='.db_input($info['name']) + .', isphar='.db_input($is_phar); if (!db_query($sql) || !db_affected_rows()) return false; + static::clearCache(); + return true; + } + static function clearCache() { static::$plugin_list = array(); - return true; } } @@ -255,7 +306,8 @@ class Plugin { `id`='.db_input($this->id); if (($res = db_query($sql)) && ($ht=db_fetch_array($res))) $this->ht = $ht; - $this->info = PluginManager::getInfoForPath($this->ht['install_path']); + $this->info = PluginManager::getInfoForPath($this->ht['install_path'], + $this->isPhar()); } function getId() { return $this->id; } @@ -283,6 +335,7 @@ class Plugin { $sql = 'DELETE FROM '.PLUGIN_TABLE .' WHERE id='.db_input($this->getId()); + PluginManager::clearCache(); if (db_query($sql) && db_affected_rows()) return $this->getConfig()->purge(); return false; @@ -302,12 +355,14 @@ class Plugin { function enable() { $sql = 'UPDATE '.PLUGIN_TABLE .' SET isactive=1 WHERE id='.db_input($this->getId()); + PluginManager::clearCache(); return (db_query($sql) && db_affected_rows()); } function disable() { $sql = 'UPDATE '.PLUGIN_TABLE .' SET isactive=0 WHERE id='.db_input($this->getId()); + PluginManager::clearCache(); return (db_query($sql) && db_affected_rows()); } diff --git a/include/staff/plugins.inc.php b/include/staff/plugins.inc.php index eab4a796ee6a3240cd30d35fac1e20f2071b17f0..4b9c5bccc3d83a0474fc4e953b8dfb5c161d0ef9 100644 --- a/include/staff/plugins.inc.php +++ b/include/staff/plugins.inc.php @@ -35,19 +35,11 @@ foreach ($ost->plugins->allInstalled() as $p) { <?php echo $sel?'checked="checked"':''; ?>></td> <td><a href="plugins.php?id=<?php echo $p->getId(); ?>" ><?php echo $p->getName(); ?></a></td> - <td>Enabled</td> + <td><?php echo ($p->isActive()) + ? 'Enabled' : '<strong>Disabled</strong>'; ?></td> <td><?php echo Format::db_datetime($p->getInstallDate()); ?></td> </tr> - <?php } else { - $p = $ost->plugins->getInfoForPath($p['install_path']); ?> - <tr> - <td><input type="checkbox" class="ckb" name="ids[]" value="<?php echo $p['install_path']; ?>" - <?php echo $sel?'checked="checked"':''; ?>></td> - <td><?php echo $p['name']; ?></td> - <td><strong>Disabled</strong></td> - <td></td> - </tr> - <?php } ?> + <?php } else {} ?> <?php } ?> </tbody> <tfoot> diff --git a/scp/plugins.php b/scp/plugins.php index c5e7e8918027296970b717289626fb4c5982d6ac..44dda73b80897b668caafe38638c163321a31e64 100644 --- a/scp/plugins.php +++ b/scp/plugins.php @@ -19,8 +19,8 @@ if($_POST) { $count = count($_POST['ids']); switch(strtolower($_POST['a'])) { case 'enable': - foreach ($_POST['ids'] as $path) { - if ($p = $ost->plugins->getInstance($path)) { + foreach ($_POST['ids'] as $id) { + if ($p = Plugin::lookup($id)) { $p->enable(); } } @@ -35,7 +35,6 @@ if($_POST) { case 'delete': foreach ($_POST['ids'] as $id) { if ($p = Plugin::lookup($id)) { - var_dump($p); $p->uninstall(); } }