Plugins.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731
  1. <?php
  2. /**
  3. * Generic plugin interface.
  4. */
  5. declare(strict_types=1);
  6. namespace PhpMyAdmin;
  7. use PhpMyAdmin\Html\MySQLDocumentation;
  8. use PhpMyAdmin\Plugins\AuthenticationPlugin;
  9. use PhpMyAdmin\Plugins\ExportPlugin;
  10. use PhpMyAdmin\Plugins\ImportPlugin;
  11. use PhpMyAdmin\Plugins\SchemaPlugin;
  12. use PhpMyAdmin\Properties\Options\Groups\OptionsPropertySubgroup;
  13. use PhpMyAdmin\Properties\Options\Items\BoolPropertyItem;
  14. use PhpMyAdmin\Properties\Options\Items\DocPropertyItem;
  15. use PhpMyAdmin\Properties\Options\Items\HiddenPropertyItem;
  16. use PhpMyAdmin\Properties\Options\Items\MessageOnlyPropertyItem;
  17. use PhpMyAdmin\Properties\Options\Items\NumberPropertyItem;
  18. use PhpMyAdmin\Properties\Options\Items\RadioPropertyItem;
  19. use PhpMyAdmin\Properties\Options\Items\SelectPropertyItem;
  20. use PhpMyAdmin\Properties\Options\Items\TextPropertyItem;
  21. use PhpMyAdmin\Properties\Options\OptionsPropertyItem;
  22. use PhpMyAdmin\Properties\Plugins\ExportPluginProperties;
  23. use PhpMyAdmin\Properties\Plugins\PluginPropertyItem;
  24. use PhpMyAdmin\Properties\Plugins\SchemaPluginProperties;
  25. use function array_pop;
  26. use function class_exists;
  27. use function count;
  28. use function explode;
  29. use function get_class;
  30. use function htmlspecialchars;
  31. use function is_file;
  32. use function mb_strlen;
  33. use function mb_strpos;
  34. use function mb_strtolower;
  35. use function mb_strtoupper;
  36. use function mb_substr;
  37. use function method_exists;
  38. use function opendir;
  39. use function preg_match;
  40. use function preg_match_all;
  41. use function readdir;
  42. use function str_replace;
  43. use function strcasecmp;
  44. use function strcmp;
  45. use function strtolower;
  46. use function ucfirst;
  47. use function usort;
  48. /**
  49. * PhpMyAdmin\Plugins class
  50. */
  51. class Plugins
  52. {
  53. /**
  54. * Includes and instantiates the specified plugin type for a certain format
  55. *
  56. * @param string $plugin_type the type of the plugin (import, export, etc)
  57. * @param string $plugin_format the format of the plugin (sql, xml, et )
  58. * @param string $plugins_dir directory with plugins
  59. * @param mixed $plugin_param parameter to plugin by which they can
  60. * decide whether they can work
  61. *
  62. * @return object|null new plugin instance
  63. */
  64. public static function getPlugin(
  65. $plugin_type,
  66. $plugin_format,
  67. $plugins_dir,
  68. $plugin_param = false
  69. ) {
  70. $GLOBALS['plugin_param'] = $plugin_param;
  71. $class_name = mb_strtoupper($plugin_type[0])
  72. . mb_strtolower(mb_substr($plugin_type, 1))
  73. . mb_strtoupper($plugin_format[0])
  74. . mb_strtolower(mb_substr($plugin_format, 1));
  75. $file = $class_name . '.php';
  76. if (is_file($plugins_dir . $file)) {
  77. //include_once $plugins_dir . $file;
  78. $fqnClass = 'PhpMyAdmin\\' . str_replace('/', '\\', mb_substr($plugins_dir, 18)) . $class_name;
  79. // check if class exists, could be caused by skip_import
  80. if (class_exists($fqnClass)) {
  81. return new $fqnClass();
  82. }
  83. }
  84. return null;
  85. }
  86. /**
  87. * @param string $type server|database|table|raw
  88. *
  89. * @return ExportPlugin[]
  90. */
  91. public static function getExport(string $type, bool $singleTable): array
  92. {
  93. return self::getPlugins('export', 'libraries/classes/Plugins/Export/', [
  94. 'export_type' => $type,
  95. 'single_table' => $singleTable,
  96. ]);
  97. }
  98. /**
  99. * @param string $type server|database|table
  100. *
  101. * @return ImportPlugin[]
  102. */
  103. public static function getImport(string $type): array
  104. {
  105. return self::getPlugins('import', 'libraries/classes/Plugins/Import/', $type);
  106. }
  107. /**
  108. * @return SchemaPlugin[]
  109. */
  110. public static function getSchema(): array
  111. {
  112. return self::getPlugins('schema', 'libraries/classes/Plugins/Schema/', null);
  113. }
  114. /**
  115. * Reads all plugin information from directory $plugins_dir
  116. *
  117. * @param string $plugin_type the type of the plugin (import, export, etc)
  118. * @param string $plugins_dir directory with plugins
  119. * @param array|string|null $plugin_param parameter to plugin by which they can
  120. * decide whether they can work
  121. *
  122. * @return array list of plugin instances
  123. */
  124. private static function getPlugins(string $plugin_type, string $plugins_dir, $plugin_param): array
  125. {
  126. global $skip_import;
  127. $GLOBALS['plugin_param'] = $plugin_param;
  128. $handle = @opendir($plugins_dir);
  129. if (! $handle) {
  130. return [];
  131. }
  132. $plugin_list = [];
  133. $namespace = 'PhpMyAdmin\\' . str_replace('/', '\\', mb_substr($plugins_dir, 18));
  134. $class_type = mb_strtoupper($plugin_type[0], 'UTF-8')
  135. . mb_strtolower(mb_substr($plugin_type, 1), 'UTF-8');
  136. $prefix_class_name = $namespace . $class_type;
  137. while ($file = @readdir($handle)) {
  138. // In some situations, Mac OS creates a new file for each file
  139. // (for example ._csv.php) so the following regexp
  140. // matches a file which does not start with a dot but ends
  141. // with ".php"
  142. if (! is_file($plugins_dir . $file)
  143. || ! preg_match(
  144. '@^' . $class_type . '([^\.]+)\.php$@i',
  145. $file,
  146. $matches
  147. )
  148. ) {
  149. continue;
  150. }
  151. /** @var bool $skip_import */
  152. $skip_import = false;
  153. include_once $plugins_dir . $file;
  154. if ($skip_import) {
  155. continue;
  156. }
  157. $class_name = $prefix_class_name . $matches[1];
  158. $plugin = new $class_name();
  159. if ($plugin->getProperties() === null) {
  160. continue;
  161. }
  162. $plugin_list[] = $plugin;
  163. }
  164. usort(
  165. $plugin_list,
  166. /**
  167. * @param mixed $cmp_name_1
  168. * @param mixed $cmp_name_2
  169. */
  170. static function ($cmp_name_1, $cmp_name_2) {
  171. return strcasecmp(
  172. $cmp_name_1->getProperties()->getText(),
  173. $cmp_name_2->getProperties()->getText()
  174. );
  175. }
  176. );
  177. return $plugin_list;
  178. }
  179. /**
  180. * Returns locale string for $name or $name if no locale is found
  181. *
  182. * @param string $name for local string
  183. *
  184. * @return string locale string for $name
  185. */
  186. public static function getString($name)
  187. {
  188. return $GLOBALS[$name] ?? $name;
  189. }
  190. /**
  191. * Returns html input tag option 'checked' if plugin $opt
  192. * should be set by config or request
  193. *
  194. * @param string $section name of config section in
  195. * $GLOBALS['cfg'][$section] for plugin
  196. * @param string $opt name of option
  197. *
  198. * @return string html input tag option 'checked'
  199. */
  200. public static function checkboxCheck($section, $opt)
  201. {
  202. // If the form is being repopulated using $_GET data, that is priority
  203. if (isset($_GET[$opt])
  204. || ! isset($_GET['repopulate'])
  205. && ((! empty($GLOBALS['timeout_passed']) && isset($_REQUEST[$opt]))
  206. || ! empty($GLOBALS['cfg'][$section][$opt]))
  207. ) {
  208. return ' checked="checked"';
  209. }
  210. return '';
  211. }
  212. /**
  213. * Returns default value for option $opt
  214. *
  215. * @param string $section name of config section in
  216. * $GLOBALS['cfg'][$section] for plugin
  217. * @param string $opt name of option
  218. *
  219. * @return string default value for option $opt
  220. */
  221. public static function getDefault($section, $opt)
  222. {
  223. if (isset($_GET[$opt])) {
  224. // If the form is being repopulated using $_GET data, that is priority
  225. return htmlspecialchars($_GET[$opt]);
  226. }
  227. if (isset($GLOBALS['timeout_passed'], $_REQUEST[$opt]) && $GLOBALS['timeout_passed']) {
  228. return htmlspecialchars($_REQUEST[$opt]);
  229. }
  230. if (! isset($GLOBALS['cfg'][$section][$opt])) {
  231. return '';
  232. }
  233. $matches = [];
  234. /* Possibly replace localised texts */
  235. if (! preg_match_all(
  236. '/(str[A-Z][A-Za-z0-9]*)/',
  237. (string) $GLOBALS['cfg'][$section][$opt],
  238. $matches
  239. )) {
  240. return htmlspecialchars((string) $GLOBALS['cfg'][$section][$opt]);
  241. }
  242. $val = $GLOBALS['cfg'][$section][$opt];
  243. foreach ($matches[0] as $match) {
  244. if (! isset($GLOBALS[$match])) {
  245. continue;
  246. }
  247. $val = str_replace($match, $GLOBALS[$match], $val);
  248. }
  249. return htmlspecialchars($val);
  250. }
  251. /**
  252. * Returns html select form element for plugin choice
  253. * and hidden fields denoting whether each plugin must be exported as a file
  254. *
  255. * @param string $section name of config section in
  256. * $GLOBALS['cfg'][$section] for plugin
  257. * @param string $name name of select element
  258. * @param array $list array with plugin instances
  259. * @param string $cfgname name of config value, if none same as $name
  260. *
  261. * @return string html select tag
  262. */
  263. public static function getChoice($section, $name, array $list, $cfgname = null)
  264. {
  265. if (! isset($cfgname)) {
  266. $cfgname = $name;
  267. }
  268. $ret = '<select id="plugins" name="' . $name . '">';
  269. $default = self::getDefault($section, $cfgname);
  270. $hidden = null;
  271. foreach ($list as $plugin) {
  272. $elem = explode('\\', get_class($plugin));
  273. $plugin_name = (string) array_pop($elem);
  274. unset($elem);
  275. $plugin_name = mb_strtolower(
  276. mb_substr(
  277. $plugin_name,
  278. mb_strlen($section)
  279. )
  280. );
  281. $ret .= '<option';
  282. // If the form is being repopulated using $_GET data, that is priority
  283. if (isset($_GET[$name])
  284. && $plugin_name == $_GET[$name]
  285. || ! isset($_GET[$name])
  286. && $plugin_name == $default
  287. ) {
  288. $ret .= ' selected="selected"';
  289. }
  290. /** @var PluginPropertyItem $properties */
  291. $properties = $plugin->getProperties();
  292. $text = null;
  293. if ($properties != null) {
  294. $text = $properties->getText();
  295. }
  296. $ret .= ' value="' . $plugin_name . '">'
  297. . self::getString($text)
  298. . '</option>' . "\n";
  299. // Whether each plugin has to be saved as a file
  300. $hidden .= '<input type="hidden" id="force_file_' . $plugin_name
  301. . '" value="';
  302. /** @var ExportPluginProperties|SchemaPluginProperties $properties */
  303. $properties = $plugin->getProperties();
  304. if (! strcmp($section, 'Import')
  305. || ($properties != null && $properties->getForceFile() != null)
  306. ) {
  307. $hidden .= 'true';
  308. } else {
  309. $hidden .= 'false';
  310. }
  311. $hidden .= '">' . "\n";
  312. }
  313. $ret .= '</select>' . "\n" . $hidden;
  314. return $ret;
  315. }
  316. /**
  317. * Returns single option in a list element
  318. *
  319. * @param string $section name of config section in $GLOBALS['cfg'][$section] for plugin
  320. * @param string $plugin_name unique plugin name
  321. * @param OptionsPropertyItem $propertyGroup options property main group instance
  322. * @param bool $is_subgroup if this group is a subgroup
  323. *
  324. * @return string table row with option
  325. */
  326. public static function getOneOption(
  327. $section,
  328. $plugin_name,
  329. &$propertyGroup,
  330. $is_subgroup = false
  331. ) {
  332. $ret = "\n";
  333. $properties = null;
  334. if (! $is_subgroup) {
  335. // for subgroup headers
  336. if (mb_strpos(get_class($propertyGroup), 'PropertyItem')) {
  337. $properties = [$propertyGroup];
  338. } else {
  339. // for main groups
  340. $ret .= '<div class="export_sub_options" id="' . $plugin_name . '_'
  341. . $propertyGroup->getName() . '">';
  342. $text = null;
  343. if (method_exists($propertyGroup, 'getText')) {
  344. $text = $propertyGroup->getText();
  345. }
  346. if ($text != null) {
  347. $ret .= '<h4>' . self::getString($text) . '</h4>';
  348. }
  349. $ret .= '<ul>';
  350. }
  351. }
  352. if (! isset($properties)) {
  353. $not_subgroup_header = true;
  354. if (method_exists($propertyGroup, 'getProperties')) {
  355. $properties = $propertyGroup->getProperties();
  356. }
  357. }
  358. $property_class = null;
  359. if (isset($properties)) {
  360. /** @var OptionsPropertySubgroup $propertyItem */
  361. foreach ($properties as $propertyItem) {
  362. $property_class = get_class($propertyItem);
  363. // if the property is a subgroup, we deal with it recursively
  364. if (mb_strpos($property_class, 'Subgroup')) {
  365. // for subgroups
  366. // each subgroup can have a header, which may also be a form element
  367. /** @var OptionsPropertyItem $subgroup_header */
  368. $subgroup_header = $propertyItem->getSubgroupHeader();
  369. if ($subgroup_header !== null) {
  370. $ret .= self::getOneOption(
  371. $section,
  372. $plugin_name,
  373. $subgroup_header
  374. );
  375. }
  376. $ret .= '<li class="subgroup"><ul';
  377. if ($subgroup_header !== null) {
  378. $ret .= ' id="ul_' . $subgroup_header->getName() . '">';
  379. } else {
  380. $ret .= '>';
  381. }
  382. $ret .= self::getOneOption(
  383. $section,
  384. $plugin_name,
  385. $propertyItem,
  386. true
  387. );
  388. continue;
  389. }
  390. // single property item
  391. $ret .= self::getHtmlForProperty(
  392. $section,
  393. $plugin_name,
  394. $propertyItem
  395. );
  396. }
  397. }
  398. if ($is_subgroup) {
  399. // end subgroup
  400. $ret .= '</ul></li>';
  401. } else {
  402. // end main group
  403. if (! empty($not_subgroup_header)) {
  404. $ret .= '</ul></div>';
  405. }
  406. }
  407. if (method_exists($propertyGroup, 'getDoc')) {
  408. $doc = $propertyGroup->getDoc();
  409. if ($doc != null) {
  410. if (count($doc) === 3) {
  411. $ret .= MySQLDocumentation::show(
  412. $doc[1],
  413. false,
  414. null,
  415. null,
  416. $doc[2]
  417. );
  418. } elseif (count($doc) === 1) {
  419. $ret .= MySQLDocumentation::showDocumentation('faq', $doc[0]);
  420. } else {
  421. $ret .= MySQLDocumentation::show(
  422. $doc[1]
  423. );
  424. }
  425. }
  426. }
  427. // Close the list element after $doc link is displayed
  428. if ($property_class !== null) {
  429. if ($property_class == BoolPropertyItem::class
  430. || $property_class == MessageOnlyPropertyItem::class
  431. || $property_class == SelectPropertyItem::class
  432. || $property_class == TextPropertyItem::class
  433. ) {
  434. $ret .= '</li>';
  435. }
  436. }
  437. return $ret . "\n";
  438. }
  439. /**
  440. * Get HTML for properties items
  441. *
  442. * @param string $section name of config section in
  443. * $GLOBALS['cfg'][$section] for plugin
  444. * @param string $plugin_name unique plugin name
  445. * @param OptionsPropertyItem $propertyItem Property item
  446. *
  447. * @return string
  448. */
  449. public static function getHtmlForProperty(
  450. $section,
  451. $plugin_name,
  452. $propertyItem
  453. ) {
  454. $ret = null;
  455. $property_class = get_class($propertyItem);
  456. switch ($property_class) {
  457. case BoolPropertyItem::class:
  458. $ret .= '<li>' . "\n";
  459. $ret .= '<input type="checkbox" name="' . $plugin_name . '_'
  460. . $propertyItem->getName() . '"'
  461. . ' value="something" id="checkbox_' . $plugin_name . '_'
  462. . $propertyItem->getName() . '"'
  463. . ' '
  464. . self::checkboxCheck(
  465. $section,
  466. $plugin_name . '_' . $propertyItem->getName()
  467. );
  468. if ($propertyItem->getForce() != null) {
  469. // Same code is also few lines lower, update both if needed
  470. $ret .= ' onclick="if (!this.checked &amp;&amp; '
  471. . '(!document.getElementById(\'checkbox_' . $plugin_name
  472. . '_' . $propertyItem->getForce() . '\') '
  473. . '|| !document.getElementById(\'checkbox_'
  474. . $plugin_name . '_' . $propertyItem->getForce()
  475. . '\').checked)) '
  476. . 'return false; else return true;"';
  477. }
  478. $ret .= '>';
  479. $ret .= '<label for="checkbox_' . $plugin_name . '_'
  480. . $propertyItem->getName() . '">'
  481. . self::getString($propertyItem->getText()) . '</label>';
  482. break;
  483. case DocPropertyItem::class:
  484. echo DocPropertyItem::class;
  485. break;
  486. case HiddenPropertyItem::class:
  487. $ret .= '<li><input type="hidden" name="' . $plugin_name . '_'
  488. . $propertyItem->getName() . '"'
  489. . ' value="' . self::getDefault(
  490. $section,
  491. $plugin_name . '_' . $propertyItem->getName()
  492. )
  493. . '"></li>';
  494. break;
  495. case MessageOnlyPropertyItem::class:
  496. $ret .= '<li>' . "\n";
  497. $ret .= '<p>' . self::getString($propertyItem->getText()) . '</p>';
  498. break;
  499. case RadioPropertyItem::class:
  500. /**
  501. * @var RadioPropertyItem $pitem
  502. */
  503. $pitem = $propertyItem;
  504. $default = self::getDefault(
  505. $section,
  506. $plugin_name . '_' . $pitem->getName()
  507. );
  508. foreach ($pitem->getValues() as $key => $val) {
  509. $ret .= '<li><input type="radio" name="' . $plugin_name
  510. . '_' . $pitem->getName() . '" value="' . $key
  511. . '" id="radio_' . $plugin_name . '_'
  512. . $pitem->getName() . '_' . $key . '"';
  513. if ($key == $default) {
  514. $ret .= ' checked="checked"';
  515. }
  516. $ret .= '><label for="radio_' . $plugin_name . '_'
  517. . $pitem->getName() . '_' . $key . '">'
  518. . self::getString($val) . '</label></li>';
  519. }
  520. break;
  521. case SelectPropertyItem::class:
  522. /**
  523. * @var SelectPropertyItem $pitem
  524. */
  525. $pitem = $propertyItem;
  526. $ret .= '<li>' . "\n";
  527. $ret .= '<label for="select_' . $plugin_name . '_'
  528. . $pitem->getName() . '" class="desc">'
  529. . self::getString($pitem->getText()) . '</label>';
  530. $ret .= '<select name="' . $plugin_name . '_'
  531. . $pitem->getName() . '"'
  532. . ' id="select_' . $plugin_name . '_'
  533. . $pitem->getName() . '">';
  534. $default = self::getDefault(
  535. $section,
  536. $plugin_name . '_' . $pitem->getName()
  537. );
  538. foreach ($pitem->getValues() as $key => $val) {
  539. $ret .= '<option value="' . $key . '"';
  540. if ($key == $default) {
  541. $ret .= ' selected="selected"';
  542. }
  543. $ret .= '>' . self::getString($val) . '</option>';
  544. }
  545. $ret .= '</select>';
  546. break;
  547. case TextPropertyItem::class:
  548. /**
  549. * @var TextPropertyItem $pitem
  550. */
  551. $pitem = $propertyItem;
  552. $ret .= '<li>' . "\n";
  553. $ret .= '<label for="text_' . $plugin_name . '_'
  554. . $pitem->getName() . '" class="desc">'
  555. . self::getString($pitem->getText()) . '</label>';
  556. $ret .= '<input type="text" name="' . $plugin_name . '_'
  557. . $pitem->getName() . '"'
  558. . ' value="' . self::getDefault(
  559. $section,
  560. $plugin_name . '_' . $pitem->getName()
  561. ) . '"'
  562. . ' id="text_' . $plugin_name . '_'
  563. . $pitem->getName() . '"'
  564. . ($pitem->getSize() != null
  565. ? ' size="' . $pitem->getSize() . '"'
  566. : '')
  567. . ($pitem->getLen() != null
  568. ? ' maxlength="' . $pitem->getLen() . '"'
  569. : '')
  570. . '>';
  571. break;
  572. case NumberPropertyItem::class:
  573. $ret .= '<li>' . "\n";
  574. $ret .= '<label for="number_' . $plugin_name . '_'
  575. . $propertyItem->getName() . '" class="desc">'
  576. . self::getString($propertyItem->getText()) . '</label>';
  577. $ret .= '<input type="number" name="' . $plugin_name . '_'
  578. . $propertyItem->getName() . '"'
  579. . ' value="' . self::getDefault(
  580. $section,
  581. $plugin_name . '_' . $propertyItem->getName()
  582. ) . '"'
  583. . ' id="number_' . $plugin_name . '_'
  584. . $propertyItem->getName() . '"'
  585. . ' min="0"'
  586. . '>';
  587. break;
  588. default:
  589. break;
  590. }
  591. return $ret;
  592. }
  593. /**
  594. * Returns html div with editable options for plugin
  595. *
  596. * @param string $section name of config section in $GLOBALS['cfg'][$section]
  597. * @param array $list array with plugin instances
  598. *
  599. * @return string html fieldset with plugin options
  600. */
  601. public static function getOptions($section, array $list)
  602. {
  603. $ret = '';
  604. // Options for plugins that support them
  605. foreach ($list as $plugin) {
  606. $properties = $plugin->getProperties();
  607. $text = null;
  608. $options = null;
  609. if ($properties != null) {
  610. $text = $properties->getText();
  611. $options = $properties->getOptions();
  612. }
  613. $elem = explode('\\', get_class($plugin));
  614. $plugin_name = (string) array_pop($elem);
  615. unset($elem);
  616. $plugin_name = mb_strtolower(
  617. mb_substr(
  618. $plugin_name,
  619. mb_strlen($section)
  620. )
  621. );
  622. $ret .= '<div id="' . $plugin_name
  623. . '_options" class="format_specific_options">';
  624. $ret .= '<h3>' . self::getString($text) . '</h3>';
  625. $no_options = true;
  626. if ($options !== null && count($options) > 0) {
  627. foreach ($options->getProperties() as $propertyMainGroup) {
  628. // check for hidden properties
  629. $no_options = true;
  630. foreach ($propertyMainGroup->getProperties() as $propertyItem) {
  631. if (strcmp(HiddenPropertyItem::class, get_class($propertyItem))) {
  632. $no_options = false;
  633. break;
  634. }
  635. }
  636. $ret .= self::getOneOption(
  637. $section,
  638. $plugin_name,
  639. $propertyMainGroup
  640. );
  641. }
  642. }
  643. if ($no_options) {
  644. $ret .= '<p>' . __('This format has no options') . '</p>';
  645. }
  646. $ret .= '</div>';
  647. }
  648. return $ret;
  649. }
  650. public static function getAuthPlugin(): AuthenticationPlugin
  651. {
  652. global $cfg;
  653. $class = 'PhpMyAdmin\\Plugins\\Auth\\Authentication' . ucfirst(strtolower($cfg['Server']['auth_type']));
  654. if (! class_exists($class)) {
  655. Core::fatalError(
  656. __('Invalid authentication method set in configuration:')
  657. . ' ' . $cfg['Server']['auth_type']
  658. );
  659. }
  660. /** @var AuthenticationPlugin $plugin */
  661. $plugin = new $class();
  662. return $plugin;
  663. }
  664. }