plugin_interface.lib.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * Generic plugin interface.
  5. *
  6. * @package PhpMyAdmin
  7. */
  8. /**
  9. * Includes and instantiates the specified plugin type for a certain format
  10. *
  11. * @param string $plugin_type the type of the plugin (import, export, etc)
  12. * @param string $plugin_format the format of the plugin (sql, xml, et )
  13. * @param string $plugins_dir directrory with plugins
  14. * @param mixed $plugin_param parameter to plugin by which they can
  15. * decide whether they can work
  16. *
  17. * @return object new plugin instance
  18. */
  19. function PMA_getPlugin(
  20. $plugin_type,
  21. $plugin_format,
  22. $plugins_dir,
  23. $plugin_param = false
  24. ) {
  25. $GLOBALS['plugin_param'] = $plugin_param;
  26. $class_name = strtoupper($plugin_type[0])
  27. . strtolower(substr($plugin_type, 1))
  28. . strtoupper($plugin_format[0])
  29. . strtolower(substr($plugin_format, 1));
  30. $file = $class_name . ".class.php";
  31. if (is_file($plugins_dir . $file)) {
  32. include_once $plugins_dir . $file;
  33. return new $class_name;
  34. }
  35. // by default, return SQL plugin
  36. return PMA_getPlugin($plugin_type, 'sql', $plugins_dir, $plugin_param);
  37. }
  38. /**
  39. * Reads all plugin information from directory $plugins_dir
  40. *
  41. * @param string $plugin_type the type of the plugin (import, export, etc)
  42. * @param string $plugins_dir directrory with plugins
  43. * @param mixed $plugin_param parameter to plugin by which they can
  44. * decide whether they can work
  45. *
  46. * @return array list of plugin instances
  47. */
  48. function PMA_getPlugins($plugin_type, $plugins_dir, $plugin_param)
  49. {
  50. $GLOBALS['plugin_param'] = $plugin_param;
  51. /* Scan for plugins */
  52. $plugin_list = array();
  53. if (!($handle = @opendir($plugins_dir))) {
  54. ksort($plugin_list);
  55. return $plugin_list;
  56. }
  57. while ($file = @readdir($handle)) {
  58. // In some situations, Mac OS creates a new file for each file
  59. // (for example ._csv.php) so the following regexp
  60. // matches a file which does not start with a dot but ends
  61. // with ".php"
  62. $class_type = mb_strtoupper($plugin_type[0], 'UTF-8')
  63. . mb_strtolower(substr($plugin_type, 1), 'UTF-8');
  64. if (is_file($plugins_dir . $file)
  65. && preg_match(
  66. '@^' . $class_type . '(.+)\.class\.php$@i',
  67. $file,
  68. $matches
  69. )
  70. ) {
  71. $GLOBALS['skip_import'] = false;
  72. include_once $plugins_dir . $file;
  73. if (! $GLOBALS['skip_import']) {
  74. $class_name = $class_type . $matches[1];
  75. $plugin = new $class_name;
  76. if (null !== $plugin->getProperties()) {
  77. $plugin_list[] = $plugin;
  78. }
  79. }
  80. }
  81. }
  82. ksort($plugin_list);
  83. return $plugin_list;
  84. }
  85. /**
  86. * Returns locale string for $name or $name if no locale is found
  87. *
  88. * @param string $name for local string
  89. *
  90. * @return string locale string for $name
  91. */
  92. function PMA_getString($name)
  93. {
  94. return isset($GLOBALS[$name]) ? $GLOBALS[$name] : $name;
  95. }
  96. /**
  97. * Returns html input tag option 'checked' if plugin $opt
  98. * should be set by config or request
  99. *
  100. * @param string $section name of config section in
  101. * $GLOBALS['cfg'][$section] for plugin
  102. * @param string $opt name of option
  103. *
  104. * @return string hmtl input tag option 'checked'
  105. */
  106. function PMA_pluginCheckboxCheck($section, $opt)
  107. {
  108. // If the form is being repopulated using $_GET data, that is priority
  109. if (isset($_GET[$opt])
  110. || ! isset($_GET['repopulate'])
  111. && ((isset($GLOBALS['timeout_passed'])
  112. && $GLOBALS['timeout_passed']
  113. && isset($_REQUEST[$opt]))
  114. || (isset($GLOBALS['cfg'][$section][$opt])
  115. && $GLOBALS['cfg'][$section][$opt]))
  116. ) {
  117. return ' checked="checked"';
  118. }
  119. return '';
  120. }
  121. /**
  122. * Returns default value for option $opt
  123. *
  124. * @param string $section name of config section in
  125. * $GLOBALS['cfg'][$section] for plugin
  126. * @param string $opt name of option
  127. *
  128. * @return string default value for option $opt
  129. */
  130. function PMA_pluginGetDefault($section, $opt)
  131. {
  132. if (isset($_GET[$opt])) {
  133. // If the form is being repopulated using $_GET data, that is priority
  134. return htmlspecialchars($_GET[$opt]);
  135. }
  136. if (isset($GLOBALS['timeout_passed'])
  137. && $GLOBALS['timeout_passed']
  138. && isset($_REQUEST[$opt])
  139. ) {
  140. return htmlspecialchars($_REQUEST[$opt]);
  141. }
  142. if (!isset($GLOBALS['cfg'][$section][$opt])) {
  143. return '';
  144. }
  145. $matches = array();
  146. /* Possibly replace localised texts */
  147. if (!preg_match_all(
  148. '/(str[A-Z][A-Za-z0-9]*)/',
  149. $GLOBALS['cfg'][$section][$opt],
  150. $matches
  151. )) {
  152. return htmlspecialchars($GLOBALS['cfg'][$section][$opt]);
  153. }
  154. $val = $GLOBALS['cfg'][$section][$opt];
  155. foreach ($matches[0] as $match) {
  156. if (isset($GLOBALS[$match])) {
  157. $val = str_replace($match, $GLOBALS[$match], $val);
  158. }
  159. }
  160. return htmlspecialchars($val);
  161. }
  162. /**
  163. * Returns html select form element for plugin choice
  164. * and hidden fields denoting whether each plugin must be exported as a file
  165. *
  166. * @param string $section name of config section in
  167. * $GLOBALS['cfg'][$section] for plugin
  168. * @param string $name name of select element
  169. * @param array &$list array with plugin instances
  170. * @param string $cfgname name of config value, if none same as $name
  171. *
  172. * @return string html select tag
  173. */
  174. function PMA_pluginGetChoice($section, $name, &$list, $cfgname = null)
  175. {
  176. if (! isset($cfgname)) {
  177. $cfgname = $name;
  178. }
  179. $ret = '<select id="plugins" name="' . $name . '">';
  180. $default = PMA_pluginGetDefault($section, $cfgname);
  181. foreach ($list as $plugin) {
  182. $plugin_name = strtolower(substr(get_class($plugin), strlen($section)));
  183. $ret .= '<option';
  184. // If the form is being repopulated using $_GET data, that is priority
  185. if (isset($_GET[$name])
  186. && $plugin_name == $_GET[$name]
  187. || ! isset($_GET[$name])
  188. && $plugin_name == $default
  189. ) {
  190. $ret .= ' selected="selected"';
  191. }
  192. $properties = $plugin->getProperties();
  193. $text = null;
  194. if ($properties != null) {
  195. $text = $properties->getText();
  196. }
  197. $ret .= ' value="' . $plugin_name . '">'
  198. . PMA_getString($text)
  199. . '</option>' . "\n";
  200. }
  201. $ret .= '</select>' . "\n";
  202. // Whether each plugin has to be saved as a file
  203. foreach ($list as $plugin) {
  204. $plugin_name = strtolower(substr(get_class($plugin), strlen($section)));
  205. $ret .= '<input type="hidden" id="force_file_' . $plugin_name
  206. . '" value="';
  207. $properties = $plugin->getProperties();
  208. if ( ! strcmp($section, 'Import')
  209. || ($properties != null && $properties->getForceFile() != null)
  210. ) {
  211. $ret .= 'true';
  212. } else {
  213. $ret .= 'false';
  214. }
  215. $ret .= '" />' . "\n";
  216. }
  217. return $ret;
  218. }
  219. /**
  220. * Returns single option in a list element
  221. *
  222. * @param string $section name of config section in
  223. * $GLOBALS['cfg'][$section] for plugin
  224. * @param string $plugin_name unique plugin name
  225. * @param array &$propertyGroup options property main group instance
  226. * @param boolean $is_subgroup if this group is a subgroup
  227. *
  228. * @return string table row with option
  229. */
  230. function PMA_pluginGetOneOption(
  231. $section,
  232. $plugin_name,
  233. &$propertyGroup,
  234. $is_subgroup = false
  235. ) {
  236. $ret = "\n";
  237. if (! $is_subgroup) {
  238. // for subgroup headers
  239. if (strpos(get_class($propertyGroup), "PropertyItem")) {
  240. $properties = array($propertyGroup);
  241. } else {
  242. // for main groups
  243. $ret .= '<div class="export_sub_options" id="' . $plugin_name . '_'
  244. . $propertyGroup->getName() . '">';
  245. if (method_exists($propertyGroup, 'getText')) {
  246. $text = $propertyGroup->getText();
  247. }
  248. if ($text != null) {
  249. $ret .= '<h4>' . PMA_getString($text) . '</h4>';
  250. }
  251. $ret .= '<ul>';
  252. }
  253. }
  254. if (! isset($properties)) {
  255. $not_subgroup_header = true;
  256. if (method_exists($propertyGroup, 'getProperties')) {
  257. $properties = $propertyGroup->getProperties();
  258. }
  259. }
  260. if (isset($properties)) {
  261. foreach ($properties as $propertyItem) {
  262. $property_class = get_class($propertyItem);
  263. // if the property is a subgroup, we deal with it recursively
  264. if (strpos($property_class, "Subgroup")) {
  265. // for subgroups
  266. // each subgroup can have a header, which may also be a form element
  267. $subgroup_header = $propertyItem->getSubgroupHeader();
  268. if (isset($subgroup_header)) {
  269. $ret .= PMA_pluginGetOneOption(
  270. $section,
  271. $plugin_name,
  272. $subgroup_header
  273. );
  274. }
  275. $ret .= '<li class="subgroup"><ul';
  276. if (isset($subgroup_header)) {
  277. $ret .= ' id="ul_' . $subgroup_header->getName() . '">';
  278. } else {
  279. $ret .= '>';
  280. }
  281. $ret .= PMA_pluginGetOneOption(
  282. $section,
  283. $plugin_name,
  284. $propertyItem,
  285. true
  286. );
  287. continue;
  288. }
  289. // single property item
  290. switch ($property_class) {
  291. case "BoolPropertyItem":
  292. $ret .= '<li>' . "\n";
  293. $ret .= '<input type="checkbox" name="' . $plugin_name . '_'
  294. . $propertyItem->getName() . '"'
  295. . ' value="something" id="checkbox_' . $plugin_name . '_'
  296. . $propertyItem->getName() . '"'
  297. . ' '
  298. . PMA_pluginCheckboxCheck(
  299. $section,
  300. $plugin_name . '_' . $propertyItem->getName()
  301. );
  302. if ($propertyItem->getForce() != null) {
  303. // Same code is also few lines lower, update both if needed
  304. $ret .= ' onclick="if (!this.checked &amp;&amp; '
  305. . '(!document.getElementById(\'checkbox_' . $plugin_name
  306. . '_' . $propertyItem->getForce() . '\') '
  307. . '|| !document.getElementById(\'checkbox_'
  308. . $plugin_name . '_' . $propertyItem->getForce()
  309. . '\').checked)) '
  310. . 'return false; else return true;"';
  311. }
  312. $ret .= ' />';
  313. $ret .= '<label for="checkbox_' . $plugin_name . '_'
  314. . $propertyItem->getName() . '">'
  315. . PMA_getString($propertyItem->getText()) . '</label>';
  316. break;
  317. case "DocPropertyItem":
  318. echo "DocPropertyItem";
  319. break;
  320. case "HiddenPropertyItem":
  321. $ret .= '<li><input type="hidden" name="' . $plugin_name . '_'
  322. . $propertyItem->getName() . '"'
  323. . ' value="' . PMA_pluginGetDefault(
  324. $section,
  325. $plugin_name . '_' . $propertyItem->getName()
  326. )
  327. . '"' . ' /></li>';
  328. break;
  329. case "MessageOnlyPropertyItem":
  330. $ret .= '<li>' . "\n";
  331. $ret .= '<p>' . PMA_getString($propertyItem->getText()) . '</p>';
  332. break;
  333. case "RadioPropertyItem":
  334. $default = PMA_pluginGetDefault(
  335. $section,
  336. $plugin_name . '_' . $propertyItem->getName()
  337. );
  338. foreach ($propertyItem->getValues() as $key => $val) {
  339. $ret .= '<li><input type="radio" name="' . $plugin_name
  340. . '_' . $propertyItem->getName() . '" value="' . $key
  341. . '" id="radio_' . $plugin_name . '_'
  342. . $propertyItem->getName() . '_' . $key . '"';
  343. if ($key == $default) {
  344. $ret .= ' checked="checked"';
  345. }
  346. $ret .= ' />' . '<label for="radio_' . $plugin_name . '_'
  347. . $propertyItem->getName() . '_' . $key . '">'
  348. . PMA_getString($val) . '</label></li>';
  349. }
  350. break;
  351. case "SelectPropertyItem":
  352. $ret .= '<li>' . "\n";
  353. $ret .= '<label for="select_' . $plugin_name . '_'
  354. . $propertyItem->getName() . '" class="desc">'
  355. . PMA_getString($propertyItem->getText()) . '</label>';
  356. $ret .= '<select name="' . $plugin_name . '_'
  357. . $propertyItem->getName() . '"'
  358. . ' id="select_' . $plugin_name . '_'
  359. . $propertyItem->getName() . '">';
  360. $default = PMA_pluginGetDefault(
  361. $section,
  362. $plugin_name . '_' . $propertyItem->getName()
  363. );
  364. foreach ($propertyItem->getValues() as $key => $val) {
  365. $ret .= '<option value="' . $key . '"';
  366. if ($key == $default) {
  367. $ret .= ' selected="selected"';
  368. }
  369. $ret .= '>' . PMA_getString($val) . '</option>';
  370. }
  371. $ret .= '</select>';
  372. break;
  373. case "TextPropertyItem":
  374. case "NumberPropertyItem":
  375. $ret .= '<li>' . "\n";
  376. $ret .= '<label for="text_' . $plugin_name . '_'
  377. . $propertyItem->getName() . '" class="desc">'
  378. . PMA_getString($propertyItem->getText()) . '</label>';
  379. $ret .= '<input type="text" name="' . $plugin_name . '_'
  380. . $propertyItem->getName() . '"'
  381. . ' value="' . PMA_pluginGetDefault(
  382. $section,
  383. $plugin_name . '_' . $propertyItem->getName()
  384. ) . '"'
  385. . ' id="text_' . $plugin_name . '_'
  386. . $propertyItem->getName() . '"'
  387. . ($propertyItem->getSize() != null
  388. ? ' size="' . $propertyItem->getSize() . '"'
  389. : '')
  390. . ($propertyItem->getLen() != null
  391. ? ' maxlength="' . $propertyItem->getLen() . '"'
  392. : '')
  393. . ' />';
  394. break;
  395. default:;
  396. }
  397. }
  398. }
  399. if ($is_subgroup) {
  400. // end subgroup
  401. $ret .= '</ul></li>';
  402. } else {
  403. // end main group
  404. if (! empty($not_subgroup_header)) {
  405. $ret .= '</ul></div>';
  406. }
  407. }
  408. if (method_exists($propertyGroup, "getDoc")) {
  409. $doc = $propertyGroup->getDoc();
  410. if ($doc != null) {
  411. if (count($doc) == 3) {
  412. $ret .= PMA_Util::showMySQLDocu(
  413. $doc[1],
  414. false,
  415. $doc[2]
  416. );
  417. } elseif (count($doc) == 1) {
  418. $ret .= PMA_Util::showDocu('faq', $doc[0]);
  419. } else {
  420. $ret .= PMA_Util::showMySQLDocu(
  421. $doc[1]
  422. );
  423. }
  424. }
  425. }
  426. // Close the list element after $doc link is displayed
  427. if (isset($property_class)) {
  428. if ($property_class == 'BoolPropertyItem'
  429. || $property_class == 'MessageOnlyPropertyItem'
  430. || $property_class == 'SelectPropertyItem'
  431. || $property_class == 'TextPropertyItem'
  432. ) {
  433. $ret .= '</li>';
  434. }
  435. }
  436. $ret .= "\n";
  437. return $ret;
  438. }
  439. /**
  440. * Returns html div with editable options for plugin
  441. *
  442. * @param string $section name of config section in $GLOBALS['cfg'][$section]
  443. * @param array &$list array with plugin instances
  444. *
  445. * @return string html fieldset with plugin options
  446. */
  447. function PMA_pluginGetOptions($section, &$list)
  448. {
  449. $ret = '';
  450. // Options for plugins that support them
  451. foreach ($list as $plugin) {
  452. $properties = $plugin->getProperties();
  453. if ($properties != null) {
  454. $text = $properties->getText();
  455. $options = $properties->getOptions();
  456. }
  457. $plugin_name = strtolower(substr(get_class($plugin), strlen($section)));
  458. $ret .= '<div id="' . $plugin_name
  459. . '_options" class="format_specific_options">';
  460. $ret .= '<h3>' . PMA_getString($text) . '</h3>';
  461. $no_options = true;
  462. if ($options != null && count($options) > 0) {
  463. foreach ($options->getProperties()
  464. as $propertyMainGroup
  465. ) {
  466. // check for hidden properties
  467. $no_options = true;
  468. foreach ($propertyMainGroup->getProperties() as $propertyItem) {
  469. if (strcmp("HiddenPropertyItem", get_class($propertyItem))) {
  470. $no_options = false;
  471. break;
  472. }
  473. }
  474. $ret .= PMA_pluginGetOneOption(
  475. $section,
  476. $plugin_name,
  477. $propertyMainGroup
  478. );
  479. }
  480. }
  481. if ($no_options) {
  482. $ret .= '<p>' . __('This format has no options') . '</p>';
  483. }
  484. $ret .= '</div>';
  485. }
  486. return $ret;
  487. }