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();
                     }
                 }