ExportOdt.php 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * Set of functions used to build OpenDocument Text dumps of tables
  5. *
  6. * @package PhpMyAdmin-Export
  7. * @subpackage ODT
  8. */
  9. declare(strict_types=1);
  10. namespace PhpMyAdmin\Plugins\Export;
  11. use PhpMyAdmin\DatabaseInterface;
  12. use PhpMyAdmin\Export;
  13. use PhpMyAdmin\OpenDocument;
  14. use PhpMyAdmin\Plugins\ExportPlugin;
  15. use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup;
  16. use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup;
  17. use PhpMyAdmin\Properties\Options\Items\BoolPropertyItem;
  18. use PhpMyAdmin\Properties\Options\Items\RadioPropertyItem;
  19. use PhpMyAdmin\Properties\Options\Items\TextPropertyItem;
  20. use PhpMyAdmin\Properties\Plugins\ExportPluginProperties;
  21. use PhpMyAdmin\Transformations;
  22. use PhpMyAdmin\Util;
  23. /**
  24. * Handles the export for the ODT class
  25. *
  26. * @package PhpMyAdmin-Export
  27. * @subpackage ODT
  28. */
  29. class ExportOdt extends ExportPlugin
  30. {
  31. /**
  32. * Constructor
  33. */
  34. public function __construct()
  35. {
  36. parent::__construct();
  37. $GLOBALS['odt_buffer'] = '';
  38. $this->setProperties();
  39. }
  40. /**
  41. * Sets the export ODT properties
  42. *
  43. * @return void
  44. */
  45. protected function setProperties()
  46. {
  47. global $plugin_param;
  48. $hide_structure = false;
  49. if ($plugin_param['export_type'] == 'table'
  50. && ! $plugin_param['single_table']
  51. ) {
  52. $hide_structure = true;
  53. }
  54. $exportPluginProperties = new ExportPluginProperties();
  55. $exportPluginProperties->setText('OpenDocument Text');
  56. $exportPluginProperties->setExtension('odt');
  57. $exportPluginProperties->setMimeType(
  58. 'application/vnd.oasis.opendocument.text'
  59. );
  60. $exportPluginProperties->setForceFile(true);
  61. $exportPluginProperties->setOptionsText(__('Options'));
  62. // create the root group that will be the options field for
  63. // $exportPluginProperties
  64. // this will be shown as "Format specific options"
  65. $exportSpecificOptions = new OptionsPropertyRootGroup(
  66. "Format Specific Options"
  67. );
  68. // what to dump (structure/data/both) main group
  69. $dumpWhat = new OptionsPropertyMainGroup(
  70. "general_opts",
  71. __('Dump table')
  72. );
  73. // create primary items and add them to the group
  74. $leaf = new RadioPropertyItem("structure_or_data");
  75. $leaf->setValues(
  76. [
  77. 'structure' => __('structure'),
  78. 'data' => __('data'),
  79. 'structure_and_data' => __('structure and data'),
  80. ]
  81. );
  82. $dumpWhat->addProperty($leaf);
  83. // add the main group to the root group
  84. $exportSpecificOptions->addProperty($dumpWhat);
  85. // structure options main group
  86. if (! $hide_structure) {
  87. $structureOptions = new OptionsPropertyMainGroup(
  88. "structure",
  89. __('Object creation options')
  90. );
  91. $structureOptions->setForce('data');
  92. // create primary items and add them to the group
  93. if (! empty($GLOBALS['cfgRelation']['relation'])) {
  94. $leaf = new BoolPropertyItem(
  95. "relation",
  96. __('Display foreign key relationships')
  97. );
  98. $structureOptions->addProperty($leaf);
  99. }
  100. $leaf = new BoolPropertyItem(
  101. "comments",
  102. __('Display comments')
  103. );
  104. $structureOptions->addProperty($leaf);
  105. if (! empty($GLOBALS['cfgRelation']['mimework'])) {
  106. $leaf = new BoolPropertyItem(
  107. "mime",
  108. __('Display media (MIME) types')
  109. );
  110. $structureOptions->addProperty($leaf);
  111. }
  112. // add the main group to the root group
  113. $exportSpecificOptions->addProperty($structureOptions);
  114. }
  115. // data options main group
  116. $dataOptions = new OptionsPropertyMainGroup(
  117. "data",
  118. __('Data dump options')
  119. );
  120. $dataOptions->setForce('structure');
  121. // create primary items and add them to the group
  122. $leaf = new BoolPropertyItem(
  123. "columns",
  124. __('Put columns names in the first row')
  125. );
  126. $dataOptions->addProperty($leaf);
  127. $leaf = new TextPropertyItem(
  128. 'null',
  129. __('Replace NULL with:')
  130. );
  131. $dataOptions->addProperty($leaf);
  132. // add the main group to the root group
  133. $exportSpecificOptions->addProperty($dataOptions);
  134. // set the options for the export plugin property item
  135. $exportPluginProperties->setOptions($exportSpecificOptions);
  136. $this->properties = $exportPluginProperties;
  137. }
  138. /**
  139. * Outputs export header
  140. *
  141. * @return bool Whether it succeeded
  142. */
  143. public function exportHeader()
  144. {
  145. $GLOBALS['odt_buffer'] .= '<?xml version="1.0" encoding="utf-8"?' . '>'
  146. . '<office:document-content '
  147. . OpenDocument::NS . ' office:version="1.0">'
  148. . '<office:body>'
  149. . '<office:text>';
  150. return true;
  151. }
  152. /**
  153. * Outputs export footer
  154. *
  155. * @return bool Whether it succeeded
  156. */
  157. public function exportFooter()
  158. {
  159. $GLOBALS['odt_buffer'] .= '</office:text>'
  160. . '</office:body>'
  161. . '</office:document-content>';
  162. if (! $this->export->outputHandler(
  163. OpenDocument::create(
  164. 'application/vnd.oasis.opendocument.text',
  165. $GLOBALS['odt_buffer']
  166. )
  167. )
  168. ) {
  169. return false;
  170. }
  171. return true;
  172. }
  173. /**
  174. * Outputs database header
  175. *
  176. * @param string $db Database name
  177. * @param string $db_alias Aliases of db
  178. *
  179. * @return bool Whether it succeeded
  180. */
  181. public function exportDBHeader($db, $db_alias = '')
  182. {
  183. if (empty($db_alias)) {
  184. $db_alias = $db;
  185. }
  186. $GLOBALS['odt_buffer']
  187. .= '<text:h text:outline-level="1" text:style-name="Heading_1"'
  188. . ' text:is-list-header="true">'
  189. . __('Database') . ' ' . htmlspecialchars($db_alias)
  190. . '</text:h>';
  191. return true;
  192. }
  193. /**
  194. * Outputs database footer
  195. *
  196. * @param string $db Database name
  197. *
  198. * @return bool Whether it succeeded
  199. */
  200. public function exportDBFooter($db)
  201. {
  202. return true;
  203. }
  204. /**
  205. * Outputs CREATE DATABASE statement
  206. *
  207. * @param string $db Database name
  208. * @param string $export_type 'server', 'database', 'table'
  209. * @param string $db_alias Aliases of db
  210. *
  211. * @return bool Whether it succeeded
  212. */
  213. public function exportDBCreate($db, $export_type, $db_alias = '')
  214. {
  215. return true;
  216. }
  217. /**
  218. * Outputs the content of a table in NHibernate format
  219. *
  220. * @param string $db database name
  221. * @param string $table table name
  222. * @param string $crlf the end of line sequence
  223. * @param string $error_url the url to go back in case of error
  224. * @param string $sql_query SQL query for obtaining data
  225. * @param array $aliases Aliases of db/table/columns
  226. *
  227. * @return bool Whether it succeeded
  228. */
  229. public function exportData(
  230. $db,
  231. $table,
  232. $crlf,
  233. $error_url,
  234. $sql_query,
  235. array $aliases = []
  236. ) {
  237. global $what;
  238. $db_alias = $db;
  239. $table_alias = $table;
  240. $this->initAlias($aliases, $db_alias, $table_alias);
  241. // Gets the data from the database
  242. $result = $GLOBALS['dbi']->query(
  243. $sql_query,
  244. DatabaseInterface::CONNECT_USER,
  245. DatabaseInterface::QUERY_UNBUFFERED
  246. );
  247. $fields_cnt = $GLOBALS['dbi']->numFields($result);
  248. $fields_meta = $GLOBALS['dbi']->getFieldsMeta($result);
  249. $field_flags = [];
  250. for ($j = 0; $j < $fields_cnt; $j++) {
  251. $field_flags[$j] = $GLOBALS['dbi']->fieldFlags($result, $j);
  252. }
  253. $GLOBALS['odt_buffer']
  254. .= '<text:h text:outline-level="2" text:style-name="Heading_2"'
  255. . ' text:is-list-header="true">'
  256. . __('Dumping data for table') . ' ' . htmlspecialchars($table_alias)
  257. . '</text:h>'
  258. . '<table:table'
  259. . ' table:name="' . htmlspecialchars($table_alias) . '_structure">'
  260. . '<table:table-column'
  261. . ' table:number-columns-repeated="' . $fields_cnt . '"/>';
  262. // If required, get fields name at the first line
  263. if (isset($GLOBALS[$what . '_columns'])) {
  264. $GLOBALS['odt_buffer'] .= '<table:table-row>';
  265. for ($i = 0; $i < $fields_cnt; $i++) {
  266. $col_as = $GLOBALS['dbi']->fieldName($result, $i);
  267. if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) {
  268. $col_as = $aliases[$db]['tables'][$table]['columns'][$col_as];
  269. }
  270. $GLOBALS['odt_buffer']
  271. .= '<table:table-cell office:value-type="string">'
  272. . '<text:p>'
  273. . htmlspecialchars(
  274. stripslashes($col_as)
  275. )
  276. . '</text:p>'
  277. . '</table:table-cell>';
  278. } // end for
  279. $GLOBALS['odt_buffer'] .= '</table:table-row>';
  280. } // end if
  281. // Format the data
  282. while ($row = $GLOBALS['dbi']->fetchRow($result)) {
  283. $GLOBALS['odt_buffer'] .= '<table:table-row>';
  284. for ($j = 0; $j < $fields_cnt; $j++) {
  285. if ($fields_meta[$j]->type === 'geometry') {
  286. // export GIS types as hex
  287. $row[$j] = '0x' . bin2hex($row[$j]);
  288. }
  289. if (! isset($row[$j]) || $row[$j] === null) {
  290. $GLOBALS['odt_buffer']
  291. .= '<table:table-cell office:value-type="string">'
  292. . '<text:p>'
  293. . htmlspecialchars($GLOBALS[$what . '_null'])
  294. . '</text:p>'
  295. . '</table:table-cell>';
  296. } elseif (false !== stripos($field_flags[$j], 'BINARY')
  297. && $fields_meta[$j]->blob
  298. ) {
  299. // ignore BLOB
  300. $GLOBALS['odt_buffer']
  301. .= '<table:table-cell office:value-type="string">'
  302. . '<text:p></text:p>'
  303. . '</table:table-cell>';
  304. } elseif ($fields_meta[$j]->numeric
  305. && $fields_meta[$j]->type != 'timestamp'
  306. && ! $fields_meta[$j]->blob
  307. ) {
  308. $GLOBALS['odt_buffer']
  309. .= '<table:table-cell office:value-type="float"'
  310. . ' office:value="' . $row[$j] . '" >'
  311. . '<text:p>'
  312. . htmlspecialchars($row[$j])
  313. . '</text:p>'
  314. . '</table:table-cell>';
  315. } else {
  316. $GLOBALS['odt_buffer']
  317. .= '<table:table-cell office:value-type="string">'
  318. . '<text:p>'
  319. . htmlspecialchars($row[$j])
  320. . '</text:p>'
  321. . '</table:table-cell>';
  322. }
  323. } // end for
  324. $GLOBALS['odt_buffer'] .= '</table:table-row>';
  325. } // end while
  326. $GLOBALS['dbi']->freeResult($result);
  327. $GLOBALS['odt_buffer'] .= '</table:table>';
  328. return true;
  329. }
  330. /**
  331. * Returns a stand-in CREATE definition to resolve view dependencies
  332. *
  333. * @param string $db the database name
  334. * @param string $view the view name
  335. * @param string $crlf the end of line sequence
  336. * @param array $aliases Aliases of db/table/columns
  337. *
  338. * @return string resulting definition
  339. */
  340. public function getTableDefStandIn($db, $view, $crlf, $aliases = [])
  341. {
  342. $db_alias = $db;
  343. $view_alias = $view;
  344. $this->initAlias($aliases, $db_alias, $view_alias);
  345. /**
  346. * Gets fields properties
  347. */
  348. $GLOBALS['dbi']->selectDb($db);
  349. /**
  350. * Displays the table structure
  351. */
  352. $GLOBALS['odt_buffer']
  353. .= '<table:table table:name="'
  354. . htmlspecialchars($view_alias) . '_data">';
  355. $columns_cnt = 4;
  356. $GLOBALS['odt_buffer']
  357. .= '<table:table-column'
  358. . ' table:number-columns-repeated="' . $columns_cnt . '"/>';
  359. /* Header */
  360. $GLOBALS['odt_buffer'] .= '<table:table-row>'
  361. . '<table:table-cell office:value-type="string">'
  362. . '<text:p>' . __('Column') . '</text:p>'
  363. . '</table:table-cell>'
  364. . '<table:table-cell office:value-type="string">'
  365. . '<text:p>' . __('Type') . '</text:p>'
  366. . '</table:table-cell>'
  367. . '<table:table-cell office:value-type="string">'
  368. . '<text:p>' . __('Null') . '</text:p>'
  369. . '</table:table-cell>'
  370. . '<table:table-cell office:value-type="string">'
  371. . '<text:p>' . __('Default') . '</text:p>'
  372. . '</table:table-cell>'
  373. . '</table:table-row>';
  374. $columns = $GLOBALS['dbi']->getColumns($db, $view);
  375. foreach ($columns as $column) {
  376. $col_as = $column['Field'] ?? null;
  377. if (! empty($aliases[$db]['tables'][$view]['columns'][$col_as])) {
  378. $col_as = $aliases[$db]['tables'][$view]['columns'][$col_as];
  379. }
  380. $GLOBALS['odt_buffer'] .= $this->formatOneColumnDefinition(
  381. $column,
  382. $col_as
  383. );
  384. $GLOBALS['odt_buffer'] .= '</table:table-row>';
  385. } // end foreach
  386. $GLOBALS['odt_buffer'] .= '</table:table>';
  387. return '';
  388. }
  389. /**
  390. * Returns $table's CREATE definition
  391. *
  392. * @param string $db the database name
  393. * @param string $table the table name
  394. * @param string $crlf the end of line sequence
  395. * @param string $error_url the url to go back in case of error
  396. * @param bool $do_relation whether to include relation comments
  397. * @param bool $do_comments whether to include the pmadb-style column
  398. * comments as comments in the structure;
  399. * this is deprecated but the parameter is
  400. * left here because export.php calls
  401. * PMA_exportStructure() also for other
  402. * @param bool $do_mime whether to include mime comments
  403. * @param bool $show_dates whether to include creation/update/check dates
  404. * @param bool $add_semicolon whether to add semicolon and end-of-line at
  405. * the end
  406. * @param bool $view whether we're handling a view
  407. * @param array $aliases Aliases of db/table/columns
  408. *
  409. * @return bool true
  410. */
  411. public function getTableDef(
  412. $db,
  413. $table,
  414. $crlf,
  415. $error_url,
  416. $do_relation,
  417. $do_comments,
  418. $do_mime,
  419. $show_dates = false,
  420. $add_semicolon = true,
  421. $view = false,
  422. array $aliases = []
  423. ) {
  424. global $cfgRelation;
  425. $db_alias = $db;
  426. $table_alias = $table;
  427. $this->initAlias($aliases, $db_alias, $table_alias);
  428. /**
  429. * Gets fields properties
  430. */
  431. $GLOBALS['dbi']->selectDb($db);
  432. // Check if we can use Relations
  433. list($res_rel, $have_rel) = $this->relation->getRelationsAndStatus(
  434. $do_relation && ! empty($cfgRelation['relation']),
  435. $db,
  436. $table
  437. );
  438. /**
  439. * Displays the table structure
  440. */
  441. $GLOBALS['odt_buffer'] .= '<table:table table:name="'
  442. . htmlspecialchars($table_alias) . '_structure">';
  443. $columns_cnt = 4;
  444. if ($do_relation && $have_rel) {
  445. $columns_cnt++;
  446. }
  447. if ($do_comments) {
  448. $columns_cnt++;
  449. }
  450. if ($do_mime && $cfgRelation['mimework']) {
  451. $columns_cnt++;
  452. }
  453. $GLOBALS['odt_buffer'] .= '<table:table-column'
  454. . ' table:number-columns-repeated="' . $columns_cnt . '"/>';
  455. /* Header */
  456. $GLOBALS['odt_buffer'] .= '<table:table-row>'
  457. . '<table:table-cell office:value-type="string">'
  458. . '<text:p>' . __('Column') . '</text:p>'
  459. . '</table:table-cell>'
  460. . '<table:table-cell office:value-type="string">'
  461. . '<text:p>' . __('Type') . '</text:p>'
  462. . '</table:table-cell>'
  463. . '<table:table-cell office:value-type="string">'
  464. . '<text:p>' . __('Null') . '</text:p>'
  465. . '</table:table-cell>'
  466. . '<table:table-cell office:value-type="string">'
  467. . '<text:p>' . __('Default') . '</text:p>'
  468. . '</table:table-cell>';
  469. if ($do_relation && $have_rel) {
  470. $GLOBALS['odt_buffer'] .= '<table:table-cell office:value-type="string">'
  471. . '<text:p>' . __('Links to') . '</text:p>'
  472. . '</table:table-cell>';
  473. }
  474. if ($do_comments) {
  475. $GLOBALS['odt_buffer'] .= '<table:table-cell office:value-type="string">'
  476. . '<text:p>' . __('Comments') . '</text:p>'
  477. . '</table:table-cell>';
  478. $comments = $this->relation->getComments($db, $table);
  479. }
  480. if ($do_mime && $cfgRelation['mimework']) {
  481. $GLOBALS['odt_buffer'] .= '<table:table-cell office:value-type="string">'
  482. . '<text:p>' . __('Media (MIME) type') . '</text:p>'
  483. . '</table:table-cell>';
  484. $mime_map = $this->transformations->getMime($db, $table, true);
  485. }
  486. $GLOBALS['odt_buffer'] .= '</table:table-row>';
  487. $columns = $GLOBALS['dbi']->getColumns($db, $table);
  488. foreach ($columns as $column) {
  489. $col_as = $field_name = $column['Field'];
  490. if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) {
  491. $col_as = $aliases[$db]['tables'][$table]['columns'][$col_as];
  492. }
  493. $GLOBALS['odt_buffer'] .= $this->formatOneColumnDefinition(
  494. $column,
  495. $col_as
  496. );
  497. if ($do_relation && $have_rel) {
  498. $foreigner = $this->relation->searchColumnInForeigners($res_rel, $field_name);
  499. if ($foreigner) {
  500. $rtable = $foreigner['foreign_table'];
  501. $rfield = $foreigner['foreign_field'];
  502. if (! empty($aliases[$db]['tables'][$rtable]['columns'][$rfield])
  503. ) {
  504. $rfield
  505. = $aliases[$db]['tables'][$rtable]['columns'][$rfield];
  506. }
  507. if (! empty($aliases[$db]['tables'][$rtable]['alias'])) {
  508. $rtable = $aliases[$db]['tables'][$rtable]['alias'];
  509. }
  510. $relation = htmlspecialchars($rtable . ' (' . $rfield . ')');
  511. $GLOBALS['odt_buffer']
  512. .= '<table:table-cell office:value-type="string">'
  513. . '<text:p>'
  514. . htmlspecialchars($relation)
  515. . '</text:p>'
  516. . '</table:table-cell>';
  517. }
  518. }
  519. if ($do_comments) {
  520. if (isset($comments[$field_name])) {
  521. $GLOBALS['odt_buffer']
  522. .= '<table:table-cell office:value-type="string">'
  523. . '<text:p>'
  524. . htmlspecialchars($comments[$field_name])
  525. . '</text:p>'
  526. . '</table:table-cell>';
  527. } else {
  528. $GLOBALS['odt_buffer']
  529. .= '<table:table-cell office:value-type="string">'
  530. . '<text:p></text:p>'
  531. . '</table:table-cell>';
  532. }
  533. }
  534. if ($do_mime && $cfgRelation['mimework']) {
  535. if (isset($mime_map[$field_name])) {
  536. $GLOBALS['odt_buffer']
  537. .= '<table:table-cell office:value-type="string">'
  538. . '<text:p>'
  539. . htmlspecialchars(
  540. str_replace('_', '/', $mime_map[$field_name]['mimetype'])
  541. )
  542. . '</text:p>'
  543. . '</table:table-cell>';
  544. } else {
  545. $GLOBALS['odt_buffer']
  546. .= '<table:table-cell office:value-type="string">'
  547. . '<text:p></text:p>'
  548. . '</table:table-cell>';
  549. }
  550. }
  551. $GLOBALS['odt_buffer'] .= '</table:table-row>';
  552. } // end foreach
  553. $GLOBALS['odt_buffer'] .= '</table:table>';
  554. return true;
  555. } // end of the '$this->getTableDef()' function
  556. /**
  557. * Outputs triggers
  558. *
  559. * @param string $db database name
  560. * @param string $table table name
  561. * @param array $aliases Aliases of db/table/columns
  562. *
  563. * @return bool true
  564. */
  565. protected function getTriggers($db, $table, array $aliases = [])
  566. {
  567. $db_alias = $db;
  568. $table_alias = $table;
  569. $this->initAlias($aliases, $db_alias, $table_alias);
  570. $GLOBALS['odt_buffer'] .= '<table:table'
  571. . ' table:name="' . htmlspecialchars($table_alias) . '_triggers">'
  572. . '<table:table-column'
  573. . ' table:number-columns-repeated="4"/>'
  574. . '<table:table-row>'
  575. . '<table:table-cell office:value-type="string">'
  576. . '<text:p>' . __('Name') . '</text:p>'
  577. . '</table:table-cell>'
  578. . '<table:table-cell office:value-type="string">'
  579. . '<text:p>' . __('Time') . '</text:p>'
  580. . '</table:table-cell>'
  581. . '<table:table-cell office:value-type="string">'
  582. . '<text:p>' . __('Event') . '</text:p>'
  583. . '</table:table-cell>'
  584. . '<table:table-cell office:value-type="string">'
  585. . '<text:p>' . __('Definition') . '</text:p>'
  586. . '</table:table-cell>'
  587. . '</table:table-row>';
  588. $triggers = $GLOBALS['dbi']->getTriggers($db, $table);
  589. foreach ($triggers as $trigger) {
  590. $GLOBALS['odt_buffer'] .= '<table:table-row>';
  591. $GLOBALS['odt_buffer'] .= '<table:table-cell office:value-type="string">'
  592. . '<text:p>'
  593. . htmlspecialchars($trigger['name'])
  594. . '</text:p>'
  595. . '</table:table-cell>';
  596. $GLOBALS['odt_buffer'] .= '<table:table-cell office:value-type="string">'
  597. . '<text:p>'
  598. . htmlspecialchars($trigger['action_timing'])
  599. . '</text:p>'
  600. . '</table:table-cell>';
  601. $GLOBALS['odt_buffer'] .= '<table:table-cell office:value-type="string">'
  602. . '<text:p>'
  603. . htmlspecialchars($trigger['event_manipulation'])
  604. . '</text:p>'
  605. . '</table:table-cell>';
  606. $GLOBALS['odt_buffer'] .= '<table:table-cell office:value-type="string">'
  607. . '<text:p>'
  608. . htmlspecialchars($trigger['definition'])
  609. . '</text:p>'
  610. . '</table:table-cell>';
  611. $GLOBALS['odt_buffer'] .= '</table:table-row>';
  612. }
  613. $GLOBALS['odt_buffer'] .= '</table:table>';
  614. return true;
  615. }
  616. /**
  617. * Outputs table's structure
  618. *
  619. * @param string $db database name
  620. * @param string $table table name
  621. * @param string $crlf the end of line sequence
  622. * @param string $error_url the url to go back in case of error
  623. * @param string $export_mode 'create_table', 'triggers', 'create_view',
  624. * 'stand_in'
  625. * @param string $export_type 'server', 'database', 'table'
  626. * @param bool $do_relation whether to include relation comments
  627. * @param bool $do_comments whether to include the pmadb-style column
  628. * comments as comments in the structure;
  629. * this is deprecated but the parameter is
  630. * left here because export.php calls
  631. * PMA_exportStructure() also for other
  632. * @param bool $do_mime whether to include mime comments
  633. * @param bool $dates whether to include creation/update/check dates
  634. * @param array $aliases Aliases of db/table/columns
  635. *
  636. * @return bool Whether it succeeded
  637. */
  638. public function exportStructure(
  639. $db,
  640. $table,
  641. $crlf,
  642. $error_url,
  643. $export_mode,
  644. $export_type,
  645. $do_relation = false,
  646. $do_comments = false,
  647. $do_mime = false,
  648. $dates = false,
  649. array $aliases = []
  650. ) {
  651. $db_alias = $db;
  652. $table_alias = $table;
  653. $this->initAlias($aliases, $db_alias, $table_alias);
  654. switch ($export_mode) {
  655. case 'create_table':
  656. $GLOBALS['odt_buffer']
  657. .= '<text:h text:outline-level="2" text:style-name="Heading_2"'
  658. . ' text:is-list-header="true">'
  659. . __('Table structure for table') . ' ' .
  660. htmlspecialchars($table_alias)
  661. . '</text:h>';
  662. $this->getTableDef(
  663. $db,
  664. $table,
  665. $crlf,
  666. $error_url,
  667. $do_relation,
  668. $do_comments,
  669. $do_mime,
  670. $dates,
  671. true,
  672. false,
  673. $aliases
  674. );
  675. break;
  676. case 'triggers':
  677. $triggers = $GLOBALS['dbi']->getTriggers($db, $table, $aliases);
  678. if ($triggers) {
  679. $GLOBALS['odt_buffer']
  680. .= '<text:h text:outline-level="2" text:style-name="Heading_2"'
  681. . ' text:is-list-header="true">'
  682. . __('Triggers') . ' '
  683. . htmlspecialchars($table_alias)
  684. . '</text:h>';
  685. $this->getTriggers($db, $table);
  686. }
  687. break;
  688. case 'create_view':
  689. $GLOBALS['odt_buffer']
  690. .= '<text:h text:outline-level="2" text:style-name="Heading_2"'
  691. . ' text:is-list-header="true">'
  692. . __('Structure for view') . ' '
  693. . htmlspecialchars($table_alias)
  694. . '</text:h>';
  695. $this->getTableDef(
  696. $db,
  697. $table,
  698. $crlf,
  699. $error_url,
  700. $do_relation,
  701. $do_comments,
  702. $do_mime,
  703. $dates,
  704. true,
  705. true,
  706. $aliases
  707. );
  708. break;
  709. case 'stand_in':
  710. $GLOBALS['odt_buffer']
  711. .= '<text:h text:outline-level="2" text:style-name="Heading_2"'
  712. . ' text:is-list-header="true">'
  713. . __('Stand-in structure for view') . ' '
  714. . htmlspecialchars($table_alias)
  715. . '</text:h>';
  716. // export a stand-in definition to resolve view dependencies
  717. $this->getTableDefStandIn($db, $table, $crlf, $aliases);
  718. } // end switch
  719. return true;
  720. } // end of the '$this->exportStructure' function
  721. /**
  722. * Formats the definition for one column
  723. *
  724. * @param array $column info about this column
  725. * @param string $col_as column alias
  726. *
  727. * @return string Formatted column definition
  728. */
  729. protected function formatOneColumnDefinition($column, $col_as = '')
  730. {
  731. if (empty($col_as)) {
  732. $col_as = $column['Field'];
  733. }
  734. $definition = '<table:table-row>';
  735. $definition .= '<table:table-cell office:value-type="string">'
  736. . '<text:p>' . htmlspecialchars($col_as) . '</text:p>'
  737. . '</table:table-cell>';
  738. $extracted_columnspec
  739. = Util::extractColumnSpec($column['Type']);
  740. $type = htmlspecialchars($extracted_columnspec['print_type']);
  741. if (empty($type)) {
  742. $type = '&nbsp;';
  743. }
  744. $definition .= '<table:table-cell office:value-type="string">'
  745. . '<text:p>' . htmlspecialchars($type) . '</text:p>'
  746. . '</table:table-cell>';
  747. if (! isset($column['Default'])) {
  748. if ($column['Null'] != 'NO') {
  749. $column['Default'] = 'NULL';
  750. } else {
  751. $column['Default'] = '';
  752. }
  753. }
  754. $definition .= '<table:table-cell office:value-type="string">'
  755. . '<text:p>'
  756. . (($column['Null'] == '' || $column['Null'] == 'NO')
  757. ? __('No')
  758. : __('Yes'))
  759. . '</text:p>'
  760. . '</table:table-cell>';
  761. $definition .= '<table:table-cell office:value-type="string">'
  762. . '<text:p>' . htmlspecialchars($column['Default']) . '</text:p>'
  763. . '</table:table-cell>';
  764. return $definition;
  765. }
  766. }