get(Relation::class), $container->get(Export::class), $container->get(Transformations::class), ); } return new $class(); } /** * @return ExportPlugin[] * @psalm-return list */ public static function getExport(ExportType $type, bool $singleTable): array { ExportPlugin::$exportType = $type; ExportPlugin::$singleTable = $singleTable; return self::getPlugins('Export'); } /** * @return ImportPlugin[] * @psalm-return list */ public static function getImport(): array { return self::getPlugins('Import'); } /** * @return SchemaPlugin[] * @psalm-return list */ public static function getSchema(): array { return self::getPlugins('Schema'); } /** * Reads all plugin information * * @param string $type the type of the plugin (import, export, etc) * @psalm-param 'Export'|'Import'|'Schema' $type * * @return Plugin[] list of plugin instances * @psalm-return ( * $type is 'Export' * ? list * : ($type is 'Import' ? list : list) * ) */ private static function getPlugins(string $type): array { try { $files = new FilesystemIterator(ROOT_PATH . 'src/Plugins/' . $type); } catch (Throwable) { return []; } $plugins = []; /** @var SplFileInfo $fileInfo */ foreach ($files as $fileInfo) { if (! $fileInfo->isReadable() || ! $fileInfo->isFile() || $fileInfo->getExtension() !== 'php') { continue; } if (! str_starts_with($fileInfo->getFilename(), $type)) { continue; } $class = sprintf('PhpMyAdmin\\Plugins\\%s\\%s', $type, $fileInfo->getBasename('.php')); if (! class_exists($class) || ! is_subclass_of($class, Plugin::class) || ! $class::isAvailable()) { continue; } if ($type === 'Export' && is_subclass_of($class, ExportPlugin::class)) { $container = ContainerBuilder::getContainer(); $plugins[] = new $class( $container->get(Relation::class), $container->get(Export::class), $container->get(Transformations::class), ); } elseif ($type === 'Import' && is_subclass_of($class, ImportPlugin::class)) { $plugins[] = new $class(); } elseif ($type === 'Schema' && is_subclass_of($class, SchemaPlugin::class)) { $plugins[] = new $class(); } } usort($plugins, static fn (Plugin $plugin1, Plugin $plugin2): int => strcasecmp( $plugin1->getProperties()->getText(), $plugin2->getProperties()->getText(), )); return $plugins; } /** * Returns html input tag option 'checked' if plugin $opt * should be set by config or request * * @param string $section name of config section in * \PhpMyAdmin\Config::getInstance()->settings[$section] for plugin * @param string $opt name of option * @psalm-param 'Export'|'Import'|'Schema' $section * * @return string html input tag option 'checked' */ public static function checkboxCheck(string $section, string $opt): string { // If the form is being repopulated using $_GET data, that is priority if ( isset($_GET[$opt]) || ! isset($_GET['repopulate']) && ((ImportSettings::$timeoutPassed && isset($_REQUEST[$opt])) || ! empty(Config::getInstance()->settings[$section][$opt])) ) { return ' checked'; } return ''; } /** * Returns default value for option $opt * * @param string $section name of config section in * \PhpMyAdmin\Config::getInstance()->settings[$section] for plugin * @param string $opt name of option * @psalm-param 'Export'|'Import'|'Schema' $section * * @return string default value for option $opt */ public static function getDefault(string $section, string $opt): string { if (isset($_GET[$opt]) && is_string($_GET[$opt])) { // If the form is being repopulated using $_GET data, that is priority return $_GET[$opt]; } if (isset($_REQUEST[$opt]) && is_string($_REQUEST[$opt]) && ImportSettings::$timeoutPassed) { return $_REQUEST[$opt]; } $config = Config::getInstance(); if (isset($config->settings[$section][$opt])) { return (string) $config->settings[$section][$opt]; } return ''; } /** * @param ExportPlugin[]|ImportPlugin[]|SchemaPlugin[] $list * * @return array> * @psalm-return list */ public static function getChoice(array $list, string $default): array { $return = []; foreach ($list as $plugin) { $pluginName = $plugin->getName(); $properties = $plugin->getProperties(); $return[] = [ 'name' => $pluginName, 'text' => $plugin->getTranslatedText($properties->getText()), 'is_selected' => $pluginName === $default, 'is_binary' => $properties->getForceFile(), ]; } return $return; } /** * Returns single option in a list element * * @param string $section name of config section in $cfg[$section] for plugin * @param string $pluginName unique plugin name * @param OptionsPropertyItem $propertyGroup options property main group instance * @param bool $isSubgroup if this group is a subgroup * @psalm-param 'Export'|'Import'|'Schema' $section * * @return string table row with option */ private static function getOneOption( Plugin $plugin, string $section, string $pluginName, OptionsPropertyItem $propertyGroup, bool $isSubgroup = false, ): string { $ret = "\n"; $properties = null; if (! $isSubgroup) { // for subgroup headers if (str_contains($propertyGroup::class, 'PropertyItem')) { $properties = [$propertyGroup]; } else { // for main groups $ret .= '
'; $text = null; if (method_exists($propertyGroup, 'getText')) { $text = $propertyGroup->getText(); } if ($text !== null && $text !== '') { $ret .= '
' . $plugin->getTranslatedText($text) . '
'; } $ret .= '
    '; } } $notSubgroupHeader = false; if ($properties === null) { $notSubgroupHeader = true; if ($propertyGroup instanceof OptionsPropertyGroup) { $properties = $propertyGroup->getProperties(); } } $propertyClass = null; if ($properties !== null) { /** @var OptionsPropertySubgroup $propertyItem */ foreach ($properties as $propertyItem) { $propertyClass = $propertyItem::class; // if the property is a subgroup, we deal with it recursively if (str_contains($propertyClass, 'Subgroup')) { // for subgroups // each subgroup can have a header, which may also be a form element /** @var OptionsPropertyItem|null $subgroupHeader */ $subgroupHeader = $propertyItem->getSubgroupHeader(); if ($subgroupHeader !== null) { $ret .= self::getOneOption($plugin, $section, $pluginName, $subgroupHeader); } $ret .= '
    • getName() . '">'; } else { $ret .= '>'; } $ret .= self::getOneOption($plugin, $section, $pluginName, $propertyItem, true); continue; } // single property item $ret .= self::getHtmlForProperty($plugin, $section, $pluginName, $propertyItem); } } if ($isSubgroup) { // end subgroup $ret .= '
  • '; } elseif ($notSubgroupHeader) { // end main group $ret .= '
