diff --git a/CHANGELOG.md b/CHANGELOG.md index ee9f680..b73b743 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ 0.8.1 - dev - [ ] orphan media cleaner -- [ ] ajouter dossier /var dans la liste des caches +- move actions to independent tools +- add var folder +- update admin page to a lighter interface 0.8 - 2021.09.07 - update DC official values (themes,settings,tables...) diff --git a/_admin.php b/_admin.php index 4635f14..cfc8b34 100644 --- a/_admin.php +++ b/_admin.php @@ -15,6 +15,8 @@ if (!defined('DC_CONTEXT_ADMIN')) { return null; } +$core->blog->settings->addNamespace('dcAdvancedCleaner'); + $_menu['Plugins']->addItem( __('Advanced cleaner'), $core->adminurl->get('admin.plugin.dcAdvancedCleaner'), @@ -24,17 +26,4 @@ $_menu['Plugins']->addItem( $_SERVER['REQUEST_URI'] ), $core->auth->isSuperAdmin() -); - -$core->addBehavior('adminDashboardFavorites', 'dcAdvancedCleanerDashboardFavorites'); - -function dcAdvancedCleanerDashboardFavorites(dcCore $core, $favs) -{ - $favs->register('dcAdvancedCleaner', [ - 'title' => __('Advanced cleaner'), - 'url' => $core->adminurl->get('admin.plugin.dcAdvancedCleaner'), - 'small-icon' => dcPage::getPF('dcAdvancedCleaner/icon.png'), - 'large-icon' => dcPage::getPF('dcAdvancedCleaner/icon-big.png'), - 'permissions' => $core->auth->isSuperAdmin() - ]); -} \ No newline at end of file +); \ No newline at end of file diff --git a/_config.php b/_config.php index f2c6f3a..420d782 100644 --- a/_config.php +++ b/_config.php @@ -14,7 +14,7 @@ if (!defined('DC_CONTEXT_MODULE')) { return null; } -if (!$core->auth->isSuperAdmin()) { +if (!dPage::checkSuper()) { return null; } if (!empty($_POST['save'])) { diff --git a/_prepend.php b/_prepend.php index 70f84d2..2d135ed 100644 --- a/_prepend.php +++ b/_prepend.php @@ -14,22 +14,42 @@ if (!defined('DC_RC_PATH')) { return null; } +if (!defined('DC_CONTEXT_ADMIN')) { + return null; +} $d = dirname(__FILE__) . '/inc/'; -$core->blog->settings->addNamespace('dcAdvancedCleaner'); - -$__autoload['dcAdvancedCleaner'] = $d . 'class.dc.advanced.cleaner.php'; -$__autoload['behaviorsDcAdvancedCleaner'] = $d . 'lib.dc.advanced.cleaner.behaviors.php'; -$__autoload['dcUninstaller'] = $d . 'class.dc.uninstaller.php'; +# dcac class +$__autoload['advancedCleaner'] = $d . 'class.advanced.cleaner.php'; +$__autoload['dcAdvancedCleaner'] = $d . 'class.dc.advanced.cleaner.php'; +$__autoload['behaviorsDcAdvancedCleaner'] = $d . 'lib.dc.advanced.cleaner.behaviors.php'; +$__autoload['dcUninstaller'] = $d . 'class.dc.uninstaller.php'; $__autoload['dcAdvancedCleanerActivityReportBehaviors'] = $d . 'lib.dc.advanced.cleaner.activityreport.php'; -$core->addBehavior('pluginsToolsTabs', - ['behaviorsDcAdvancedCleaner', 'pluginsToolsTabs']); -$core->addBehavior('pluginsBeforeDelete', - ['behaviorsDcAdvancedCleaner', 'pluginsBeforeDelete']); -$core->addBehavior('themeBeforeDelete', - ['behaviorsDcAdvancedCleaner', 'themeBeforeDelete']); +# cleaners class +$__autoload['advancedCleanerVersions'] = $d . 'lib.advanced.cleaner.php'; +$__autoload['advancedCleanerSettings'] = $d . 'lib.advanced.cleaner.php'; +$__autoload['advancedCleanerTables'] = $d . 'lib.advanced.cleaner.php'; +$__autoload['advancedCleanerThemes'] = $d . 'lib.advanced.cleaner.php'; +$__autoload['advancedCleanerPlugins'] = $d . 'lib.advanced.cleaner.php'; +$__autoload['advancedCleanerCaches'] = $d . 'lib.advanced.cleaner.php'; +$__autoload['advancedCleanerVars'] = $d . 'lib.advanced.cleaner.php'; + +$core->addBehavior('advancedCleanerAdd', ['advancedCleanerVersions', 'create']); +$core->addBehavior('advancedCleanerAdd', ['advancedCleanerSettings', 'create']); +$core->addBehavior('advancedCleanerAdd', ['advancedCleanerTables', 'create']); +$core->addBehavior('advancedCleanerAdd', ['advancedCleanerThemes', 'create']); +$core->addBehavior('advancedCleanerAdd', ['advancedCleanerPlugins', 'create']); +$core->addBehavior('advancedCleanerAdd', ['advancedCleanerCaches', 'create']); +$core->addBehavior('advancedCleanerAdd', ['advancedCleanerVars', 'create']); + +# dcac behaviors +$core->addBehavior('adminDashboardFavorites', ['behaviorsDcAdvancedCleaner', 'adminDashboardFavorites']); +$core->addBehavior('pluginsToolsTabs', ['behaviorsDcAdvancedCleaner', 'pluginsToolsTabs']); +$core->addBehavior('adminModulesListDoActions', ['behaviorsDcAdvancedCleaner', 'adminModulesListDoActions']); +$core->addBehavior('pluginsBeforeDelete', ['behaviorsDcAdvancedCleaner', 'pluginsBeforeDelete']); +$core->addBehavior('themeBeforeDelete', ['behaviorsDcAdvancedCleaner', 'themeBeforeDelete']); if (defined('ACTIVITY_REPORT')) { dcAdvancedCleanerActivityReportBehaviors::add($core); diff --git a/inc/class.advanced.cleaner.php b/inc/class.advanced.cleaner.php new file mode 100644 index 0000000..ed6add0 --- /dev/null +++ b/inc/class.advanced.cleaner.php @@ -0,0 +1,183 @@ + '', + 'name' => '', + 'desc' => '' + ]; + + private $actions = []; + + final public function __construct(dcCore $core) + { + $this->core = $core; + + $this->init(); + + } + + public static function create(arrayObject $o, dcCore $core) + { + $c = get_called_class(); + $o->append(new $c($core)); + } + + final public function __get(string $property) + { + return $this->getProperty($property); + } + + final public function getProperty(string $property) + { + return $this->properties[$property] ?? null; + } + + final protected function setProperties($property, $value = null): bool + { + $properties = is_array($property) ? $property : [$property => $value]; + foreach($properties as $k => $v) { + if (isset($this->properties[$k])) { + $this->properties[$k] = (string) $v; + } + } + return true; + } + + final public function getActions() + { + return $this->actions; + } + + final protected function setActions($action, $name = null): bool + { + $actions = is_array($action) ? $action : [$action => $name]; + foreach($actions as $k => $v) { + $this->actions[$k] = (string) $v; + } + + return true; + } + + abstract protected function init(): bool; + + abstract public function error($action): string; + + abstract public function official(): array; + + abstract public function get(): array; + + abstract public function set($action, $ns): bool; + + # helpers + + protected static function getDirs($roots) + { + if (!is_array($roots)) { + $roots = [$roots]; + } + $rs = []; + $i = 0; + foreach ($roots as $root) { + $dirs = files::scanDir($root); + foreach($dirs as $k) { + if ('.' == $k || '..' == $k || !is_dir($root .'/' . $k)) { + continue; + } + $rs[$i]['key'] = $k; + $rs[$i]['value'] = count(self::scanDir($root . '/' . $k)); + $i++; + } + } + return $rs; + } + + protected static function delDir($roots, $folder, $delfolder = true) + { + if (strpos($folder,'/')) { + return false; + } + if (!is_array($roots)) { + $roots = [$roots]; + } + foreach ($roots as $root) { + if (file_exists($root . '/' . $folder)) + return self::delTree($root . '/' . $folder, $delfolder); + } + return false; + } + + protected static function scanDir($path, $dir = '', $res = []) + { + $exclude = self::$exclude; + + $path = path::real($path); + if (!is_dir($path) || !is_readable($path)) { + return []; + } + $files = files::scandir($path); + + foreach($files AS $file) { + if (in_array($file, $exclude)) { + continue; + } + if (is_dir($path . '/' . $file)) { + $res[] = $file; + $res = self::scanDir($path . '/' . $file, $dir . '/' . $file, $res); + } else { + $res[] = empty($dir) ? $file : $dir . '/' . $file; + } + } + return $res; + } + + protected static function delTree($dir, $delroot = true) + { + if (!is_dir($dir) || !is_readable($dir)) { + return false; + } + if (substr($dir,-1) != '/') { + $dir .= '/'; + } + if (($d = @dir($dir)) === false) { + return false; + } + while (($entryname = $d->read()) !== false) { + if ($entryname != '.' && $entryname != '..') { + if (is_dir($dir . '/' . $entryname)) { + if (!self::delTree($dir . '/' . $entryname)) {return false; + } + } else { + if (!@unlink($dir . '/' . $entryname)) { + return false; + } + } + } + } + $d->close(); + + if ($delroot) { + return @rmdir($dir); + } else { + return true; + } + } +} \ No newline at end of file diff --git a/inc/class.dc.advanced.cleaner.php b/inc/class.dc.advanced.cleaner.php index 6e6b8cf..8f9aee1 100644 --- a/inc/class.dc.advanced.cleaner.php +++ b/inc/class.dc.advanced.cleaner.php @@ -17,397 +17,60 @@ if (!defined('DC_ADMIN_CONTEXT')) { class dcAdvancedCleaner { - protected static $errors = [ - 'settings' => [ - 'delete_global' => 'Failed to delete global settings', - 'delete_local' => 'Failed to delete local settings', - 'delete_all' => 'Failed to delete all settings' - ], - 'tables' => [ - 'empty' => 'Failed to empty table', - 'delete' => 'Failed to delete table' - ], - 'plugins' => [ - 'empty' => 'Failed to empty plugin folder', - 'delete' => 'Failed to delete plugin folder' - ], - 'themes' => [ - 'empty' => 'Failed to empty themes folder', - 'delete' => 'Failed to delete themes folder' - ], - 'caches' => [ - 'empty' => 'Failed to empty cache folder', - 'delete' => 'Failed to delete cache folder' - ], - 'versions' => [ - 'delete' => 'Failed to delete version' - ] - ]; + protected $core; + protected $cleaners = []; - public static $dotclear = [ - 'settings' => [ - 'akismet', 'antispam', 'breadcrumb', 'dcckeditor', 'dclegacyeditor', 'maintenance', - 'pages', 'pings', 'system', 'themes', 'widgets' - ], - 'tables' => [ - 'blog', 'category', 'comment', 'link', 'log', 'media', - 'meta', 'permissions', 'ping', 'post','post_media', 'pref', 'session', - 'setting', 'spamrule', 'user', 'version' - ], - 'plugins' => [ - 'aboutConfig', 'akismet', 'antispam', 'attachments', 'blogroll', 'blowupConfig', - 'breadcrumb', 'dcCKEditor', 'dclegacy', 'dcLegacyEditor', 'fairTrackbacks', 'importExport', 'maintenance', - 'pages', 'pings', 'simpleMenu', 'tags', 'themeEditor', 'userPref', 'widgets' - ], - 'themes' => [ - 'default', 'customCSS', 'blueSilence', 'berlin', 'ductile' - ], - 'caches' => [ - 'cbfeed', 'cbtpl', 'dcrepo', 'versions' - ], - 'versions' => [ - 'antispam', 'blogroll', 'blowupConfig', 'core', 'dcCKEditor', 'dcLegacyEditor', 'pages', 'pings', 'simpleMenu', 'tags', 'widgets' - ] - ]; - - public static $exclude = [ - '.', '..', '__MACOSX', '.svn', 'CVS', '.DS_Store', 'Thumbs.db' - ]; - - public static function getOfficial($type = '') + public function __construct($core) { - $official = array_merge( - self::$dotclear, - [ - 'plugins' => explode(',', DC_DISTRIB_PLUGINS), - 'themes' => explode(',', DC_DISTRIB_THEMES) - ] - ); - if (empty($type)) { - return $official; - } - return array_key_exists($type, $official) ? $official[$type] : []; - } + $this->core = $core; + $cleaners = new arrayObject(); - public static function getSettings($core) - { - $res = $core->con->select( - 'SELECT setting_ns ' . - 'FROM ' . $core->prefix . 'setting ' . - 'WHERE blog_id IS NULL ' . - "OR blog_id IS NOT NULL " . - 'GROUP BY setting_ns' - ); + try { + $this->core->callBehavior('advancedCleanerAdd', $cleaners, $this->core); - $rs = []; - $i = 0; - while($res->fetch()) { - $rs[$i]['key'] = $res->setting_ns; - $rs[$i]['value'] = $core->con->select( - 'SELECT count(*) FROM ' . $core->prefix .'setting ' . - "WHERE setting_ns = '" . $res->setting_ns ."' " . - "AND (blog_id IS NULL OR blog_id IS NOT NULL) " . - "GROUP BY setting_ns " - )->f(0); - $i++; - } - return $rs; - } - - protected static function deleteGlobalSettings($core, $entry) - { - $core->con->execute( - 'DELETE FROM ' .$core->prefix . 'setting ' . - 'WHERE blog_id IS NULL ' . - "AND setting_ns = '" . $core->con->escape($entry) . "' " - ); - } - - protected static function deleteLocalSettings($core, $entry) - { - $core->con->execute( - 'DELETE FROM ' . $core->prefix . 'setting ' . - "WHERE blog_id = '" . $core->con->escape($core->blog->id) . "' " . - "AND setting_ns = '" . $core->con->escape($entry) . "' " - ); - } - - protected static function deleteAllSettings($core, $entry) - { - $core->con->execute( - 'DELETE FROM ' .$core->prefix . 'setting ' . - "WHERE setting_ns = '" . $core->con->escape($entry) . "' " . - "AND (blog_id IS NULL OR blog_id != '') " - ); - } - - public static function getTables($core) - { - $object = dbSchema::init($core->con); - $res = $object->getTables(); - - $rs = []; - $i = 0; - foreach($res as $k => $v) { - if ('' != $core->prefix) { - if (!preg_match('/^' . preg_quote($core->prefix) . '(.*?)$/', $v, $m)) { - continue; + foreach($cleaners as $cleaner) { + if ($cleaner instanceOf advancedCleaner && !isset($this->cleaners[$cleaner->id])) { + $this->cleaners[$cleaner->id] = $cleaner; } - $v = $m[1]; } - $rs[$i]['key'] = $v; - $rs[$i]['value'] = $core->con->select('SELECT count(*) FROM ' . $res[$k])->f(0); - $i++; + } catch (Exception $e) { + $core->error->add($e->getMessage()); } - return $rs; } - protected static function emptyTable($core, $entry) + public function get($type = null, $silent = false) { - $core->con->execute( - 'DELETE FROM ' . $core->con->escapeSystem($core->prefix . $entry) - ); - } - - protected static function deleteTable($core, $entry) - { - self::emptyTable($core,$entry); - - $core->con->execute( - 'DROP TABLE ' . $core->con->escapeSystem($core->prefix . $entry) - ); - } - - public static function getVersions($core) - { - $res = $core->con->select('SELECT * FROM ' . $core->prefix . 'version'); - - $rs = []; - $i = 0; - while ($res->fetch()) { - $rs[$i]['key'] = $res->module; - $rs[$i]['value'] = $res->version; - $i++; + if (null === $type) { + return $this->cleaners; } - return $rs; + if (isset($this->cleaners[$type])) { + return $this->cleaners[$type]; + } + if ($silent) { + return false; + } + throw new exception(sprintf(__('unknow cleaner type %s'), $type)); } - protected static function deleteVersion($core, $entry) - { - $core->con->execute( - 'DELETE FROM '. $core->prefix . 'version ' . - "WHERE module = '" . $core->con->escape($entry) . "' " - ); - } - - public static function getPlugins($core) - { - $res = explode(PATH_SEPARATOR, DC_PLUGINS_ROOT); - return self::getDirs($res); - } - - protected static function emptyPlugin($core, $entry) - { - $res = explode(PATH_SEPARATOR, DC_PLUGINS_ROOT); - self::delDir($res, $entry, false); - } - - protected static function deletePlugin($core, $entry) - { - $res = explode(PATH_SEPARATOR, DC_PLUGINS_ROOT); - self::delDir($res, $entry, true); - } - - public static function getThemes($core) - { - return self::getDirs($core->blog->themes_path); - } - - protected static function emptyTheme($core, $entry) - { - self::delDir($core->blog->themes_path, $entry, false); - } - - protected static function deleteTheme($core, $entry) - { - self::delDir($core->blog->themes_path, $entry, true); - } - - public static function getCaches($core) - { - return self::getDirs(DC_TPL_CACHE); - } - - protected static function emptyCache($core, $entry) - { - self::delDir(DC_TPL_CACHE, $entry, false); - } - - protected static function deleteCache($core, $entry) - { - self::delDir(DC_TPL_CACHE, $entry, true); - } - - public static function execute($core, $type, $action, $ns) + public function set($type, $action, $ns) { + if (!isset($this->cleaners[$type])) { + throw new exception(sprintf(__('unknow cleaner type %s'), $type)); + } if (strtolower($ns) == 'dcadvancedcleaner') { - throw new exception("dcAdvancedCleaner can't remove itself"); + throw new exception(__("dcAdvancedCleaner can't remove itself")); } # BEHAVIOR dcAdvancedCleanerBeforeAction - $core->callBehavior('dcAdvancedCleanerBeforeAction', $type, $action, $ns); + $this->core->callBehavior('dcAdvancedCleanerBeforeAction', $type, $action, $ns); - try { - # Delete global settings - if ($type == 'settings' && $action == 'delete_global') { - self::deleteGlobalSettings($core, $ns); - } - # Delete local settings - if ($type == 'settings' && $action == 'delete_local') { - self::deleteLocalSettings($core, $ns); - } - # Delete all settings - if ($type == 'settings' && $action == 'delete_all') { - self::deleteAllSettings($core, $ns); - } - # Empty tables - if ($type == 'tables' && $action == 'empty') { - self::emptyTable($core, $ns); - } - # Delete tables - if ($type == 'tables' && $action == 'delete') { - self::deleteTable($core, $ns); - } - # Delete versions - if ($type == 'versions' && $action == 'delete') { - self::deleteVersion($core, $ns); - } - # Empty plugins - if ($type == 'plugins' && $action == 'empty') { - self::emptyPlugin($core, $ns); - } - # Delete plugins - if ($type == 'plugins' && $action == 'delete') { - self::deletePlugin($core, $ns); - } - # Empty themes - if ($type == 'themes' && $action == 'empty') { - self::emptyTheme($core, $ns); - } - # Delete themes - if ($type == 'themes' && $action == 'delete') { - self::deleteTheme($core, $ns); - } - # Empty caches - if ($type == 'caches' && $action == 'empty') { - self::emptyCache($core, $ns); - } - # Delete caches - if ($type == 'caches' && $action == 'delete') { - self::deleteCache($core, $ns); - } - return true; - } catch(Exception $e) { - $errors = self::$errors; - if (isset($errors[$type][$action])) { - throw new Exception(__($errors[$type][$action])); - } - else { - throw new Exception(sprintf(__('Cannot execute "%s" of type "%s"'), $action, $type)); - } - return false; - } - } + $ret = $this->cleaners[$type]->set($action, $ns); - protected static function getDirs($roots) - { - if (!is_array($roots)) { - $roots = [$roots]; + if ($ret === false) { + $msg = $this->cleaners[$type]->error($action); + throw new Exception($msg ?? __('Unknow error')); } - $rs = []; - $i = 0; - foreach ($roots as $root) { - $dirs = files::scanDir($root); - foreach($dirs as $k) { - if ('.' == $k || '..' == $k || !is_dir($root .'/' . $k)) { - continue; - } - $rs[$i]['key'] = $k; - $rs[$i]['value'] = count(self::scanDir($root . '/' . $k)); - $i++; - } - } - return $rs; - } - protected static function delDir($roots, $folder, $delfolder = true) - { - if (strpos($folder,'/')) { - return false; - } - if (!is_array($roots)) { - $roots = [$roots]; - } - foreach ($roots as $root) { - if (file_exists($root . '/' . $folder)) - return self::delTree($root . '/' . $folder, $delfolder); - } - return false; - } - - protected static function scanDir($path, $dir = '', $res = []) - { - $exclude = self::$exclude; - - $path = path::real($path); - if (!is_dir($path) || !is_readable($path)) { - return []; - } - $files = files::scandir($path); - - foreach($files AS $file) { - if (in_array($file, $exclude)) { - continue; - } - if (is_dir($path . '/' . $file)) { - $res[] = $file; - $res = self::scanDir($path . '/' . $file, $dir . '/' . $file, $res); - } else { - $res[] = empty($dir) ? $file : $dir . '/' . $file; - } - } - return $res; - } - - protected static function delTree($dir, $delroot = true) - { - if (!is_dir($dir) || !is_readable($dir)) { - return false; - } - if (substr($dir,-1) != '/') { - $dir .= '/'; - } - if (($d = @dir($dir)) === false) { - return false; - } - while (($entryname = $d->read()) !== false) { - if ($entryname != '.' && $entryname != '..') { - if (is_dir($dir . '/' . $entryname)) { - if (!self::delTree($dir . '/' . $entryname)) {return false; - } - } else { - if (!@unlink($dir . '/' . $entryname)) { - return false; - } - } - } - } - $d->close(); - - if ($delroot) { - return @rmdir($dir); - } else { - return true; - } + return true; } } \ No newline at end of file diff --git a/inc/class.dc.uninstaller.php b/inc/class.dc.uninstaller.php index 69ee0b9..e3d2040 100644 --- a/inc/class.dc.uninstaller.php +++ b/inc/class.dc.uninstaller.php @@ -15,89 +15,75 @@ if (!defined('DC_ADMIN_CONTEXT')) { return null; } -/** -@brief Modules uninstall features handler +# Localized l10n +__('delete table'); +__('delete cache files'); +__('delete plugin files'); +__('delete theme files'); +__('delete the version number'); +__('Uninstall extensions'); +__('delete %s blog settings'); +__('delete %s global settings'); +__('delete all %s settings'); +__('delete %s table'); +__('delete %s version number'); +__('delete %s plugin files'); +__('delete %s theme file'); +__('delete %s cache files'); -Provides an object to handle modules uninstall features -(themes or plugins). -This class used dcAdvancedCleaner. -*/ +/** + * @brief Modules uninstall features handler + * + * Provides an object to handle modules uninstall features + * (themes or plugins). + * This class used dcAdvancedCleaner. + */ class dcUninstaller { protected $path; - protected $modules = []; ///< array Modules informations array + protected $modules = []; protected $actions = ['user' => [], 'callback' => []]; protected $callbacks = ['user' => [], 'callback' => []]; protected $id = null; protected $mroot = null; - /** - Array of all allowed properties to uninstall parts of modules. - 'settings' : settings set on dcSettings, - 'tables' : if module creates table, - 'plugins' : if module has files on plugin path, - 'themes' : if module has files on theme path, (on current blog) - 'caches' : if module has files on DC caches path, - 'versions' : if module set a versions on DC table 'version' - */ - protected static $allowed_properties = [ - 'versions' => [ - 'delete' => 'delete version in dc' - ], - 'settings' => [ - 'delete_global' => 'delete global settings', - 'delete_local' => 'delete local settings', - 'delete_all' => 'delete all settings' - ], - 'tables' => [ - 'empty' => 'empty table', - 'delete' => 'delete table' - ], - 'plugins' => [ - 'empty' => 'empty plugin folder', - 'delete' => 'delete plugin folder' - ], - 'themes' => [ - 'empty' => 'empty theme folder', - 'delete' => 'delete theme folder' - ], - 'caches' => [ - 'empty' => 'empty cache folder', - 'delete' => 'delete cache folder' - ] - ]; - - protected static $priority_properties = [ - 'versions','settings','tables','themes','plugins','caches' - ]; - - public $core; ///< dcCore dcCore instance + public $core; + private $ac; + private $allowed_actions = null; /** - Object constructor. - - @param core dcCore dcCore instance - */ + * Object constructor. + * + * @param dcCore $core dcCore instance + */ public function __construct(dcCore $core) { $this->core =& $core; + $this->ac = new dcAdvancedCleaner($core); + + $res = []; + foreach($this->ac->get() as $cleaner) { + $res[$cleaner->id] = $cleaner->getActions(); + } + $this->allowed_actions = $res; } - public static function getAllowedProperties() + public function getAllowedActions() { - return self::$allowed_properties; + return $this->allowed_actions; } /** - Loads modules. - Files _defines.php and _uninstall.php must be present on module - to be recognized. - (path separator depends on your OS). - - @param path string Separated list of paths - */ + * Loads modules. + * + * Files _defines.php and _uninstall.php must be present on module + * to be recognized. + * (path separator depends on your OS). + * + * @param string $path Separated list of paths + */ public function loadModules($path) { $this->path = explode(PATH_SEPARATOR,$path); @@ -127,12 +113,13 @@ class dcUninstaller } /** - Load one module. - Files _defines.php and _uninstall.php must be present on module - to be recognized. - - @param root string path of module - */ + * Load one module. + * + * Files _defines.php and _uninstall.php must be present on module + * to be recognized. + * + * @param string $root path of module + */ public function loadModule($root) { if (file_exists($root . '/_define.php') @@ -150,13 +137,13 @@ class dcUninstaller } /** - This method registers a module in modules list. - - @param name string Module name - @param desc string Module description - @param author string Module author name - @param version string Module version - */ + * This method registers a module in modules list. + * + * @param string $name Module name + * @param string $desc Module description + * @param string $author Module author name + * @param string $version Module version + */ public function registerModule($name, $desc, $author, $version, $properties = []) { if ($this->id) { @@ -172,12 +159,13 @@ class dcUninstaller } /** - Returns all modules associative array or only one module if $id - is present. - - @param id string Optionnal module ID - @return array - */ + * Returns all modules associative array or only one module if $id + * is present. + * + * @param string $id Optionnal module ID + * + * @return array Modules + */ public function getModules($id = null) { if ($id && isset($this->modules[$id])) { @@ -187,25 +175,27 @@ class dcUninstaller } /** - Returns true if the module with ID $id exists. - - @param id string Module ID - @return boolean - */ + * Returns true if the module with ID $id exists. + * + * @param string $idModule ID + * + * @return boolean Success + */ public function moduleExists($id) { return isset($this->modules[$id]); } /** - Add a predefined action to unsintall features. - This action is set in _uninstall.php. - - @param type string Type of action (from $allowed_properties) - @param action string Action (from $allowed_properties) - @param ns string Name of setting related to module. - @param desc string Description of action - */ + * Add a predefined action to unsintall features. + * + * This action is set in _uninstall.php. + * + * @param string $type Type of action (from $allowed_actions) + * @param string $action Action (from $allowed_actions) + * @param string $ns Name of setting related to module. + * @param string $desc Description of action + */ protected function addUserAction($type, $action, $ns, $desc = '') { $this->addAction('user', $type, $action, $ns, $desc); @@ -226,26 +216,25 @@ class dcUninstaller if (empty($type) || empty($ns)) { return null; } - if (!isset(self::$allowed_properties[$type][$action])) { + if (!isset($this->allowed_actions[$type][$action])) { return null; } if (empty($desc)) { $desc = __($action); } $this->actions[$group][$this->id][$type][] = [ - 'ns' => $ns, + 'ns' => $ns, 'action' => $action, - 'desc' => $desc + 'desc' => $desc ]; } /** - Returns modules $id predefined actions associative array - ordered by priority - - @param id string Optionnal module ID - @return array - */ + * Returns modules $id predefined actions associative array + * + * @param string $id Optionnal module ID + * @return array Modules id + */ public function getUserActions($id) { return $this->getActions('user', $id); @@ -264,22 +253,23 @@ class dcUninstaller return []; } $res = []; - foreach(self::$priority_properties as $k => $v) { - if (!isset($this->actions[$group][$id][$v])) { + foreach($this->allowed_actions as $k => $v) { + if (!isset($this->actions[$group][$id][$k])) { continue; } - $res[$v] = $this->actions[$group][$id][$v]; + $res[$k] = $this->actions[$group][$id][$k]; } return $res; } /** - Add a callable function for unsintall features. - This action is set in _uninstall.php. - - @param func string Callable function - @param desc string Description of action - */ + * Add a callable function for unsintall features. + * + * This action is set in _uninstall.php. + * + * @param string $func Callable function + * @param string $desc Description of action + */ protected function addUserCallback($func, $desc= '') { $this->addCallback('user', $func, $desc); @@ -310,11 +300,12 @@ class dcUninstaller } /** - Returns modules $id callback actions associative array + * Returns modules $id callback actions associative array - @param id string Optionnal module ID - @return array - */ + * @param string $id Optionnal module ID + * + * @return array Modules id + */ public function getUserCallbacks($id) { return $this->getCallbacks('user', $id); @@ -336,22 +327,24 @@ class dcUninstaller } /** - Execute a predifined action. This function call dcAdvancedCleaner - to do actions. - - @param type string Type of action (from $allowed_properties) - @param action string Action (from $allowed_properties) - @param ns string Name of setting related to module. - @return array - */ + * Execute a predifined action. + * + * This function call dcAdvancedCleaner to do actions. + * + * @param string $type Type of action (from $allowed_actions) + * @param string $action Action (from $allowed_actions) + * @param string $ns Name of setting related to module. + * + * @return boolean Success + */ public function execute($type, $action, $ns) { - $prop = $this->getAllowedProperties(); - - if (!isset($prop[$type][$action]) || empty($ns)) { - return null; + if (!isset($this->allowed_actions[$type][$action]) || empty($ns)) { + return false; } - dcAdvancedCleaner::execute($this->core, $type, $action, $ns); + $this->ac->set($type, $action, $ns); + + return true; } private function sortModules($a, $b) diff --git a/inc/lib.advanced.cleaner.php b/inc/lib.advanced.cleaner.php new file mode 100644 index 0000000..d317d25 --- /dev/null +++ b/inc/lib.advanced.cleaner.php @@ -0,0 +1,515 @@ +setProperties([ + 'id' => 'settings', + 'name' => __('Settings'), + 'desc' => __('Namespaces registered in dcSettings') + ]); + + $this->setActions([ + 'delete_global' => __('delete global settings'), + 'delete_local' => __('delete blog settings'), + 'delete_all' => __('delete all settings') + ]); + + return true; + } + + public function error($action): string + { + if ($action == 'delete_global') { + return __('Failed to delete global settings'); + } + if ($action == 'delete_local') { + return __('Failed to delete local settings'); + } + if ($action == 'delete_all') { + return __('Failed to delete all settings'); + } + + return ''; + } + + public function official(): array + { + return [ + 'akismet', + 'antispam', + 'breadcrumb', + 'dcckeditor', + 'dclegacyeditor', + 'maintenance', + 'pages', + 'pings', + 'system', + 'themes', + 'widgets' + ]; + } + + public function get(): array + { + $res = $this->core->con->select( + 'SELECT setting_ns ' . + 'FROM ' . $this->core->prefix . 'setting ' . + 'WHERE blog_id IS NULL ' . + "OR blog_id IS NOT NULL " . + 'GROUP BY setting_ns' + ); + + $rs = []; + $i = 0; + while($res->fetch()) { + $rs[$i]['key'] = $res->setting_ns; + $rs[$i]['value'] = $this->core->con->select( + 'SELECT count(*) FROM ' . $this->core->prefix .'setting ' . + "WHERE setting_ns = '" . $res->setting_ns ."' " . + "AND (blog_id IS NULL OR blog_id IS NOT NULL) " . + "GROUP BY setting_ns " + )->f(0); + $i++; + } + + return $rs; + } + + public function set($action, $ns): bool + { + if ($action == 'delete_global') { + $this->core->con->execute( + 'DELETE FROM ' .$this->core->prefix . 'setting ' . + 'WHERE blog_id IS NULL ' . + "AND setting_ns = '" . $this->core->con->escape($ns) . "' " + ); + + return true; + } + if ($action == 'delete_local') { + $this->core->con->execute( + 'DELETE FROM ' . $this->core->prefix . 'setting ' . + "WHERE blog_id = '" . $this->core->con->escape($this->core->blog->id) . "' " . + "AND setting_ns = '" . $this->core->con->escape($ns) . "' " + ); + + return true; + } + if ($action == 'delete_all') { + $this->core->con->execute( + 'DELETE FROM ' .$this->core->prefix . 'setting ' . + "WHERE setting_ns = '" . $this->core->con->escape($ns) . "' " . + "AND (blog_id IS NULL OR blog_id != '') " + ); + + return true; + } + + return false; + } +} + +class advancedCleanerTables extends advancedCleaner +{ + protected function init(): bool + { + $this->setProperties([ + 'id' => 'tables', + 'name' => __('Tables'), + 'desc' => __('All database tables of Dotclear') + ]); + + $this->setActions([ + 'delete' => __('delete'), + 'empty' => __('empty') + ]); + + return true; + } + + public function error($action): string + { + if ($action == 'empty') { + return __('Failed to empty table'); + } + if ($action == 'delete') { + return __('Failed to delete table'); + } + return ''; + } + + public function official(): array + { + return [ + 'blog', + 'category', + 'comment', + 'link', + 'log', + 'media', + 'meta', + 'permissions', + 'ping', + 'post', + 'post_media', + 'pref', + 'session', + 'setting', + 'spamrule', + 'user', + 'version' + ]; + } + + public function get(): array + { + $object = dbSchema::init($this->core->con); + $res = $object->getTables(); + + $rs = []; + $i = 0; + foreach($res as $k => $v) { + if ('' != $this->core->prefix) { + if (!preg_match('/^' . preg_quote($this->core->prefix) . '(.*?)$/', $v, $m)) { + continue; + } + $v = $m[1]; + } + $rs[$i]['key'] = $v; + $rs[$i]['value'] = $this->core->con->select('SELECT count(*) FROM ' . $res[$k])->f(0); + $i++; + } + + return $rs; + } + + public function set($action, $ns): bool + { + if (in_array($action, ['empty', 'delete'])) { + $this->core->con->execute( + 'DELETE FROM ' . $this->core->con->escapeSystem($this->core->prefix . $ns) + ); + } + if ($action == 'empty') { + return true; + } + if ($action == 'delete') { + $this->core->con->execute( + 'DROP TABLE ' . $this->core->con->escapeSystem($this->core->prefix . $ns) + ); + + return true; + } + + return false; + } +} + +class advancedCleanerVersions extends advancedCleaner +{ + protected function init(): bool + { + $this->setProperties([ + 'id' => 'versions', + 'name' => __('Versions'), + 'desc' => __('Versions registered in table "version" of Dotclear') + ]); + + $this->setActions([ + 'delete' => __('delete') + ]); + + return true; + } + + public function error($action): string + { + if ($action == 'delete') { + return __('Failed to delete version'); + } + + return ''; + } + + public function official(): array + { + return [ + 'antispam', + 'blogroll', + 'blowupConfig', + 'core', + 'dcCKEditor', + 'dcLegacyEditor', + 'pages', + 'pings', + 'simpleMenu', + 'tags', + 'widgets' + ]; + } + + public function get(): array + { + $res = $this->core->con->select('SELECT * FROM ' . $this->core->prefix . 'version'); + + $rs = []; + $i = 0; + while ($res->fetch()) { + $rs[$i]['key'] = $res->module; + $rs[$i]['value'] = $res->version; + $i++; + } + + return $rs; + } + + public function set($action, $ns): bool + { + if ($action == 'delete') { + $this->core->con->execute( + 'DELETE FROM '. $this->core->prefix . 'version ' . + "WHERE module = '" . $this->core->con->escape($ns) . "' " + ); + + return true; + } + + return false; + } +} + +class advancedCleanerPlugins extends advancedCleaner +{ + protected function init(): bool + { + $this->setProperties([ + 'id' => 'plugins', + 'name' => __('Plugins'), + 'desc' => __('Folders from plugins directories') + ]); + + $this->setActions([ + 'delete' => __('delete'), + 'empty' => __('empty') + ]); + + return true; + } + + public function error($action): string + { + if ($action == 'empty') { + return __('Failed to empty plugin folder'); + } + if ($action == 'delete') { + return __('Failed to delete plugin folder'); + } + return ''; + } + + public function official(): array + { + return explode(',', DC_DISTRIB_PLUGINS); + } + + public function get(): array + { + $res = self::getDirs(explode(PATH_SEPARATOR, DC_PLUGINS_ROOT)); + sort($res); + + return $res; + } + + public function set($action, $ns): bool + { + if ($action == 'empty') { + $res = explode(PATH_SEPARATOR, DC_PLUGINS_ROOT); + self::delDir($res, $ns, false); + + return true; + } + if ($action == 'delete') { + $res = explode(PATH_SEPARATOR, DC_PLUGINS_ROOT); + self::delDir($res, $ns, true); + + return true; + } + + return false; + } +} + +class advancedCleanerThemes extends advancedCleaner +{ + protected function init(): bool + { + $this->setProperties([ + 'id' => 'themes', + 'name' => __('Themes'), + 'desc' => __('Folders from blog themes directory') + ]); + + $this->setActions([ + 'delete' => __('delete'), + 'empty' => __('empty') + ]); + + return true; + } + + public function error($action): string + { + if ($action == 'empty') { + return __('Failed to empty themes folder'); + } + if ($action == 'delete') { + return __('Failed to delete themes folder'); + } + return ''; + } + + public function official(): array + { + return explode(',', DC_DISTRIB_THEMES); + } + + public function get(): array + { + $res = self::getDirs($this->core->blog->themes_path); + sort($res); + + return $res; + } + + public function set($action, $ns): bool + { + if ($action == 'empty') { + self::delDir($this->core->blog->themes_path, $ns, false); + + return true; + } + if ($action == 'delete') { + self::delDir($this->core->blog->themes_path, $ns, true); + + return true; + } + + return false; + } +} + +class advancedCleanerCaches extends advancedCleaner +{ + protected function init(): bool + { + $this->setProperties([ + 'id' => 'caches', + 'name' => __('Cache'), + 'desc' => __('Folders from cache directory') + ]); + + $this->setActions([ + 'delete' => __('delete'), + 'empty' => __('empty') + ]); + + return true; + } + + public function error($action): string + { + if ($action == 'empty') { + return __('Failed to empty cache folder'); + } + if ($action == 'delete') { + return __('Failed to delete cache folder'); + } + return ''; + } + + public function official(): array + { + return ['cbfeed', 'cbtpl', 'dcrepo', 'versions']; + } + + public function get(): array + { + return self::getDirs(DC_TPL_CACHE); + } + + public function set($action, $ns): bool + { + if ($action == 'empty') { + self::delDir(DC_TPL_CACHE, $ns, false); + + return true; + } + if ($action == 'delete') { + self::delDir(DC_TPL_CACHE, $ns, true); + + return true; + } + + return false; + } +} + +class advancedCleanerVars extends advancedCleaner +{ + protected function init(): bool + { + $this->setProperties([ + 'id' => 'vars', + 'name' => __('Var'), + 'desc' => __('Folders from Dotclear VAR directory') + ]); + + $this->setActions([ + 'delete' => __('delete') + ]); + + return true; + } + + public function error($action): string + { + if ($action == 'delete') { + return __('Failed to delete var folder'); + } + return ''; + } + + public function official(): array + { + return []; + } + + public function get(): array + { + return self::getDirs(DC_VAR); + } + + public function set($action, $ns): bool + { + if ($action == 'delete') { + self::delDir(DC_VAR, $ns, true); + + return true; + } + + return false; + } +} \ No newline at end of file diff --git a/inc/lib.dc.advanced.cleaner.activityreport.php b/inc/lib.dc.advanced.cleaner.activityreport.php index b408081..77d2359 100644 --- a/inc/lib.dc.advanced.cleaner.activityreport.php +++ b/inc/lib.dc.advanced.cleaner.activityreport.php @@ -19,9 +19,7 @@ class dcAdvancedCleanerActivityReportBehaviors { public static function maintenance($type, $action, $ns) { - $logs = array($type ,$action, $ns); - - $GLOBALS['core']->activityReport->addLog('dcadvancedcleaner', 'maintenance', $logs); + $GLOBALS['core']->activityReport->addLog('dcadvancedcleaner', 'maintenance', [$type ,$action, $ns]); } public static function add($core) diff --git a/inc/lib.dc.advanced.cleaner.behaviors.php b/inc/lib.dc.advanced.cleaner.behaviors.php index 407db3e..c23ae39 100644 --- a/inc/lib.dc.advanced.cleaner.behaviors.php +++ b/inc/lib.dc.advanced.cleaner.behaviors.php @@ -17,6 +17,17 @@ if (!defined('DC_ADMIN_CONTEXT')) { class behaviorsDcAdvancedCleaner { + public static function adminDashboardFavorites(dcCore $core, $favs) + { + $favs->register('dcAdvancedCleaner', [ + 'title' => __('Advanced cleaner'), + 'url' => $core->adminurl->get('admin.plugin.dcAdvancedCleaner'), + 'small-icon' => dcPage::getPF('dcAdvancedCleaner/icon.png'), + 'large-icon' => dcPage::getPF('dcAdvancedCleaner/icon-big.png'), + 'permissions' => $core->auth->isSuperAdmin() + ]); + } + public static function pluginsBeforeDelete($plugin) { self::moduleBeforeDelete($plugin, 'plugins.php?removed=1'); @@ -62,7 +73,7 @@ class behaviorsDcAdvancedCleaner public static function pluginsToolsTabs($core) { - self::modulesTabs($core, DC_PLUGINS_ROOT, $core->adminurl->get('admin.plugins', ['tab' => 'uninstaller'])); + self::modulesTabs($core, DC_PLUGINS_ROOT, $core->adminurl->get('admin.plugins') . '#uninstaller'); } public static function modulesTabs($core, $path, $redir, $title = '') @@ -70,61 +81,15 @@ class behaviorsDcAdvancedCleaner if (!$core->blog->settings->dcAdvancedCleaner->dcAdvancedCleaner_behavior_active) { return null; } - $err = ''; $title = empty($title) ? __('Advanced uninstall') : $title; $uninstaller = new dcUninstaller($core); $uninstaller->loadModules($path); $modules = $uninstaller->getModules(); - $props = $uninstaller->getAllowedProperties(); - - // Execute - if (isset($_POST['action']) && $_POST['action'] == 'uninstall' - && (!empty($_POST['extras']) || !empty($_POST['actions'])) - ) { - try { - // Extras - if (!empty($_POST['extras'])) { - foreach($_POST['extras'] as $module_id => $extras) { - foreach($extras as $k => $sentence) { - $extra = @unserialize(@base64_decode($sentence)); - - if (!$extra || !is_callable($extra)) { - continue; - } - call_user_func($extra, $modul_id); - } - } - } - // Actions - if (!empty($_POST['actions'])) { - foreach($_POST['actions'] as $module_id => $actions) { - foreach($actions as $k => $sentence) { - $action = @unserialize(@base64_decode($sentence)); - - if (!$action - || !isset($action['type']) - || !isset($action['action']) - || !isset($action['ns']) - ) { - continue; - } - $uninstaller->execute($action['type'], $action['action'], $action['ns']); - } - } - } - dcPage::addSuccessNotice(__('Action successfuly excecuted')); - http::redirect($redir); - } catch(Exception $e) { - $err = $e->getMessage(); - } - } + $props = $uninstaller->getAllowedActions(); echo '
' . $err . '
'; - } if(!count($modules)) { echo '' . __('There is no module with uninstall features') . '
' . $core->formNonce() . + form::hidden(['path'], $path) . form::hidden(['redir'], $redir) . form::hidden(['action'], 'uninstall') . ' ' . @@ -212,4 +178,59 @@ class behaviorsDcAdvancedCleaner echo ''; } + + public static function adminModulesListDoActions($list, $modules, $type) + { + if (!$list->core->blog->settings->dcAdvancedCleaner->dcAdvancedCleaner_behavior_active) { + return null; + } + + if (!isset($_POST['action']) || $_POST['action'] != 'uninstall' + || (empty($_POST['extras']) && empty($_POST['actions'])) + ) { + return null; + } + + $uninstaller = new dcUninstaller($list->core); + $uninstaller->loadModules($_POST['path']); + $modules = $uninstaller->getModules(); + $props = $uninstaller->getAllowedActions(); + + try { + // Extras + if (!empty($_POST['extras'])) { + foreach($_POST['extras'] as $module_id => $extras) { + foreach($extras as $k => $sentence) { + $extra = @unserialize(@base64_decode($sentence)); + + if (!$extra || !is_callable($extra)) { + continue; + } + call_user_func($extra, $modul_id); + } + } + } + // Actions + if (!empty($_POST['actions'])) { + foreach($_POST['actions'] as $module_id => $actions) { + foreach($actions as $k => $sentence) { + $action = @unserialize(@base64_decode($sentence)); + + if (!$action + || !isset($action['type']) + || !isset($action['action']) + || !isset($action['ns']) + ) { + continue; + } + $uninstaller->execute($action['type'], $action['action'], $action['ns']); + } + } + } + dcPage::addSuccessNotice(__('Action successfuly excecuted')); + http::redirect($_POST['redir']); + } catch(Exception $e) { + $list->core->error->add($e->getMessage()); + } + } } \ No newline at end of file diff --git a/index.php b/index.php index 4060a9f..2b399d2 100644 --- a/index.php +++ b/index.php @@ -17,106 +17,32 @@ if (!defined('DC_CONTEXT_ADMIN')) { dcPage::checkSuper(); -# Localized l10n -__('Settings'); __('settings'); __('setting'); -__('Tables'); __('tables'); __('table'); -__('Plugins'); __('plugins'); __('plugin'); -__('Themes'); __('themes'); __('theme'); -__('Caches'); __('caches'); __('cache'); -__('Versions'); __('versions'); __('version'); -__('delete table'); -__('delete cache files'); -__('delete plugin files'); -__('delete theme files'); -__('delete the version number'); -__('Uninstall extensions'); -__('delete %s blog settings'); -__('delete %s global settings'); -__('delete all %s settings'); -__('delete %s table'); -__('delete %s version number'); -__('delete %s plugin files'); -__('delete %s theme file'); -__('delete %s cache files'); +$ac = new dcAdvancedCleaner($core); -# vars -$part = $_REQUEST['part'] ?? 'caches'; -$entries = $_POST['entries'] ?? []; -$action = $_POST['action'] ?? ''; - -# Combos -$combo_title = [ - 'settings' => __('Settings'), - 'tables' => __('Tables'), - 'plugins' => __('Extensions'), - 'themes' => __('Themes'), - 'caches' => __('Cache'), - 'versions' => __('Versions') -]; -$combo_type = [ - 'settings' => ['delete_global', 'delete_local', 'delete_all'], - 'tables' => ['empty', 'delete'], - 'plugins' => ['empty', 'delete'], - 'themes' => ['empty', 'delete'], - 'caches' => ['empty', 'delete'], - 'versions' => ['delete'] -]; -$combo_funcs = [ - 'settings' => ['dcAdvancedCleaner', 'getSettings'], - 'tables' => ['dcAdvancedCleaner', 'getTables'], - 'plugins' => ['dcAdvancedCleaner', 'getPlugins'], - 'themes' => ['dcAdvancedCleaner', 'getThemes'], - 'caches' => ['dcAdvancedCleaner', 'getCaches'], - 'versions' => ['dcAdvancedCleaner', 'getVersions'] -]; -$combo_actions = [ - 'settings' => [ - __('delete global settings') => 'delete_global', - __('delete blog settings') => 'delete_local', - __('delete all settings') =>'delete_all' - ], - 'tables' => [ - __('delete') => 'delete', - __('empty') => 'empty' - ], - 'plugins' => [ - __('delete') => 'delete', - __('empty') => 'empty' - ], - 'themes' => [ - __('delete') => 'delete', - __('empty') => 'empty' - ], - 'caches' => [ - __('delete') => 'delete', - __('empty') => 'empty' - ], - 'versions' => [ - __('delete') => 'delete' - ] -]; -$combo_help = [ - 'settings' => __('Namespaces registered in dcSettings'), - 'tables' => __('All database tables of Dotclear'), - 'plugins' => __('Folders from plugins directories'), - 'themes' => __('Folders from blog themes directory'), - 'caches' => __('Folders from cache directory'), - 'versions' => __('Versions registered in table "version" of Dotclear') -]; +$cleaner = false; +$select_menu = []; +foreach($ac->get() as $k) { + $select_menu[$k->name] = $k->id; + if ($k->id == $_REQUEST['part']) { + $cleaner = $k; + } +} +if (!$cleaner) { + if (!($cleaner = $ac->get('caches', true))) { + return false; + } +} # Actions -if (!empty($entries) - && isset($combo_type[$part]) - && in_array($action, $combo_type[$part]) -) { +if (!empty($_POST['entries']) && !empty($_POST['action'])) { try { - foreach($entries as $v) { - dcAdvancedCleaner::execute($core, $part, $action, $v); + foreach($_POST['entries'] as $ns) { + $ac->set($cleaner->id, $_POST['action'], $ns); } dcPage::addSuccessNotice(__('Action successfuly excecuted')); $core->adminurl->redirect( 'admin.plugin.dcAdvancedCleaner', - ['part' => $part] + ['part' => $cleaner->id] ); } catch(Exception $e) { @@ -124,6 +50,7 @@ if (!empty($entries) } } +# Display echo '
' . $combo_help[$part] . '
'; +'' . $cleaner->desc . '
'; - $rs = call_user_func($combo_funcs[$part], $core); +$rs = $cleaner->get(); - if (empty($rs)) { - echo '' . sprintf(__('There is no %s'), __(substr($part, 0, -1))) . '
'; - } else { - echo - ''; } + if ($core->blog->settings->dcAdvancedCleaner->dcAdvancedCleaner_dcproperty_hide) { echo '' . __('Default values of Dotclear are hidden. You can change this in settings') .