Skip to content
Snippets Groups Projects
Commit a6e54770 authored by Jared Hancock's avatar Jared Hancock
Browse files

Support PHAR plugins

And make plugin internal handling more consistent
parent d0ed0c14
Branches
Tags
No related merge requests found
...@@ -114,25 +114,39 @@ class PluginManager { ...@@ -114,25 +114,39 @@ class PluginManager {
if (!($res = db_query($sql))) if (!($res = db_query($sql)))
return static::$plugin_list; return static::$plugin_list;
$infos = static::allInfos();
while ($ht = db_fetch_array($res)) { while ($ht = db_fetch_array($res)) {
// XXX: Only read active plugins here. allInfos() will // XXX: Only read active plugins here. allInfos() will
// read all plugins // read all plugins
if (isset($infos[$ht['install_path']])) { $info = static::getInfoForPath(
$info = $infos[$ht['install_path']]; INCLUDE_DIR . $ht['install_path'], $ht['isphar']);
if ($ht['isactive']) { list($path, $class) = explode(':', $info['plugin']);
list($path, $class) = explode(':', $info['plugin']); if (!$class)
if (!$class) $class = $path;
$class = $path; elseif ($ht['isphar'])
else require_once('phar://' . INCLUDE_DIR . $ht['install_path']
require_once(INCLUDE_DIR . $ht['install_path'] . '/' . $path);
. '/' . $path); else
static::$plugin_list[$ht['install_path']] require_once(INCLUDE_DIR . $ht['install_path']
= new $class($ht['id']); . '/' . $path);
} if ($ht['isactive']) {
else { static::$plugin_list[$ht['install_path']]
static::$plugin_list[$ht['install_path']] = $ht; = 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; return static::$plugin_list;
...@@ -146,6 +160,10 @@ class PluginManager { ...@@ -146,6 +160,10 @@ class PluginManager {
return $plugins; return $plugins;
} }
function throwException($errno, $errstr) {
throw new RuntimeException($errstr);
}
/** /**
* allInfos * allInfos
* *
...@@ -158,34 +176,62 @@ class PluginManager { ...@@ -158,34 +176,62 @@ class PluginManager {
* queried to determine if the plugin is installed * queried to determine if the plugin is installed
*/ */
static function allInfos() { static function allInfos() {
static $defaults = array( foreach (glob(INCLUDE_DIR . 'plugins/*',
'include' => 'include/', GLOB_NOSORT|GLOB_BRACE) as $p) {
'stream' => false, $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')) if (!is_file($p . '/plugin.php'))
// Invalid plugin -- must define "/plugin.php" // Invalid plugin -- must define "/plugin.php"
continue; 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 // Cache the info into static::$plugin_info
static::$plugin_info[$info['install_path']] = $info; static::getInfoForPath($p, $is_phar);
} }
return static::$plugin_info; return static::$plugin_info;
} }
static function getInfoForPath($path) { static function getInfoForPath($path, $is_phar=false) {
$infos = static::allInfos(); static $defaults = array(
if (isset($infos[$path])) 'include' => 'include/',
return $infos[$path]; 'stream' => false,
return null; );
$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) { function getInstance($path) {
...@@ -215,17 +261,22 @@ class PluginManager { ...@@ -215,17 +261,22 @@ class PluginManager {
* registered in the plugin registry -- the %plugin table. * registered in the plugin registry -- the %plugin table.
*/ */
function install($path) { 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; return false;
$sql='INSERT INTO '.PLUGIN_TABLE.' SET installed=NOW() ' $sql='INSERT INTO '.PLUGIN_TABLE.' SET installed=NOW() '
.', install_path='.db_input($path) .', 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()) if (!db_query($sql) || !db_affected_rows())
return false; return false;
static::clearCache();
return true;
}
static function clearCache() {
static::$plugin_list = array(); static::$plugin_list = array();
return true;
} }
} }
...@@ -255,7 +306,8 @@ class Plugin { ...@@ -255,7 +306,8 @@ class Plugin {
`id`='.db_input($this->id); `id`='.db_input($this->id);
if (($res = db_query($sql)) && ($ht=db_fetch_array($res))) if (($res = db_query($sql)) && ($ht=db_fetch_array($res)))
$this->ht = $ht; $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; } function getId() { return $this->id; }
...@@ -283,6 +335,7 @@ class Plugin { ...@@ -283,6 +335,7 @@ class Plugin {
$sql = 'DELETE FROM '.PLUGIN_TABLE $sql = 'DELETE FROM '.PLUGIN_TABLE
.' WHERE id='.db_input($this->getId()); .' WHERE id='.db_input($this->getId());
PluginManager::clearCache();
if (db_query($sql) && db_affected_rows()) if (db_query($sql) && db_affected_rows())
return $this->getConfig()->purge(); return $this->getConfig()->purge();
return false; return false;
...@@ -302,12 +355,14 @@ class Plugin { ...@@ -302,12 +355,14 @@ class Plugin {
function enable() { function enable() {
$sql = 'UPDATE '.PLUGIN_TABLE $sql = 'UPDATE '.PLUGIN_TABLE
.' SET isactive=1 WHERE id='.db_input($this->getId()); .' SET isactive=1 WHERE id='.db_input($this->getId());
PluginManager::clearCache();
return (db_query($sql) && db_affected_rows()); return (db_query($sql) && db_affected_rows());
} }
function disable() { function disable() {
$sql = 'UPDATE '.PLUGIN_TABLE $sql = 'UPDATE '.PLUGIN_TABLE
.' SET isactive=0 WHERE id='.db_input($this->getId()); .' SET isactive=0 WHERE id='.db_input($this->getId());
PluginManager::clearCache();
return (db_query($sql) && db_affected_rows()); return (db_query($sql) && db_affected_rows());
} }
......
...@@ -35,19 +35,11 @@ foreach ($ost->plugins->allInstalled() as $p) { ...@@ -35,19 +35,11 @@ foreach ($ost->plugins->allInstalled() as $p) {
<?php echo $sel?'checked="checked"':''; ?>></td> <?php echo $sel?'checked="checked"':''; ?>></td>
<td><a href="plugins.php?id=<?php echo $p->getId(); ?>" <td><a href="plugins.php?id=<?php echo $p->getId(); ?>"
><?php echo $p->getName(); ?></a></td> ><?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> <td><?php echo Format::db_datetime($p->getInstallDate()); ?></td>
</tr> </tr>
<?php } else { <?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 } ?> <?php } ?>
</tbody> </tbody>
<tfoot> <tfoot>
......
...@@ -19,8 +19,8 @@ if($_POST) { ...@@ -19,8 +19,8 @@ if($_POST) {
$count = count($_POST['ids']); $count = count($_POST['ids']);
switch(strtolower($_POST['a'])) { switch(strtolower($_POST['a'])) {
case 'enable': case 'enable':
foreach ($_POST['ids'] as $path) { foreach ($_POST['ids'] as $id) {
if ($p = $ost->plugins->getInstance($path)) { if ($p = Plugin::lookup($id)) {
$p->enable(); $p->enable();
} }
} }
...@@ -35,7 +35,6 @@ if($_POST) { ...@@ -35,7 +35,6 @@ if($_POST) {
case 'delete': case 'delete':
foreach ($_POST['ids'] as $id) { foreach ($_POST['ids'] as $id) {
if ($p = Plugin::lookup($id)) { if ($p = Plugin::lookup($id)) {
var_dump($p);
$p->uninstall(); $p->uninstall();
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment