<?php namespace BitApps\FM\Providers; use BitApps\FM\Config; use BitApps\WPKit\Http\RequestType; use BitApps\WPKit\Utils\Capabilities; use BitApps\FM\Plugin; use BitApps\FM\Providers\FileManager\ClientOptions; \defined('ABSPATH') || exit(); class PreferenceProvider { public $preferences; private $_availableLang; private $_availableThemes; public function __construct() { $this->preferences = Config::getOption('preferences', $this->defaultPrefs()); $this->fallback(); } public function all() { return $this->preferences; } public function permissions() { return Plugin::instance()->permissions(); } public function defaultPrefs() { return [ 'show_url_path' => 'show', 'language' => 'en', 'size' => [ 'width' => 'auto', 'height' => '500', ], 'default_view_type' => 'icons', 'display_ui_options' => [ 'toolbar', 'places', 'tree', 'path', 'stat', ], 'root_folder_path' => ABSPATH, 'root_folder_url' => Config::get('SITE_URL'), ]; } /** * Saves pref * */ public function saveOptions() { return Config::updateOption('preferences', $this->preferences, true); } /** * Returns all available themes * * @return array */ public function themes() { if (isset($this->_availableThemes)) { return $this->_availableThemes; } $this->_availableThemes = []; $themeBase = BFM_ROOT_DIR . DIRECTORY_SEPARATOR . 'assets' . DIRECTORY_SEPARATOR . 'themes'; $themeDirs = scandir($themeBase); foreach ($themeDirs as $theme) { if ($theme === '.' || $theme === '..') { continue; } $variants = scandir($themeBase . DIRECTORY_SEPARATOR . $theme); foreach ($variants as $variant) { if ($variant === '.' || $variant === '..') { continue; } if ( is_readable( $themeBase . DIRECTORY_SEPARATOR . $theme . DIRECTORY_SEPARATOR . $variant . DIRECTORY_SEPARATOR . $variant . '.json' )) { $this->_availableThemes[$variant] = BFM_ASSET_URL . "themes/{$theme}/{$variant}/{$variant}.json"; } } } return $this->_availableThemes; } /** * Returns available themes as an array of Assoc-array * * @return array<int, array<string,string>> */ public function getThemes() { $themes = []; foreach ($this->themes() as $key => $config) { $themes[] = [ 'key' => $key, 'title' => ucfirst(str_replace('-', ' ', $key)), ]; } $themes[] = [ 'key' => 'default', 'title' => 'Default', ]; return $themes; } /** * Returns selected theme from settings * * @return array */ public function getTheme() { $theme = 'material-default'; if (isset($this->preferences['theme'])) { $theme = esc_attr($this->preferences['theme']); } return $theme; } /** * Sets theme * * @param mixed $theme * * @return array */ public function setTheme($theme) { $this->preferences['theme'] = $theme; } /** * Sets theme * * @param string $view */ public function setLinkPathVisibility($view) { $this->preferences['show_url_path'] = $view; } /** * Returns selected show_url_path from settings * * @return string */ public function isLinkPathVisibleInInfo() { $view = true; if (isset($this->preferences['show_url_path'])) { $view = \boolval($this->preferences['show_url_path']); } return esc_attr($view); } public function getDefaultLangCode() { if (get_locale() === 'en_US') { $code = 'en'; } else { $code = get_locale(); } return esc_attr($code); } public function availableLanguages() { if (!isset($this->_availableLang)) { $allLangs = [ 'LANG' => __('Default', 'file-manager'), 'aa' => __('Afar', 'file-manager'), 'ab' => __('Abkhazian', 'file-manager'), 'ae' => __('Avestan', 'file-manager'), 'af' => __('Afrikaans', 'file-manager'), 'ak' => __('Akan', 'file-manager'), 'am' => __('Amharic', 'file-manager'), 'an' => __('Aragonese', 'file-manager'), 'ar' => __('Arabic', 'file-manager'), 'as' => __('Assamese', 'file-manager'), 'av' => __('Avaric', 'file-manager'), 'ay' => __('Aymara', 'file-manager'), 'az' => __('Azerbaijani', 'file-manager'), 'ba' => __('Bashkir', 'file-manager'), 'be' => __('Belarusian', 'file-manager'), 'bg' => __('Bulgarian', 'file-manager'), 'bh' => __('Bihari', 'file-manager'), 'bi' => __('Bislama', 'file-manager'), 'bm' => __('Bambara', 'file-manager'), 'bn' => __('Bengali', 'file-manager'), 'bo' => __('Tibetan', 'file-manager'), 'br' => __('Breton', 'file-manager'), 'bs' => __('Bosnian', 'file-manager'), 'ca' => __('Catalan', 'file-manager'), 'ce' => __('Chechen', 'file-manager'), 'ch' => __('Chamorro', 'file-manager'), 'co' => __('Corsican', 'file-manager'), 'cr' => __('Cree', 'file-manager'), 'cs' => __('Czech', 'file-manager'), 'cu' => __('Church Slavic', 'file-manager'), 'cv' => __('Chuvash', 'file-manager'), 'cy' => __('Welsh', 'file-manager'), 'da' => __('Danish', 'file-manager'), 'de' => __('German', 'file-manager'), 'dv' => __('Divehi', 'file-manager'), 'dz' => __('Dzongkha', 'file-manager'), 'ee' => __('Ewe', 'file-manager'), 'el' => __('Greek', 'file-manager'), 'en' => __('English', 'file-manager'), 'eo' => __('Esperanto', 'file-manager'), 'es' => __('Spanish', 'file-manager'), 'et' => __('Estonian', 'file-manager'), 'eu' => __('Basque', 'file-manager'), 'fa' => __('Persian', 'file-manager'), 'ff' => __('Fulah', 'file-manager'), 'fi' => __('Finnish', 'file-manager'), 'fj' => __('Fijian', 'file-manager'), 'fo' => __('Faroese', 'file-manager'), 'fr' => __('French', 'file-manager'), 'fr_CA' => __('Française', 'file-manager'), 'fy' => __('Western Frisian', 'file-manager'), 'ga' => __('Irish', 'file-manager'), 'gd' => __('Scottish Gaelic', 'file-manager'), 'gl' => __('Galician', 'file-manager'), 'gn' => __('Guarani', 'file-manager'), 'gu' => __('Gujarati', 'file-manager'), 'gv' => __('Manx', 'file-manager'), 'ha' => __('Hausa', 'file-manager'), 'he' => __('Hebrew', 'file-manager'), 'hi' => __('Hindi', 'file-manager'), 'ho' => __('Hiri Motu', 'file-manager'), 'hr' => __('Croatian', 'file-manager'), 'ht' => __('Haitian', 'file-manager'), 'hu' => __('Hungarian', 'file-manager'), 'hy' => __('Armenian', 'file-manager'), 'hz' => __('Herero', 'file-manager'), 'ia' => __('Interlingua (International Auxiliary Language Association)', 'file-manager'), 'id' => __('Indonesian', 'file-manager'), 'ie' => __('Interlingue', 'file-manager'), 'ig' => __('Igbo', 'file-manager'), 'ii' => __('Sichuan Yi', 'file-manager'), 'ik' => __('Inupiaq', 'file-manager'), 'io' => __('Ido', 'file-manager'), 'is' => __('Icelandic', 'file-manager'), 'it' => __('Italian', 'file-manager'), 'iu' => __('Inuktitut', 'file-manager'), 'ja' => __('Japanese', 'file-manager'), 'jp' => __('Japanese', 'file-manager'), 'jv' => __('Javanese', 'file-manager'), 'ka' => __('Georgian', 'file-manager'), 'kg' => __('Kongo', 'file-manager'), 'ki' => __('Kikuyu', 'file-manager'), 'kj' => __('Kwanyama', 'file-manager'), 'kk' => __('Kazakh', 'file-manager'), 'kl' => __('Kalaallisut', 'file-manager'), 'km' => __('Khmer', 'file-manager'), 'kn' => __('Kannada', 'file-manager'), 'ko' => __('Korean', 'file-manager'), 'kr' => __('Kanuri', 'file-manager'), 'ks' => __('Kashmiri', 'file-manager'), 'ku' => __('Kurdish', 'file-manager'), 'kv' => __('Komi', 'file-manager'), 'kw' => __('Cornish', 'file-manager'), 'ky' => __('Kirghiz', 'file-manager'), 'la' => __('Latin', 'file-manager'), 'lb' => __('Luxembourgish', 'file-manager'), 'lg' => __('Ganda', 'file-manager'), 'li' => __('Limburgish', 'file-manager'), 'ln' => __('Lingala', 'file-manager'), 'lo' => __('Lao', 'file-manager'), 'lt' => __('Lithuanian', 'file-manager'), 'lu' => __('Luba-Katanga', 'file-manager'), 'lv' => __('Latvian', 'file-manager'), 'mg' => __('Malagasy', 'file-manager'), 'mh' => __('Marshallese', 'file-manager'), 'mi' => __('Maori', 'file-manager'), 'mk' => __('Macedonian', 'file-manager'), 'ml' => __('Malayalam', 'file-manager'), 'mn' => __('Mongolian', 'file-manager'), 'mr' => __('Marathi', 'file-manager'), 'ms' => __('Malay', 'file-manager'), 'mt' => __('Maltese', 'file-manager'), 'my' => __('Burmese', 'file-manager'), 'na' => __('Nauru', 'file-manager'), 'nb' => __('Norwegian Bokmal', 'file-manager'), 'nd' => __('North Ndebele', 'file-manager'), 'ne' => __('Nepali', 'file-manager'), 'ng' => __('Ndonga', 'file-manager'), 'nl' => __('Dutch', 'file-manager'), 'nn' => __('Norwegian Nynorsk', 'file-manager'), 'no' => __('Norwegian', 'file-manager'), 'nr' => __('South Ndebele', 'file-manager'), 'nv' => __('Navajo', 'file-manager'), 'ny' => __('Chichewa', 'file-manager'), 'oc' => __('Occitan', 'file-manager'), 'oj' => __('Ojibwa', 'file-manager'), 'om' => __('Oromo', 'file-manager'), 'or' => __('Oriya', 'file-manager'), 'os' => __('Ossetian', 'file-manager'), 'pa' => __('Panjabi', 'file-manager'), 'pi' => __('Pali', 'file-manager'), 'pl' => __('Polish', 'file-manager'), 'ps' => __('Pashto', 'file-manager'), 'pt' => __('Portuguese', 'file-manager'), 'pt_BR' => __('Portuguese(Brazil)', 'file-manager'), 'qu' => __('Quechua', 'file-manager'), 'rm' => __('Raeto-Romance', 'file-manager'), 'rn' => __('Kirundi', 'file-manager'), 'ro' => __('Romanian', 'file-manager'), 'ru' => __('Russian', 'file-manager'), 'rw' => __('Kinyarwanda', 'file-manager'), 'sa' => __('Sanskrit', 'file-manager'), 'sc' => __('Sardinian', 'file-manager'), 'sd' => __('Sindhi', 'file-manager'), 'se' => __('Northern Sami', 'file-manager'), 'sg' => __('Sango', 'file-manager'), 'si' => __('Sinhala', 'file-manager'), 'sk' => __('Slovak', 'file-manager'), 'sl' => __('Slovenian', 'file-manager'), 'sm' => __('Samoan', 'file-manager'), 'sn' => __('Shona', 'file-manager'), 'so' => __('Somali', 'file-manager'), 'sq' => __('Albanian', 'file-manager'), 'sr' => __('Serbian', 'file-manager'), 'ss' => __('Swati', 'file-manager'), 'st' => __('Southern Sotho', 'file-manager'), 'su' => __('Sundanese', 'file-manager'), 'sv' => __('Swedish', 'file-manager'), 'sw' => __('Swahili', 'file-manager'), 'ta' => __('Tamil', 'file-manager'), 'te' => __('Telugu', 'file-manager'), 'tg' => __('Tajik', 'file-manager'), 'th' => __('Thai', 'file-manager'), 'ti' => __('Tigrinya', 'file-manager'), 'tk' => __('Turkmen', 'file-manager'), 'tl' => __('Tagalog', 'file-manager'), 'tn' => __('Tswana', 'file-manager'), 'to' => __('Tonga', 'file-manager'), 'tr' => __('Turkish', 'file-manager'), 'ts' => __('Tsonga', 'file-manager'), 'tt' => __('Tatar', 'file-manager'), 'tw' => __('Twi', 'file-manager'), 'ty' => __('Tahitian', 'file-manager'), 'ug' => __('Uighur', 'file-manager'), 'ug_CN' => __('Uighur(China)', 'file-manager'), 'uk' => __('Ukrainian', 'file-manager'), 'ur' => __('Urdu', 'file-manager'), 'uz' => __('Uzbek', 'file-manager'), 've' => __('Venda', 'file-manager'), 'vi' => __('Vietnamese', 'file-manager'), 'vo' => __('Volapuk', 'file-manager'), 'wa' => __('Walloon', 'file-manager'), 'wo' => __('Wolof', 'file-manager'), 'xh' => __('Xhosa', 'file-manager'), 'yi' => __('Yiddish', 'file-manager'), 'yo' => __('Yoruba', 'file-manager'), 'za' => __('Zhuang', 'file-manager'), 'zh' => __('Chinese', 'file-manager'), 'zh_CN' => __('Chinese(China)', 'file-manager'), 'zh_TW' => __('Chinese(Taiwan)', 'file-manager'), 'zu' => __('Zulu', 'file-manager'), ]; $dirs = scandir(BFM_FINDER_DIR . 'js/i18n'); foreach ($dirs as $lang) { if (\in_array($lang, ['.', '..', 'help'])) { continue; } $lang = str_replace(['elfinder.', '.js'], '', $lang); if (isset($allLangs[$lang])) { $this->_availableLang[$lang] = $allLangs[$lang]; } } } return $this->_availableLang; } /** * Returns available languages as an array of Assoc-array * * @return array<int, array<string,string>> */ public function getLanguages() { $languages = []; foreach ($this->availableLanguages() as $code => $name) { $languages[] = compact('code', 'name'); } return $languages; } public function getLangCode() { return isset($this->preferences['language']) && isset($this->availableLanguages()[(string) $this->preferences['language']]) ? esc_attr($this->preferences['language']) : $this->getDefaultLangCode(); } public function getLangUrl() { $langUrl = BFM_FINDER_URL . 'js/i18n/elfinder.' . $this->getLangCode() . '.js'; if (file_exists($langUrl)) { $langUrl = BFM_FINDER_URL . 'js/i18n/elfinder.en.js'; } return esc_attr($langUrl); } public function setLang($lang) { $this->preferences['language'] = isset($this->availableLanguages()[$lang]) ? $lang : $this->getDefaultLangCode(); } public function setRootPath($path) { $this->preferences['root_folder_path'] = $this->realPath($path); } public function getRootPath() { $defaultPath = Capabilities::check('manage_options') ? ABSPATH : $this->permissions()->getDefaultPublicRootPath(); return isset($this->preferences['root_folder_path']) ? esc_attr($this->preferences['root_folder_path']) : $defaultPath; } public function realPath($path) { if (\is_null($path) || !\is_string($path)) { return $path; } // whether $path is unix or not $unipath = \strlen($path) == 0 || $path[0] != '/'; $prefixed = false; // attempts to detect if path is relative in which case, add cwd if (strpos($path, ':') === false && $unipath) { $path = ABSPATH . $path; $prefixed = true; } // resolve path parts (single dot, double dot and double delimiters) $path = str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $path); $parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen'); $absolutes = []; foreach ($parts as $part) { if ($part == '.') { continue; } if ($part == '..') { array_pop($absolutes); } else { $absolutes[] = $part; } } $realpath = implode(DIRECTORY_SEPARATOR, $absolutes); if ($prefixed) { $realpath = DIRECTORY_SEPARATOR . $realpath; } // resolve any symlinks if (file_exists($realpath) && is_link($realpath)) { $realpath = readlink($realpath); } // put initial separator that could have been lost return $unipath ? $realpath : '/' . $realpath; } public function setRootUrl($url) { $this->preferences['root_folder_url'] = $url; } public function getRootUrl() { $defaultUrl = Capabilities::check('manage_options') ? Config::get('SITE_URL') : $this->permissions()->getDefaultPublicRootURL(); return isset($this->preferences['root_folder_url']) ? $this->preferences['root_folder_url'] : $defaultUrl; } public function setRootVolumeName($name) { $this->preferences['root_folder_name'] = $name; } public function getRootVolumeName() { return isset($this->preferences['root_folder_name']) ? esc_attr($this->preferences['root_folder_name']) : basename($this->getRootPath()); } public function setWidth($width) { $this->preferences['size']['width'] = $width; } public function getWidth() { return isset($this->preferences['size']['width']) && $this->preferences['size']['width'] ? esc_attr($this->preferences['size']['width']) : 'auto'; } public function setHeight($height) { $this->preferences['size']['height'] = $height; } public function getHeight() { return isset($this->preferences['size']['height']) ? esc_attr($this->preferences['size']['height']) : '500'; } public function setVisibilityOfHiddenFile($visibility) { $this->preferences['show_hidden_files'] = $visibility; } public function getVisibilityOfHiddenFile() { return \array_key_exists('show_hidden_files', $this->preferences) && esc_attr($this->preferences['show_hidden_files']) ? true : false; } public function setPermissionForHiddenFolderCreation($permission) { $this->preferences['create_hidden_files_folders'] = $permission; } public function isHiddenFolderAllowed() { return \array_key_exists('create_hidden_files_folders', $this->preferences) && $this->preferences['create_hidden_files_folders'] ? true : false; } public function setPermissionForTrashCreation($permission) { $this->preferences['create_trash_files_folders'] = $permission; } public function isTrashAllowed() { return \array_key_exists('create_trash_files_folders', $this->preferences) && $this->preferences['create_trash_files_folders'] ? true : false; } public function setViewType($type) { $this->preferences['default_view_type'] = $type; } public function getViewType() { return isset($this->preferences['default_view_type']) ? $this->preferences['default_view_type'] : 'icons'; } public function setRememberLastDir($remember) { $this->preferences['remember_last_dir'] = $remember; } public function getRememberLastDir() { return \array_key_exists('remember_last_dir', $this->preferences) && $this->preferences['remember_last_dir'] ? esc_attr($this->preferences['remember_last_dir']) : false; } public function setClearHistoryOnReload($clearHistory) { $this->preferences['clear_history_on_reload'] = $clearHistory; } public function getClearHistoryOnReload() { return \array_key_exists('clear_history_on_reload', $this->preferences) && $this->preferences['clear_history_on_reload'] ? $this->preferences['clear_history_on_reload'] : false; } public function setUiOptions($options) { $this->preferences['display_ui_options'] = $options; } public function getUiOptions() { $uiOptions = isset($this->preferences['display_ui_options']) ? array_map( function ($option) { return esc_attr($option); }, $this->preferences['display_ui_options'] ) : ['toolbar', 'places', 'tree', 'path', 'stat']; if (RequestType::is(RequestType::ADMIN)) { $uiOptions = array_diff($uiOptions, ['path']); } if (!is_user_logged_in()) { $uiOptions = array_diff($uiOptions, ['toolbar']); } return $uiOptions; } public function finderOptions() { $options = new ClientOptions(); $options->setOption('url', admin_url('admin-ajax.php')); $options->setOption('themes', $this->themes()); $options->setOption('theme', $this->getTheme()); $options->setOption('lang', $this->getLangCode()); $options->setOption('width', $this->getWidth()); $options->setOption('height', $this->getHeight()); $options->setOption('commands', $this->permissions()->getEnabledCommand()); $disabledCommands = array_diff($this->permissions()->allCommands(), $this->permissions()->getEnabledCommand()); if (\in_array('download', $disabledCommands)) { $disabledCommands[] = 'dblclick'; } $options->setOption('disabled', array_values($disabledCommands)); $options->setOption('commandsOptions', $this->finderCommandsOptions()); $options->setOption('rememberLastDir', $this->getRememberLastDir()); $options->setOption('reloadClearHistory', $this->getClearHistoryOnReload()); $options->setOption('defaultView', $this->getViewType()); $options->setOption('ui', $this->getUiOptions()); // $options->setOption('resizable', true); $options->setOption( 'contextmenu', $this->finderContextMenu() ); return $options->getOptions(); } public function finderContextMenu() { $contextMenu = [ // 'commands' => ['*'], // phpcs:ignore 'files' => [ 'getfile', '|', 'emailto', 'open', 'opennew', 'download', 'opendir', 'quicklook', 'email', '|', 'upload', 'mkdir', '|', 'copy', 'cut', 'paste', 'duplicate', '|', 'rm', 'empty', 'hide', '|', 'rename', 'edit', 'resize', '|', 'archive', 'extract', '|', 'selectall', 'selectinvert', '|', 'places', 'info', 'chmod', 'netunmount'] ]; if (!is_user_logged_in()) { $contextMenu = [ 'navbar' => [], 'cwd' => ['reload', 'back', 'sort'], 'files' => [], ]; if (\count($this->permissions()->getEnabledCommand())) { $contextMenu['files'] = ['download']; } } return $contextMenu; } public function finderCommandsOptions() { $commandOptions = []; $commandOptions['info'] = []; $commandOptions['info']['hideItems'] = ['md5', 'sha256']; $commandOptions['download']['maxRequests'] = 10; $commandOptions['download']['minFilesZipdl'] = 2; // need to check $commandOptions['quicklook']['googleDocsMimes'] = ['application/pdf', 'image/tiff', 'application/vnd.ms-office', 'application/msword', 'application/vnd.ms-word', 'application/vnd.ms-excel', 'application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']; if (!$this->isLinkPathVisibleInInfo()) { $commandOptions['info']['hideItems'][] = 'link'; $commandOptions['info']['hideItems'][] = 'path'; } return $commandOptions; } private function fallback() { // TODO: Need to remove $fallbackSettings = [ 'fm_root_folder_name' => 'root_folder_name', 'fm-show-hidden-files' => 'show_hidden_files', 'fm-create-hidden-files-folders' => 'create_hidden_files_folders', 'fm-create-trash-files-folders' => 'create_trash_files_folders', 'fm_default_view_type' => 'default_view_type', 'fm-remember-last-dir' => 'remember_last_dir', 'fm-clear-history-on-reload' => 'clear_history_on_reload', 'fm_display_ui_options' => 'display_ui_options', ]; foreach ($fallbackSettings as $key => $newKey) { if (\array_key_exists($key, $this->preferences)) { $this->preferences[$newKey] = $this->preferences[$key]; unset($this->preferences[$key]); } } $this->preferences['size']['width'] = $this->getWidth(); $this->preferences['show_url_path'] = $this->isLinkPathVisibleInInfo(); $this->preferences['show_hidden_files'] = $this->getVisibilityOfHiddenFile(); $this->preferences['create_trash_files_folders'] = $this->isTrashAllowed(); $this->preferences['create_hidden_files_folders'] = $this->isHiddenFolderAllowed(); $this->preferences['remember_last_dir'] = $this->getRememberLastDir(); $this->preferences['clear_history_on_reload'] = $this->getClearHistoryOnReload(); } }