ExportHtmlword.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * HTML-Word export code
  5. *
  6. * @package PhpMyAdmin-Export
  7. * @subpackage HTML-Word
  8. */
  9. namespace PhpMyAdmin\Plugins\Export;
  10. use PhpMyAdmin\DatabaseInterface;
  11. use PhpMyAdmin\Export;
  12. use PhpMyAdmin\Plugins\ExportPlugin;
  13. use PhpMyAdmin\Properties\Plugins\ExportPluginProperties;
  14. use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup;
  15. use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup;
  16. use PhpMyAdmin\Properties\Options\Items\BoolPropertyItem;
  17. use PhpMyAdmin\Properties\Options\Items\RadioPropertyItem;
  18. use PhpMyAdmin\Properties\Options\Items\TextPropertyItem;
  19. use PhpMyAdmin\Relation;
  20. use PhpMyAdmin\Transformations;
  21. use PhpMyAdmin\Util;
  22. /**
  23. * Handles the export for the HTML-Word format
  24. *
  25. * @package PhpMyAdmin-Export
  26. * @subpackage HTML-Word
  27. */
  28. class ExportHtmlword extends ExportPlugin
  29. {
  30. /**
  31. * Constructor
  32. */
  33. public function __construct()
  34. {
  35. parent::__construct();
  36. $this->setProperties();
  37. }
  38. /**
  39. * Sets the export HTML-Word properties
  40. *
  41. * @return void
  42. */
  43. protected function setProperties()
  44. {
  45. $exportPluginProperties = new ExportPluginProperties();
  46. $exportPluginProperties->setText('Microsoft Word 2000');
  47. $exportPluginProperties->setExtension('doc');
  48. $exportPluginProperties->setMimeType('application/vnd.ms-word');
  49. $exportPluginProperties->setForceFile(true);
  50. $exportPluginProperties->setOptionsText(__('Options'));
  51. // create the root group that will be the options field for
  52. // $exportPluginProperties
  53. // this will be shown as "Format specific options"
  54. $exportSpecificOptions = new OptionsPropertyRootGroup(
  55. "Format Specific Options"
  56. );
  57. // what to dump (structure/data/both)
  58. $dumpWhat = new OptionsPropertyMainGroup(
  59. "dump_what", __('Dump table')
  60. );
  61. // create primary items and add them to the group
  62. $leaf = new RadioPropertyItem("structure_or_data");
  63. $leaf->setValues(
  64. array(
  65. 'structure' => __('structure'),
  66. 'data' => __('data'),
  67. 'structure_and_data' => __('structure and data'),
  68. )
  69. );
  70. $dumpWhat->addProperty($leaf);
  71. // add the main group to the root group
  72. $exportSpecificOptions->addProperty($dumpWhat);
  73. // data options main group
  74. $dataOptions = new OptionsPropertyMainGroup(
  75. "dump_what", __('Data dump options')
  76. );
  77. $dataOptions->setForce('structure');
  78. // create primary items and add them to the group
  79. $leaf = new TextPropertyItem(
  80. "null",
  81. __('Replace NULL with:')
  82. );
  83. $dataOptions->addProperty($leaf);
  84. $leaf = new BoolPropertyItem(
  85. "columns",
  86. __('Put columns names in the first row')
  87. );
  88. $dataOptions->addProperty($leaf);
  89. // add the main group to the root group
  90. $exportSpecificOptions->addProperty($dataOptions);
  91. // set the options for the export plugin property item
  92. $exportPluginProperties->setOptions($exportSpecificOptions);
  93. $this->properties = $exportPluginProperties;
  94. }
  95. /**
  96. * Outputs export header
  97. *
  98. * @return bool Whether it succeeded
  99. */
  100. public function exportHeader()
  101. {
  102. global $charset;
  103. return Export::outputHandler(
  104. '<html xmlns:o="urn:schemas-microsoft-com:office:office"
  105. xmlns:x="urn:schemas-microsoft-com:office:word"
  106. xmlns="http://www.w3.org/TR/REC-html40">
  107. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"'
  108. . ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  109. <html>
  110. <head>
  111. <meta http-equiv="Content-type" content="text/html;charset='
  112. . (isset($charset) ? $charset : 'utf-8') . '" />
  113. </head>
  114. <body>'
  115. );
  116. }
  117. /**
  118. * Outputs export footer
  119. *
  120. * @return bool Whether it succeeded
  121. */
  122. public function exportFooter()
  123. {
  124. return Export::outputHandler('</body></html>');
  125. }
  126. /**
  127. * Outputs database header
  128. *
  129. * @param string $db Database name
  130. * @param string $db_alias Aliases of db
  131. *
  132. * @return bool Whether it succeeded
  133. */
  134. public function exportDBHeader($db, $db_alias = '')
  135. {
  136. if (empty($db_alias)) {
  137. $db_alias = $db;
  138. }
  139. return Export::outputHandler(
  140. '<h1>' . __('Database') . ' ' . htmlspecialchars($db_alias) . '</h1>'
  141. );
  142. }
  143. /**
  144. * Outputs database footer
  145. *
  146. * @param string $db Database name
  147. *
  148. * @return bool Whether it succeeded
  149. */
  150. public function exportDBFooter($db)
  151. {
  152. return true;
  153. }
  154. /**
  155. * Outputs CREATE DATABASE statement
  156. *
  157. * @param string $db Database name
  158. * @param string $export_type 'server', 'database', 'table'
  159. * @param string $db_alias Aliases of db
  160. *
  161. * @return bool Whether it succeeded
  162. */
  163. public function exportDBCreate($db, $export_type, $db_alias = '')
  164. {
  165. return true;
  166. }
  167. /**
  168. * Outputs the content of a table in HTML-Word format
  169. *
  170. * @param string $db database name
  171. * @param string $table table name
  172. * @param string $crlf the end of line sequence
  173. * @param string $error_url the url to go back in case of error
  174. * @param string $sql_query SQL query for obtaining data
  175. * @param array $aliases Aliases of db/table/columns
  176. *
  177. * @return bool Whether it succeeded
  178. */
  179. public function exportData(
  180. $db,
  181. $table,
  182. $crlf,
  183. $error_url,
  184. $sql_query,
  185. array $aliases = array()
  186. ) {
  187. global $what;
  188. $db_alias = $db;
  189. $table_alias = $table;
  190. $this->initAlias($aliases, $db_alias, $table_alias);
  191. if (!Export::outputHandler(
  192. '<h2>'
  193. . __('Dumping data for table') . ' ' . htmlspecialchars($table_alias)
  194. . '</h2>'
  195. )
  196. ) {
  197. return false;
  198. }
  199. if (!Export::outputHandler(
  200. '<table class="width100" cellspacing="1">'
  201. )
  202. ) {
  203. return false;
  204. }
  205. // Gets the data from the database
  206. $result = $GLOBALS['dbi']->query(
  207. $sql_query,
  208. DatabaseInterface::CONNECT_USER,
  209. DatabaseInterface::QUERY_UNBUFFERED
  210. );
  211. $fields_cnt = $GLOBALS['dbi']->numFields($result);
  212. // If required, get fields name at the first line
  213. if (isset($GLOBALS['htmlword_columns'])) {
  214. $schema_insert = '<tr class="print-category">';
  215. for ($i = 0; $i < $fields_cnt; $i++) {
  216. $col_as = $GLOBALS['dbi']->fieldName($result, $i);
  217. if (!empty($aliases[$db]['tables'][$table]['columns'][$col_as])) {
  218. $col_as = $aliases[$db]['tables'][$table]['columns'][$col_as];
  219. }
  220. $col_as = stripslashes($col_as);
  221. $schema_insert .= '<td class="print"><strong>'
  222. . htmlspecialchars($col_as)
  223. . '</strong></td>';
  224. } // end for
  225. $schema_insert .= '</tr>';
  226. if (!Export::outputHandler($schema_insert)) {
  227. return false;
  228. }
  229. } // end if
  230. // Format the data
  231. while ($row = $GLOBALS['dbi']->fetchRow($result)) {
  232. $schema_insert = '<tr class="print-category">';
  233. for ($j = 0; $j < $fields_cnt; $j++) {
  234. if (!isset($row[$j]) || is_null($row[$j])) {
  235. $value = $GLOBALS[$what . '_null'];
  236. } elseif ($row[$j] == '0' || $row[$j] != '') {
  237. $value = $row[$j];
  238. } else {
  239. $value = '';
  240. }
  241. $schema_insert .= '<td class="print">'
  242. . htmlspecialchars($value)
  243. . '</td>';
  244. } // end for
  245. $schema_insert .= '</tr>';
  246. if (!Export::outputHandler($schema_insert)) {
  247. return false;
  248. }
  249. } // end while
  250. $GLOBALS['dbi']->freeResult($result);
  251. return Export::outputHandler('</table>');
  252. }
  253. /**
  254. * Returns a stand-in CREATE definition to resolve view dependencies
  255. *
  256. * @param string $db the database name
  257. * @param string $view the view name
  258. * @param string $crlf the end of line sequence
  259. * @param array $aliases Aliases of db/table/columns
  260. *
  261. * @return string resulting definition
  262. */
  263. public function getTableDefStandIn($db, $view, $crlf, $aliases = array())
  264. {
  265. $schema_insert = '<table class="width100" cellspacing="1">'
  266. . '<tr class="print-category">'
  267. . '<th class="print">'
  268. . __('Column')
  269. . '</th>'
  270. . '<td class="print"><strong>'
  271. . __('Type')
  272. . '</strong></td>'
  273. . '<td class="print"><strong>'
  274. . __('Null')
  275. . '</strong></td>'
  276. . '<td class="print"><strong>'
  277. . __('Default')
  278. . '</strong></td>'
  279. . '</tr>';
  280. /**
  281. * Get the unique keys in the view
  282. */
  283. $unique_keys = array();
  284. $keys = $GLOBALS['dbi']->getTableIndexes($db, $view);
  285. foreach ($keys as $key) {
  286. if ($key['Non_unique'] == 0) {
  287. $unique_keys[] = $key['Column_name'];
  288. }
  289. }
  290. $columns = $GLOBALS['dbi']->getColumns($db, $view);
  291. foreach ($columns as $column) {
  292. $col_as = $column['Field'];
  293. if (!empty($aliases[$db]['tables'][$view]['columns'][$col_as])) {
  294. $col_as = $aliases[$db]['tables'][$view]['columns'][$col_as];
  295. }
  296. $schema_insert .= $this->formatOneColumnDefinition(
  297. $column,
  298. $unique_keys,
  299. $col_as
  300. );
  301. $schema_insert .= '</tr>';
  302. }
  303. $schema_insert .= '</table>';
  304. return $schema_insert;
  305. }
  306. /**
  307. * Returns $table's CREATE definition
  308. *
  309. * @param string $db the database name
  310. * @param string $table the table name
  311. * @param bool $do_relation whether to include relation comments
  312. * @param bool $do_comments whether to include the pmadb-style column
  313. * comments as comments in the structure;
  314. * this is deprecated but the parameter is
  315. * left here because export.php calls
  316. * PMA_exportStructure() also for other
  317. * export types which use this parameter
  318. * @param bool $do_mime whether to include mime comments
  319. * at the end
  320. * @param bool $view whether we're handling a view
  321. * @param array $aliases Aliases of db/table/columns
  322. *
  323. * @return string resulting schema
  324. */
  325. public function getTableDef(
  326. $db,
  327. $table,
  328. $do_relation,
  329. $do_comments,
  330. $do_mime,
  331. $view = false,
  332. array $aliases = array()
  333. ) {
  334. // set $cfgRelation here, because there is a chance that it's modified
  335. // since the class initialization
  336. global $cfgRelation;
  337. $schema_insert = '';
  338. /**
  339. * Gets fields properties
  340. */
  341. $GLOBALS['dbi']->selectDb($db);
  342. // Check if we can use Relations
  343. list($res_rel, $have_rel) = $this->relation->getRelationsAndStatus(
  344. $do_relation && !empty($cfgRelation['relation']),
  345. $db,
  346. $table
  347. );
  348. /**
  349. * Displays the table structure
  350. */
  351. $schema_insert .= '<table class="width100" cellspacing="1">';
  352. $schema_insert .= '<tr class="print-category">';
  353. $schema_insert .= '<th class="print">'
  354. . __('Column')
  355. . '</th>';
  356. $schema_insert .= '<td class="print"><strong>'
  357. . __('Type')
  358. . '</strong></td>';
  359. $schema_insert .= '<td class="print"><strong>'
  360. . __('Null')
  361. . '</strong></td>';
  362. $schema_insert .= '<td class="print"><strong>'
  363. . __('Default')
  364. . '</strong></td>';
  365. if ($do_relation && $have_rel) {
  366. $schema_insert .= '<td class="print"><strong>'
  367. . __('Links to')
  368. . '</strong></td>';
  369. }
  370. if ($do_comments) {
  371. $schema_insert .= '<td class="print"><strong>'
  372. . __('Comments')
  373. . '</strong></td>';
  374. $comments = $this->relation->getComments($db, $table);
  375. }
  376. if ($do_mime && $cfgRelation['mimework']) {
  377. $schema_insert .= '<td class="print"><strong>'
  378. . htmlspecialchars('MIME')
  379. . '</strong></td>';
  380. $mime_map = Transformations::getMIME($db, $table, true);
  381. }
  382. $schema_insert .= '</tr>';
  383. $columns = $GLOBALS['dbi']->getColumns($db, $table);
  384. /**
  385. * Get the unique keys in the table
  386. */
  387. $unique_keys = array();
  388. $keys = $GLOBALS['dbi']->getTableIndexes($db, $table);
  389. foreach ($keys as $key) {
  390. if ($key['Non_unique'] == 0) {
  391. $unique_keys[] = $key['Column_name'];
  392. }
  393. }
  394. foreach ($columns as $column) {
  395. $col_as = $column['Field'];
  396. if (!empty($aliases[$db]['tables'][$table]['columns'][$col_as])) {
  397. $col_as = $aliases[$db]['tables'][$table]['columns'][$col_as];
  398. }
  399. $schema_insert .= $this->formatOneColumnDefinition(
  400. $column,
  401. $unique_keys,
  402. $col_as
  403. );
  404. $field_name = $column['Field'];
  405. if ($do_relation && $have_rel) {
  406. $schema_insert .= '<td class="print">'
  407. . htmlspecialchars(
  408. $this->getRelationString(
  409. $res_rel,
  410. $field_name,
  411. $db,
  412. $aliases
  413. )
  414. )
  415. . '</td>';
  416. }
  417. if ($do_comments && $cfgRelation['commwork']) {
  418. $schema_insert .= '<td class="print">'
  419. . (isset($comments[$field_name])
  420. ? htmlspecialchars($comments[$field_name])
  421. : '') . '</td>';
  422. }
  423. if ($do_mime && $cfgRelation['mimework']) {
  424. $schema_insert .= '<td class="print">'
  425. . (isset($mime_map[$field_name]) ?
  426. htmlspecialchars(
  427. str_replace('_', '/', $mime_map[$field_name]['mimetype'])
  428. )
  429. : '') . '</td>';
  430. }
  431. $schema_insert .= '</tr>';
  432. } // end foreach
  433. $schema_insert .= '</table>';
  434. return $schema_insert;
  435. }
  436. /**
  437. * Outputs triggers
  438. *
  439. * @param string $db database name
  440. * @param string $table table name
  441. *
  442. * @return string Formatted triggers list
  443. */
  444. protected function getTriggers($db, $table)
  445. {
  446. $dump = '<table class="width100" cellspacing="1">';
  447. $dump .= '<tr class="print-category">';
  448. $dump .= '<th class="print">' . __('Name') . '</th>';
  449. $dump .= '<td class="print"><strong>' . __('Time') . '</strong></td>';
  450. $dump .= '<td class="print"><strong>' . __('Event') . '</strong></td>';
  451. $dump .= '<td class="print"><strong>' . __('Definition') . '</strong></td>';
  452. $dump .= '</tr>';
  453. $triggers = $GLOBALS['dbi']->getTriggers($db, $table);
  454. foreach ($triggers as $trigger) {
  455. $dump .= '<tr class="print-category">';
  456. $dump .= '<td class="print">'
  457. . htmlspecialchars($trigger['name'])
  458. . '</td>'
  459. . '<td class="print">'
  460. . htmlspecialchars($trigger['action_timing'])
  461. . '</td>'
  462. . '<td class="print">'
  463. . htmlspecialchars($trigger['event_manipulation'])
  464. . '</td>'
  465. . '<td class="print">'
  466. . htmlspecialchars($trigger['definition'])
  467. . '</td>'
  468. . '</tr>';
  469. }
  470. $dump .= '</table>';
  471. return $dump;
  472. }
  473. /**
  474. * Outputs table's structure
  475. *
  476. * @param string $db database name
  477. * @param string $table table name
  478. * @param string $crlf the end of line sequence
  479. * @param string $error_url the url to go back in case of error
  480. * @param string $export_mode 'create_table', 'triggers', 'create_view',
  481. * 'stand_in'
  482. * @param string $export_type 'server', 'database', 'table'
  483. * @param bool $do_relation whether to include relation comments
  484. * @param bool $do_comments whether to include the pmadb-style column
  485. * comments as comments in the structure;
  486. * this is deprecated but the parameter is
  487. * left here because export.php calls
  488. * PMA_exportStructure() also for other
  489. * export types which use this parameter
  490. * @param bool $do_mime whether to include mime comments
  491. * @param bool $dates whether to include creation/update/check dates
  492. * @param array $aliases Aliases of db/table/columns
  493. *
  494. * @return bool Whether it succeeded
  495. */
  496. public function exportStructure(
  497. $db,
  498. $table,
  499. $crlf,
  500. $error_url,
  501. $export_mode,
  502. $export_type,
  503. $do_relation = false,
  504. $do_comments = false,
  505. $do_mime = false,
  506. $dates = false,
  507. array $aliases = array()
  508. ) {
  509. $db_alias = $db;
  510. $table_alias = $table;
  511. $this->initAlias($aliases, $db_alias, $table_alias);
  512. $dump = '';
  513. switch ($export_mode) {
  514. case 'create_table':
  515. $dump .= '<h2>'
  516. . __('Table structure for table') . ' '
  517. . htmlspecialchars($table_alias)
  518. . '</h2>';
  519. $dump .= $this->getTableDef(
  520. $db,
  521. $table,
  522. $do_relation,
  523. $do_comments,
  524. $do_mime,
  525. false,
  526. $aliases
  527. );
  528. break;
  529. case 'triggers':
  530. $dump = '';
  531. $triggers = $GLOBALS['dbi']->getTriggers($db, $table);
  532. if ($triggers) {
  533. $dump .= '<h2>'
  534. . __('Triggers') . ' ' . htmlspecialchars($table_alias)
  535. . '</h2>';
  536. $dump .= $this->getTriggers($db, $table);
  537. }
  538. break;
  539. case 'create_view':
  540. $dump .= '<h2>'
  541. . __('Structure for view') . ' ' . htmlspecialchars($table_alias)
  542. . '</h2>';
  543. $dump .= $this->getTableDef(
  544. $db,
  545. $table,
  546. $do_relation,
  547. $do_comments,
  548. $do_mime,
  549. true,
  550. $aliases
  551. );
  552. break;
  553. case 'stand_in':
  554. $dump .= '<h2>'
  555. . __('Stand-in structure for view') . ' '
  556. . htmlspecialchars($table_alias)
  557. . '</h2>';
  558. // export a stand-in definition to resolve view dependencies
  559. $dump .= $this->getTableDefStandIn($db, $table, $crlf, $aliases);
  560. } // end switch
  561. return Export::outputHandler($dump);
  562. }
  563. /**
  564. * Formats the definition for one column
  565. *
  566. * @param array $column info about this column
  567. * @param array $unique_keys unique keys of the table
  568. * @param string $col_alias Column Alias
  569. *
  570. * @return string Formatted column definition
  571. */
  572. protected function formatOneColumnDefinition(
  573. array $column,
  574. array $unique_keys,
  575. $col_alias = ''
  576. ) {
  577. if (empty($col_alias)) {
  578. $col_alias = $column['Field'];
  579. }
  580. $definition = '<tr class="print-category">';
  581. $extracted_columnspec = Util::extractColumnSpec($column['Type']);
  582. $type = htmlspecialchars($extracted_columnspec['print_type']);
  583. if (empty($type)) {
  584. $type = '&nbsp;';
  585. }
  586. if (!isset($column['Default'])) {
  587. if ($column['Null'] != 'NO') {
  588. $column['Default'] = 'NULL';
  589. }
  590. }
  591. $fmt_pre = '';
  592. $fmt_post = '';
  593. if (in_array($column['Field'], $unique_keys)) {
  594. $fmt_pre = '<strong>' . $fmt_pre;
  595. $fmt_post = $fmt_post . '</strong>';
  596. }
  597. if ($column['Key'] == 'PRI') {
  598. $fmt_pre = '<em>' . $fmt_pre;
  599. $fmt_post = $fmt_post . '</em>';
  600. }
  601. $definition .= '<td class="print">' . $fmt_pre
  602. . htmlspecialchars($col_alias) . $fmt_post . '</td>';
  603. $definition .= '<td class="print">' . htmlspecialchars($type) . '</td>';
  604. $definition .= '<td class="print">'
  605. . (($column['Null'] == '' || $column['Null'] == 'NO')
  606. ? __('No')
  607. : __('Yes'))
  608. . '</td>';
  609. $definition .= '<td class="print">'
  610. . htmlspecialchars(isset($column['Default']) ? $column['Default'] : '')
  611. . '</td>';
  612. return $definition;
  613. }
  614. }