Pdf.php 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * PhpMyAdmin\Plugins\Export\Helpers\Pdf class
  5. *
  6. * @package PhpMyAdmin-Export
  7. * @subpackage PDF
  8. */
  9. namespace PhpMyAdmin\Plugins\Export\Helpers;
  10. use PhpMyAdmin\DatabaseInterface;
  11. use PhpMyAdmin\Pdf as PdfLib;
  12. use PhpMyAdmin\Relation;
  13. use PhpMyAdmin\Transformations;
  14. use PhpMyAdmin\Util;
  15. use TCPDF_STATIC;
  16. /**
  17. * Adapted from a LGPL script by Philip Clarke
  18. *
  19. * @package PhpMyAdmin-Export
  20. * @subpackage PDF
  21. */
  22. class Pdf extends PdfLib
  23. {
  24. var $tablewidths;
  25. var $headerset;
  26. /**
  27. * @var Relation $relation
  28. */
  29. private $relation;
  30. /**
  31. * Constructs PDF and configures standard parameters.
  32. *
  33. * @param string $orientation page orientation
  34. * @param string $unit unit
  35. * @param string $format the format used for pages
  36. * @param boolean $unicode true means that the input text is unicode
  37. * @param string $encoding charset encoding; default is UTF-8.
  38. * @param boolean $diskcache if true reduce the RAM memory usage by caching
  39. * temporary data on filesystem (slower).
  40. * @param boolean $pdfa If TRUE set the document to PDF/A mode.
  41. *
  42. * @access public
  43. */
  44. public function __construct(
  45. $orientation = 'P',
  46. $unit = 'mm',
  47. $format = 'A4',
  48. $unicode = true,
  49. $encoding = 'UTF-8',
  50. $diskcache = false,
  51. $pdfa = false
  52. ) {
  53. parent::__construct(
  54. $orientation,
  55. $unit,
  56. $format,
  57. $unicode,
  58. $encoding,
  59. $diskcache,
  60. $pdfa
  61. );
  62. $this->relation = new Relation();
  63. }
  64. /**
  65. * Add page if needed.
  66. *
  67. * @param float|int $h cell height. Default value: 0
  68. * @param mixed $y starting y position, leave empty for current
  69. * position
  70. * @param boolean $addpage if true add a page, otherwise only return
  71. * the true/false state
  72. *
  73. * @return boolean true in case of page break, false otherwise.
  74. */
  75. public function checkPageBreak($h = 0, $y = '', $addpage = true)
  76. {
  77. if (TCPDF_STATIC::empty_string($y)) {
  78. $y = $this->y;
  79. }
  80. $current_page = $this->page;
  81. if ((($y + $h) > $this->PageBreakTrigger)
  82. && (!$this->InFooter)
  83. && ($this->AcceptPageBreak())
  84. ) {
  85. if ($addpage) {
  86. //Automatic page break
  87. $x = $this->x;
  88. $this->AddPage($this->CurOrientation);
  89. $this->y = $this->dataY;
  90. $oldpage = $this->page - 1;
  91. $this_page_orm = $this->pagedim[$this->page]['orm'];
  92. $old_page_orm = $this->pagedim[$oldpage]['orm'];
  93. $this_page_olm = $this->pagedim[$this->page]['olm'];
  94. $old_page_olm = $this->pagedim[$oldpage]['olm'];
  95. if ($this->rtl) {
  96. if ($this_page_orm != $old_page_orm) {
  97. $this->x = $x - ($this_page_orm - $old_page_orm);
  98. } else {
  99. $this->x = $x;
  100. }
  101. } else {
  102. if ($this_page_olm != $old_page_olm) {
  103. $this->x = $x + ($this_page_olm - $old_page_olm);
  104. } else {
  105. $this->x = $x;
  106. }
  107. }
  108. }
  109. return true;
  110. }
  111. // account for columns mode
  112. return $current_page != $this->page;
  113. }
  114. /**
  115. * This method is used to render the page header.
  116. *
  117. * @return void
  118. */
  119. // @codingStandardsIgnoreLine
  120. public function Header()
  121. {
  122. global $maxY;
  123. // We don't want automatic page breaks while generating header
  124. // as this can lead to infinite recursion as auto generated page
  125. // will want header as well causing another page break
  126. // FIXME: Better approach might be to try to compact the content
  127. $this->SetAutoPageBreak(false);
  128. // Check if header for this page already exists
  129. if (!isset($this->headerset[$this->page])) {
  130. $fullwidth = 0;
  131. foreach ($this->tablewidths as $width) {
  132. $fullwidth += $width;
  133. }
  134. $this->SetY(($this->tMargin) - ($this->FontSizePt / $this->k) * 5);
  135. $this->cellFontSize = $this->FontSizePt;
  136. $this->SetFont(
  137. PdfLib::PMA_PDF_FONT,
  138. '',
  139. ($this->titleFontSize
  140. ? $this->titleFontSize
  141. : $this->FontSizePt)
  142. );
  143. $this->Cell(0, $this->FontSizePt, $this->titleText, 0, 1, 'C');
  144. $this->SetFont(PdfLib::PMA_PDF_FONT, '', $this->cellFontSize);
  145. $this->SetY(($this->tMargin) - ($this->FontSizePt / $this->k) * 2.5);
  146. $this->Cell(
  147. 0,
  148. $this->FontSizePt,
  149. __('Database:') . ' ' . $this->dbAlias . ', '
  150. . __('Table:') . ' ' . $this->tableAlias . ', '
  151. . __('Purpose:') . ' ' . $this->purpose,
  152. 0,
  153. 1,
  154. 'L'
  155. );
  156. $l = ($this->lMargin);
  157. foreach ($this->colTitles as $col => $txt) {
  158. $this->SetXY($l, ($this->tMargin));
  159. $this->MultiCell(
  160. $this->tablewidths[$col],
  161. $this->FontSizePt,
  162. $txt
  163. );
  164. $l += $this->tablewidths[$col];
  165. $maxY = ($maxY < $this->getY()) ? $this->getY() : $maxY;
  166. }
  167. $this->SetXY($this->lMargin, $this->tMargin);
  168. $this->setFillColor(200, 200, 200);
  169. $l = ($this->lMargin);
  170. foreach ($this->colTitles as $col => $txt) {
  171. $this->SetXY($l, $this->tMargin);
  172. $this->cell(
  173. $this->tablewidths[$col],
  174. $maxY - ($this->tMargin),
  175. '',
  176. 1,
  177. 0,
  178. 'L',
  179. 1
  180. );
  181. $this->SetXY($l, $this->tMargin);
  182. $this->MultiCell(
  183. $this->tablewidths[$col],
  184. $this->FontSizePt,
  185. $txt,
  186. 0,
  187. 'C'
  188. );
  189. $l += $this->tablewidths[$col];
  190. }
  191. $this->setFillColor(255, 255, 255);
  192. // set headerset
  193. $this->headerset[$this->page] = 1;
  194. }
  195. $this->dataY = $maxY;
  196. $this->SetAutoPageBreak(true);
  197. }
  198. /**
  199. * Generate table
  200. *
  201. * @param int $lineheight Height of line
  202. *
  203. * @return void
  204. */
  205. public function morepagestable($lineheight = 8)
  206. {
  207. // some things to set and 'remember'
  208. $l = $this->lMargin;
  209. $startheight = $h = $this->dataY;
  210. $startpage = $currpage = $this->page;
  211. // calculate the whole width
  212. $fullwidth = 0;
  213. foreach ($this->tablewidths as $width) {
  214. $fullwidth += $width;
  215. }
  216. // Now let's start to write the table
  217. $row = 0;
  218. $tmpheight = array();
  219. $maxpage = $this->page;
  220. while ($data = $GLOBALS['dbi']->fetchRow($this->results)) {
  221. $this->page = $currpage;
  222. // write the horizontal borders
  223. $this->Line($l, $h, $fullwidth + $l, $h);
  224. // write the content and remember the height of the highest col
  225. foreach ($data as $col => $txt) {
  226. $this->page = $currpage;
  227. $this->SetXY($l, $h);
  228. if ($this->tablewidths[$col] > 0) {
  229. $this->MultiCell(
  230. $this->tablewidths[$col],
  231. $lineheight,
  232. $txt,
  233. 0,
  234. $this->colAlign[$col]
  235. );
  236. $l += $this->tablewidths[$col];
  237. }
  238. if (!isset($tmpheight[$row . '-' . $this->page])) {
  239. $tmpheight[$row . '-' . $this->page] = 0;
  240. }
  241. if ($tmpheight[$row . '-' . $this->page] < $this->GetY()) {
  242. $tmpheight[$row . '-' . $this->page] = $this->GetY();
  243. }
  244. if ($this->page > $maxpage) {
  245. $maxpage = $this->page;
  246. }
  247. unset($data[$col]);
  248. }
  249. // get the height we were in the last used page
  250. $h = $tmpheight[$row . '-' . $maxpage];
  251. // set the "pointer" to the left margin
  252. $l = $this->lMargin;
  253. // set the $currpage to the last page
  254. $currpage = $maxpage;
  255. unset($data[$row]);
  256. $row++;
  257. }
  258. // draw the borders
  259. // we start adding a horizontal line on the last page
  260. $this->page = $maxpage;
  261. $this->Line($l, $h, $fullwidth + $l, $h);
  262. // now we start at the top of the document and walk down
  263. for ($i = $startpage; $i <= $maxpage; $i++) {
  264. $this->page = $i;
  265. $l = $this->lMargin;
  266. $t = ($i == $startpage) ? $startheight : $this->tMargin;
  267. $lh = ($i == $maxpage) ? $h : $this->h - $this->bMargin;
  268. $this->Line($l, $t, $l, $lh);
  269. foreach ($this->tablewidths as $width) {
  270. $l += $width;
  271. $this->Line($l, $t, $l, $lh);
  272. }
  273. }
  274. // set it to the last page, if not it'll cause some problems
  275. $this->page = $maxpage;
  276. }
  277. /**
  278. * Sets a set of attributes.
  279. *
  280. * @param array $attr array containing the attributes
  281. *
  282. * @return void
  283. */
  284. public function setAttributes(array $attr = array())
  285. {
  286. foreach ($attr as $key => $val) {
  287. $this->$key = $val;
  288. }
  289. }
  290. /**
  291. * Defines the top margin.
  292. * The method can be called before creating the first page.
  293. *
  294. * @param float $topMargin the margin
  295. *
  296. * @return void
  297. */
  298. public function setTopMargin($topMargin)
  299. {
  300. $this->tMargin = $topMargin;
  301. }
  302. /**
  303. * Prints triggers
  304. *
  305. * @param string $db database name
  306. * @param string $table table name
  307. *
  308. * @return void
  309. */
  310. public function getTriggers($db, $table)
  311. {
  312. $i = 0;
  313. $triggers = $GLOBALS['dbi']->getTriggers($db, $table);
  314. foreach ($triggers as $trigger) {
  315. $i++;
  316. break;
  317. }
  318. if ($i == 0) {
  319. return; //prevents printing blank trigger list for any table
  320. }
  321. unset($this->tablewidths);
  322. unset($this->colTitles);
  323. unset($this->titleWidth);
  324. unset($this->colFits);
  325. unset($this->display_column);
  326. unset($this->colAlign);
  327. /**
  328. * Making table heading
  329. * Keeping column width constant
  330. */
  331. $this->colTitles[0] = __('Name');
  332. $this->tablewidths[0] = 90;
  333. $this->colTitles[1] = __('Time');
  334. $this->tablewidths[1] = 80;
  335. $this->colTitles[2] = __('Event');
  336. $this->tablewidths[2] = 40;
  337. $this->colTitles[3] = __('Definition');
  338. $this->tablewidths[3] = 240;
  339. for ($columns_cnt = 0; $columns_cnt < 4; $columns_cnt++) {
  340. $this->colAlign[$columns_cnt] = 'L';
  341. $this->display_column[$columns_cnt] = true;
  342. }
  343. // Starting to fill table with required info
  344. $this->setY($this->tMargin);
  345. $this->AddPage();
  346. $this->SetFont(PdfLib::PMA_PDF_FONT, '', 9);
  347. $l = $this->lMargin;
  348. $startheight = $h = $this->dataY;
  349. $startpage = $currpage = $this->page;
  350. // calculate the whole width
  351. $fullwidth = 0;
  352. foreach ($this->tablewidths as $width) {
  353. $fullwidth += $width;
  354. }
  355. $row = 0;
  356. $tmpheight = array();
  357. $maxpage = $this->page;
  358. $data = array();
  359. $triggers = $GLOBALS['dbi']->getTriggers($db, $table);
  360. foreach ($triggers as $trigger) {
  361. $data[] = $trigger['name'];
  362. $data[] = $trigger['action_timing'];
  363. $data[] = $trigger['event_manipulation'];
  364. $data[] = $trigger['definition'];
  365. $this->page = $currpage;
  366. // write the horizontal borders
  367. $this->Line($l, $h, $fullwidth + $l, $h);
  368. // write the content and remember the height of the highest col
  369. foreach ($data as $col => $txt) {
  370. $this->page = $currpage;
  371. $this->SetXY($l, $h);
  372. if ($this->tablewidths[$col] > 0) {
  373. $this->MultiCell(
  374. $this->tablewidths[$col],
  375. $this->FontSizePt,
  376. $txt,
  377. 0,
  378. $this->colAlign[$col]
  379. );
  380. $l += $this->tablewidths[$col];
  381. }
  382. if (!isset($tmpheight[$row . '-' . $this->page])) {
  383. $tmpheight[$row . '-' . $this->page] = 0;
  384. }
  385. if ($tmpheight[$row . '-' . $this->page] < $this->GetY()) {
  386. $tmpheight[$row . '-' . $this->page] = $this->GetY();
  387. }
  388. if ($this->page > $maxpage) {
  389. $maxpage = $this->page;
  390. }
  391. }
  392. // get the height we were in the last used page
  393. $h = $tmpheight[$row . '-' . $maxpage];
  394. // set the "pointer" to the left margin
  395. $l = $this->lMargin;
  396. // set the $currpage to the last page
  397. $currpage = $maxpage;
  398. unset($data);
  399. $row++;
  400. }
  401. // draw the borders
  402. // we start adding a horizontal line on the last page
  403. $this->page = $maxpage;
  404. $this->Line($l, $h, $fullwidth + $l, $h);
  405. // now we start at the top of the document and walk down
  406. for ($i = $startpage; $i <= $maxpage; $i++) {
  407. $this->page = $i;
  408. $l = $this->lMargin;
  409. $t = ($i == $startpage) ? $startheight : $this->tMargin;
  410. $lh = ($i == $maxpage) ? $h : $this->h - $this->bMargin;
  411. $this->Line($l, $t, $l, $lh);
  412. foreach ($this->tablewidths as $width) {
  413. $l += $width;
  414. $this->Line($l, $t, $l, $lh);
  415. }
  416. }
  417. // set it to the last page, if not it'll cause some problems
  418. $this->page = $maxpage;
  419. }
  420. /**
  421. * Print $table's CREATE definition
  422. *
  423. * @param string $db the database name
  424. * @param string $table the table name
  425. * @param bool $do_relation whether to include relation comments
  426. * @param bool $do_comments whether to include the pmadb-style column
  427. * comments as comments in the structure;
  428. * this is deprecated but the parameter is
  429. * left here because export.php calls
  430. * PMA_exportStructure() also for other
  431. * export types which use this parameter
  432. * @param bool $do_mime whether to include mime comments
  433. * @param bool $view whether we're handling a view
  434. * @param array $aliases aliases of db/table/columns
  435. *
  436. * @return void
  437. */
  438. public function getTableDef(
  439. $db,
  440. $table,
  441. $do_relation,
  442. $do_comments,
  443. $do_mime,
  444. $view = false,
  445. array $aliases = array()
  446. ) {
  447. // set $cfgRelation here, because there is a chance that it's modified
  448. // since the class initialization
  449. global $cfgRelation;
  450. unset($this->tablewidths);
  451. unset($this->colTitles);
  452. unset($this->titleWidth);
  453. unset($this->colFits);
  454. unset($this->display_column);
  455. unset($this->colAlign);
  456. /**
  457. * Gets fields properties
  458. */
  459. $GLOBALS['dbi']->selectDb($db);
  460. /**
  461. * All these three checks do_relation, do_comment and do_mime is
  462. * not required. As presently all are set true by default.
  463. * But when, methods to take user input will be developed,
  464. * it will be of use
  465. */
  466. // Check if we can use Relations
  467. if ($do_relation) {
  468. // Find which tables are related with the current one and write it in
  469. // an array
  470. $res_rel = $this->relation->getForeigners($db, $table);
  471. $have_rel = !empty($res_rel);
  472. } else {
  473. $have_rel = false;
  474. } // end if
  475. //column count and table heading
  476. $this->colTitles[0] = __('Column');
  477. $this->tablewidths[0] = 90;
  478. $this->colTitles[1] = __('Type');
  479. $this->tablewidths[1] = 80;
  480. $this->colTitles[2] = __('Null');
  481. $this->tablewidths[2] = 40;
  482. $this->colTitles[3] = __('Default');
  483. $this->tablewidths[3] = 120;
  484. for ($columns_cnt = 0; $columns_cnt < 4; $columns_cnt++) {
  485. $this->colAlign[$columns_cnt] = 'L';
  486. $this->display_column[$columns_cnt] = true;
  487. }
  488. if ($do_relation && $have_rel) {
  489. $this->colTitles[$columns_cnt] = __('Links to');
  490. $this->display_column[$columns_cnt] = true;
  491. $this->colAlign[$columns_cnt] = 'L';
  492. $this->tablewidths[$columns_cnt] = 120;
  493. $columns_cnt++;
  494. }
  495. if ($do_comments /*&& $cfgRelation['commwork']*/) {
  496. $this->colTitles[$columns_cnt] = __('Comments');
  497. $this->display_column[$columns_cnt] = true;
  498. $this->colAlign[$columns_cnt] = 'L';
  499. $this->tablewidths[$columns_cnt] = 120;
  500. $columns_cnt++;
  501. }
  502. if ($do_mime && $cfgRelation['mimework']) {
  503. $this->colTitles[$columns_cnt] = __('MIME');
  504. $this->display_column[$columns_cnt] = true;
  505. $this->colAlign[$columns_cnt] = 'L';
  506. $this->tablewidths[$columns_cnt] = 120;
  507. $columns_cnt++;
  508. }
  509. // Starting to fill table with required info
  510. $this->setY($this->tMargin);
  511. $this->AddPage();
  512. $this->SetFont(PdfLib::PMA_PDF_FONT, '', 9);
  513. // Now let's start to write the table structure
  514. if ($do_comments) {
  515. $comments = $this->relation->getComments($db, $table);
  516. }
  517. if ($do_mime && $cfgRelation['mimework']) {
  518. $mime_map = Transformations::getMIME($db, $table, true);
  519. }
  520. $columns = $GLOBALS['dbi']->getColumns($db, $table);
  521. /**
  522. * Get the unique keys in the table.
  523. * Presently, this information is not used. We will have to find out
  524. * way of displaying it.
  525. */
  526. $unique_keys = array();
  527. $keys = $GLOBALS['dbi']->getTableIndexes($db, $table);
  528. foreach ($keys as $key) {
  529. if ($key['Non_unique'] == 0) {
  530. $unique_keys[] = $key['Column_name'];
  531. }
  532. }
  533. // some things to set and 'remember'
  534. $l = $this->lMargin;
  535. $startheight = $h = $this->dataY;
  536. $startpage = $currpage = $this->page;
  537. // calculate the whole width
  538. $fullwidth = 0;
  539. foreach ($this->tablewidths as $width) {
  540. $fullwidth += $width;
  541. }
  542. $row = 0;
  543. $tmpheight = array();
  544. $maxpage = $this->page;
  545. $data = array();
  546. // fun begin
  547. foreach ($columns as $column) {
  548. $extracted_columnspec
  549. = Util::extractColumnSpec($column['Type']);
  550. $type = $extracted_columnspec['print_type'];
  551. if (empty($type)) {
  552. $type = ' ';
  553. }
  554. if (!isset($column['Default'])) {
  555. if ($column['Null'] != 'NO') {
  556. $column['Default'] = 'NULL';
  557. }
  558. }
  559. $data [] = $column['Field'];
  560. $data [] = $type;
  561. $data [] = ($column['Null'] == '' || $column['Null'] == 'NO')
  562. ? 'No'
  563. : 'Yes';
  564. $data [] = isset($column['Default']) ? $column['Default'] : '';
  565. $field_name = $column['Field'];
  566. if ($do_relation && $have_rel) {
  567. $data [] = isset($res_rel[$field_name])
  568. ? $res_rel[$field_name]['foreign_table']
  569. . ' (' . $res_rel[$field_name]['foreign_field']
  570. . ')'
  571. : '';
  572. }
  573. if ($do_comments) {
  574. $data [] = isset($comments[$field_name])
  575. ? $comments[$field_name]
  576. : '';
  577. }
  578. if ($do_mime) {
  579. $data [] = isset($mime_map[$field_name])
  580. ? $mime_map[$field_name]['mimetype']
  581. : '';
  582. }
  583. $this->page = $currpage;
  584. // write the horizontal borders
  585. $this->Line($l, $h, $fullwidth + $l, $h);
  586. // write the content and remember the height of the highest col
  587. foreach ($data as $col => $txt) {
  588. $this->page = $currpage;
  589. $this->SetXY($l, $h);
  590. if ($this->tablewidths[$col] > 0) {
  591. $this->MultiCell(
  592. $this->tablewidths[$col],
  593. $this->FontSizePt,
  594. $txt,
  595. 0,
  596. $this->colAlign[$col]
  597. );
  598. $l += $this->tablewidths[$col];
  599. }
  600. if (!isset($tmpheight[$row . '-' . $this->page])) {
  601. $tmpheight[$row . '-' . $this->page] = 0;
  602. }
  603. if ($tmpheight[$row . '-' . $this->page] < $this->GetY()) {
  604. $tmpheight[$row . '-' . $this->page] = $this->GetY();
  605. }
  606. if ($this->page > $maxpage) {
  607. $maxpage = $this->page;
  608. }
  609. }
  610. // get the height we were in the last used page
  611. $h = $tmpheight[$row . '-' . $maxpage];
  612. // set the "pointer" to the left margin
  613. $l = $this->lMargin;
  614. // set the $currpage to the last page
  615. $currpage = $maxpage;
  616. unset($data);
  617. $row++;
  618. }
  619. // draw the borders
  620. // we start adding a horizontal line on the last page
  621. $this->page = $maxpage;
  622. $this->Line($l, $h, $fullwidth + $l, $h);
  623. // now we start at the top of the document and walk down
  624. for ($i = $startpage; $i <= $maxpage; $i++) {
  625. $this->page = $i;
  626. $l = $this->lMargin;
  627. $t = ($i == $startpage) ? $startheight : $this->tMargin;
  628. $lh = ($i == $maxpage) ? $h : $this->h - $this->bMargin;
  629. $this->Line($l, $t, $l, $lh);
  630. foreach ($this->tablewidths as $width) {
  631. $l += $width;
  632. $this->Line($l, $t, $l, $lh);
  633. }
  634. }
  635. // set it to the last page, if not it'll cause some problems
  636. $this->page = $maxpage;
  637. }
  638. /**
  639. * MySQL report
  640. *
  641. * @param string $query Query to execute
  642. *
  643. * @return void
  644. */
  645. public function mysqlReport($query)
  646. {
  647. unset($this->tablewidths);
  648. unset($this->colTitles);
  649. unset($this->titleWidth);
  650. unset($this->colFits);
  651. unset($this->display_column);
  652. unset($this->colAlign);
  653. /**
  654. * Pass 1 for column widths
  655. */
  656. $this->results = $GLOBALS['dbi']->query(
  657. $query,
  658. DatabaseInterface::CONNECT_USER,
  659. DatabaseInterface::QUERY_UNBUFFERED
  660. );
  661. $this->numFields = $GLOBALS['dbi']->numFields($this->results);
  662. $this->fields = $GLOBALS['dbi']->getFieldsMeta($this->results);
  663. // sColWidth = starting col width (an average size width)
  664. $availableWidth = $this->w - $this->lMargin - $this->rMargin;
  665. $this->sColWidth = $availableWidth / $this->numFields;
  666. $totalTitleWidth = 0;
  667. // loop through results header and set initial
  668. // col widths/ titles/ alignment
  669. // if a col title is less than the starting col width,
  670. // reduce that column size
  671. $colFits = array();
  672. $titleWidth = array();
  673. for ($i = 0; $i < $this->numFields; $i++) {
  674. $col_as = $this->fields[$i]->name;
  675. $db = $this->currentDb;
  676. $table = $this->currentTable;
  677. if (!empty($this->aliases[$db]['tables'][$table]['columns'][$col_as])) {
  678. $col_as = $this->aliases[$db]['tables'][$table]['columns'][$col_as];
  679. }
  680. $stringWidth = $this->getstringwidth($col_as) + 6;
  681. // save the real title's width
  682. $titleWidth[$i] = $stringWidth;
  683. $totalTitleWidth += $stringWidth;
  684. // set any column titles less than the start width to
  685. // the column title width
  686. if ($stringWidth < $this->sColWidth) {
  687. $colFits[$i] = $stringWidth;
  688. }
  689. $this->colTitles[$i] = $col_as;
  690. $this->display_column[$i] = true;
  691. switch ($this->fields[$i]->type) {
  692. case 'int':
  693. $this->colAlign[$i] = 'R';
  694. break;
  695. case 'blob':
  696. case 'tinyblob':
  697. case 'mediumblob':
  698. case 'longblob':
  699. /**
  700. * @todo do not deactivate completely the display
  701. * but show the field's name and [BLOB]
  702. */
  703. if (stristr($this->fields[$i]->flags, 'BINARY')) {
  704. $this->display_column[$i] = false;
  705. unset($this->colTitles[$i]);
  706. }
  707. $this->colAlign[$i] = 'L';
  708. break;
  709. default:
  710. $this->colAlign[$i] = 'L';
  711. }
  712. }
  713. // title width verification
  714. if ($totalTitleWidth > $availableWidth) {
  715. $adjustingMode = true;
  716. } else {
  717. $adjustingMode = false;
  718. // we have enough space for all the titles at their
  719. // original width so use the true title's width
  720. foreach ($titleWidth as $key => $val) {
  721. $colFits[$key] = $val;
  722. }
  723. }
  724. // loop through the data; any column whose contents
  725. // is greater than the column size is resized
  726. /**
  727. * @todo force here a LIMIT to avoid reading all rows
  728. */
  729. while ($row = $GLOBALS['dbi']->fetchRow($this->results)) {
  730. foreach ($colFits as $key => $val) {
  731. $stringWidth = $this->getstringwidth($row[$key]) + 6;
  732. if ($adjustingMode && ($stringWidth > $this->sColWidth)) {
  733. // any column whose data's width is bigger than
  734. // the start width is now discarded
  735. unset($colFits[$key]);
  736. } else {
  737. // if data's width is bigger than the current column width,
  738. // enlarge the column (but avoid enlarging it if the
  739. // data's width is very big)
  740. if ($stringWidth > $val
  741. && $stringWidth < ($this->sColWidth * 3)
  742. ) {
  743. $colFits[$key] = $stringWidth;
  744. }
  745. }
  746. }
  747. }
  748. $totAlreadyFitted = 0;
  749. foreach ($colFits as $key => $val) {
  750. // set fitted columns to smallest size
  751. $this->tablewidths[$key] = $val;
  752. // to work out how much (if any) space has been freed up
  753. $totAlreadyFitted += $val;
  754. }
  755. if ($adjustingMode) {
  756. $surplus = (sizeof($colFits) * $this->sColWidth) - $totAlreadyFitted;
  757. $surplusToAdd = $surplus / ($this->numFields - sizeof($colFits));
  758. } else {
  759. $surplusToAdd = 0;
  760. }
  761. for ($i = 0; $i < $this->numFields; $i++) {
  762. if (!in_array($i, array_keys($colFits))) {
  763. $this->tablewidths[$i] = $this->sColWidth + $surplusToAdd;
  764. }
  765. if ($this->display_column[$i] == false) {
  766. $this->tablewidths[$i] = 0;
  767. }
  768. }
  769. ksort($this->tablewidths);
  770. $GLOBALS['dbi']->freeResult($this->results);
  771. // Pass 2
  772. $this->results = $GLOBALS['dbi']->query(
  773. $query,
  774. DatabaseInterface::CONNECT_USER,
  775. DatabaseInterface::QUERY_UNBUFFERED
  776. );
  777. $this->setY($this->tMargin);
  778. $this->AddPage();
  779. $this->SetFont(PdfLib::PMA_PDF_FONT, '', 9);
  780. $this->morepagestable($this->FontSizePt);
  781. $GLOBALS['dbi']->freeResult($this->results);
  782. } // end of mysqlReport function
  783. } // end of Pdf class