plugin_interface.lib.php 18 KB

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