PageRenderTime 46ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/phpmyfaq/src/phpMyFAQ/Export/Pdf/Wrapper.php

http://github.com/thorsten/phpMyFAQ
PHP | 576 lines | 244 code | 75 blank | 257 comment | 15 complexity | b249ca57b5f597b64970a09b2e6d48fb MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, LGPL-3.0
  1. <?php
  2. /**
  3. * Main PDF class for phpMyFAQ which "just" extends the TCPDF library.
  4. *
  5. * This Source Code Form is subject to the terms of the Mozilla Public License,
  6. * v. 2.0. If a copy of the MPL was not distributed with this file, You can
  7. * obtain one at http://mozilla.org/MPL/2.0/.
  8. *
  9. * @package phpMyFAQ
  10. * @author Thorsten Rinne <thorsten@phpmyfaq.de>
  11. * @author Peter Beauvain <pbeauvain@web.de>
  12. * @author Krzysztof Kruszynski <thywolf@wolf.homelinux.net>
  13. * @copyright 2004-2021 phpMyFAQ Team
  14. * @license http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
  15. * @link https://www.phpmyfaq.de
  16. * @since 2004-11-21
  17. */
  18. namespace phpMyFAQ\Export\Pdf;
  19. use Exception;
  20. use phpMyFAQ\Configuration;
  21. use phpMyFAQ\Date;
  22. use phpMyFAQ\Link;
  23. use phpMyFAQ\Strings;
  24. use TCPDF;
  25. define('K_TCPDF_EXTERNAL_CONFIG', true);
  26. define('K_PATH_URL', '');
  27. /*
  28. * path to TCPDF
  29. *
  30. */
  31. define('K_PATH_MAIN', PMF_SRC_DIR . '/libs/tecnickcom/tcpdf/');
  32. /*
  33. * path for PDF fonts
  34. */
  35. define('K_PATH_FONTS', PMF_SRC_DIR . '/fonts/');
  36. /*
  37. * cache directory for temporary files (full path)
  38. */
  39. define('K_PATH_CACHE', PMF_ROOT_DIR . '/images/');
  40. /*
  41. * cache directory for temporary files (url path)
  42. */
  43. define('K_PATH_URL_CACHE', K_PATH_CACHE);
  44. /*
  45. * images directory
  46. */
  47. define('K_PATH_IMAGES', K_PATH_MAIN . 'images/');
  48. /*
  49. * blank image
  50. */
  51. define('K_BLANK_IMAGE', K_PATH_IMAGES . '_blank.png');
  52. /*
  53. * page format
  54. */
  55. define('PDF_PAGE_FORMAT', 'A4');
  56. /*
  57. * page orientation (P=portrait, L=landscape)
  58. */
  59. define('PDF_PAGE_ORIENTATION', 'P');
  60. /*
  61. * document creator
  62. */
  63. define('PDF_CREATOR', 'TCPDF');
  64. /*
  65. * document author
  66. */
  67. define('PDF_AUTHOR', 'TCPDF');
  68. /*
  69. * header title
  70. */
  71. define('PDF_HEADER_TITLE', 'phpMyFAQ');
  72. /*
  73. * header description string
  74. */
  75. define('PDF_HEADER_STRING', 'by phpMyFAQ - www.phpmyfaq.de');
  76. /*
  77. * image logo
  78. */
  79. define('PDF_HEADER_LOGO', 'tcpdf_logo.jpg');
  80. /*
  81. * header logo image width [mm]
  82. */
  83. define('PDF_HEADER_LOGO_WIDTH', 30);
  84. /*
  85. * document unit of measure [pt=point, mm=millimeter, cm=centimeter, in=inch]
  86. */
  87. define('PDF_UNIT', 'mm');
  88. /*
  89. * header margin
  90. */
  91. define('PDF_MARGIN_HEADER', 5);
  92. /*
  93. * footer margin
  94. */
  95. define('PDF_MARGIN_FOOTER', 10);
  96. /*
  97. * top margin
  98. */
  99. define('PDF_MARGIN_TOP', 27);
  100. /*
  101. * bottom margin
  102. */
  103. define('PDF_MARGIN_BOTTOM', 25);
  104. /*
  105. * left margin
  106. */
  107. define('PDF_MARGIN_LEFT', 15);
  108. /*
  109. * right margin
  110. */
  111. define('PDF_MARGIN_RIGHT', 15);
  112. /*
  113. * default main font name
  114. */
  115. define('PDF_FONT_NAME_MAIN', 'arialunicid0');
  116. /*
  117. * default main font size
  118. */
  119. define('PDF_FONT_SIZE_MAIN', 10);
  120. /*
  121. * default data font name
  122. */
  123. define('PDF_FONT_NAME_DATA', 'arialunicid0');
  124. /*
  125. * default data font size
  126. */
  127. define('PDF_FONT_SIZE_DATA', 8);
  128. /*
  129. * default monospaced font name
  130. */
  131. define('PDF_FONT_MONOSPACED', 'courier');
  132. /*
  133. * ratio used to adjust the conversion of pixels to user units
  134. */
  135. define('PDF_IMAGE_SCALE_RATIO', 1);
  136. /*
  137. * magnification factor for titles
  138. */
  139. define('HEAD_MAGNIFICATION', 1.1);
  140. /*
  141. * height of cell repect font height
  142. */
  143. define('K_CELL_HEIGHT_RATIO', 1.25);
  144. /*
  145. * title magnification respect main font size
  146. */
  147. define('K_TITLE_MAGNIFICATION', 1.3);
  148. /*
  149. * reduction factor for small font
  150. */
  151. define('K_SMALL_RATIO', 2 / 3);
  152. /**
  153. * Class Wrapper
  154. *
  155. * @package phpMyFAQ\Export\Pdf
  156. */
  157. class Wrapper extends TCPDF
  158. {
  159. /**
  160. * With or without bookmarks.
  161. *
  162. * @var bool
  163. */
  164. public $enableBookmarks = false;
  165. /**
  166. * Full export from admin backend?
  167. *
  168. * @var bool
  169. */
  170. public $isFullExport = false;
  171. /**
  172. * Categories.
  173. *
  174. * @var array
  175. */
  176. public $categories = [];
  177. /**
  178. * The current category.
  179. */
  180. public $category = null;
  181. /**
  182. * The current faq.
  183. *
  184. * @var array
  185. */
  186. public $faq = [];
  187. /**
  188. * Configuration.
  189. *
  190. * @var Configuration
  191. */
  192. protected $config = null;
  193. /**
  194. * Question.
  195. *
  196. * @var string
  197. */
  198. private $question = '';
  199. /**
  200. * Font files.
  201. *
  202. * @var array
  203. */
  204. private $fontFiles = [
  205. 'zh' => 'arialunicid0',
  206. 'tw' => 'arialunicid0',
  207. 'ja' => 'arialunicid0',
  208. 'ko' => 'arialunicid0',
  209. 'cs' => 'dejavusans',
  210. 'sk' => 'dejavusans',
  211. 'el' => 'arialunicid0',
  212. 'he' => 'arialunicid0',
  213. 'tr' => 'dejavusans',
  214. 'default' => 'dejavusans',
  215. ];
  216. /**
  217. * Current font.
  218. *
  219. * @var string
  220. */
  221. private $currentFont = 'dejavusans';
  222. /**
  223. * @var string
  224. */
  225. private $customHeader;
  226. /**
  227. * @var string
  228. */
  229. private $customFooter;
  230. /**
  231. * Constructor.
  232. */
  233. public function __construct()
  234. {
  235. global $PMF_LANG;
  236. parent::__construct(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
  237. $this->setFontSubsetting(false);
  238. // set image scale factor
  239. $this->setImageScale(PDF_IMAGE_SCALE_RATIO);
  240. // Check on RTL
  241. if ('rtl' == $PMF_LANG['dir']) {
  242. $this->setRTL(true);
  243. }
  244. // Set font
  245. if (array_key_exists($PMF_LANG['metaLanguage'], $this->fontFiles)) {
  246. $this->currentFont = (string)$this->fontFiles[$PMF_LANG['metaLanguage']];
  247. }
  248. }
  249. /**
  250. * Setter for the category name.
  251. *
  252. * @param string $category Entity name
  253. */
  254. public function setCategory($category)
  255. {
  256. $this->category = $category;
  257. }
  258. /**
  259. * Setter for the question.
  260. *
  261. * @param string $question Question
  262. */
  263. public function setQuestion($question = '')
  264. {
  265. $this->question = $question;
  266. }
  267. /**
  268. * Setter for categories array.
  269. *
  270. * @param array $categories Categories
  271. */
  272. public function setCategories(array $categories)
  273. {
  274. $this->categories = $categories;
  275. }
  276. /**
  277. * @param Configuration $config
  278. */
  279. public function setConfig(Configuration $config)
  280. {
  281. $this->config = $config;
  282. }
  283. /**
  284. * The header of the PDF file.
  285. */
  286. public function Header(): void // phpcs:ignore
  287. {
  288. // Set custom header and footer
  289. $this->setCustomHeader();
  290. if (array_key_exists($this->category, $this->categories)) {
  291. $title = $this->categories[$this->category]['name'];
  292. } else {
  293. $title = '';
  294. }
  295. $this->SetTextColor(0, 0, 0);
  296. $this->SetFont($this->currentFont, 'B', 18);
  297. if (0 < Strings::strlen($this->customHeader)) {
  298. $this->writeHTMLCell(0, 0, '', '', $this->customHeader);
  299. $this->Ln();
  300. $this->writeHTMLCell(0, 0, '', '', html_entity_decode($title, ENT_QUOTES, 'utf-8'), 0, 0, false, true, 'C');
  301. } else {
  302. $this->MultiCell(0, 10, html_entity_decode($title, ENT_QUOTES, 'utf-8'), 0, 'C', 0);
  303. $this->SetMargins(PDF_MARGIN_LEFT, $this->getLastH() + 5, PDF_MARGIN_RIGHT);
  304. }
  305. }
  306. /**
  307. * Sets custom header.
  308. */
  309. public function setCustomHeader()
  310. {
  311. $this->customHeader = html_entity_decode($this->config->get('main.customPdfHeader'), ENT_QUOTES, 'utf-8');
  312. }
  313. /**
  314. * The footer of the PDF file.
  315. * @throws Exception
  316. */
  317. public function Footer(): void // phpcs:ignore
  318. {
  319. global $PMF_LANG;
  320. // Set custom footer
  321. $this->setCustomFooter();
  322. $date = new Date($this->config);
  323. $footer = sprintf(
  324. '(c) %d %s <%s> | %s',
  325. date('Y'),
  326. $this->config->get('main.metaPublisher'),
  327. $this->config->getAdminEmail(),
  328. $date->format(date('Y-m-d H:i'))
  329. );
  330. if (0 < Strings::strlen($this->customFooter)) {
  331. $this->writeHTMLCell(0, 0, '', '', $this->customFooter);
  332. }
  333. $currentTextColor = $this->TextColor;
  334. $this->SetTextColor(0, 0, 0);
  335. $this->SetY(-25);
  336. $this->SetFont($this->currentFont, '', 10);
  337. $this->Cell(
  338. 0,
  339. 10,
  340. $PMF_LANG['ad_gen_page'] . ' ' . $this->getAliasNumPage() . ' / ' . $this->getAliasNbPages(),
  341. 0,
  342. 0,
  343. 'C'
  344. );
  345. $this->SetY(-20);
  346. $this->SetFont($this->currentFont, 'B', 8);
  347. $this->Cell(0, 10, $footer, 0, 1, 'C');
  348. if ($this->enableBookmarks == false) {
  349. $this->SetY(-15);
  350. $this->SetFont($this->currentFont, '', 8);
  351. $baseUrl = 'index.php';
  352. if (is_array($this->faq) && !empty($this->faq)) {
  353. $baseUrl .= '?action=faq&amp;';
  354. if (array_key_exists($this->category, $this->categories)) {
  355. $baseUrl .= 'cat=' . $this->categories[$this->category]['id'];
  356. } else {
  357. $baseUrl .= 'cat=0';
  358. }
  359. $baseUrl .= '&amp;id=' . $this->faq['id'];
  360. $baseUrl .= '&amp;artlang=' . $this->faq['lang'];
  361. }
  362. $url = $this->config->getDefaultUrl() . $baseUrl;
  363. $urlObj = new Link($url, $this->config);
  364. $urlObj->itemTitle = $this->question;
  365. $_url = str_replace('&amp;', '&', $urlObj->toString());
  366. $this->Cell(0, 10, 'URL: ' . $_url, 0, 1, 'C', 0, $_url);
  367. }
  368. $this->TextColor = $currentTextColor;
  369. }
  370. /**
  371. * Sets custom footer.
  372. */
  373. public function setCustomFooter()
  374. {
  375. $this->customFooter = $this->config->get('main.customPdfFooter');
  376. }
  377. /**
  378. * Adds a table of content for exports of the complete FAQ.
  379. */
  380. public function addFaqToc()
  381. {
  382. global $PMF_LANG;
  383. $this->addTOCPage();
  384. // Title
  385. $this->SetFont($this->currentFont, 'B', 24);
  386. $this->MultiCell(0, 0, $this->config->getTitle(), 0, 'C', 0, 1, '', '', true, 0);
  387. $this->Ln();
  388. // TOC
  389. $this->SetFont($this->currentFont, 'B', 16);
  390. $this->MultiCell(0, 0, $PMF_LANG['msgTableOfContent'], 0, 'C', 0, 1, '', '', true, 0);
  391. $this->Ln();
  392. $this->SetFont($this->currentFont, '', 12);
  393. // Render TOC
  394. $this->addTOC(1, $this->currentFont, '.', $PMF_LANG['msgTableOfContent'], 'B', array(128, 0, 0));
  395. $this->endTOCPage();
  396. }
  397. /**
  398. * Returns the current font for PDF export.
  399. *
  400. * @return string
  401. */
  402. public function getCurrentFont()
  403. {
  404. return $this->currentFont;
  405. }
  406. /**
  407. * Sets the FAQ array.
  408. *
  409. * @param array $faq
  410. */
  411. public function setFaq(array $faq)
  412. {
  413. $this->faq = $faq;
  414. }
  415. /**
  416. * Extends the TCPDF::Image() method to handle base64 encoded images.
  417. *
  418. * @param string $file Name of the file containing the image or a '@' character followed by the image data
  419. * string. To link an image without embedding it on the document, set an asterisk
  420. * character before the URL (i.e.: '*http://www.example.com/image.jpg').
  421. * @param string $x Abscissa of the upper-left corner (LTR) or upper-right corner (RTL).
  422. * @param string $y Ordinate of the upper-left corner (LTR) or upper-right corner (RTL).
  423. * @param int $w Width of the image in the page. If not specified or equal to zero, it is automatically
  424. * calculated.
  425. * @param int $h Height of the image in the page. If not specified or equal to zero, it is automatically
  426. * calculated.
  427. * @param string $type Image format. Possible values are (case insensitive): JPEG and PNG (whitout GD library)
  428. * and all images supported by GD: GD, GD2, GD2PART, GIF, JPEG, PNG, BMP, XBM, XPM;. If
  429. * not specified, the type is inferred from the file extension.
  430. * @param string $link URL or identifier returned by AddLink().
  431. * @param string $align Indicates the alignment of the pointer next to image insertion relative to image height.
  432. * @param bool $resize If true resize (reduce) the image to fit $w and $h (requires GD or ImageMagick library);
  433. * if false do not resize; if 2 force resize in all cases (upscaling and downscaling).
  434. * @param int $dpi dot-per-inch resolution used on resize
  435. * @param string $palign Allows to center or align the image on the current line.
  436. * @param bool $ismask true if this image is a mask, false otherwise
  437. * @param mixed $imgmask Image object returned by this function or false
  438. * @param int $border Indicates if borders must be drawn around the cell.
  439. * @param mixed $fitbox If not false scale image dimensions proportionally to fit within the ($w, $h) box.
  440. * $fitbox can be true or a 2 characters string indicating the image alignment inside
  441. * the box. The first character indicate the horizontal alignment (L = left, C =
  442. * center, R = right) the second character indicate the vertical algnment (T = top, M
  443. * = middle, B = bottom).
  444. * @param bool $hidden If true do not display the image.
  445. * @param bool $fitonpage If true the image is resized to not exceed page dimensions.
  446. * @param bool $alt If true the image will be added as alternative and not directly printed (the ID of the
  447. * image will be returned).
  448. * @param array $altimgs Array of alternate images IDs. Each alternative image must be an array with two values:
  449. * an integer representing the image ID (the value returned by the Image method) and a
  450. * boolean value to indicate if the image is the default for printing.
  451. * @return void
  452. */
  453. public function Image(// phpcs:ignore
  454. $file,
  455. $x = '',
  456. $y = '',
  457. $w = 0,
  458. $h = 0,
  459. $type = '',
  460. $link = '',
  461. $align = '',
  462. $resize = false,
  463. $dpi = 300,
  464. $palign = '',
  465. $ismask = false,
  466. $imgmask = false,
  467. $border = 0,
  468. $fitbox = false,
  469. $hidden = false,
  470. $fitonpage = false,
  471. $alt = false,
  472. $altimgs = []
  473. ): void {
  474. if (!strpos($file, 'data:image/png;base64,') === false) {
  475. $file = '@' . base64_decode(
  476. chunk_split(str_replace(' ', '+', str_replace('data:image/png;base64,', '', $file)))
  477. );
  478. }
  479. parent::Image(
  480. $file,
  481. $x,
  482. $y,
  483. $w,
  484. $h,
  485. $type,
  486. $link,
  487. $align,
  488. $resize,
  489. $dpi,
  490. $palign,
  491. $ismask,
  492. $imgmask,
  493. $border,
  494. $fitbox,
  495. $hidden,
  496. $fitonpage,
  497. $alt,
  498. $altimgs
  499. );
  500. }
  501. }