PMA_ExportPdf.class.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * TableProperty class
  5. *
  6. * @package PhpMyAdmin-Export
  7. * @subpackage PDF
  8. */
  9. if (! defined('PHPMYADMIN')) {
  10. exit;
  11. }
  12. /* Get the PDF class */
  13. require_once 'libraries/PDF.class.php';
  14. /**
  15. * Adapted from a LGPL script by Philip Clarke
  16. *
  17. * @package PhpMyAdmin-Export
  18. * @subpackage PDF
  19. */
  20. class PMA_ExportPdf extends PMA_PDF
  21. {
  22. var $tablewidths;
  23. var $headerset;
  24. /**
  25. * Add page if needed.
  26. *
  27. * @param float $h cell height. Default value: 0
  28. * @param mixed $y starting y position, leave empty for current position
  29. * @param boolean $addpage if true add a page, otherwise only return
  30. * the true/false state
  31. *
  32. * @return boolean true in case of page break, false otherwise.
  33. */
  34. function checkPageBreak($h = 0, $y = '', $addpage = true)
  35. {
  36. if ($this->empty_string($y)) {
  37. $y = $this->y;
  38. }
  39. $current_page = $this->page;
  40. if ((($y + $h) > $this->PageBreakTrigger)
  41. AND (! $this->InFooter)
  42. AND ($this->AcceptPageBreak())
  43. ) {
  44. if ($addpage) {
  45. //Automatic page break
  46. $x = $this->x;
  47. $this->AddPage($this->CurOrientation);
  48. $this->y = $this->dataY;
  49. $oldpage = $this->page - 1;
  50. $this_page_orm = $this->pagedim[$this->page]['orm'];
  51. $old_page_orm = $this->pagedim[$oldpage]['orm'];
  52. $this_page_olm = $this->pagedim[$this->page]['olm'];
  53. $old_page_olm = $this->pagedim[$oldpage]['olm'];
  54. if ($this->rtl) {
  55. if ($this_page_orm!= $old_page_orm) {
  56. $this->x = $x - ($this_page_orm - $old_page_orm);
  57. } else {
  58. $this->x = $x;
  59. }
  60. } else {
  61. if ($this_page_olm != $old_page_olm) {
  62. $this->x = $x + ($this_page_olm - $old_page_olm);
  63. } else {
  64. $this->x = $x;
  65. }
  66. }
  67. }
  68. return true;
  69. }
  70. if ($current_page != $this->page) {
  71. // account for columns mode
  72. return true;
  73. }
  74. return false;
  75. }
  76. /**
  77. * This method is used to render the page header.
  78. *
  79. * @return void
  80. */
  81. function Header()
  82. {
  83. global $maxY;
  84. // We don't want automatic page breaks while generating header
  85. // as this can lead to infinite recursion as auto generated page
  86. // will want header as well causing another page break
  87. // FIXME: Better approach might be to try to compact the content
  88. $this->SetAutoPageBreak(false);
  89. // Check if header for this page already exists
  90. if (! isset($this->headerset[$this->page])) {
  91. $fullwidth = 0;
  92. foreach ($this->tablewidths as $width) {
  93. $fullwidth += $width;
  94. }
  95. $this->SetY(($this->tMargin) - ($this->FontSizePt / $this->k) * 5);
  96. $this->cellFontSize = $this->FontSizePt ;
  97. $this->SetFont(
  98. PMA_PDF_FONT,
  99. '',
  100. ($this->titleFontSize
  101. ? $this->titleFontSize
  102. : $this->FontSizePt)
  103. );
  104. $this->Cell(0, $this->FontSizePt, $this->titleText, 0, 1, 'C');
  105. $this->SetFont(PMA_PDF_FONT, '', $this->cellFontSize);
  106. $this->SetY(($this->tMargin) - ($this->FontSizePt / $this->k) * 2.5);
  107. $this->Cell(
  108. 0,
  109. $this->FontSizePt,
  110. __('Database') . ': ' . $this->currentDb . ', '
  111. . __('Table') . ': ' . $this->currentTable,
  112. 0, 1, 'L'
  113. );
  114. $l = ($this->lMargin);
  115. foreach ($this->colTitles as $col => $txt) {
  116. $this->SetXY($l, ($this->tMargin));
  117. $this->MultiCell(
  118. $this->tablewidths[$col],
  119. $this->FontSizePt,
  120. $txt
  121. );
  122. $l += $this->tablewidths[$col] ;
  123. $maxY = ($maxY < $this->getY()) ? $this->getY() : $maxY ;
  124. }
  125. $this->SetXY($this->lMargin, $this->tMargin);
  126. $this->setFillColor(200, 200, 200);
  127. $l = ($this->lMargin);
  128. foreach ($this->colTitles as $col => $txt) {
  129. $this->SetXY($l, $this->tMargin);
  130. $this->cell(
  131. $this->tablewidths[$col],
  132. $maxY-($this->tMargin),
  133. '',
  134. 1,
  135. 0,
  136. 'L',
  137. 1
  138. );
  139. $this->SetXY($l, $this->tMargin);
  140. $this->MultiCell(
  141. $this->tablewidths[$col],
  142. $this->FontSizePt,
  143. $txt,
  144. 0,
  145. 'C'
  146. );
  147. $l += $this->tablewidths[$col];
  148. }
  149. $this->setFillColor(255, 255, 255);
  150. // set headerset
  151. $this->headerset[$this->page] = 1;
  152. }
  153. $this->dataY = $maxY;
  154. $this->SetAutoPageBreak(true);
  155. }
  156. function morepagestable($lineheight = 8)
  157. {
  158. // some things to set and 'remember'
  159. $l = $this->lMargin;
  160. $startheight = $h = $this->dataY;
  161. $startpage = $currpage = $this->page;
  162. // calculate the whole width
  163. $fullwidth = 0;
  164. foreach ($this->tablewidths as $width) {
  165. $fullwidth += $width;
  166. }
  167. // Now let's start to write the table
  168. $row = 0;
  169. $tmpheight = array();
  170. $maxpage = $this->page;
  171. while ($data = PMA_DBI_fetch_row($this->results)) {
  172. $this->page = $currpage;
  173. // write the horizontal borders
  174. $this->Line($l, $h, $fullwidth+$l, $h);
  175. // write the content and remember the height of the highest col
  176. foreach ($data as $col => $txt) {
  177. $this->page = $currpage;
  178. $this->SetXY($l, $h);
  179. if ($this->tablewidths[$col] > 0) {
  180. $this->MultiCell(
  181. $this->tablewidths[$col],
  182. $lineheight,
  183. $txt,
  184. 0,
  185. $this->colAlign[$col]
  186. );
  187. $l += $this->tablewidths[$col];
  188. }
  189. if (! isset($tmpheight[$row.'-'.$this->page])) {
  190. $tmpheight[$row.'-'.$this->page] = 0;
  191. }
  192. if ($tmpheight[$row.'-'.$this->page] < $this->GetY()) {
  193. $tmpheight[$row.'-'.$this->page] = $this->GetY();
  194. }
  195. if ($this->page > $maxpage) {
  196. $maxpage = $this->page;
  197. }
  198. unset($data[$col]);
  199. }
  200. // get the height we were in the last used page
  201. $h = $tmpheight[$row.'-'.$maxpage];
  202. // set the "pointer" to the left margin
  203. $l = $this->lMargin;
  204. // set the $currpage to the last page
  205. $currpage = $maxpage;
  206. unset($data[$row]);
  207. $row++;
  208. }
  209. // draw the borders
  210. // we start adding a horizontal line on the last page
  211. $this->page = $maxpage;
  212. $this->Line($l, $h, $fullwidth+$l, $h);
  213. // now we start at the top of the document and walk down
  214. for ($i = $startpage; $i <= $maxpage; $i++) {
  215. $this->page = $i;
  216. $l = $this->lMargin;
  217. $t = ($i == $startpage) ? $startheight : $this->tMargin;
  218. $lh = ($i == $maxpage) ? $h : $this->h-$this->bMargin;
  219. $this->Line($l, $t, $l, $lh);
  220. foreach ($this->tablewidths as $width) {
  221. $l += $width;
  222. $this->Line($l, $t, $l, $lh);
  223. }
  224. }
  225. // set it to the last page, if not it'll cause some problems
  226. $this->page = $maxpage;
  227. }
  228. /**
  229. * Sets a set of attributes.
  230. *
  231. * @param array $attr array containing the attributes
  232. *
  233. * @return void
  234. */
  235. function setAttributes($attr = array())
  236. {
  237. foreach ($attr as $key => $val) {
  238. $this->$key = $val ;
  239. }
  240. }
  241. /**
  242. * Defines the top margin.
  243. * The method can be called before creating the first page.
  244. *
  245. * @param float $topMargin the margin
  246. *
  247. * @return void
  248. */
  249. function setTopMargin($topMargin)
  250. {
  251. $this->tMargin = $topMargin;
  252. }
  253. function mysqlReport($query)
  254. {
  255. unset($this->tablewidths);
  256. unset($this->colTitles);
  257. unset($this->titleWidth);
  258. unset($this->colFits);
  259. unset($this->display_column);
  260. unset($this->colAlign);
  261. /**
  262. * Pass 1 for column widths
  263. */
  264. $this->results = PMA_DBI_query($query, null, PMA_DBI_QUERY_UNBUFFERED);
  265. $this->numFields = PMA_DBI_num_fields($this->results);
  266. $this->fields = PMA_DBI_get_fields_meta($this->results);
  267. // sColWidth = starting col width (an average size width)
  268. $availableWidth = $this->w - $this->lMargin - $this->rMargin;
  269. $this->sColWidth = $availableWidth / $this->numFields;
  270. $totalTitleWidth = 0;
  271. // loop through results header and set initial
  272. // col widths/ titles/ alignment
  273. // if a col title is less than the starting col width,
  274. // reduce that column size
  275. $colFits = array();
  276. for ($i = 0; $i < $this->numFields; $i++) {
  277. $stringWidth = $this->getstringwidth($this->fields[$i]->name) + 6 ;
  278. // save the real title's width
  279. $titleWidth[$i] = $stringWidth;
  280. $totalTitleWidth += $stringWidth;
  281. // set any column titles less than the start width to
  282. // the column title width
  283. if ($stringWidth < $this->sColWidth) {
  284. $colFits[$i] = $stringWidth ;
  285. }
  286. $this->colTitles[$i] = $this->fields[$i]->name;
  287. $this->display_column[$i] = true;
  288. switch ($this->fields[$i]->type) {
  289. case 'int':
  290. $this->colAlign[$i] = 'R';
  291. break;
  292. case 'blob':
  293. case 'tinyblob':
  294. case 'mediumblob':
  295. case 'longblob':
  296. /**
  297. * @todo do not deactivate completely the display
  298. * but show the field's name and [BLOB]
  299. */
  300. if (stristr($this->fields[$i]->flags, 'BINARY')) {
  301. $this->display_column[$i] = false;
  302. unset($this->colTitles[$i]);
  303. }
  304. $this->colAlign[$i] = 'L';
  305. break;
  306. default:
  307. $this->colAlign[$i] = 'L';
  308. }
  309. }
  310. // title width verification
  311. if ($totalTitleWidth > $availableWidth) {
  312. $adjustingMode = true;
  313. } else {
  314. $adjustingMode = false;
  315. // we have enough space for all the titles at their
  316. // original width so use the true title's width
  317. foreach ($titleWidth as $key => $val) {
  318. $colFits[$key] = $val;
  319. }
  320. }
  321. // loop through the data; any column whose contents
  322. // is greater than the column size is resized
  323. /**
  324. * @todo force here a LIMIT to avoid reading all rows
  325. */
  326. while ($row = PMA_DBI_fetch_row($this->results)) {
  327. foreach ($colFits as $key => $val) {
  328. $stringWidth = $this->getstringwidth($row[$key]) + 6 ;
  329. if ($adjustingMode && ($stringWidth > $this->sColWidth)) {
  330. // any column whose data's width is bigger than
  331. // the start width is now discarded
  332. unset($colFits[$key]);
  333. } else {
  334. // if data's width is bigger than the current column width,
  335. // enlarge the column (but avoid enlarging it if the
  336. // data's width is very big)
  337. if ($stringWidth > $val
  338. && $stringWidth < ($this->sColWidth * 3)
  339. ) {
  340. $colFits[$key] = $stringWidth ;
  341. }
  342. }
  343. }
  344. }
  345. $totAlreadyFitted = 0;
  346. foreach ($colFits as $key => $val) {
  347. // set fitted columns to smallest size
  348. $this->tablewidths[$key] = $val;
  349. // to work out how much (if any) space has been freed up
  350. $totAlreadyFitted += $val;
  351. }
  352. if ($adjustingMode) {
  353. $surplus = (sizeof($colFits) * $this->sColWidth) - $totAlreadyFitted;
  354. $surplusToAdd = $surplus / ($this->numFields - sizeof($colFits));
  355. } else {
  356. $surplusToAdd = 0;
  357. }
  358. for ($i = 0; $i < $this->numFields; $i++) {
  359. if (! in_array($i, array_keys($colFits))) {
  360. $this->tablewidths[$i] = $this->sColWidth + $surplusToAdd;
  361. }
  362. if ($this->display_column[$i] == false) {
  363. $this->tablewidths[$i] = 0;
  364. }
  365. }
  366. ksort($this->tablewidths);
  367. PMA_DBI_free_result($this->results);
  368. // Pass 2
  369. $this->results = PMA_DBI_query($query, null, PMA_DBI_QUERY_UNBUFFERED);
  370. $this->setY($this->tMargin);
  371. $this->AddPage();
  372. $this->SetFont(PMA_PDF_FONT, '', 9);
  373. $this->morepagestable($this->FontSizePt);
  374. PMA_DBI_free_result($this->results);
  375. } // end of mysqlReport function
  376. } // end of PMA_Export_PDF class
  377. ?>