* [MOD] Improved plugins manager

* [MOD] Code refactoring and cleanup
* [MOD] Make classes final for performance improvements and avoid some side behaviours
This commit is contained in:
nuxsmin
2018-07-28 21:45:49 +02:00
parent 3e26a1df71
commit cd2c0379db
90 changed files with 517 additions and 1071 deletions

View File

@@ -33,11 +33,9 @@ use RuntimeException;
use SP\Config\Config;
use SP\Config\ConfigData;
use SP\Config\ConfigUtil;
use SP\Core\Context\ContextInterface;
use SP\Core\Exceptions\ConfigException;
use SP\Core\Exceptions\InitializationException;
use SP\Core\Language;
use SP\Core\UI\Theme;
use SP\Http\Request;
use SP\Modules\Api\Init as InitApi;
use SP\Modules\Web\Init as InitWeb;
@@ -46,6 +44,7 @@ use SP\Services\Api\JsonRpcResponse;
use SP\Services\Upgrade\UpgradeConfigService;
use SP\Services\Upgrade\UpgradeUtil;
use SP\Util\Checks;
use SP\Util\Filter;
use SP\Util\Util;
defined('APP_ROOT') || die();
@@ -57,10 +56,6 @@ defined('APP_ROOT') || die();
*/
final class Bootstrap
{
/**
* @var string The installation path on the server (e.g. /srv/www/syspass)
*/
public static $SERVERROOT = '';
/**
* @var string The current request path relative to the sysPass root (e.g. files/index.php)
*/
@@ -70,9 +65,9 @@ final class Bootstrap
*/
public static $WEBURI = '';
/**
* @var bool True if sysPass has been updated. Only for notices.
* @var string
*/
public static $UPDATED = false;
public static $SUBURI = '';
/**
* @var mixed
*/
@@ -81,34 +76,22 @@ final class Bootstrap
* @var bool Indica si la versión de PHP es correcta
*/
public static $checkPhpVersion;
/**
* @var string
*/
public static $SUBURI = '';
/**
* @var ContainerInterface|Container
*/
protected static $container;
/**
* @var ContextInterface
*/
protected $context;
/**
* @var Theme
*/
protected $theme;
private static $container;
/**
* @var Klein
*/
protected $router;
private $router;
/**
* @var Language
*/
protected $language;
private $language;
/**
* @var Request
*/
protected $request;
private $request;
/**
* @var Config
*/
@@ -146,9 +129,6 @@ final class Bootstrap
{
$oops = "Oops, it looks like this content doesn't exist...";
// Update request when we have a subdirectory
// $_SERVER['REQUEST_URI'] = self::$WEBROOT;
$this->router->onError(function ($router, $err_msg, $type, $err) {
debugLog('Routing error: ' . $err_msg);
@@ -201,26 +181,16 @@ final class Bootstrap
function ($request, $response, $service) use ($oops) {
try {
/** @var \Klein\Request $request */
$route = filter_var($request->param('r', 'index/index'), FILTER_SANITIZE_STRING);
$route = Filter::getString($request->param('r', 'index/index'));
if (!preg_match_all('#(?P<controller>[a-zA-Z]+)(?:/(?P<action>[a-zA-Z]+))?(?P<params>(/[a-zA-Z\d]+)+)?#', $route, $matches)) {
if (!preg_match_all('#(?P<controller>[a-zA-Z]+)(?:/(?P<action>[a-zA-Z]+))?(?P<params>/[a-zA-Z\d]+)?#', $route, $matches)) {
throw new RuntimeException($oops);
}
// $app = $matches['app'][0] ?: 'web';
$controller = $matches['controller'][0];
$method = !empty($matches['action'][0]) ? $matches['action'][0] . 'Action' : 'indexAction';
$params = [];
if (!empty($matches['params'][0])) {
foreach (explode('/', $matches['params'][0]) as $value) {
if (is_numeric($value)) {
$params[] = (int)filter_var($value, FILTER_SANITIZE_NUMBER_INT);
} elseif (!empty($value)) {
$params[] = filter_var($value, FILTER_SANITIZE_STRING);
}
}
}
$params = !empty($matches['params'][0]) ? Filter::getArray(explode('/', trim($matches['params'][0], '/'))) : [];
$controllerClass = 'SP\\Modules\\' . ucfirst(APP_MODULE) . '\\Controllers\\' . ucfirst($controller) . 'Controller';
@@ -326,7 +296,9 @@ final class Bootstrap
public function initPHPVars()
{
// Establecer el modo debug si una sesión de xdebug está activa
if (isset($_COOKIE['XDEBUG_SESSION']) && !defined('DEBUG')) {
if ($this->router->request()->cookies()->get('XDEBUG_SESSION')
&& !defined('DEBUG')
) {
define('DEBUG', true);
}
@@ -338,7 +310,10 @@ final class Bootstrap
ini_set('display_errors', 'Off');
}
if (!file_exists(LOG_FILE) && touch(LOG_FILE) && chmod(LOG_FILE, 0600)) {
if (!file_exists(LOG_FILE)
&& touch(LOG_FILE)
&& chmod(LOG_FILE, 0600)
) {
debugLog('Setup log file: ' . LOG_FILE);
}
@@ -358,14 +333,13 @@ final class Bootstrap
*/
private function initPaths()
{
self::$SERVERROOT = dirname(BASE_PATH);
self::$SUBURI = str_replace("\\", '/', substr(realpath($this->request->getServer('SCRIPT_FILENAME')), strlen(APP_ROOT)));
self::$SUBURI = str_replace("\\", '/', substr(realpath($_SERVER['SCRIPT_FILENAME']), strlen(self::$SERVERROOT)));
$scriptName = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
$scriptName = $this->request->getServer('REQUEST_URI');
if (substr($scriptName, -1) === '/') {
$scriptName .= 'index.php';
// Asegurar que suburi sigue las mismas reglas que scriptName
if (substr(self::$SUBURI, -9) !== 'index.php') {
if (substr(self::$SUBURI, -1) !== '/') {

View File

@@ -1,202 +0,0 @@
<?php
/**
* sysPass
*
* @author nuxsmin
* @link https://syspass.org
* @copyright 2012-2018, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sysPass is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*/
namespace SP\Core\Dic;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use ReflectionMethod;
/**
* Class Dic
*
* @package SP\Core\Dic
*/
final class Container implements DicInterface
{
/**
* @var array Shared objects
*/
private $shared = [];
/**
* @var array Factory objects
*/
private $factory = [];
/**
* @var array Trasient objects (dinamically created and reusable)
*/
private $trasient = [];
/**
* Store shared object
*
* @param string $name
* @param callable $callable
*
* @internal param callable|string $class
*/
public function share($name, $callable = null)
{
$this->shared[$name] = $callable;
}
/**
* Store factory object
*
* @param string $name
* @param callable $callable
*
* @internal param callable|string $class
*/
public function add($name, $callable = null)
{
$this->factory[$name] = $callable;
}
/**
* Inject object
*
* @param $context
*
* @return mixed
* @throws \Psr\Container\ContainerExceptionInterface
*/
public function inject($context)
{
try {
$reflectionMethod = new ReflectionMethod($context, 'inject');
$methodParams = $reflectionMethod->getParameters();
$params = [];
if (!count($methodParams)) {
return false;
}
foreach ($methodParams as $key => $methodParam) {
if ($methodParam->getClass()) {
$className = $methodParam->getClass()->getName();
if ($this->has($className)) {
$params[$key] = $this->get($className);
} else {
$params[$key] = new $className;
}
} else {
$params[$key] = null;
}
}
return $reflectionMethod->invokeArgs($context, $params);
} catch (\ReflectionException $e) {
throw new ContainerException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* Returns true if the container can return an entry for the given identifier.
* Returns false otherwise.
*
* `has($id)` returning true does not mean that `get($id)` will not throw an exception.
* It does however mean that `get($id)` will not throw a `NotFoundExceptionInterface`.
*
* @param string $id Identifier of the entry to look for.
*
* @return bool
*/
public function has($id)
{
return array_key_exists($id, $this->shared) || array_key_exists($id, $this->factory);
}
/**
* Finds an entry of the container by its identifier and returns it.
*
* @param string $id Identifier of the entry to look for.
*
* @throws NotFoundExceptionInterface No entry was found for **this** identifier.
* @throws ContainerExceptionInterface Error while retrieving the entry.
*
* @return mixed Entry.
*/
public function get($id)
{
if (array_key_exists($id, $this->trasient)) {
return $this->trasient[$id];
}
if (array_key_exists($id, $this->factory)) {
return $this->getFactoryObject($id);
}
if (array_key_exists($id, $this->shared)) {
return $this->getSharedObject($id);
}
throw new NotFoundException(sprintf('Object not found (%s)', $id));
}
/**
* @param $id
*
* @return mixed
* @throws ContainerExceptionInterface
*/
private function getFactoryObject($id)
{
if (is_callable($this->factory[$id])) {
return $this->factory[$id]($this);
}
if (class_exists($id)) {
$trasient = new $id();
$this->trasient[$id] = $trasient;
return $trasient;
}
throw new ContainerException(sprintf('Invalid class (%s)', $id));
}
/**
* @param $id
*
* @return mixed
*/
private function getSharedObject($id)
{
if (get_class($this->shared[$id]) === $id) {
return $this->shared[$id];
}
if (is_callable($this->shared[$id])) {
$this->shared[$id] = $this->shared[$id]($this);
} elseif (class_exists($id)) {
$this->shared[$id] = new $id();
}
return $this->shared[$id];
}
}

View File

@@ -1,39 +0,0 @@
<?php
/**
* sysPass
*
* @author nuxsmin
* @link https://syspass.org
* @copyright 2012-2018, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sysPass is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*/
namespace SP\Core\Dic;
use Exception;
use Psr\Container\ContainerExceptionInterface;
/**
* Class ContainerException
*
* @package SP\Core\Dic
*/
class ContainerException extends Exception implements ContainerExceptionInterface
{
}

View File

@@ -1,60 +0,0 @@
<?php
/**
* sysPass
*
* @author nuxsmin
* @link https://syspass.org
* @copyright 2012-2018, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sysPass is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*/
namespace SP\Core\Dic;
use Psr\Container\ContainerInterface;
/**
* Interface DicInterface
*
* @package SP\Core\Dic
*/
interface DicInterface extends ContainerInterface
{
/**
* Store shared object
*
* @param string $name
* @param callable $callable
*/
public function share($name, $callable = null);
/**
* Store factory object
*
* @param string $name
* @param callable $callable
*/
public function add($name, $callable = null);
/**
* Inject object
*
* @param $context
*
* @return mixed
*/
public function inject($context);
}

View File

@@ -1,47 +0,0 @@
<?php
/**
* sysPass
*
* @author nuxsmin
* @link https://syspass.org
* @copyright 2012-2018, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sysPass is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*/
namespace SP\Core\Dic;
use SP\Bootstrap;
/**
* Trait InjectTrait
*
* @package SP\Core\Traits
*/
trait InjectableTrait
{
/**
* Injects dependencies through the DI container
*
* @throws \SP\Core\Dic\ContainerException
*/
final protected function injectDependencies()
{
if (method_exists($this, 'inject')) {
Injector::inject(Bootstrap::getContainer(), $this);
}
}
}

View File

@@ -1,73 +0,0 @@
<?php
/**
* sysPass
*
* @author nuxsmin
* @link https://syspass.org
* @copyright 2012-2018, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sysPass is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*/
namespace SP\Core\Dic;
use Interop\Container\ContainerInterface;
use Psr\Container\ContainerExceptionInterface;
use ReflectionMethod;
/**
* Class Injector
*
* @package SP\Core\Dic
*/
class Injector
{
/**
* Inject object
*
* @param ContainerInterface $container
* @param $context
*
* @return mixed
* @throws ContainerException
*/
public static function inject(ContainerInterface $container, $context)
{
try {
$reflectionMethod = new ReflectionMethod($context, 'inject');
if ($reflectionMethod->getNumberOfParameters() === 0) {
return false;
}
$params = [];
foreach ($reflectionMethod->getParameters() as $key => $methodParam) {
if ($methodParam->getClass()) {
$params[$key] = $container->get($methodParam->getClass()->getName());
} else {
$params[$key] = null;
}
}
return $reflectionMethod->invokeArgs($context, $params);
} catch (\Exception $e) {
throw new ContainerException($e->getMessage(), $e->getCode(), $e);
} catch (ContainerExceptionInterface $e) {
throw new ContainerException($e->getMessage(), $e->getCode(), $e);
}
}
}

View File

@@ -1,38 +0,0 @@
<?php
/**
* sysPass
*
* @author nuxsmin
* @link https://syspass.org
* @copyright 2012-2018, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sysPass is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*/
namespace SP\Core\Dic;
use Exception;
use Psr\Container\NotFoundExceptionInterface;
/**
* Class NotFoundException
*
* @package SP\Core\Dic
*/
class NotFoundException extends Exception implements NotFoundExceptionInterface
{
}

View File

@@ -1,93 +0,0 @@
<?php
/**
* sysPass
*
* @author nuxsmin
* @link https://syspass.org
* @copyright 2012-2018, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sysPass is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*/
namespace SP\Core\Plugin;
use SP\DataModel\PluginData;
use SP\Log\Log;
use SP\Mgmt\Plugins\Plugin;
/**
* Class PluginDataStore
*
* @package SP\Core\Plugin
*/
class PluginDataStore
{
/**
* Guardar los datos de un plugin
*
* @param PluginInterface $Plugin
*
* @throws \SP\Core\Exceptions\SPException
*/
public static function save(PluginInterface $Plugin)
{
$PluginData = new PluginData();
$PluginData->setName($Plugin->getName());
$PluginData->setEnabled(1);
$PluginData->setData(serialize($Plugin->getData()));
Plugin::getItem($PluginData)->update();
}
/**
* Cargar los datos de un plugin
*
* @param PluginInterface $Plugin
*
* @return bool
* @throws \SP\Core\Exceptions\InvalidClassException
* @throws \SP\Core\Exceptions\SPException
*/
public static function load(PluginInterface $Plugin)
{
/** @var PluginData $PluginData */
$PluginData = Plugin::getItem()->getByName($Plugin->getName());
if (!is_object($PluginData)) {
$PluginData = new PluginData();
$PluginData->setName($Plugin->getName());
$PluginData->setEnabled(0);
Plugin::getItem($PluginData)->add();
$Log = new Log();
$Log->getLogMessage()
->setAction(__('Nuevo Plugin', false))
->addDetails(__('Nombre', false), $Plugin->getName());
$Log->writeLog();
return false;
}
$data = $PluginData->getData();
if ($data !== '') {
$Plugin->setData(unserialize($PluginData->getData()));
}
return (bool)$PluginData->getEnabled();
}
}

View File

@@ -1,245 +0,0 @@
<?php
/**
* sysPass
*
* @author nuxsmin
* @link https://syspass.org
* @copyright 2012-2018, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sysPass is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*/
namespace SP\Core\Plugin;
use ReflectionClass;
use SP\Core\DiFactory;
use SP\Core\Exceptions\SPException;
use SP\Core\SessionFactory;
use SP\DataModel\PluginData;
use SP\Log\Log;
use SP\Mgmt\Plugins\Plugin;
/**
* Class PluginUtil
*
* @package SP\Core\Plugin
*/
class PluginUtil
{
/**
* @var array Plugins habilitados
*/
private static $enabledPlugins;
/**
* @var PluginInterface[] Plugins ya cargados
*/
private static $loadedPlugins = [];
/**
* @var array Plugins deshabilitados
*/
private static $disabledPlugins = [];
/**
* Devuelve la lista de Plugins disponibles
*
* @return array
*/
public static function getPlugins()
{
$pluginDirH = opendir(PLUGINS_PATH);
$plugins = [];
if ($pluginDirH) {
while (false !== ($entry = readdir($pluginDirH))) {
$pluginDir = PLUGINS_PATH . DIRECTORY_SEPARATOR . $entry;
if (strpos($entry, '.') === false
&& is_dir($pluginDir)
&& file_exists($pluginDir . DIRECTORY_SEPARATOR . $entry . 'Plugin.class.php')
) {
$plugins[] = $entry;
}
}
closedir($pluginDirH);
}
return $plugins;
}
/**
* Cargar un plugin
*
* @param string $name Nombre del plugin
*
* @return bool|PluginInterface
* @throws \SP\Core\Exceptions\SPException
*/
public static function loadPlugin($name)
{
$name = ucfirst($name);
if (in_array($name, SessionFactory::getPluginsDisabled(), true)) {
return false;
}
if (isset(self::$loadedPlugins[$name])) {
return self::$loadedPlugins[$name];
}
try {
$pluginClass = 'Plugins\\' . $name . '\\' . $name . 'Plugin';
$Reflection = new ReflectionClass($pluginClass);
/** @var PluginInterface $Plugin */
$Plugin = $Reflection->newInstance();
if (PluginDataStore::load($Plugin) === true) {
self::$loadedPlugins[$name] = $Plugin;
return $Plugin;
}
self::$disabledPlugins[] = $name;
} catch (\ReflectionException $e) {
Log::writeNewLog(__FUNCTION__,
sprintf(__('No es posible cargar el plugin "%s"'), $name));
} catch (SPException $e) {
Log::writeNewLog(__FUNCTION__,
sprintf(__('No es posible cargar el plugin "%s"'), $name));
}
return false;
}
/**
* Devolver los plugins cargados
*
* @return PluginInterface[]
*/
public static function getLoadedPlugins()
{
return self::$loadedPlugins;
}
/**
* Devolver los plugins deshabilidatos
*
* @return string[]
*/
public static function getDisabledPlugins()
{
return self::$disabledPlugins;
}
/**
* Obtener la información de un plugin
*
* @param string $name Nombre del plugin
*
* @return bool|PluginInterface
* @throws \SP\Core\Exceptions\SPException
*/
public static function getPluginInfo($name)
{
$name = ucfirst($name);
$pluginClass = 'Plugins\\' . $name . '\\' . $name . 'Plugin';
if (isset(self::$loadedPlugins[$name])) {
return self::$loadedPlugins[$name];
}
try {
$Reflection = new \ReflectionClass($pluginClass);
/** @var PluginBase $Plugin */
$Plugin = $Reflection->newInstance();
self::$loadedPlugins[$name] = $Plugin;
return $Plugin;
} catch (\ReflectionException $e) {
Log::writeNewLog(__FUNCTION__, sprintf(__('No es posible cargar el plugin "%s"'), $name));
}
return false;
}
/**
* Comprobar disponibilidad de plugins habilitados
*
* @throws \SP\Core\Exceptions\SPException
*/
public static function checkEnabledPlugins()
{
$PluginData = new PluginData();
$PluginData->setAvailable(false);
$PluginData->setEnabled(false);
foreach (self::getEnabledPlugins() as $plugin) {
if (!in_array($plugin, self::$loadedPlugins)) {
$PluginClone = clone $PluginData;
$PluginClone->setName($plugin);
Plugin::getItem($PluginClone)->toggleAvaliableByName();
}
}
}
/**
* Devolver los plugins habilitados
*
* @return PluginInterface[]
*/
public static function getEnabledPlugins()
{
if (self::$enabledPlugins !== null) {
return self::$enabledPlugins;
}
self::$enabledPlugins = [];
foreach (Plugin::getItem()->getEnabled() as $plugin) {
self::$enabledPlugins[] = $plugin->plugin_name;
}
return self::$enabledPlugins;
}
/**
* Cargar los Plugins disponibles
*
* @throws \SP\Core\Exceptions\SPException
*/
public static function loadPlugins()
{
$PluginsLoader = new \SplClassLoader('Plugins', PLUGINS_PATH);
$PluginsLoader->register();
foreach (self::getPlugins() as $plugin) {
$Plugin = self::loadPlugin($plugin);
if ($Plugin !== false) {
DiFactory::getEventDispatcher()->attach($Plugin);
}
}
SessionFactory::setPluginsLoaded(PluginUtil::getLoadedPlugins());
SessionFactory::setPluginsDisabled(PluginUtil::getDisabledPlugins());
}
}

View File

@@ -2,8 +2,8 @@
/**
* sysPass
*
* @author nuxsmin
* @link https://syspass.org
* @author nuxsmin
* @link https://syspass.org
* @copyright 2012-2018, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
@@ -22,12 +22,12 @@
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*/
namespace SP\Core\Plugin;
namespace SP\Plugin;
/**
* Class PluginBase
*
* @package SP\Core\Plugin
* @package SP\Plugin
*/
abstract class PluginBase implements PluginInterface
{

View File

@@ -2,8 +2,8 @@
/**
* sysPass
*
* @author nuxsmin
* @link https://syspass.org
* @author nuxsmin
* @link https://syspass.org
* @copyright 2012-2018, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
@@ -22,7 +22,7 @@
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*/
namespace SP\Core\Plugin;
namespace SP\Plugin;
use SP\Core\Events\Event;
use SplObserver;

View File

@@ -2,8 +2,8 @@
/**
* sysPass
*
* @author nuxsmin
* @link https://syspass.org
* @author nuxsmin
* @link https://syspass.org
* @copyright 2012-2018, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
@@ -22,12 +22,12 @@
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*/
namespace SP\Core\Plugin;
namespace SP\Plugin;
/**
* Interface PluginInterface
*
* @package SP\Core\Plugin
* @package SP\Plugin
*/
interface PluginInterface extends PluginEventReceiver
{

View File

@@ -0,0 +1,282 @@
<?php
/**
* sysPass
*
* @author nuxsmin
* @link https://syspass.org
* @copyright 2012-2018, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sysPass is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*/
namespace SP\Plugin;
use ReflectionClass;
use SP\Core\Context\ContextInterface;
use SP\Core\Events\Event;
use SP\Core\Events\EventDispatcher;
use SP\Core\Events\EventMessage;
use SP\DataModel\PluginData;
use SP\Repositories\NoSuchItemException;
use SP\Services\Plugin\PluginService;
/**
* Class PluginUtil
*
* @package SP\Plugin
*/
class PluginManager
{
/**
* @var array Plugins habilitados
*/
private $enabledPlugins;
/**
* @var PluginInterface[] Plugins ya cargados
*/
private $loadedPlugins = [];
/**
* @var array Plugins deshabilitados
*/
private $disabledPlugins = [];
/**
* @var PluginService
*/
private $pluginService;
/**
* @var ContextInterface
*/
private $context;
/**
* @var EventDispatcher
*/
private $eventDispatcher;
/**
* PluginManager constructor.
*
* @param PluginService $pluginService
* @param ContextInterface $context
* @param EventDispatcher $eventDispatcher
*/
public function __construct(PluginService $pluginService, ContextInterface $context, EventDispatcher $eventDispatcher)
{
$this->pluginService = $pluginService;
$this->context = $context;
$this->eventDispatcher = $eventDispatcher;
}
/**
* Obtener la información de un plugin
*
* @param string $name Nombre del plugin
*
* @return PluginInterface
*/
public function getPluginInfo($name)
{
$name = ucfirst($name);
$pluginClass = 'Plugins\\' . $name . '\\' . $name . 'Plugin';
if (isset($this->loadedPlugins[$name])) {
return $this->loadedPlugins[$name];
}
try {
$reflectionClass = new \ReflectionClass($pluginClass);
/** @var PluginBase $plugin */
$plugin = $reflectionClass->newInstance();
$this->loadedPlugins[$name] = $plugin;
return $plugin;
} catch (\ReflectionException $e) {
processException($e);
$this->eventDispatcher->notifyEvent('exception',
new Event($e, EventMessage::factory()
->addDescription(sprintf(__('No es posible cargar el plugin "%s"'), $name)))
);
}
return null;
}
/**
* Comprobar disponibilidad de plugins habilitados
*
* @throws \SP\Core\Exceptions\SPException
*/
public function checkEnabledPlugins()
{
foreach ($this->getEnabledPlugins() as $plugin) {
if (!in_array($plugin, $this->loadedPlugins)) {
$this->pluginService->toggleAvailableByName($plugin, false);
}
}
}
/**
* Devolver los plugins habilitados
*
* @return PluginInterface[]
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
public function getEnabledPlugins()
{
if ($this->enabledPlugins !== null) {
return $this->enabledPlugins;
}
$this->enabledPlugins = [];
foreach ($this->pluginService->getEnabled() as $plugin) {
$this->enabledPlugins[] = $plugin->getName();
}
return $this->enabledPlugins;
}
/**
* Cargar los Plugins disponibles
*/
public function loadPlugins()
{
$classLoader = new \SplClassLoader('Plugins', PLUGINS_PATH);
$classLoader->register();
foreach ($this->getPlugins() as $name) {
if (($plugin = $this->loadPlugin($name)) !== null) {
debugLog('Plugin loaded: ' . $name);
$this->eventDispatcher->attach($plugin);
}
}
}
/**
* Devuelve la lista de Plugins disponibles em el directorio
*
* @return array
*/
public function getPlugins()
{
$pluginDirH = opendir(PLUGINS_PATH);
$plugins = [];
if ($pluginDirH) {
while (false !== ($entry = readdir($pluginDirH))) {
$pluginDir = PLUGINS_PATH . DIRECTORY_SEPARATOR . $entry;
if (strpos($entry, '.') === false
&& is_dir($pluginDir)
&& file_exists($pluginDir . DIRECTORY_SEPARATOR . $entry . 'Plugin.php')
) {
$plugins[] = $entry;
}
}
closedir($pluginDirH);
}
return $plugins;
}
/**
* Cargar un plugin
*
* @param string $name Nombre del plugin
*
* @return PluginInterface
*/
public function loadPlugin($name)
{
$name = ucfirst($name);
if (isset($this->loadedPlugins[$name])) {
return $this->loadedPlugins[$name];
}
try {
$pluginClass = 'Plugins\\' . $name . '\\' . $name . 'Plugin';
$reflectionClass = new ReflectionClass($pluginClass);
/** @var PluginInterface $plugin */
$plugin = $reflectionClass->newInstance();
try {
$pluginData = $this->pluginService->getByName($plugin);
if ($pluginData->getEnabled() === 1) {
if (!empty($pluginData->getData())) {
$pluginData->setData(unserialize($pluginData->getData()));
}
return $plugin;
} else {
$this->disabledPlugins[] = $name;
}
} catch (NoSuchItemException $noSuchItemException) {
$pluginData = new PluginData();
$pluginData->setName($name);
$pluginData->setEnabled(0);
$this->pluginService->create($pluginData);
$this->eventDispatcher->notifyEvent('create.plugin',
new Event($this, EventMessage::factory()
->addDescription(__u('Nuevo Plugin'))
->addDetail(__u('Nombre'), $name)
));
$this->disabledPlugins[] = $name;
}
} catch (\Exception $e) {
processException($e);
$this->eventDispatcher->notifyEvent('exception',
new Event($e, EventMessage::factory()
->addDescription(sprintf(__('No es posible cargar el plugin "%s"'), $name)))
);
}
return null;
}
/**
* Devolver los plugins cargados
*
* @return PluginInterface[]
*/
public function getLoadedPlugins()
{
return $this->loadedPlugins;
}
/**
* Devolver los plugins deshabilidatos
*
* @return string[]
*/
public function getDisabledPlugins()
{
return $this->disabledPlugins;
}
}

View File

@@ -343,7 +343,7 @@ final class PluginRepository extends Repository implements RepositoryItemInterfa
{
$queryData = new QueryData();
$queryData->setQuery('UPDATE Plugin SET enabled = ? WHERE id = ? LIMIT 1');
$queryData->setParams([$enabled, $id]);
$queryData->setParams([(int)$enabled, $id]);
$queryData->setOnErrorMessage(__u('Error al actualizar el plugin'));
return $this->db->doQuery($queryData)->getAffectedNumRows();
@@ -363,7 +363,7 @@ final class PluginRepository extends Repository implements RepositoryItemInterfa
{
$queryData = new QueryData();
$queryData->setQuery('UPDATE Plugin SET enabled = ? WHERE name = ? LIMIT 1');
$queryData->setParams([$enabled, $name]);
$queryData->setParams([(int)$enabled, $name]);
$queryData->setOnErrorMessage(__u('Error al actualizar el plugin'));
return $this->db->doQuery($queryData)->getAffectedNumRows();
@@ -382,8 +382,8 @@ final class PluginRepository extends Repository implements RepositoryItemInterfa
public function toggleAvailable($id, $available)
{
$queryData = new QueryData();
$queryData->setQuery('UPDATE Plugin SET available = ? WHERE id = ? LIMIT 1');
$queryData->setParams([$available, $id]);
$queryData->setQuery('UPDATE Plugin SET available = ?, enabled = 0 WHERE id = ? LIMIT 1');
$queryData->setParams([(int)$available, $id]);
$queryData->setOnErrorMessage(__u('Error al actualizar el plugin'));
return $this->db->doQuery($queryData)->getAffectedNumRows();
@@ -402,8 +402,8 @@ final class PluginRepository extends Repository implements RepositoryItemInterfa
public function toggleAvailableByName($name, $available)
{
$queryData = new QueryData();
$queryData->setQuery('UPDATE Plugin SET available = ? WHERE `name` = ? LIMIT 1');
$queryData->setParams([$available, $name]);
$queryData->setQuery('UPDATE Plugin SET available = ?, enabled = 0 WHERE `name` = ? LIMIT 1');
$queryData->setParams([(int)$available, $name]);
$queryData->setOnErrorMessage(__u('Error al actualizar el plugin'));
return $this->db->doQuery($queryData)->getAffectedNumRows();
@@ -439,7 +439,7 @@ final class PluginRepository extends Repository implements RepositoryItemInterfa
{
$queryData = new QueryData();
$queryData->setMapClassName(ItemData::class);
$queryData->setQuery('SELECT id, `name` FROM Plugin WHERE enabled = 1 ORDER BY id');
$queryData->setQuery('SELECT id, `name` FROM Plugin WHERE available = 1 AND enabled = 1 ORDER BY id');
return $this->db->doSelect($queryData);
}

View File

@@ -245,8 +245,8 @@ final class PluginService extends Service
/**
* Cambiar el estado del plugin
*
* @param $name
* @param $available
* @param string $name
* @param int $available
*
* @throws NoSuchItemException
* @throws \SP\Core\Exceptions\ConstraintException

View File

@@ -50,9 +50,29 @@ final class Filter
*
* @return string
*/
public static function getString($value): string
public static function getEmail($value): string
{
return filter_var(trim($value), FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES);
return filter_var(trim($value), FILTER_SANITIZE_EMAIL);
}
/**
* @param array $array
*
* @return array
*/
public static function getArray(array $array): array
{
return array_map(function ($value) {
if ($value !== null) {
if (is_numeric($value)) {
return Filter::getInt($value);
} else {
return Filter::getString($value);
}
}
return null;
}, $array);
}
/**
@@ -70,8 +90,8 @@ final class Filter
*
* @return string
*/
public static function getEmail($value): string
public static function getString($value): string
{
return filter_var(trim($value), FILTER_SANITIZE_EMAIL);
return filter_var(trim($value), FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES);
}
}

View File

@@ -53,49 +53,6 @@ final class HttpUtil
}
}
/**
* Devolver las cabeceras enviadas desde el cliente.
*
* @param string $header nombre de la cabecera a devolver
*
* @return array|string
*/
public static function getRequestHeaders($header = '')
{
if (!empty($header)) {
$header = strpos($header, 'HTTP_') === false ? 'HTTP_' . str_replace('-', '_', strtoupper($header)) : $header;
return isset($_SERVER[$header]) ? $_SERVER[$header] : '';
}
return self::getApacheHeaders();
}
/**
* Función que sustituye a apache_request_headers
*
* @return array
*/
private static function getApacheHeaders()
{
if (function_exists('\apache_request_headers')) {
return apache_request_headers();
}
$headers = [];
foreach ($_SERVER as $key => $value) {
if (strpos($key, 'HTTP_') === 0) {
$key = ucwords(strtolower(str_replace('_', '-', substr($key, 5))), '-');
$headers[$key] = $value;
} else {
$headers[$key] = $value;
}
}
return $headers;
}
/**
* Comprobar si existen parámetros pasados por POST para enviarlos por GET
*/