'; } if (method_exists($propertyGroup, 'getDoc')) { $doc = $propertyGroup->getDoc(); if (is_array($doc)) { if (count($doc) === 3) { $ret .= MySQLDocumentation::show($doc[1], false, null, null, $doc[2]); } elseif (count($doc) === 1) { $ret .= MySQLDocumentation::showDocumentation('faq', $doc[0]); } else { $ret .= MySQLDocumentation::show($doc[1]); } } } // Close the list element after $doc link is displayed if ( $propertyClass === BoolPropertyItem::class || $propertyClass === MessageOnlyPropertyItem::class || $propertyClass === SelectPropertyItem::class || $propertyClass === TextPropertyItem::class ) { $ret .= ''; } return $ret . "\n"; } /** * Get HTML for properties items * * @param string $section name of config section in $cfg[$section] for plugin * @param string $pluginName unique plugin name * @param OptionsPropertyItem $propertyItem Property item * @psalm-param 'Export'|'Import'|'Schema' $section */ public static function getHtmlForProperty( Plugin $plugin, string $section, string $pluginName, OptionsPropertyItem $propertyItem, ): string { $ret = ''; $propertyClass = $propertyItem::class; switch ($propertyClass) { case BoolPropertyItem::class: $ret .= '
  • ' . "\n"; $ret .= '
    ' . "\n"; $ret .= 'getName(), ); if ($propertyItem->getForce() != null) { // Same code is also few lines lower, update both if needed $ret .= ' onclick="if (!this.checked && ' . '(!document.getElementById(\'checkbox_' . $pluginName . '_' . $propertyItem->getForce() . '\') ' . '|| !document.getElementById(\'checkbox_' . $pluginName . '_' . $propertyItem->getForce() . '\').checked)) ' . 'return false; else return true;"'; } $ret .= '>'; $ret .= '
    '; break; case DocPropertyItem::class: echo DocPropertyItem::class; break; case HiddenPropertyItem::class: $ret .= '
  • '; break; case MessageOnlyPropertyItem::class: $ret .= '
  • ' . "\n"; $ret .= $plugin->getTranslatedText($propertyItem->getText() ?? ''); break; case RadioPropertyItem::class: /** @var RadioPropertyItem $pitem */ $pitem = $propertyItem; $default = htmlspecialchars($plugin->getTranslatedText(self::getDefault( $section, $pluginName . '_' . $pitem->getName(), ))); $ret .= '
  • '; foreach ($pitem->getValues() as $key => $val) { $ret .= '
    getName() . '_' . $key . '">' . $plugin->getTranslatedText((string) $val) . '
    '; } $ret .= '
  • '; break; case SelectPropertyItem::class: /** @var SelectPropertyItem $pitem */ $pitem = $propertyItem; $ret .= '
  • ' . "\n"; $ret .= ''; $ret .= ''; break; case TextPropertyItem::class: /** @var TextPropertyItem $pitem */ $pitem = $propertyItem; $ret .= '
  • ' . "\n"; $ret .= ''; $ret .= 'getSize() !== 0 ? ' size="' . $pitem->getSize() . '"' : '') . ($pitem->getLen() !== 0 ? ' maxlength="' . $pitem->getLen() . '"' : '') . '>'; break; case NumberPropertyItem::class: $ret .= '
  • ' . "\n"; $ret .= ''; $ret .= ''; break; default: break; } return $ret; } /** * Returns html div with editable options for plugin * * @param string $section name of config section in $cfg[$section] * @param ExportPlugin[]|ImportPlugin[]|SchemaPlugin[] $list array with plugin instances * @psalm-param 'Export'|'Import'|'Schema' $section * * @return string html fieldset with plugin options */ public static function getOptions(string $section, array $list): string { $ret = ''; // Options for plugins that support them foreach ($list as $plugin) { $properties = $plugin->getProperties(); $text = $properties->getText(); $options = $properties->getOptions(); $pluginName = $plugin->getName(); $ret .= '
    '; $ret .= '

    ' . $plugin->getTranslatedText($text) . '

    '; $noOptions = true; if ($options !== null && count($options) > 0) { foreach ($options->getProperties() as $propertyMainGroup) { // check for hidden properties $noOptions = true; foreach ($propertyMainGroup->getProperties() as $propertyItem) { if (! $propertyItem instanceof HiddenPropertyItem) { $noOptions = false; break; } } $ret .= self::getOneOption($plugin, $section, $pluginName, $propertyMainGroup); } } if ($noOptions) { $ret .= '

    ' . __('This format has no options') . '

    '; } $ret .= '
    '; } return $ret; } }